From 691b3882283b59296868cf887892064293d68ae1 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Tue, 9 Nov 2021 19:28:23 +0100 Subject: [PATCH] Implemented load/save of settings and VFO configuration for MDx devices --- meson.build | 1 + openrtx/src/main.c | 7 +- openrtx/src/state.c | 4 +- openrtx/src/threads.c | 3 - platform/drivers/NVM/mcuFlash_MDx.c | 82 -------------- platform/drivers/NVM/nvmem_settings_MDx.c | 102 ++++++++++++++++- platform/mcu/STM32F4xx/drivers/flash.c | 94 ++++++++++++++++ .../STM32F4xx/drivers/flash.h} | 106 ++++++++++-------- platform/mcu/STM32F4xx/linker_script.ld | 3 +- platform/targets/MD-3x0/platform.c | 6 +- platform/targets/MD-UV3x0/platform.c | 5 +- 11 files changed, 265 insertions(+), 148 deletions(-) delete mode 100644 platform/drivers/NVM/mcuFlash_MDx.c create mode 100644 platform/mcu/STM32F4xx/drivers/flash.c rename platform/{drivers/NVM/mcuFlash.h => mcu/STM32F4xx/drivers/flash.h} (88%) diff --git a/meson.build b/meson.build index cdaeade7..b0d6100e 100644 --- a/meson.build +++ b/meson.build @@ -169,6 +169,7 @@ stm32f405_src = ['platform/mcu/STM32F4xx/boot/startup.cpp', 'platform/mcu/STM32F4xx/drivers/rtc.c', 'platform/mcu/STM32F4xx/drivers/SPI2.c', 'platform/mcu/STM32F4xx/drivers/USART3.cpp', + 'platform/mcu/STM32F4xx/drivers/flash.c', 'platform/mcu/CMSIS/Device/ST/STM32F4xx/Source/system_stm32f4xx.c'] stm32f405_inc = ['platform/mcu/CMSIS/Include', diff --git a/openrtx/src/main.c b/openrtx/src/main.c index 0a9a3838..470026de 100644 --- a/openrtx/src/main.c +++ b/openrtx/src/main.c @@ -48,11 +48,14 @@ int main(void) // Initialize platform drivers platform_init(); + // Initialize radio state + state_init(); + // Initialize display and graphics driver gfx_init(); // Set default contrast - display_setContrast(default_settings.contrast); + display_setContrast(state.settings.contrast); // Initialize user interface ui_init(); @@ -63,7 +66,7 @@ int main(void) // Wait 30ms before turning on backlight to hide random pixels on screen sleepFor(0u, 30u); - platform_setBacklightLevel(255); + platform_setBacklightLevel(state.settings.brightness); // Keep the splash screen for 1 second sleepFor(1u, 0u); diff --git a/openrtx/src/state.c b/openrtx/src/state.c index fed01c18..6b0ef7b7 100644 --- a/openrtx/src/state.c +++ b/openrtx/src/state.c @@ -34,7 +34,7 @@ void state_init() * Try loading settings from nonvolatile memory and default to sane values * in case of failure. */ - if(nvm_readSettings(&state.settings) != 0) + if(nvm_readSettings(&state.settings) < 0) { state.settings = default_settings; strncpy(state.settings.callsign, "OPNRTX", 10); @@ -44,7 +44,7 @@ void state_init() * Try loading VFO configuration from nonvolatile memory and default to sane * values in case of failure. */ - if(nvm_readVFOChannelData(&state.channel) != 0) + if(nvm_readVFOChannelData(&state.channel) < 0) { state.channel.mode = FM; state.channel.bandwidth = BW_25; diff --git a/openrtx/src/threads.c b/openrtx/src/threads.c index 32f5620d..8e9a27a3 100644 --- a/openrtx/src/threads.c +++ b/openrtx/src/threads.c @@ -327,9 +327,6 @@ void create_threads() // Create UI event queue queue_init(&ui_queue); - // State initialization, execute before starting all tasks - state_init(); - // Create rtx radio thread pthread_t rtx_thread; pthread_attr_t rtx_attr; diff --git a/platform/drivers/NVM/mcuFlash_MDx.c b/platform/drivers/NVM/mcuFlash_MDx.c deleted file mode 100644 index 5df510ab..00000000 --- a/platform/drivers/NVM/mcuFlash_MDx.c +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************** - * 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 "mcuFlash.h" - -inline bool unlock() -{ - // Flash already unlocked - if((FLASH->CR & FLASH_CR_LOCK) == 0) - { - return true; - } - - FLASH->KEYR = 0x45670123; - FLASH->KEYR = 0xCDEF89AB; - - // Succesful unlock - if((FLASH->CR & FLASH_CR_LOCK) == 0) - { - return true; - } - - return false; -} - -bool mcuFlash_eraseSector(const uint8_t secNum) -{ - if(secNum > 11) return false; - if(unlock() == false) return false; - - // Flash busy, wait until previous operation finishes - while((FLASH->SR & FLASH_SR_BSY) != 0) ; - - FLASH->CR |= FLASH_CR_PSIZE_1 // 32-bit program parallelism - | (secNum << 3) // Sector number - | FLASH_CR_SER // Sector erase - | FLASH_CR_STRT; // Start erase - - // Wait until erase ends - while((FLASH->SR & FLASH_SR_BSY) != 0) ; - - return true; -} - -void mcuFlash_write(const uint32_t address, const void *data, const size_t len) -{ - if((data == NULL) || (len == 0)) return; - - // Flash busy, wait until previous operation finishes - while((FLASH->SR & FLASH_SR_BSY) != 0) ; - - // Request programming with 8-bit parallelism - FLASH->CR = FLASH_CR_PG; - - const uint8_t *buf = ((uint8_t *) data); - const uint8_t *mem = ((uint8_t *) address); - for(size_t i = 0; i < len; i++) - { - *mem = buf[i]; - mem++; - } - - // Wait until the end of the write operation - while((FLASH->SR & FLASH_SR_BSY) != 0) ; -} \ No newline at end of file diff --git a/platform/drivers/NVM/nvmem_settings_MDx.c b/platform/drivers/NVM/nvmem_settings_MDx.c index 4c78fabc..a830b62f 100644 --- a/platform/drivers/NVM/nvmem_settings_MDx.c +++ b/platform/drivers/NVM/nvmem_settings_MDx.c @@ -21,18 +21,112 @@ #include #include #include +#include "flash.h" -int nvm_readSettings(settings_t *settings) + +typedef struct { - return -1; + uint32_t magic; + uint32_t flags[64]; + struct dataBlock + { + settings_t settings; + channel_t vfoData; + } + data[2048]; } +__attribute__((packed)) memory_t; + +static const uint32_t validMagic = 0x5854524F; // "ORTX" +static const uint32_t baseAddress = 0x080E0000; +memory_t *memory = ((memory_t *) baseAddress); + + +/** + * \internal + * Utility function to find the currently active data block inside memory, that + * is the one containing the last saved settings. + * + * @return number currently active data block or -1 if memory data is invalid. + */ +int findActiveBlock() +{ + if(memory->magic != validMagic) return -1; + + uint16_t block = 0; + for(; block < 64; block++) + { + if(memory->flags[block] != 0x00000000) + { + break; + } + } + + uint16_t bit = 0; + for(; bit < 32; bit++) + { + if((memory->flags[block] & (1 << bit)) != 0) + { + break; + } + } + + block = (block * 32) + bit; + return block - 1; +} + + int nvm_readVFOChannelData(channel_t *channel) { - return -1; + int block = findActiveBlock(); + if(block < 0) return -1; + memcpy(channel, &(memory->data[block].vfoData), sizeof(channel_t)); + return 0; +} + +int nvm_readSettings(settings_t *settings) +{ + int block = findActiveBlock(); + if(block < 0) return -1; + memcpy(settings, &(memory->data[block].settings), sizeof(settings_t)); + return 0; } int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo) { - return -1; + uint32_t addr = 0; + int block = findActiveBlock(); + + /* + * Memory never initialised or save space finished: erase all the sector. + * On STM32F405 the settings are saved in sector 11, starting at address + * 0x08060000. + */ + if((block < 0) || (block >= 2047)) + { + flash_eraseSector(11); + addr = ((uint32_t) &(memory->magic)); + flash_write(addr, &validMagic, sizeof(validMagic)); + block = 0; + } + else + { + block += 1; + } + + // Save settings + addr = ((uint32_t) &(memory->data[block].settings)); + flash_write(addr, settings, sizeof(settings_t)); + + // Save VFO configuration + addr = ((uint32_t) &(memory->data[block].vfoData)); + flash_write(addr, vfo, sizeof(channel_t)); + + // Update the flags marking used data blocks + uint32_t flag = ~(1 << (block % 32)); + addr = ((uint32_t) &(memory->flags[block / 32])); + flash_write(addr, &flag, sizeof(uint32_t)); + + return 0; } diff --git a/platform/mcu/STM32F4xx/drivers/flash.c b/platform/mcu/STM32F4xx/drivers/flash.c new file mode 100644 index 00000000..c05326c7 --- /dev/null +++ b/platform/mcu/STM32F4xx/drivers/flash.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * 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 "flash.h" + +/** + * \internal + * Utility function performing unlock of flash erase and write access. + * + * @true on success, false on failure. + */ +static inline bool unlock() +{ + // Flash already unlocked + if((FLASH->CR & FLASH_CR_LOCK) == 0) + { + return true; + } + + FLASH->KEYR = 0x45670123; + FLASH->KEYR = 0xCDEF89AB; + + // Succesful unlock + if((FLASH->CR & FLASH_CR_LOCK) == 0) + { + return true; + } + + return false; +} + + + +bool flash_eraseSector(const uint8_t secNum) +{ + if(secNum > 11) return false; + if(unlock() == false) return false; + + // Flash busy, wait until previous operation finishes + while((FLASH->SR & FLASH_SR_BSY) != 0) ; + + FLASH->CR |= FLASH_CR_PSIZE_1 // 32-bit program parallelism + | (secNum << 3) // Sector number + | FLASH_CR_SER // Sector erase + | FLASH_CR_STRT; // Start erase + + // Wait until erase ends + while((FLASH->SR & FLASH_SR_BSY) != 0) ; + + return true; +} + +void flash_write(const uint32_t address, const void *data, const size_t len) +{ + if(unlock() == false) return; + if((data == NULL) || (len == 0)) return; + + // Flash busy, wait until previous operation finishes + while((FLASH->SR & FLASH_SR_BSY) != 0) ; + + // Request programming with 8-bit parallelism + FLASH->CR = FLASH_CR_PG; + + // Write data to memory + const uint8_t *buf = ((uint8_t *) data); + uint8_t *mem = ((uint8_t *) address); + for(size_t i = 0; i < len; i++) + { + *mem = buf[i]; + mem++; + } + + // Wait until the end of the write operation + while((FLASH->SR & FLASH_SR_BSY) != 0) ; +} diff --git a/platform/drivers/NVM/mcuFlash.h b/platform/mcu/STM32F4xx/drivers/flash.h similarity index 88% rename from platform/drivers/NVM/mcuFlash.h rename to platform/mcu/STM32F4xx/drivers/flash.h index fbfceefe..b63e1149 100644 --- a/platform/drivers/NVM/mcuFlash.h +++ b/platform/mcu/STM32F4xx/drivers/flash.h @@ -1,49 +1,57 @@ -/*************************************************************************** - * 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 * - ***************************************************************************/ - -#ifndef MCUFLASH_H -#define MCUFLASH_H - -#include -#include - -/** - * Driver for MCU's internal flash management, allowing for sector erase and data - * writing. - */ - -/** - * Erase one sector of the MCU flash memory. - * - * @param secNum: sector number. - * @return true for successful erase, false otherwise. - */ -bool mcuFlash_eraseSector(const uint8_t secNum); - -/** - * Write data to the MCU flash memory. - * - * @param address: starting address for the write operation. - * @param data: data to be written. - * @param len: data length. - */ -void mcuFlash_write(const uint32_t address, const void *data, const size_t len); - -#endif /* MCUFLASH_H */ \ No newline at end of file +/*************************************************************************** + * 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 * + ***************************************************************************/ + +#ifndef FLASH_H +#define FLASH_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Driver for MCU's internal flash management, allowing for sector erase and data + * writing. + */ + +/** + * Erase one sector of the MCU flash memory. + * + * @param secNum: sector number. + * @return true for successful erase, false otherwise. + */ +bool flash_eraseSector(const uint8_t secNum); + +/** + * Write data to the MCU flash memory. + * + * @param address: starting address for the write operation. + * @param data: data to be written. + * @param len: data length. + */ +void flash_write(const uint32_t address, const void *data, const size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* FLASH_H */ diff --git a/platform/mcu/STM32F4xx/linker_script.ld b/platform/mcu/STM32F4xx/linker_script.ld index 5520da0a..598d8724 100644 --- a/platform/mcu/STM32F4xx/linker_script.ld +++ b/platform/mcu/STM32F4xx/linker_script.ld @@ -59,7 +59,8 @@ ENTRY(_Z13Reset_Handlerv) /* specify the memory areas */ MEMORY { - flash(rx) : ORIGIN = 0x0800C000, LENGTH = 1M - 48K + /* Reserve space for bootloader and settings */ + flash(rx) : ORIGIN = 0x0800C000, 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. diff --git a/platform/targets/MD-3x0/platform.c b/platform/targets/MD-3x0/platform.c index f6596e5c..aeb12fec 100644 --- a/platform/targets/MD-3x0/platform.c +++ b/platform/targets/MD-3x0/platform.c @@ -38,9 +38,6 @@ void platform_init() 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); @@ -50,6 +47,7 @@ void platform_init() gpio_setMode(PTT_EXT, INPUT); gpio_setMode(PWR_SW, OUTPUT); + gpio_setPin(PWR_SW); /* * Initialise ADC1, for vbat, RSSI, ... @@ -146,7 +144,7 @@ bool platform_pwrButtonStatus() * is always a bit of noise in the ADC measurement making the returned * voltage not to be exactly zero. */ - return (platform_getVbat() > 1.0f) ? true : false; + return (platform_getVbat() > 1000) ? true : false; } void platform_ledOn(led_t led) diff --git a/platform/targets/MD-UV3x0/platform.c b/platform/targets/MD-UV3x0/platform.c index d1cd9d64..0f704948 100644 --- a/platform/targets/MD-UV3x0/platform.c +++ b/platform/targets/MD-UV3x0/platform.c @@ -45,6 +45,9 @@ void platform_init() gpio_setMode(PTT_SW, INPUT_PULL_UP); gpio_setMode(PTT_EXT, INPUT_PULL_UP); + gpio_setMode(PWR_SW, OUTPUT); + gpio_setPin(PWR_SW); + /* * Initialise ADC1, for vbat, RSSI, ... * Configuration of corresponding GPIOs in analog input mode is done inside @@ -141,7 +144,7 @@ bool platform_pwrButtonStatus() * is always a bit of noise in the ADC measurement making the returned * voltage not to be exactly zero. */ - return (platform_getVbat() > 1.0f) ? true : false; + return (platform_getVbat() > 1000) ? true : false; } void platform_ledOn(led_t led)