diff --git a/meson.build b/meson.build index 7cbb54ba..79a22e82 100644 --- a/meson.build +++ b/meson.build @@ -224,7 +224,8 @@ mduv3x0_def = def + stm32f405_def + {'PLATFORM_MDUV3x0': '', 'timegm': 'mktime'} ## TYT MD-9600 ## md9600_src = src + stm32f405_src + ['platform/targets/MD-9600/platform.c', - 'platform/drivers/tones/toneGenerator_MDx.cpp'] + 'platform/drivers/tones/toneGenerator_MDx.cpp', + 'platform/drivers/keyboard/keyboard_MD9600.c'] md9600_inc = inc + stm32f405_inc + ['platform/targets/MD-9600'] md9600_def = def + stm32f405_def + {'PLATFORM_MD9600': ''} diff --git a/platform/drivers/keyboard/keyboard_MD9600.c b/platform/drivers/keyboard/keyboard_MD9600.c new file mode 100644 index 00000000..345e8415 --- /dev/null +++ b/platform/drivers/keyboard/keyboard_MD9600.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2021 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 "hwconfig.h" + +void kbd_init() +{ + gpio_setMode(KB_COL1, INPUT_PULL_UP); + gpio_setMode(KB_COL2, INPUT_PULL_UP); + gpio_setMode(KB_COL3, INPUT_PULL_UP); + gpio_setMode(KB_COL4, INPUT_PULL_UP); + + gpio_setMode(KB_ROW1, OUTPUT); + gpio_setMode(KB_ROW2, OUTPUT); + gpio_setMode(KB_ROW3, OUTPUT); + + gpio_setPin(KB_ROW1); + gpio_setPin(KB_ROW2); + gpio_setPin(KB_ROW3); +} + +void kbd_terminate() +{ + /* Back to default state */ + gpio_setMode(KB_ROW1, INPUT); + gpio_setMode(KB_ROW2, INPUT); + gpio_setMode(KB_ROW3, INPUT); +} + +keyboard_t kbd_getKeys() +{ + keyboard_t keys = 0; + + /* Use absolute position knob to emulate left and right buttons */ + static uint8_t old_pos = 0; + uint8_t new_pos = platform_getChSelector(); + if (old_pos != new_pos) + { + if (new_pos < old_pos) + keys |= KEY_LEFT; + else + keys |= KEY_RIGHT; + old_pos = new_pos; + } + + /* + * Mapping of front buttons: + * + * +------+-----+-------+-----+ + * | PD0 | PD1 | PE0 | PE1 | + * +-----+------+-----+-------+-----+ + * | PD2 | ENT | | P1 | P4 | + * +-----+------+-----+-------+-----+ + * | PD3 | down | | red | P3 | + * +-----+------+-----+-------+-----+ + * | PD4 | ESC | up | green | P2 | + * +-----+------+-----+-------+-----+ + * + * The coloumn lines have pull-up resistors, thus the detection of a button + * press follows an active-low logic. + * + */ + + gpio_clearPin(KB_ROW1); + + delayUs(10); + if(gpio_readPin(KB_COL1) == 0) keys |= KEY_ENTER; + if(gpio_readPin(KB_COL3) == 0) keys |= KEY_F1; + if(gpio_readPin(KB_COL4) == 0) keys |= KEY_F4; + gpio_setPin(KB_ROW1); + + /* Row 2: button on col. 3 ("red") is not mapped */ + gpio_clearPin(KB_ROW2); + delayUs(10); + + if(gpio_readPin(KB_COL1) == 0) keys |= KEY_DOWN; + if(gpio_readPin(KB_COL4) == 0) keys |= KEY_F3; + gpio_setPin(KB_ROW2); + + /* Row 3: button on col. 3 ("green") is not mapped */ + gpio_clearPin(KB_ROW3); + delayUs(10); + + if(gpio_readPin(KB_COL1) == 0) keys |= KEY_ESC; + if(gpio_readPin(KB_COL2) == 0) keys |= KEY_UP; + if(gpio_readPin(KB_COL4) == 0) keys |= KEY_F2; + gpio_setPin(KB_ROW3); + + return keys; +} diff --git a/platform/targets/MD-9600/hwconfig.h b/platform/targets/MD-9600/hwconfig.h index 0d468c29..b0565abe 100644 --- a/platform/targets/MD-9600/hwconfig.h +++ b/platform/targets/MD-9600/hwconfig.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * * Niccolò Izzo IU2KIN, * * Frederik Saraci IU2NRO, * * Silvano Seva IU2KWO * @@ -52,4 +52,55 @@ /* Battery type */ #define BAT_NONE +/* Power keep switch */ +#define PWR_SW GPIOD,15 + +/* Display */ +#define LCD_BKLIGHT GPIOC,6 +#define LCD_RST GPIOD,12 +#define LCD_RS GPIOC,13 +#define LCD_CS GPIOD,14 + +/* Analog inputs */ +#define AIN_VBAT GPIOA,1 + +/* Channel selection rotary encoder */ +#define CH_SELECTOR_0 GPIOB,10 +#define CH_SELECTOR_1 GPIOB,11 + +/* Push-to-talk switch */ +#define PTT_SW GPIOE,10 + +/* Keyboard */ +#define KB_ROW1 GPIOD,2 +#define KB_ROW2 GPIOD,3 +#define KB_ROW3 GPIOD,4 +#define KB_COL1 GPIOD,0 +#define KB_COL2 GPIOD,1 +#define KB_COL3 GPIOE,0 +#define KB_COL4 GPIOE,1 + +/* Tone generator */ +#define CTCSS_OUT GPIOC,7 /* System "beep" */ +#define BEEP_OUT GPIOC,8 /* CTCSS tone */ + +/* SPI2, connected to external flash and LCD */ +#define FLASH_CS GPIOB,12 +#define SPI2_CLK GPIOB,13 +#define SPI2_SDO GPIOB,14 +#define SPI2_SDI GPIOB,15 + +/* Audio control */ +#define SPK_MUTE GPIOB,6 + +/* GPS, for the devices who have it */ +#define GPS_EN GPIOA,9 +#define GPS_DATA GPIOA,10 + +/* HR_C6000 control interface */ +#define DMR_CS GPIOE,2 +#define DMR_CLK GPIOE,3 +#define DMR_MOSI GPIOE,4 +#define DMR_MISO GPIOE,5 + #endif diff --git a/platform/targets/MD-9600/platform.c b/platform/targets/MD-9600/platform.c index c4928b52..4d18bce1 100644 --- a/platform/targets/MD-9600/platform.c +++ b/platform/targets/MD-9600/platform.c @@ -1,7 +1,6 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * - * Niccolò Izzo IU2KIN, * - * Frederik Saraci IU2NRO, * + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * @@ -18,19 +17,94 @@ * along with this program; if not, see * ***************************************************************************/ -#include #include -#include -#include #include +#include +#include +#include +#include +#include +#include #include +hwInfo_t hwInfo; + void platform_init() { + gpio_setMode(LCD_BKLIGHT, ALTERNATE); + gpio_setAlternateFunction(LCD_BKLIGHT, 3); + + gpio_setMode(CH_SELECTOR_0, INPUT_PULL_UP); + gpio_setMode(CH_SELECTOR_1, INPUT_PULL_UP); + + gpio_setMode(PTT_SW, INPUT); + + gpio_setMode(PWR_SW, OUTPUT); + + /* + * Initialise ADC1, for vbat, RSSI, ... + * Configuration of corresponding GPIOs in analog input mode is done inside + * the driver. + */ +// adc1_init(); + + memset(&hwInfo, 0x00, sizeof(hwInfo)); + +// nvm_init(); /* Initialise non volatile memory manager */ + toneGen_init(); /* Initialise tone generator */ + rtc_init(); /* Initialise RTC */ + + /* + * Configure TIM8 for backlight PWM: Fpwm = 100kHz with 8 bit of resolution. + * APB2 freq. is 84MHz, but timer runs at twice this frequency. + * Then: PSC = 655 to have Ftick = 256.097kHz + * With ARR = 256, Fpwm is 100kHz; + * Backlight pin is connected to TIM8 CR1. + */ + RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; + __DSB(); + + TIM8->ARR = 255; + TIM8->PSC = 654; + 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 timer */ + RCC->APB2ENR &= ~RCC_APB2ENR_TIM8EN; + __DSB(); + + /* Shut down all the modules */ +// adc1_terminate(); + toneGen_terminate(); + rtc_terminate(); + + /* Finally, remove power supply */ + gpio_clearPin(PWR_SW); +} + +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 0.0f; } float platform_getMicLevel() @@ -43,6 +117,33 @@ float platform_getVolumeLevel() return 0.0f; } +uint8_t platform_getChSelector() +{ + static const uint8_t rsPositions[] = { 1, 4, 2, 3}; + int pos = gpio_readPin(CH_SELECTOR_0) + | (gpio_readPin(CH_SELECTOR_1) << 1); + + 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) +{ + /* No LEDs on this platform */ + (void) led; +} + +void platform_ledOff(led_t led) +{ + /* No LEDs on this platform */ + (void) led; +} + void platform_beepStart(uint16_t freq) { /* TODO */ @@ -53,3 +154,18 @@ void platform_beepStop() { /* TODO */ } + +void platform_setBacklightLevel(uint8_t level) +{ + TIM8->CCR1 = level; +} + +const void *platform_getCalibrationData() +{ + return NULL; +} + +const hwInfo_t *platform_getHwInfo() +{ + return &hwInfo; +}