From 4a76d67184f810532e730d5fb2be4760ca7a5833 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Sat, 13 Apr 2024 11:02:00 +0200 Subject: [PATCH] Build target for Connect Systems CS7000 --- meson.build | 67 ++++++++++- platform/targets/CS7000/hwconfig.c | 61 ++++++++++ platform/targets/CS7000/hwconfig.h | 51 +++++++++ platform/targets/CS7000/pinmap.h | 173 +++++++++++++++++++++++++++++ platform/targets/CS7000/platform.c | 160 ++++++++++++++++++++++++++ scripts/dfu-convert.py | 140 +++++++++++++++++++++++ 6 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 platform/targets/CS7000/hwconfig.c create mode 100644 platform/targets/CS7000/hwconfig.h create mode 100644 platform/targets/CS7000/pinmap.h create mode 100644 platform/targets/CS7000/platform.c create mode 100755 scripts/dfu-convert.py diff --git a/meson.build b/meson.build index 65fc422c..9df1ed87 100644 --- a/meson.build +++ b/meson.build @@ -454,6 +454,28 @@ mod17_src += openrtx_src + stm32f405_src + ui_src_module17 mod17_inc += openrtx_inc + stm32f405_inc mod17_def += openrtx_def + stm32f405_def +## +## Connect Systems CS70000 +## +cs7000_src = ['platform/drivers/stubs/nvmem_stub.c', + 'platform/drivers/stubs/cps_io_stub.c', + 'platform/drivers/stubs/radio_stub.c', + 'platform/drivers/stubs/keyboard_stub.c', + 'platform/drivers/stubs/display_stub.c', + 'platform/drivers/stubs/audio_stub.c', + 'platform/drivers/GPIO/gpio_shiftReg.c', + 'platform/drivers/SPI/spi_custom.c', + 'platform/drivers/SPI/spi_bitbang.c', + 'platform/targets/CS7000/hwconfig.c', + 'platform/targets/CS7000/platform.c'] + +cs7000_inc = ['platform/targets/CS7000'] +cs7000_def = {'PLATFORM_CS7000': '', 'timegm': 'mktime'} + +cs7000_src += openrtx_src + stm32f405_src + ui_src_default +cs7000_inc += openrtx_inc + stm32f405_inc +cs7000_def += openrtx_def + stm32f405_def + ## ## -------------------------- Compilation arguments ---------------------------- ## @@ -549,6 +571,15 @@ foreach k, v : mod17_def endif endforeach +cs7000_args = [] +foreach k, v : cs7000_def + if v == '' + cs7000_args += '-D@0@'.format(k) + else + cs7000_args += '-D@0@=@1@'.format(k, v) + endif +endforeach + linux_opts = { 'sources' : linux_default_src, 'include_directories': linux_inc, @@ -639,6 +670,15 @@ ttwrplus_opts = { 'link_args' : [], } +cs7000_opts = { + 'sources' : cs7000_src, + 'include_directories': cs7000_inc, + 'dependencies' : [codec2_dep], + 'c_args' : cs7000_args, + 'cpp_args' : cs7000_args, + 'link_args' : ['-Wl,-T../platform/mcu/STM32F4xx/stm32_1m+192k_rom.ld'] +} + ## ## ---------------------------- Compilation targets ---------------------------- ## @@ -708,6 +748,13 @@ targets = [ 'wrap' : ' ', 'load_addr': ' ' }, + { + 'name' : 'cs7000', + 'opts' : cs7000_opts, + 'flashable': true, + 'wrap' : ' ', + 'load_addr': '0x08000000' + }, ] if build_machine.system() == 'linux' @@ -724,6 +771,7 @@ gd77_loader = find_program('scripts/gd-77_firmware_loader.py', required:false, d dfu_util = find_program('dfu-util', required:false, disabler:true) west = find_program('west', required:false, disabler:true) uf2conv = find_program('scripts/uf2conv.py', required:false, disabler:true) +dfu_convert = find_program('scripts/dfu-convert.py', required:false, disabler:true) foreach t : targets @@ -816,7 +864,7 @@ foreach t : targets output : name+'_flash', command : [gd77_loader, '-f', '@INPUT@', '-m', t['wrap']]) - # Module17 also uses dfu-tool for flashing + # Module17 uses dfu-tool for flashing elif name == 'openrtx_mod17' # Wrap target for Module17 for consistency, same output as bin target @@ -835,6 +883,23 @@ foreach t : targets '-D', '@INPUT@', '-s', '0x08000000']) + # For CS7000 'wrap' target prepares a .dfu file + elif name == 'openrtx_cs7000' + + custom_target(name+'_wrap', + output : name+'.dfu', + input : bin, + command : [dfu_convert, '-b', t['load_addr']+':@INPUT@', '@OUTPUT@']) + + + custom_target(name+'_flash', + input : bin, + output : name+'_flash', + command : [dfu_util, + '-d', '0483:df11', + '-a', '0', + '-D', '@INPUT@', + '-s', t['load_addr']]) else wrap = custom_target(name+'_wrap', diff --git a/platform/targets/CS7000/hwconfig.c b/platform/targets/CS7000/hwconfig.c new file mode 100644 index 00000000..dc251b42 --- /dev/null +++ b/platform/targets/CS7000/hwconfig.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2024 by Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include + +/** + * SPI bitbang function for SN74HC595 gpio extender. + * + * Hand-tuned to be as fast as possible, gives the following clock performance + * when compiled with -Os and run on STM32F405 at 168MHz: + * + * - Freq 8.46MHz + * - Pos. width 36ns + * - Neg. with 82ns + */ +static uint8_t spiSr_func(const void *priv, uint8_t value) +{ + (void) priv; + + for(uint8_t cnt = 0; cnt < 8; cnt++) + { + GPIOE->BSRR = (1 << 23); // Clear PE7 (CLK) + + if(value & (0x80 >> cnt)) + GPIOE->BSRR = 1 << 9; // Set PE9 (MOSI) + else + GPIOE->BSRR = 1 << 25; // Clear PE9 (MOSI) + + // ~70ns delay + asm volatile(" mov r1, #1 \n" + "___loop_2: cmp r1, #0 \n" + " itt ne \n" + " subne r1, r1, #1 \n" + " bne ___loop_2 \n":::"r1"); + + GPIOE->BSRR = (1 << 7); // Set PE7 (CLK) + } + + return 0; +} + +static const struct gpioPin shiftRegStrobe = { GPIOEXT_STR }; + +SPI_CUSTOM_DEVICE_DEFINE(spiSr, spiSr_func, NULL, NULL) +GPIO_SHIFTREG_DEVICE_DEFINE(extGpio, (const struct spiDevice *) &spiSr, shiftRegStrobe, 24) diff --git a/platform/targets/CS7000/hwconfig.h b/platform/targets/CS7000/hwconfig.h new file mode 100644 index 00000000..9e7efadf --- /dev/null +++ b/platform/targets/CS7000/hwconfig.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2024 by Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef HWCONFIG_H +#define HWCONFIG_H + +#include +#include "pinmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct spiCustomDevice spiSr; +extern const struct gpioDev extGpio; + +/* Screen dimensions */ +#define CONFIG_SCREEN_WIDTH 160 +#define CONFIG_SCREEN_HEIGHT 128 + +/* Screen pixel format */ +#define CONFIG_PIX_FMT_RGB565 + +/* Screen has adjustable brightness */ +#define CONFIG_SCREEN_BRIGHTNESS + +/* Battery type */ +#define CONFIG_BAT_LIPO_2S + +/* Device supports M17 mode */ +#define CONFIG_M17 + +#ifdef __cplusplus +} +#endif + +#endif /* HWCONFIG_H */ diff --git a/platform/targets/CS7000/pinmap.h b/platform/targets/CS7000/pinmap.h new file mode 100644 index 00000000..595d3179 --- /dev/null +++ b/platform/targets/CS7000/pinmap.h @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (C) 2024 by Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef PINMAP_H +#define PINMAP_H + +#include + +/* Power control */ +#define BAT_DETECT GPIOB,2 +#define MAIN_PWR_DET GPIOA,6 +#define MAIN_PWR_SW &extGpio,20 + +/* Display */ +#define LCD_D0 GPIOD,0 +#define LCD_D1 GPIOD,1 +#define LCD_D2 GPIOD,2 +#define LCD_D3 GPIOD,3 +#define LCD_D4 GPIOD,4 +#define LCD_D5 GPIOD,5 +#define LCD_D6 GPIOD,6 +#define LCD_D7 GPIOD,7 +#define LCD_WR GPIOD,13 +#define LCD_RD GPIOD,14 +#define LCD_DC GPIOD,12 +#define LCD_RST GPIOE,0 +#define LCD_CS GPIOE,1 +#define LCD_BKLIGHT GPIOC,9 + +/* + * Keyboard. Rows and columns, except for column 5, are shared with the LCD + * data lines. Commens reports the resistor number in the schematic for reference. + */ +#define KB_ROW1 LCD_D0 // R905 +#define KB_ROW2 LCD_D1 // R906 +#define KB_ROW3 LCD_D2 // R907 +#define KB_ROW4 LCD_D3 // R908 +#define KB_COL1 LCD_D7 // R902 +#define KB_COL2 LCD_D6 // R903 +#define KB_COL3 LCD_D5 // R904 +#define KB_COL4 LCD_D4 // R909 +#define KB_COL5 GPIOB,7 // R926 +#define KBD_BKLIGHT &extGpio,16 + +/* Push-to-talk and side keys */ +#define PTT_SW GPIOA,8 +#define PTT_EXT GPIOE,11 +#define SIDE_KEY1 GPIOD,15 +#define SIDE_KEY2 GPIOE,12 +#define SIDE_KEY3 GPIOE,13 +#define ALARM_KEY GPIOE,10 + +/* Channel selection rotary encoder */ +#define CH_SELECTOR_0 GPIOE,14 +#define CH_SELECTOR_1 GPIOE,15 +#define CH_SELECTOR_2 GPIOB,10 +#define CH_SELECTOR_3 GPIOB,11 + +/* LEDs */ +#define GREEN_LED &extGpio,12 +#define RED_LED &extGpio,13 + +/* Analog inputs */ +#define AIN_VOLUME GPIOC,5 +#define AIN_VBAT GPIOC,4 // BATT +#define AIN_MIC GPIOA,3 // VOX +#define AIN_RSSI GPIOB,0 +#define AIN_NOISE GPIOB,1 +#define AIN_RTX GPIOA,7 // 2T/5T +#define AIN_CTCSS GPIOA,2 // QT_DQT_IN +#define AIN_TEMP GPIOA,7 // Batt. temp. + +/* Tone generator */ +#define CTCSS_OUT GPIOC,8 // CTCSS tone +#define BEEP_OUT GPIOA,5 // System "beep" + +/* External flash */ +#define FLASH_CS GPIOE,2 +#define FLASH_CLK GPIOE,3 +#define FLASH_SDO GPIOE,4 +#define FLASH_SDI GPIOE,5 + +/* PLL */ +#define PLL_CS &GpioD,9 +#define PLL_CLK GPIOD,10 +#define PLL_DAT GPIOD,8 +#define PLL_LD GPIOD,11 + +/* HR_C6000 */ +#define C6K_CS &GpioB,12 +#define C6K_CLK GPIOB,13 +#define C6K_MISO GPIOB,14 +#define C6K_MOSI GPIOB,15 +#define C6K_SLEEP &extGpio,7 + +#define VOC_CS GPIOB,6 +#define VOC_CLK GPIOB,3 +#define VOC_MOSI GPIOB,4 +#define VOC_MISO GPIOB,5 + +#define I2S_FS GPIOA,15 +#define I2S_CLK GPIOC,10 +#define I2S_RX GPIOC,11 +#define I2S_TX GPIOC,12 + +#define DMR_TS_INT GPIOC,0 +#define DMR_SYS_INT GPIOC,1 +#define DMR_TX_INT GPIOC,2 + +/* AK2365 */ +#define DET_PDN &extGpio,6 +#define DET_CS &extGpio,0 +#define DET_CLK GPIOE,6 +#define DET_DAT GPIOC,13 +#define DET_RST &GpioC,14 + +/* RTX control */ +#define RF_APC_SW &extGpio,3 +#define VCOVCC_SW &extGpio,8 +#define TX_PWR_EN &extGpio,9 +#define RX_PWR_EN &extGpio,15 +#define VCO_PWR_EN &extGpio,11 +#define CTCSS_AMP_EN &extGpio,22 +#define APC_TV GPIOA,4 + +/* Audio control */ +#define AUDIO_AMP_EN &extGpio,14 +#define INT_SPK_MUTE &extGpio,17 +#define EXT_SPK_MUTE &extGpio,19 +#define MIC_PWR_EN &extGpio,18 +#define INT_MIC_SEL &extGpio,10 +#define EXT_MIC_SEL &extGpio,5 +#define AF_MUTE &extGpio,23 +#define PHONE_DETECT GPIOA,13 + +/* GPS */ +#define GPS_RXD GPIOC,6 +#define GPS_TXD GPIOC,7 + +/* Accessory connector */ +#define PHONE_TXD GPIOA,0 +#define PHONE_RXD GPIOA,1 + +/* SN74HC595 gpio extenders */ +#define GPIOEXT_CLK GPIOE,7 +#define GPIOEXT_DAT GPIOE,9 +#define GPIOEXT_STR &GpioE,8 + +/* Bluetooth module */ +#define BLTH_DETECT GPIOA,14 +#define BLTH_PWR_EN &extGpio,4 +#define BLTH_RXD GPIOA,9 +#define BLTH_TXD GPIOA,10 + +/* ALPU-MP */ +#define ALPU_SDA GPIOB,9 +#define ALPU_SCL GPIOB,8 + +#endif /* PINMAP_H */ diff --git a/platform/targets/CS7000/platform.c b/platform/targets/CS7000/platform.c new file mode 100644 index 00000000..a9938f2f --- /dev/null +++ b/platform/targets/CS7000/platform.c @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (C) 2024 by Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +static const hwInfo_t hwInfo = +{ + .name = "CS7000", + .hw_version = 0, + .vhf_band = 0, + .uhf_band = 1, + .vhf_minFreq = 0, + .vhf_maxFreq = 0, + .uhf_minFreq = 400, + .uhf_maxFreq = 527 +}; + + +void platform_init() +{ + gpio_setMode(PTT_SW, INPUT); + gpio_setMode(PTT_EXT, INPUT); + + gpio_setMode(GPIOEXT_CLK, OUTPUT); + gpio_setMode(GPIOEXT_DAT, OUTPUT); + + spi_init((const struct spiDevice *) &spiSr); + gpioShiftReg_init(&extGpio); + + #ifndef RUNNING_TESTSUITE + gpioDev_set(MAIN_PWR_SW); + #endif +} + +void platform_terminate() +{ + + #ifndef RUNNING_TESTSUITE + gpioDev_clear(MAIN_PWR_SW); + #endif + + gpioShiftReg_terminate(&extGpio); +} + +uint16_t platform_getVbat() +{ + return 7400; // TODO +} + +uint8_t platform_getMicLevel() +{ + return 0; // TODO +} + +uint8_t platform_getVolumeLevel() +{ + return 0; // TODO +} + +int8_t platform_getChSelector() +{ + return 0; // TODO +} + +bool platform_getPttStatus() +{ + /* PTT line has a pullup resistor with PTT switch closing to ground */ + uint8_t intPttStatus = gpio_readPin(PTT_SW); + uint8_t extPttStatus = gpio_readPin(PTT_EXT); + return ((intPttStatus == 0) || (extPttStatus == 0)) ? true : false; +} + +bool platform_pwrButtonStatus() +{ + /* + * When power knob is set to off, battery voltage measurement returns 0V. + * Here we set the threshold to 1V since, with knob in off position, there + * is always a bit of noise in the ADC measurement making the returned + * voltage not to be exactly zero. + */ + return (platform_getVbat() > 1000) ? true : false; +} + +void platform_ledOn(led_t led) +{ + switch(led) + { + case GREEN: + gpioDev_set(GREEN_LED); + break; + + case RED: + gpioDev_set(RED_LED); + break; + + case YELLOW: + gpioDev_set(GREEN_LED); + gpioDev_set(RED_LED); + break; + + default: + break; + } +} + +void platform_ledOff(led_t led) +{ + switch(led) + { + case GREEN: + gpioDev_clear(GREEN_LED); + break; + + case RED: + gpioDev_clear(RED_LED); + break; + + case YELLOW: + gpioDev_clear(GREEN_LED); + gpioDev_clear(RED_LED); + break; + + default: + break; + } +} + +void platform_beepStart(uint16_t freq) +{ + (void) freq; +} + +void platform_beepStop() +{ + +} + +const hwInfo_t *platform_getHwInfo() +{ + return &hwInfo; +} diff --git a/scripts/dfu-convert.py b/scripts/dfu-convert.py new file mode 100755 index 00000000..031b82ad --- /dev/null +++ b/scripts/dfu-convert.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +# Written by Antonio Galea - 2010/11/18 +# Distributed under Gnu LGPL 3.0 +# see http://www.gnu.org/licenses/lgpl-3.0.txt + +import sys,struct,zlib,os +from optparse import OptionParser +from intelhex import IntelHex + +DEFAULT_DEVICE="0x0483:0xdf11" + +def named(tuple,names): + return dict(zip(names.split(),tuple)) +def consume(fmt,data,names): + n = struct.calcsize(fmt) + return named(struct.unpack(fmt,data[:n]),names),data[n:] +def cstring(string): + return string.split('\0',1)[0] +def compute_crc(data): + return 0xFFFFFFFF & -zlib.crc32(data) -1 + +def parse(file, dump_images=False): + print ('File: "%s"' % file) + data = open(file,'rb').read() + crc = compute_crc(data[:-4]) + prefix, data = consume('<5sBIB',data,'signature version size targets') + print ('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) + for t in range(prefix['targets']): + tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') + tprefix['num'] = t + if not tprefix['named']: + tprefix['name'] = '' + print ('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix) + tsize = tprefix['size'] + target, data = data[:tsize], data[tsize:] + for e in range(tprefix['elements']): + eprefix, target = consume('<2I',target,'address size') + eprefix['num'] = e + print (' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix) + esize = eprefix['size'] + image, target = target[:esize], target[esize:] + if dump_images: + out = '%s.target%d.image%d.bin' % (file,t,e) + open(out,'wb').write(image) + print (' DUMPED IMAGE TO "%s"' % out) + if len(target): + print ("target %d: PARSE ERROR" % t) + suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') + print ('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix) + if crc != suffix['crc']: + print ("CRC ERROR: computed crc32 is 0x%08x" % crc) + data = data[16:] + if data: + print ("PARSE ERROR") + +def build(file, targets, device=DEFAULT_DEVICE): + data = b'' + for t,target in enumerate(targets): + tdata = b'' + for image in target: + tdata += struct.pack('<2I',image['address'],len(image['data']))+ image['data'] + tdata = struct.pack('<6sBI255s2I',b'Target',0,1,b'ST...',len(tdata),len(target)) + tdata + data += tdata + data = struct.pack('<5sBIB',b'DfuSe',1,len(data)+11,len(targets)) + data + v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) + data += struct.pack('<4H3sB',0,d,v,0x011a,b'UFD',16) + crc = compute_crc(data) + data += struct.pack('