diff --git a/meson.build b/meson.build
index 7bad9a54..9441ddce 100644
--- a/meson.build
+++ b/meson.build
@@ -134,12 +134,24 @@ md380_src = src + stm32f405_src + ['platform/drivers/display/HX83XX_MDxx380.c',
'platform/drivers/keyboard/keyboard_MDxx380.c',
'platform/drivers/ADC/ADC1_MDxx380.c',
'platform/drivers/tones/toneGenerator_MDxx380.c',
- 'platform/targets/MD380/platform.c',
+ 'platform/targets/MD-380/platform.c',
'openrtx/src/graphics/graphics_rgb565.c']
+md380_inc = inc + stm32f405_inc + ['platform/targets/MD-380']
md380_def = def + stm32f405_def
-md380_inc = inc + stm32f405_inc + ['platform/targets/MD380']
+
+## TYT MD390
+md390_src = src + stm32f405_src + ['platform/drivers/display/HX83XX_MDxx380.c',
+ 'platform/drivers/keyboard/keyboard_MDxx380.c',
+ 'platform/drivers/ADC/ADC1_MDxx380.c',
+ 'platform/drivers/tones/toneGenerator_MDxx380.c',
+ 'platform/targets/MD-390/platform.c',
+ 'openrtx/src/graphics/graphics_rgb565.c']
+
+md390_inc = inc + stm32f405_inc + ['platform/targets/MD-390']
+md390_def = def + stm32f405_def
+
## TYT MD-UV380
@@ -149,9 +161,9 @@ mduv380_src = src + stm32f405_src + ['platform/drivers/display/HX83XX_MDxx380.c'
'platform/targets/MD-UV380/platform.c',
'openrtx/src/graphics/graphics_rgb565.c']
+mduv380_inc = inc + stm32f405_inc + ['platform/targets/MD-UV380']
mduv380_def = def + stm32f405_def
-mduv380_inc = inc + stm32f405_inc + ['platform/targets/MD-UV380']
##
## Compilation defines
@@ -182,6 +194,15 @@ foreach k, v : md380_def
endif
endforeach
+md390_args = []
+foreach k, v : md390_def
+ if v == ''
+ md390_args += '-D@0@'.format(k)
+ else
+ md390_args += '-D@0@=@1@'.format(k, v)
+ endif
+endforeach
+
mduv380_args = []
foreach k, v : mduv380_def
if v == ''
@@ -202,6 +223,10 @@ md380_opts = {'sources': md380_src,
'link_args' : '-Wl,-T../platform/mcu/STM32F4xx/linker_script.ld',
'include_directories': md380_inc}
+md390_opts = {'sources': md390_src,
+ 'c_args': md390_args,
+ 'link_args' : '-Wl,-T../platform/mcu/STM32F4xx/linker_script.ld',
+ 'include_directories': md390_inc}
mduv380_opts = {'sources': mduv380_src,
'c_args': mduv380_args,
@@ -224,7 +249,7 @@ targets = [
'load_addr': '0x0800C000'},
{'name': 'md390',
- 'opts': md380_opts,
+ 'opts': md390_opts,
'flashable': true,
'wrap': 'MD390',
'load_addr': '0x0800C000'},
diff --git a/platform/drivers/ADC/ADC1_MDxx380.c b/platform/drivers/ADC/ADC1_MDxx380.c
index 2d079a76..336c76d0 100644
--- a/platform/drivers/ADC/ADC1_MDxx380.c
+++ b/platform/drivers/ADC/ADC1_MDxx380.c
@@ -34,7 +34,7 @@ void adc1_init()
* - PB0: RSSI level
*/
gpio_setMode(AIN_VBAT, INPUT_ANALOG);
- #ifdef PLATFORM_MD380
+ #if defined(PLATFORM_MD380) || defined(PLATFORM_MD390)
gpio_setMode(AIN_VOLUME, INPUT_ANALOG);
gpio_setMode(AIN_MIC, INPUT_ANALOG);
gpio_setMode(AIN_RSSI, INPUT_ANALOG);
@@ -64,7 +64,7 @@ void adc1_init()
| ADC_CR2_ADON;
/* Scan sequence config. */
- #ifdef PLATFORM_MD380
+ #if defined(PLATFORM_MD380) || defined(PLATFORM_MD390)
ADC1->SQR1 = 3 << 20; /* Four channels to be converted */
ADC1->SQR3 |= (1 << 0) /* CH1, battery voltage on PA1 */
| (8 << 5) /* CH8, RSSI value on PB0 */
diff --git a/platform/targets/MD380/hwconfig.h b/platform/targets/MD-380/hwconfig.h
similarity index 100%
rename from platform/targets/MD380/hwconfig.h
rename to platform/targets/MD-380/hwconfig.h
diff --git a/platform/targets/MD380/platform.c b/platform/targets/MD-380/platform.c
similarity index 100%
rename from platform/targets/MD380/platform.c
rename to platform/targets/MD-380/platform.c
diff --git a/platform/targets/MD-390/hwconfig.h b/platform/targets/MD-390/hwconfig.h
new file mode 100644
index 00000000..c3b9d19f
--- /dev/null
+++ b/platform/targets/MD-390/hwconfig.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * 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
+
+#define PLATFORM_MD390
+
+/* Screen dimensions */
+#define SCREEN_WIDTH 160
+#define SCREEN_HEIGHT 128
+
+/* 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 GPIOC,6
+
+/* 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_RSSI GPIOB,0
+
+/* 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
+
+/* Push-to-talk switch */
+#define PTT_SW GPIOE,11
+
+/*
+ * Keyboard. Here we define only rows, since coloumn lines are the same as
+ * LCD_Dx. See also: https://www.qsl.net/dl4yhf/RT3/md380_hw.html#keyboard
+ */
+#define KB_ROW1 GPIOA,6 /* K1 */
+#define KB_ROW2 GPIOD,2 /* K2 */
+#define KB_ROW3 GPIOD,3 /* K3 */
+
+/* Tone generator */
+#define CTCSS_OUT GPIOC,7 /* System "beep" */
+#define BEEP_OUT GPIOC,8 /* CTCSS tone */
+
+#endif
diff --git a/platform/targets/MD-390/platform.c b/platform/targets/MD-390/platform.c
new file mode 100644
index 00000000..aecc9bd7
--- /dev/null
+++ b/platform/targets/MD-390/platform.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * 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 "hwconfig.h"
+#include "ADC1_MDxx380.h"
+
+void platform_init()
+{
+ /* Configure GPIOs */
+ gpio_setMode(GREEN_LED, OUTPUT);
+ gpio_setMode(RED_LED, OUTPUT);
+
+ gpio_setMode(LCD_BKLIGHT, ALTERNATE);
+ gpio_setAlternateFunction(LCD_BKLIGHT, 3);
+
+ gpio_setMode(CH_SELECTOR_0, INPUT);
+ gpio_setMode(CH_SELECTOR_1, INPUT);
+ gpio_setMode(CH_SELECTOR_2, INPUT);
+ gpio_setMode(CH_SELECTOR_3, INPUT);
+
+ gpio_setMode(PTT_SW, INPUT);
+
+ /*
+ * Initialise ADC1, for vbat, RSSI, ...
+ * Configuration of corresponding GPIOs in analog input mode is done inside
+ * the driver.
+ */
+ adc1_init();
+
+ /*
+ * Configure TIM8 for backlight PWM: Fpwm = 100kHz, 8 bit of resolution
+ * APB2 freq. is 84MHz, then: PSC = 327 to have Ftick = 256.097kHz
+ * With ARR = 256, Fpwm is 100kHz;
+ * Backlight pin is connected to TIM8 CR1.
+ */
+ RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;
+ TIM8->ARR = 255;
+ TIM8->PSC = 327;
+ TIM8->CNT = 0;
+ TIM8->CR1 |= TIM_CR1_ARPE; /* LCD backlight is on PC6, TIM8-CH1 */
+ TIM8->CCMR1 |= TIM_CCMR1_OC1M_2
+ | TIM_CCMR1_OC1M_1
+ | TIM_CCMR1_OC1PE;
+ TIM8->CCER |= TIM_CCER_CC1E;
+ TIM8->BDTR |= TIM_BDTR_MOE;
+ TIM8->CCR1 = 0;
+ TIM8->EGR = TIM_EGR_UG; /* Update registers */
+ TIM8->CR1 |= TIM_CR1_CEN; /* Start timer */
+}
+
+void platform_terminate()
+{
+ /* Shut down backlight */
+ gpio_setMode(LCD_BKLIGHT, OUTPUT);
+ gpio_clearPin(LCD_BKLIGHT);
+
+ /* Shut down LEDs */
+ gpio_clearPin(GREEN_LED);
+ gpio_clearPin(RED_LED);
+
+ /* Shut down timer */
+ RCC->APB2ENR &= ~RCC_APB2ENR_TIM8EN;
+
+ /* Shut down ADC */
+ adc1_terminate();
+}
+
+float platform_getVbat()
+{
+ /*
+ * Battery voltage is measured through an 1:3 voltage divider and
+ * adc1_getMeasurement returns a value in mV. Thus, to have effective
+ * battery voltage multiply by three and divide by 1000
+ */
+ return adc1_getMeasurement(0)*3.0f/1000.0f;
+}
+
+float platform_getMicLevel()
+{
+ return adc1_getMeasurement(2);
+}
+
+float platform_getVolumeLevel()
+{
+ return adc1_getMeasurement(3);
+}
+
+uint8_t platform_getChSelector()
+{
+ static const uint8_t rsPositions[] = { 11, 14, 10, 15, 6, 3, 7, 2, 12, 13,
+ 9, 16, 5, 4, 8, 1 };
+ int pos = gpio_readPin(CH_SELECTOR_0)
+ | (gpio_readPin(CH_SELECTOR_1) << 1)
+ | (gpio_readPin(CH_SELECTOR_2) << 2)
+ | (gpio_readPin(CH_SELECTOR_3) << 3);
+ return rsPositions[pos];
+}
+
+bool platform_getPttStatus()
+{
+ /* PTT line has a pullup resistor with PTT switch closing to ground */
+ return (gpio_readPin(PTT_SW) == 0) ? 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)
+{
+ /* TODO */
+ (void) freq;
+}
+
+void platform_beepStop()
+{
+ /* TODO */
+}
+
+void platform_setBacklightLevel(uint8_t level)
+{
+ TIM8->CCR1 = level;
+}