From f7fde110bb8884fae70d9ad466b901be22498a3b Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Fri, 13 Nov 2020 14:31:21 +0100 Subject: [PATCH] Tone generator for CTCSS and user interface 'beep' on MD380 --- meson.build | 6 +- .../drivers/tones/toneGenerator_MDxx380.c | 179 ++++++++++++++++++ .../drivers/tones/toneGenerator_MDxx380.h | 82 ++++++++ platform/targets/MD380/hwconfig.h | 4 + 4 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 platform/drivers/tones/toneGenerator_MDxx380.c create mode 100644 platform/drivers/tones/toneGenerator_MDxx380.h diff --git a/meson.build b/meson.build index af55ec4a..7bad9a54 100644 --- a/meson.build +++ b/meson.build @@ -18,7 +18,8 @@ openrtx_src = ['openrtx/src/main.c', openrtx_inc = ['openrtx/include/interfaces', 'openrtx/include/fonts', - 'platform/drivers/ADC'] + 'platform/drivers/ADC', + 'platform/drivers/tones'] ## RTOS rtos_src = ['rtos/uC-OS3/Source/__dbg_uCOS-III.c', @@ -96,7 +97,7 @@ stm32f405_inc = ['platform/mcu/CMSIS/Include', 'rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M', 'rtos/uC-CPU/ARM-Cortex-M/ARMv7-M'] -stm32f405_def = {'STM32F40_41xxx': '', 'HSE_VALUE':'8000000'} +stm32f405_def = {'STM32F40_41xxx': '', 'HSE_VALUE':'8000000'} ## ## Platform specializations @@ -132,6 +133,7 @@ endif 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', 'openrtx/src/graphics/graphics_rgb565.c'] diff --git a/platform/drivers/tones/toneGenerator_MDxx380.c b/platform/drivers/tones/toneGenerator_MDxx380.c new file mode 100644 index 00000000..e907ba6d --- /dev/null +++ b/platform/drivers/tones/toneGenerator_MDxx380.c @@ -0,0 +1,179 @@ +/*************************************************************************** + * Copyright (C) 2020 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 + +/* + * Sine table for PWM-based sinewave generation, containing 256 samples over one + * period of a 64Hz sinewave. This gives a PWM base frequency of 16.384kHz. + */ +uint8_t sineTable[] = +{ + 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182, + 185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228, + 230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253, + 253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250, + 250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222, + 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173, + 170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115, + 112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47, + 44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2, + 2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23, + 25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88, + 90,93,97,100,103,106,109,112,115,118,121,124 +}; + +/* + * Correction factor to compensate for the (slight) difference between the exact + * sampling frequency of the sine table and the PWM frequency generated by the + * timer. This difference causes a frequency error in the resulting output of + * both CTCSS and "beep" signals. + * To compensate for this, simply multiply the target frequency by this + * correction factor. + */ +const float freqCorrFactor = 16384.0f/16406.25; +const uint32_t baseSineFreq = 64; + +uint32_t toneTableIndex = 0; /* Current sine table index for CTCSS generator */ +uint32_t toneTableIncr = 0; /* CTCSS sine table index increment per tick */ + +uint32_t beepTableIndex = 0; /* Current sine table index for "beep" generator */ +uint32_t beepTableIncr = 0; /* "beep" sine table index increment per tick */ +uint32_t beepTimerCount = 0; /* Downcounter for timed "beep" */ + +void __attribute__((used)) TIM3_IRQHandler() +{ + toneTableIndex += toneTableIncr; + beepTableIndex += beepTableIncr; + + TIM3->CCR2 = sineTable[(toneTableIndex >> 16) & 0xFF]; + TIM3->CCR3 = sineTable[(beepTableIndex >> 16) & 0xFF]; + TIM3->SR = 0; + + if(beepTimerCount > 0) + { + beepTimerCount--; + if(beepTimerCount == 0) + { + TIM3->CCER &= ~TIM_CCER_CC3E; + } + } + + /* Shutdown timer if both compare channels are inactive */ + if((TIM3->CCER & (TIM_CCER_CC2E | TIM_CCER_CC3E)) == 0) + { + TIM3->CR1 &= ~TIM_CR1_CEN; + } +} + +void toneGen_init() +{ + /* + * Configure GPIOs: + * - CTCSS output is on PC7 (on MD380), that is TIM3-CH2, AF2 + * - "beep" output is on PC8 (on MD380), that is TIM3-CH3, AF2 + */ + gpio_setMode(CTCSS_OUT, ALTERNATE); + gpio_setMode(BEEP_OUT, ALTERNATE); + gpio_setAlternateFunction(CTCSS_OUT, 2); + gpio_setAlternateFunction(BEEP_OUT, 2); + + /* + * Timer configuration: + * - APB1 frequency = 42MHz, with 1:10 prescaler we have Ftick = 4.2MHz + * - ARR = 255 (8-bit PWM), gives an update rate of 16.406kHz + * - Nominal update rate is 16.384kHz -> error = +22.25Hz + */ + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + + TIM3->ARR = 0xFF; + TIM3->PSC = 9; + TIM3->CCMR1 = TIM_CCMR1_OC2M_2 /* CH2 in PWM mode 1, preload enabled */ + | TIM_CCMR1_OC2M_1 + | TIM_CCMR1_OC2PE; + TIM3->CCMR2 = TIM_CCMR2_OC3M_2 /* The same for CH3 */ + | TIM_CCMR2_OC3M_1 + | TIM_CCMR2_OC3PE; + TIM3->DIER |= TIM_DIER_UIE; /* Interrupt on counter update */ + TIM3->CR1 |= TIM_CR1_ARPE; /* Enable auto preload on reload */ + + NVIC_SetPriority(TIM3_IRQn, 10); + NVIC_EnableIRQ(TIM3_IRQn); +} + +void toneGen_shutdown() +{ + RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN; + gpio_setMode(CTCSS_OUT, INPUT); + gpio_setMode(BEEP_OUT, INPUT); +} + +void toneGen_setToneFreq(float toneFreq) +{ + /* + * Convert to 16.16 fixed point number, then divide by the frequency of + * sinewave stored in the PWM table + */ + float dividend = toneFreq * freqCorrFactor * 65536.0f; + toneTableIncr = ((uint32_t) dividend)/baseSineFreq; +} + +void toneGen_toneOn() +{ + TIM3->CCER |= TIM_CCER_CC2E; + TIM3->CR1 |= TIM_CR1_CEN; +} + +void toneGen_toneOff() +{ + TIM3->CCER &= ~TIM_CCER_CC2E; +} + +void toneGen_setBeepFreq(float beepFreq) +{ + float dividend = beepFreq * freqCorrFactor * 65536.0f; + beepTableIncr = ((uint32_t) dividend)/baseSineFreq; +} + +void toneGen_beepOn() +{ + TIM3->CCER |= TIM_CCER_CC3E; + TIM3->CR1 |= TIM_CR1_CEN; +} + +void toneGen_beepOff() +{ + TIM3->CCER &= ~TIM_CCER_CC3E; +} + +void toneGen_timedBeep(uint16_t duration) +{ + /* + * Duration is in milliseconds, while counter update rate is 16.406kHz. + * Thus, the value for downcounter is (duration * 16.406)/1000. + */ + beepTimerCount = (duration * 16406)/1000; + TIM3->CCER |= TIM_CCER_CC3E; + TIM3->CR1 |= TIM_CR1_CEN; +} diff --git a/platform/drivers/tones/toneGenerator_MDxx380.h b/platform/drivers/tones/toneGenerator_MDxx380.h new file mode 100644 index 00000000..6f3c855a --- /dev/null +++ b/platform/drivers/tones/toneGenerator_MDxx380.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2020 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 TONE_GENERATOR_H +#define TONE_GENERATOR_H + +#include + +/** + * Tone generator for MDxx380 family, used for both CTCSS tones and user + * interface "beeps". + * This driver uses TIM3 of STM32F405 mcu in PWM mode to generate sinewaves + * using a precomputed sine table. + */ + +/** + * Initialise tone generator. + */ +void toneGen_init(); + +/** + * Terminate tone generator. + */ +void toneGen_shutdown(); + +/** + * Set frequency for CTCSS tone generation. + * @param toneFreq: CTCSS tone frequency. + */ +void toneGen_setToneFreq(float toneFreq); + +/** + * Activate generation of CTCSS tone. + */ +void toneGen_toneOn(); + +/** + * Terminate generation of CTCSS tone. + */ +void toneGen_toneOff(); + +/** + * Set frequency for user interface "beep". + * @param beepFreq: frequency of "beep" tone. + */ +void toneGen_setBeepFreq(float beepFreq); + +/** + * Activate generation of "beep" tone. + */ +void toneGen_beepOn(); + +/** + * Terminate generation of "beep" tone. + */ +void toneGen_beepOff(); + +/** + * Activate generation of "beep" tone with automatic termination after a given + * amount of time. + * @param duration: duration of "beep" tone, in milliseconds. + */ +void toneGen_timedBeep(uint16_t duration); + +#endif /* TONE_GENERATOR_H */ diff --git a/platform/targets/MD380/hwconfig.h b/platform/targets/MD380/hwconfig.h index 636000bc..9bea489b 100644 --- a/platform/targets/MD380/hwconfig.h +++ b/platform/targets/MD380/hwconfig.h @@ -71,4 +71,8 @@ #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