kopia lustrzana https://github.com/OpenRTX/OpenRTX
Add Baofeng MD-1702/DM-X target
rodzic
ae8bba88b6
commit
5800849cd7
39
meson.build
39
meson.build
|
@ -323,6 +323,22 @@ mduv3x0_src = src + mdx_src + stm32f405_src + ['platform/drivers/NVM/nvmem_MDUV3
|
|||
mduv3x0_inc = inc + stm32f405_inc + ['platform/targets/MD-UV3x0']
|
||||
mduv3x0_def = def + stm32f405_def + {'PLATFORM_MDUV3x0': '', 'timegm': 'mktime'}
|
||||
|
||||
##
|
||||
## Baofeng MD-1702
|
||||
##
|
||||
md1702_src = src + mdx_src + stm32f405_src + ['platform/drivers/NVM/nvmem_MDUV3x0.c',
|
||||
'platform/drivers/NVM/spiFlash_MD3x.c',
|
||||
'platform/drivers/CPS/cps_io_native_MDUV3x0.c',
|
||||
'platform/targets/MD-1702/platform.c',
|
||||
'platform/drivers/keyboard/keyboard_MD1702.c',
|
||||
'platform/drivers/display/HX8353_MD3x.cpp',
|
||||
'platform/drivers/baseband/radio_UV3x0.cpp',
|
||||
'platform/drivers/baseband/AT1846S_UV3x0.cpp',
|
||||
'platform/drivers/baseband/HR_C6000_UV3x0.cpp']
|
||||
|
||||
md1702_inc = inc + stm32f405_inc + ['platform/targets/MD-1702']
|
||||
md1702_def = def + stm32f405_def + {'PLATFORM_MDUV3x0': '', 'timegm': 'mktime'}
|
||||
|
||||
##
|
||||
## TYT MD-9600
|
||||
##
|
||||
|
@ -421,6 +437,15 @@ foreach k, v : mduv3x0_def
|
|||
endif
|
||||
endforeach
|
||||
|
||||
md1702_args = []
|
||||
foreach k, v : md1702_def
|
||||
if v == ''
|
||||
md1702_args += '-D@0@'.format(k)
|
||||
else
|
||||
md1702_args += '-D@0@=@1@'.format(k, v)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
gd77_args = []
|
||||
foreach k, v : gd77_def
|
||||
if v == ''
|
||||
|
@ -480,6 +505,14 @@ mduv3x0_opts = {'sources': mduv3x0_src,
|
|||
'dependencies': [codec2_dep],
|
||||
'include_directories': mduv3x0_inc}
|
||||
|
||||
md1702_opts = {'sources': md1702_src,
|
||||
'c_args': md1702_args,
|
||||
'cpp_args': md1702_args,
|
||||
'link_args' : ['-Wl,-T../platform/mcu/STM32F4xx/linker_script_MD-1702.ld',
|
||||
'-Wl,--print-memory-usage'],
|
||||
'dependencies': [codec2_dep],
|
||||
'include_directories': md1702_inc}
|
||||
|
||||
gd77_opts = {'sources': gd77_src,
|
||||
'c_args': gd77_args,
|
||||
'cpp_args': gd77_args,
|
||||
|
@ -534,6 +567,12 @@ targets = [
|
|||
'wrap': 'UV3X0',
|
||||
'load_addr': '0x0800C000'},
|
||||
|
||||
{'name': 'md1702',
|
||||
'opts': md1702_opts,
|
||||
'flashable': true,
|
||||
'wrap': '',
|
||||
'load_addr': '0x08008000'},
|
||||
|
||||
{'name': 'gd77',
|
||||
'opts': gd77_opts,
|
||||
'flashable': true,
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2020 - 2022 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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <interfaces/gpio.h>
|
||||
#include <interfaces/delays.h>
|
||||
#include <interfaces/keyboard.h>
|
||||
#include <interfaces/platform.h>
|
||||
#include "hwconfig.h"
|
||||
|
||||
void kbd_init()
|
||||
{
|
||||
/* Set the two row lines as outputs */
|
||||
gpio_setMode(KB_ROW1, OUTPUT);
|
||||
gpio_setMode(KB_ROW2, OUTPUT);
|
||||
gpio_setMode(KB_ROW3, OUTPUT);
|
||||
gpio_clearPin(KB_ROW1);
|
||||
gpio_clearPin(KB_ROW2);
|
||||
gpio_clearPin(KB_ROW3);
|
||||
|
||||
}
|
||||
|
||||
void kbd_terminate()
|
||||
{
|
||||
/* Back to default state */
|
||||
gpio_clearPin(KB_ROW1);
|
||||
gpio_clearPin(KB_ROW2);
|
||||
gpio_clearPin(KB_ROW3);
|
||||
gpio_setMode(KB_ROW1, INPUT);
|
||||
gpio_setMode(KB_ROW2, INPUT);
|
||||
gpio_setMode(KB_ROW3, INPUT);
|
||||
}
|
||||
|
||||
keyboard_t kbd_getKeys()
|
||||
{
|
||||
keyboard_t keys = 0;
|
||||
|
||||
/*
|
||||
* The row lines are in common with the display, so we have to configure
|
||||
* them as inputs before scanning. However, before configuring them as inputs,
|
||||
* we put them as outputs and force a low logical level in order to be sure
|
||||
* that any residual charge on both the display controller's inputs and in
|
||||
* the capacitors in parallel to the Dx lines is dissipated.
|
||||
*/
|
||||
gpio_setMode(LCD_D0, OUTPUT);
|
||||
gpio_setMode(LCD_D1, OUTPUT);
|
||||
gpio_setMode(LCD_D2, OUTPUT);
|
||||
gpio_setMode(LCD_D3, OUTPUT);
|
||||
gpio_setMode(LCD_D4, OUTPUT);
|
||||
gpio_setMode(LCD_D5, OUTPUT);
|
||||
|
||||
gpio_clearPin(LCD_D0);
|
||||
gpio_clearPin(LCD_D1);
|
||||
gpio_clearPin(LCD_D2);
|
||||
gpio_clearPin(LCD_D3);
|
||||
gpio_clearPin(LCD_D4);
|
||||
gpio_clearPin(LCD_D5);
|
||||
|
||||
|
||||
gpio_setMode(LCD_D0, INPUT_PULL_DOWN);
|
||||
gpio_setMode(LCD_D1, INPUT_PULL_DOWN);
|
||||
gpio_setMode(LCD_D2, INPUT_PULL_DOWN);
|
||||
gpio_setMode(LCD_D3, INPUT_PULL_DOWN);
|
||||
gpio_setMode(LCD_D4, INPUT_PULL_DOWN);
|
||||
gpio_setMode(LCD_D5, INPUT_PULL_DOWN);
|
||||
/*
|
||||
* Scan keyboard by coloumns.
|
||||
* For key configuration, see: https://www.qsl.net/dl4yhf/RT3/md380_hw.html#keyboard
|
||||
*
|
||||
* Keys coloumns (LCD_D...) have 1k series resistor and a 10pF capacitor
|
||||
* connected to ground, making a low-pass filter with a settling time of
|
||||
* ~50ns. CPU runs at 168MHz and 50ns are approximately eigth instructions,
|
||||
* this means that we have to put a small delay before reading the GPIOs to
|
||||
* allow voltage to settle.
|
||||
*/
|
||||
|
||||
|
||||
gpio_setPin(KB_ROW1);
|
||||
|
||||
delayUs(10);
|
||||
|
||||
if(gpio_readPin(LCD_D0)) keys |= KEY_1;
|
||||
if(gpio_readPin(LCD_D1)) keys |= KEY_4;
|
||||
if(gpio_readPin(LCD_D2)) keys |= KEY_7;
|
||||
if(gpio_readPin(LCD_D3)) keys |= KEY_STAR;
|
||||
if(gpio_readPin(LCD_D4)) keys |= KEY_UP;
|
||||
if(gpio_readPin(LCD_D5)) keys |= KEY_ENTER;
|
||||
|
||||
|
||||
gpio_clearPin(KB_ROW1);
|
||||
gpio_setPin(KB_ROW2);
|
||||
|
||||
delayUs(10);
|
||||
if(gpio_readPin(LCD_D0)) keys |= KEY_2;
|
||||
if(gpio_readPin(LCD_D1)) keys |= KEY_5;
|
||||
if(gpio_readPin(LCD_D2)) keys |= KEY_8;
|
||||
if(gpio_readPin(LCD_D3)) keys |= KEY_0;
|
||||
if(gpio_readPin(LCD_D4)) keys |= KEY_DOWN;
|
||||
if(gpio_readPin(LCD_D5)) keys |= KEY_ESC;
|
||||
|
||||
gpio_clearPin(KB_ROW2);
|
||||
gpio_setPin(KB_ROW3);
|
||||
|
||||
delayUs(10);
|
||||
if(gpio_readPin(LCD_D0)) keys |= KEY_3;
|
||||
if(gpio_readPin(LCD_D1)) keys |= KEY_6;
|
||||
if(gpio_readPin(LCD_D2)) keys |= KEY_9;
|
||||
if(gpio_readPin(LCD_D3)) keys |= KEY_HASH;
|
||||
if(gpio_readPin(FUNC_SW)) keys |= KEY_F1;
|
||||
if(gpio_readPin(MONI_SW)) keys |= KEY_MONI;
|
||||
|
||||
gpio_clearPin(KB_ROW3);
|
||||
return keys;
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* C++ enabled linker script for stm32 (1M FLASH, 192K RAM)
|
||||
* Developed by TFT: Terraneo Federico Technologies
|
||||
* Optimized for use with the Miosix kernel
|
||||
*/
|
||||
|
||||
/*
|
||||
* This chip has an unusual quirk that the RAM is divided in two block mapped
|
||||
* at two non contiguous memory addresses. I don't know why they've done that,
|
||||
* probably doing the obvious thing would have made writing code too easy...
|
||||
* Anyway, since hardware can't be changed, we've got to live with that and
|
||||
* try to make use of both RAMs.
|
||||
*
|
||||
* Given the constraints above, this linker script puts:
|
||||
* - read only data and code (.text, .rodata, .eh_*) in FLASH
|
||||
* - .data and .bss in the "small" 64KB RAM
|
||||
* - the 512Byte main (IRQ) stack, stacks and heap in the "large" 128KB RAM.
|
||||
*
|
||||
* Unfortunately thread stacks can't be put in the small RAM as Miosix
|
||||
* allocates them inside the heap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The main stack is used for interrupt handling by the kernel.
|
||||
*
|
||||
* *** Readme ***
|
||||
* This linker script places the main stack (used by the kernel for interrupts)
|
||||
* at the bottom of the ram, instead of the top. This is done for two reasons:
|
||||
*
|
||||
* - as an optimization for microcontrollers with little ram memory. In fact
|
||||
* the implementation of malloc from newlib requests memory to the OS in 4KB
|
||||
* block (except the first block that can be smaller). This is probably done
|
||||
* for compatibility with OSes with an MMU and paged memory. To see why this
|
||||
* is bad, consider a microcontroller with 8KB of ram: when malloc finishes
|
||||
* up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will
|
||||
* fail because the top part of the ram is used by the main stack. As a
|
||||
* result, the top part of the memory will not be used by malloc, even if
|
||||
* available (and it is nearly *half* the ram on an 8KB mcu). By placing the
|
||||
* main stack at the bottom of the ram, the upper 4KB block will be entirely
|
||||
* free and available as heap space.
|
||||
*
|
||||
* - In case of main stack overflow the cpu will fault because access to memory
|
||||
* before the beginning of the ram faults. Instead with the default stack
|
||||
* placement the main stack will silently collide with the heap.
|
||||
* Note: if increasing the main stack size also increase the ORIGIN value in
|
||||
* the MEMORY definitions below accordingly.
|
||||
*/
|
||||
_main_stack_size = 0x00000200; /* main stack = 512Bytes */
|
||||
_main_stack_top = 0x20000000 + _main_stack_size;
|
||||
ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error");
|
||||
|
||||
/* Mapping the heap into the large 128KB RAM */
|
||||
_heap_end = 0x20020000; /* end of available ram */
|
||||
|
||||
/* identify the Entry Point */
|
||||
ENTRY(_Z13Reset_Handlerv)
|
||||
|
||||
/* specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
/* Reserve space for bootloader and settings */
|
||||
flash(rx) : ORIGIN = 0x08008000, LENGTH = 1M - 48K - 128K
|
||||
/*
|
||||
* Note, the small ram starts at 0x10000000 but it is necessary to add the
|
||||
* size of the main stack, so it is 0x10000200.
|
||||
*/
|
||||
smallram(wx) : ORIGIN = 0x10000000, LENGTH = 64K
|
||||
largeram(wx) : ORIGIN = 0x20000200, LENGTH = 128K-0x200
|
||||
}
|
||||
|
||||
/* now define the output sections */
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
/* .text section: code goes to flash */
|
||||
.text :
|
||||
{
|
||||
/* Startup code must go at address 0 */
|
||||
KEEP(*(.isr_vector))
|
||||
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
/* these sections for thumb interwork? */
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
/* these sections for C++? */
|
||||
*(.gcc_except_table)
|
||||
*(.gcc_except_table.*)
|
||||
*(.ARM.extab*)
|
||||
*(.gnu.linkonce.armextab.*)
|
||||
|
||||
. = ALIGN(4);
|
||||
/* .rodata: constant data */
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
|
||||
/* C++ Static constructors/destructors (eabi) */
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.init))
|
||||
|
||||
. = ALIGN(4);
|
||||
__miosix_init_array_start = .;
|
||||
KEEP (*(SORT(.miosix_init_array.*)))
|
||||
KEEP (*(.miosix_init_array))
|
||||
__miosix_init_array_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__preinit_array_start = .;
|
||||
KEEP (*(.preinit_array))
|
||||
__preinit_array_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__init_array_start = .;
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
__init_array_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.fini))
|
||||
|
||||
. = ALIGN(4);
|
||||
__fini_array_start = .;
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
__fini_array_end = .;
|
||||
|
||||
/* C++ Static constructors/destructors (elf) */
|
||||
. = ALIGN(4);
|
||||
_ctor_start = .;
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
_ctor_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
} > flash
|
||||
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > flash
|
||||
__exidx_end = .;
|
||||
|
||||
/* .data section: global variables go to ram, but also store a copy to
|
||||
flash to initialize them */
|
||||
.data : ALIGN(8)
|
||||
{
|
||||
_data = .;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
. = ALIGN(8);
|
||||
_edata = .;
|
||||
} > smallram AT > flash
|
||||
_etext = LOADADDR(.data);
|
||||
|
||||
/* .bss section: uninitialized global variables go to ram */
|
||||
_bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
. = ALIGN(8);
|
||||
} > smallram
|
||||
_bss_end = .;
|
||||
|
||||
/* Second BSS section located in the "large" RAM, explicitly request to not
|
||||
initialize it */
|
||||
.bss2 (NOLOAD) :
|
||||
{
|
||||
*(.bss2)
|
||||
. = ALIGN(8);
|
||||
} > largeram
|
||||
|
||||
_end = .;
|
||||
PROVIDE(end = .);
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2020 - 2022 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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef HWCONFIG_H
|
||||
#define HWCONFIG_H
|
||||
|
||||
#include <stm32f4xx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Device has a working real time clock */
|
||||
#define RTC_PRESENT
|
||||
|
||||
/* Device supports an optional GPS chip */
|
||||
#define GPS_PRESENT
|
||||
|
||||
/* Screen dimensions */
|
||||
#define SCREEN_WIDTH 160
|
||||
#define SCREEN_HEIGHT 128
|
||||
|
||||
/* Screen pixel format */
|
||||
#define PIX_FMT_RGB565
|
||||
|
||||
/* Battery type */
|
||||
#define BAT_LIPO_2S
|
||||
|
||||
/* 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
|
||||
|
||||
/* Push-to-talk switch */
|
||||
#define PTT_SW GPIOE,11
|
||||
#define PTT_EXT GPIOE,12
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* "Monitor" and "Function" buttons, on the other hand, are connected to
|
||||
* keyboard row 3 and on LCD_D6 and LCD_D7. They are SWAPPED with respect to
|
||||
* connections made on MD-380.
|
||||
*/
|
||||
#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
|
||||
#define RX_AUDIO_MUX GPIOD,9
|
||||
|
||||
/* GPS, for the devices who have it */
|
||||
#define GPS_EN GPIOA,9
|
||||
#define GPS_DATA GPIOA,10
|
||||
|
||||
/* RTX stage control */
|
||||
#define VHF_LNA_EN GPIOA,5
|
||||
#define UHF_LNA_EN GPIOA,2
|
||||
#define PA_EN_1 GPIOC,5
|
||||
#define PA_EN_2 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
|
||||
|
||||
|
||||
/*
|
||||
* 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/MD-1702 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 ENABLE_BKLIGHT_DIMMING
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HWCONFIG_H */
|
|
@ -0,0 +1,229 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2020 - 2022 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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <interfaces/platform.h>
|
||||
#include <interfaces/gpio.h>
|
||||
#include <hwconfig.h>
|
||||
#include <string.h>
|
||||
#include <ADC1_MDx.h>
|
||||
#include <calibInfo_MDx.h>
|
||||
#include <interfaces/nvmem.h>
|
||||
#include <toneGenerator_MDx.h>
|
||||
#include <interfaces/rtc.h>
|
||||
#include <interfaces/audio.h>
|
||||
#include <chSelector.h>
|
||||
|
||||
#ifdef ENABLE_BKLIGHT_DIMMING
|
||||
#include <backlight.h>
|
||||
#endif
|
||||
|
||||
mduv3x0Calib_t calibration;
|
||||
hwInfo_t hwInfo;
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
nvm_readCalibData(&calibration); /* Load calibration data */
|
||||
nvm_readHwInfo(&hwInfo); /* Load hardware information data */
|
||||
toneGen_init(); /* Initialise tone generator */
|
||||
rtc_init(); /* Initialise RTC */
|
||||
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 */
|
||||
adc1_terminate();
|
||||
nvm_terminate();
|
||||
toneGen_terminate();
|
||||
audio_terminate();
|
||||
|
||||
/* Finally, remove power supply */
|
||||
gpio_clearPin(PWR_SW);
|
||||
}
|
||||
|
||||
uint16_t 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.
|
||||
*/
|
||||
return adc1_getMeasurement(ADC_VBAT_CH) * 3;
|
||||
}
|
||||
|
||||
uint8_t platform_getMicLevel()
|
||||
{
|
||||
/* Value from ADC is 12 bit wide: shift right by four to get 0 - 255 */
|
||||
return (adc1_getRawSample(ADC_VOX_CH) >> 4);
|
||||
}
|
||||
|
||||
uint8_t platform_getVolumeLevel()
|
||||
{
|
||||
/*
|
||||
* Knob position corresponds to an analog signal in the range 0 - 1600mV,
|
||||
* converted to a value in range 0 - 255 using fixed point math: divide by
|
||||
* 1600 and then multiply by 256.
|
||||
*/
|
||||
uint16_t value = adc1_getMeasurement(ADC_VOL_CH);
|
||||
if(value > 1599) value = 1599;
|
||||
uint32_t level = value << 16;
|
||||
level /= 1600;
|
||||
return ((uint8_t) (level >> 8));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// calculate appropriate volume.
|
||||
uint8_t vol = platform_getVolumeLevel();
|
||||
// Since beeps have been requested, we do not want to have 0 volume.
|
||||
// We also do not want the volume to be excessive.
|
||||
if (vol < 10)
|
||||
vol = 5;
|
||||
if (vol > 176)
|
||||
vol = 176;
|
||||
toneGen_beepOn((float)freq, vol, 0);
|
||||
}
|
||||
|
||||
void platform_beepStop()
|
||||
{
|
||||
toneGen_beepOff();
|
||||
}
|
||||
|
||||
const void *platform_getCalibrationData()
|
||||
{
|
||||
return ((const void *) &calibration);
|
||||
}
|
||||
|
||||
const hwInfo_t *platform_getHwInfo()
|
||||
{
|
||||
return &hwInfo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: when backligth dimming is enabled, the implementation of this API
|
||||
* function is provided in platform/drivers/backlight/backlight_MDx.c to avoid
|
||||
* an useless function call.
|
||||
*/
|
||||
#ifndef ENABLE_BKLIGHT_DIMMING
|
||||
void platform_setBacklightLevel(uint8_t level)
|
||||
{
|
||||
if(level > 1)
|
||||
{
|
||||
gpio_setPin(LCD_BKLIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpio_clearPin(LCD_BKLIGHT);
|
||||
}
|
||||
}
|
||||
#endif
|
Ładowanie…
Reference in New Issue