diff --git a/meson.build b/meson.build index 5aa968ec..2881b66c 100644 --- a/meson.build +++ b/meson.build @@ -156,8 +156,7 @@ openrtx_def += {'GIT_VERSION': git_version} ## TYT MDx family ## -mdx_src = ['platform/drivers/GPS/GPS_MDx.cpp', - 'platform/drivers/NVM/W25Qx.c', +mdx_src = ['platform/drivers/NVM/W25Qx.c', 'platform/drivers/NVM/nvmem_settings_MDx.c', 'platform/drivers/NVM/nvmem_MDx.c', 'platform/drivers/audio/audio_MDx.cpp', @@ -386,6 +385,7 @@ md3x0_src = ['platform/drivers/CPS/cps_io_native_MD3x0.c', 'platform/drivers/keyboard/keyboard_MD3x.c', 'platform/drivers/display/HX8353_MD3x.cpp', 'platform/drivers/backlight/backlight_MDx.c', + 'platform/drivers/GPS/GPS_MDx.cpp', 'platform/targets/MD-3x0/platform.c', 'platform/targets/MD-3x0/hwconfig.c'] @@ -402,6 +402,7 @@ md3x0_def += openrtx_def + stm32f405_def mduv3x0_src = ['platform/drivers/CPS/cps_io_native_MDUV3x0.c', 'platform/targets/MD-UV3x0/platform.c', 'platform/targets/MD-UV3x0/hwconfig.c', + 'platform/drivers/GPS/GPS_MDx.cpp', 'platform/drivers/keyboard/keyboard_MD3x.c', 'platform/drivers/display/HX8353_MD3x.cpp', 'platform/drivers/backlight/backlight_MDx.c', @@ -544,6 +545,28 @@ cs7000p_src += openrtx_src + stm32h743_src + miosix_cm7_src + ui_src_default cs7000p_inc += openrtx_inc + stm32h743_inc + miosix_cm7_inc cs7000p_def += openrtx_def + stm32h743_def + miosix_cm7_def +## +## Baofeng DM-1701 +## +dm1701_src = ['platform/targets/DM-1701/platform.c', + 'platform/targets/DM-1701/hwconfig.c', + 'platform/drivers/keyboard/keyboard_DM1701.c', + 'platform/drivers/CPS/cps_io_native_MDUV3x0.c', + 'platform/drivers/display/HX8353_MD3x.cpp', + 'platform/drivers/backlight/backlight_MDx.c', + 'platform/drivers/chSelector/chSelector_UV3x0.c', + 'platform/drivers/audio/Cx000_dac.cpp', + 'platform/drivers/baseband/radio_UV3x0.cpp', + 'platform/drivers/baseband/AT1846S_UV3x0.cpp', + 'platform/drivers/baseband/HR_C6000_UV3x0.cpp'] + +dm1701_inc = ['platform/targets/DM-1701'] +dm1701_def = {'PLATFORM_DM1701': '', 'timegm': 'mktime'} + +dm1701_src += openrtx_src + stm32f405_src + ui_src_default + mdx_src +dm1701_inc += openrtx_inc + stm32f405_inc +dm1701_def += openrtx_def + stm32f405_def + ## ## -------------------------- Compilation arguments ---------------------------- ## @@ -657,6 +680,15 @@ foreach k, v : cs7000p_def endif endforeach +dm1701_args = [] +foreach k, v : dm1701_def + if v == '' + dm1701_args += '-D@0@'.format(k) + else + dm1701_args += '-D@0@=@1@'.format(k, v) + endif +endforeach + linux_opts = { 'sources' : linux_default_src, 'include_directories': linux_inc, @@ -766,6 +798,15 @@ cs7000p_opts = { '-Wl,--print-memory-usage'] } +dm1701_opts = { + 'sources' : dm1701_src, + 'include_directories': dm1701_inc, + 'dependencies' : [codec2_dep], + 'c_args' : dm1701_args, + 'cpp_args' : dm1701_args, + 'link_args' : ['-Wl,-T../platform/mcu/STM32F4xx/linker_script_MDx.ld'] +} + ## ## ---------------------------- Compilation targets ---------------------------- ## @@ -849,6 +890,13 @@ targets = [ 'wrap' : ' ', 'load_addr': '0x08100000' }, + { + 'name' : 'dm1701', + 'opts' : dm1701_opts, + 'flashable': true, + 'wrap' : 'DM1701', + 'load_addr': '0x0800C000' + }, ] if build_machine.system() == 'linux' diff --git a/platform/drivers/backlight/backlight_MDx.c b/platform/drivers/backlight/backlight_MDx.c index 37cd4afd..f2a365bc 100644 --- a/platform/drivers/backlight/backlight_MDx.c +++ b/platform/drivers/backlight/backlight_MDx.c @@ -53,7 +53,7 @@ void _Z29TIM1_TRG_COM_TIM11_IRQHandlerv() void backlight_init() { - #ifndef PLATFORM_MDUV3x0 /* MD-3x0 and MD-9600 */ + #if !defined(PLATFORM_MDUV3x0) && !defined(PLATFORM_DM1701) /* MD-3x0 and MD-9600 */ gpio_setMode(LCD_BKLIGHT, ALTERNATE | ALTERNATE_FUNC(3)); /* @@ -136,7 +136,7 @@ void display_setBacklightLevel(uint8_t level) uint8_t pwmLevel = (2 * level) + (level * 55)/100; // Convert value to 0 - 255 - #ifndef PLATFORM_MDUV3x0 + #if !defined(PLATFORM_MDUV3x0) && !defined(PLATFORM_DM1701) TIM8->CCR1 = pwmLevel; #else /* diff --git a/platform/targets/DM-1701/hwconfig.c b/platform/targets/DM-1701/hwconfig.c new file mode 100644 index 00000000..6967315e --- /dev/null +++ b/platform/targets/DM-1701/hwconfig.c @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2023 - 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO * + * 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 +#include + +static pthread_mutex_t c6000_mutex; +static pthread_mutex_t adcMutex; + +/** + * SPI bitbang function for HR_C6000 command interface (U_SPI). + * + * Hand-tuned to be as fast as possible, gives the following clock performance + * when compiled with -Os and run on STM32F405 at 168MHz: + * + * - Freq 6.46MHz + * - Pos. width 71ns + * - Neg. with 83ns + */ +static uint8_t spiC6000_func(const void *priv, uint8_t value) +{ + (void) priv; + uint8_t incoming = 0; + + __disable_irq(); + + for(uint8_t cnt = 0; cnt < 8; cnt++) + { + GPIOE->BSRR = (1 << 3); // Set PE3 (CLK) + + if(value & (0x80 >> cnt)) + GPIOE->BSRR = 1 << 4; // Set PE4 (MOSI) + else + GPIOE->BSRR = 1 << 20; // Clear PE4 (MOSI) + + // ~70ns delay + asm volatile(" mov r1, #1 \n" + "___loop_1: cmp r1, #0 \n" + " itt ne \n" + " subne r1, r1, #1 \n" + " bne ___loop_1 \n":::"r1"); + + incoming <<= 1; + GPIOE->BSRR = (1 << 19); // Clear PE3 (CLK) + incoming |= (GPIOE->IDR >> 5) & 0x01; // Read PE5 (MISO) + } + + __enable_irq(); + + return incoming; +} + +SPI_CUSTOM_DEVICE_DEFINE(c6000_spi, spiC6000_func, NULL, &c6000_mutex) +SPI_STM32_DEVICE_DEFINE(nvm_spi, SPI1, NULL) +ADC_STM32_DEVICE_DEFINE(adc1, ADC1, &adcMutex, ADC_COUNTS_TO_UV(3300000, 12)) diff --git a/platform/targets/DM-1701/hwconfig.h b/platform/targets/DM-1701/hwconfig.h new file mode 100644 index 00000000..aa956e72 --- /dev/null +++ b/platform/targets/DM-1701/hwconfig.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2023 - 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO * + * 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 + +// Export the HR_C6000 driver only for C++ sources +#include + +extern HR_C6000 C6000; + +extern "C" { +#endif + +enum AdcChannel +{ + ADC_VOL_CH = 0, + ADC_VBAT_CH = 1, + ADC_MIC_CH = 3, +}; + +extern const struct spiCustomDevice c6000_spi; +extern const struct spiDevice nvm_spi; +extern const struct Adc adc1; + +/* Device has a working real time clock */ +#define CONFIG_RTC + +/* Screen dimensions */ +#define CONFIG_SCREEN_WIDTH 160 +#define CONFIG_SCREEN_HEIGHT 128 + +/* Screen pixel format */ +#define CONFIG_PIX_FMT_RGB565 + +/* Battery type */ +#define CONFIG_BAT_LIPO_2S + +/* Device supports M17 mode */ +#define CONFIG_M17 + +/* + * To enable pwm for display backlight dimming uncomment this directive. + * + * WARNING: backlight pwm is disabled by default because it generates a + * continuous tone in the speaker and headphones. + * + * This issue cannot be solved in any way because it derives from how the + * MD-UV380 mcu pins are used: to have a noiseless backlight pwm, the control + * pin has to be connected to a mcu pin having between its alternate functions + * an output compare channel of one of the timers. With this configuration, the + * pwm signal can completely generated in hardware and its frequency can be well + * above 22kHz, which is the upper limit for human ears. + * + * In the MD-UV380 radio, display backlight is connected to PD8, which is not + * connected to any of the available output compare channels. Thus, the pwm + * signal generation is managed inside the TIM11 ISR by toggling the backlight + * pin and its frequency has to be low (~250Hz) to not put too much overehad on + * the processor due to timer ISR triggering at an high rate. + * + * #define CONFIG_SCREEN_BRIGHTNESS + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/targets/DM-1701/pinmap.h b/platform/targets/DM-1701/pinmap.h new file mode 100644 index 00000000..6f92e7c9 --- /dev/null +++ b/platform/targets/DM-1701/pinmap.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO, * + * 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 keep switch */ +#define PWR_SW GPIOA,7 + +/* Display */ +#define LCD_D0 GPIOD,14 +#define LCD_D1 GPIOD,15 +#define LCD_D2 GPIOD,0 +#define LCD_D3 GPIOD,1 +#define LCD_D4 GPIOE,7 +#define LCD_D5 GPIOE,8 +#define LCD_D6 GPIOE,9 +#define LCD_D7 GPIOE,10 +#define LCD_WR GPIOD,5 +#define LCD_RD GPIOD,4 +#define LCD_CS GPIOD,6 +#define LCD_RS GPIOD,12 +#define LCD_RST GPIOD,13 +#define LCD_BKLIGHT GPIOD,8 + +/* Signalling LEDs */ +#define GREEN_LED GPIOE,0 +#define RED_LED GPIOE,1 + +/* Analog inputs */ +#define AIN_VOLUME GPIOA,0 +#define AIN_VBAT GPIOA,1 +#define AIN_MIC GPIOA,3 +#define AIN_RTX GPIOC,3 + +/* Channel selection rotary encoder */ +#define CH_SELECTOR_0 GPIOE,14 +#define CH_SELECTOR_1 GPIOB,11 + +/* Push-to-talk switch */ +#define PTT_SW GPIOE,11 +#define PTT_EXT GPIOE,12 + +#define KB_ROW1 GPIOA,6 /* K1 */ +#define KB_ROW2 GPIOD,2 /* K2 */ +#define KB_ROW3 GPIOD,3 /* K3 */ +#define MONI_SW LCD_D6 +#define FUNC_SW LCD_D7 + +/* Tone generator */ +#define CTCSS_OUT GPIOC,7 /* System "beep" */ +#define BEEP_OUT GPIOC,8 /* CTCSS tone */ + +/* External flash */ +#define FLASH_CS &GpioD,7 +#define FLASH_CLK GPIOB,3 +#define FLASH_SDO GPIOB,4 +#define FLASH_SDI GPIOB,5 + +/* Audio control */ +#define AUDIO_AMP_EN GPIOB,9 +#define SPK_MUTE GPIOB,8 +#define MIC_PWR GPIOA,13 + +/* RTX stage control */ +#define VHF_LNA_EN GPIOA,5 +#define UHF_LNA_EN GPIOA,2 +#define TX_PA_EN GPIOC,5 +#define RF_APC_SW GPIOC,4 +#define PA_SEL_SW GPIOC,6 +#define APC_REF GPIOA,4 + +/* I2C for AT1846S */ +#define I2C_SDA GPIOC,9 +#define I2C_SCL GPIOA,8 + +/* HR_C6000 control interface */ +#define DMR_SLEEP GPIOE,6 +#define DMR_CS &GpioE,2 +#define DMR_CLK GPIOE,3 +#define DMR_MOSI GPIOE,4 +#define DMR_MISO GPIOE,5 + +#endif /* PINMAP_H */ diff --git a/platform/targets/DM-1701/platform.c b/platform/targets/DM-1701/platform.c new file mode 100644 index 00000000..c2a90099 --- /dev/null +++ b/platform/targets/DM-1701/platform.c @@ -0,0 +1,237 @@ +/*************************************************************************** + * Copyright (C) 2023 - 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO * + * 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 +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_BKLIGHT_DIMMING +#include +#endif + +static const hwInfo_t hwInfo = +{ + .vhf_maxFreq = 174, + .vhf_minFreq = 136, + .vhf_band = 1, + .uhf_maxFreq = 470, + .uhf_minFreq = 400, + .uhf_band = 1, + .hw_version = 0, + .name = "DM-1701" +}; + + +void platform_init() +{ + /* Configure GPIOs */ + gpio_setMode(GREEN_LED, OUTPUT); + gpio_setMode(RED_LED, OUTPUT); + + gpio_setMode(PTT_SW, INPUT_PULL_UP); + gpio_setMode(PTT_EXT, INPUT_PULL_UP); + + #ifndef RUNNING_TESTSUITE + gpio_setMode(PWR_SW, OUTPUT); + gpio_setPin(PWR_SW); + #endif + + adcStm32_init(&adc1); + + nvm_init(); /* Initialise non volatile memory manager */ + toneGen_init(); /* Initialise tone generator */ + rtc_init(); /* Initialise RTC */ + chSelector_init(); /* Initialise channel selector handler */ + audio_init(); /* Initialise audio management module */ + + #ifdef ENABLE_BKLIGHT_DIMMING + backlight_init(); /* Initialise backlight driver */ + #else + gpio_setMode(LCD_BKLIGHT, OUTPUT); + gpio_clearPin(LCD_BKLIGHT); + #endif +} + +void platform_terminate() +{ + /* Shut down backlight */ + #ifdef ENABLE_BKLIGHT_DIMMING + backlight_terminate(); + #else + gpio_clearPin(LCD_BKLIGHT); + #endif + + /* Shut down LEDs */ + gpio_clearPin(GREEN_LED); + gpio_clearPin(RED_LED); + + /* Shut down all the modules */ + adcStm32_init(&adc1); + nvm_terminate(); + toneGen_terminate(); + chSelector_terminate(); + audio_terminate(); + + /* Finally, remove power supply */ + gpio_clearPin(PWR_SW); +} + +uint16_t platform_getVbat() +{ + /* + * Battery voltage is measured through an 1:3.26 voltage divider and + * adc_getVoltage returns a value in uV. + */ + uint32_t vbat = adc_getVoltage(&adc1, ADC_VBAT_CH) * 326; + return vbat / 100000; +} + +uint8_t platform_getMicLevel() +{ + /* Value from ADC is 12 bit wide: shift right by four to get 0 - 255 */ + return adc_getRawSample(&adc1, ADC_MIC_CH) >> 4; +} + +uint8_t platform_getVolumeLevel() +{ + /* + * Volume level corresponds to an analog signal in the range 20 - 1650mV. + * Potentiometer has pseudo-logarithmic law, well described with two straight + * lines with a breakpoint around 270mV. + * Output value has range 0 - 255 with breakpoint at 150. + */ + uint16_t value = adc_getVoltage(&adc1, ADC_VOL_CH) / 1000; + uint32_t output; + + if(value < 20) + return 0; + + if(value <= 270) + { + // First line: offset zero, slope 0.556 + output = value; + output = (output * 556) / 1000; + } + else + { + // Second line: offset 270, slope 0.076 + output = value - 270; + output = (output * 76) / 1000; + output += 150; + } + + if(output > 255) + output = 255; + + return output; +} + +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: + gpio_setPin(GREEN_LED); + break; + + case RED: + gpio_setPin(RED_LED); + break; + + default: + break; + } +} + +void platform_ledOff(led_t led) +{ + switch(led) + { + case GREEN: + gpio_clearPin(GREEN_LED); + break; + + case RED: + gpio_clearPin(RED_LED); + break; + + default: + break; + } +} + +void platform_beepStart(uint16_t freq) +{ + Cx000dac_startBeep(freq); +} + +void platform_beepStop() +{ + Cx000dac_stopBeep(); +} + +datetime_t platform_getCurrentTime() +{ + return rtc_getTime(); +} + +void platform_setTime(datetime_t t) +{ + rtc_setTime(t); +} + +const hwInfo_t *platform_getHwInfo() +{ + return &hwInfo; +} + +/* + * NOTE: implementation of this API function is provided in + * platform/drivers/chSelector/chSelector_UV3x0.c + */ +// int8_t platform_getChSelector()