Implemented load/save of settings and VFO configuration for MDx devices

pull/53/head
Silvano Seva 2021-11-09 19:28:23 +01:00
rodzic 756812ca31
commit 691b388228
11 zmienionych plików z 265 dodań i 148 usunięć

Wyświetl plik

@ -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',

Wyświetl plik

@ -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);

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#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) ;
}

Wyświetl plik

@ -21,18 +21,112 @@
#include <string.h>
#include <interfaces/nvmem.h>
#include <cps.h>
#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;
}

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <stm32f4xx.h>
#include <stddef.h>
#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) ;
}

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#ifndef MCUFLASH_H
#define MCUFLASH_H
#include <stdint.h>
#include <stdbool.h>
/**
* 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 */
/***************************************************************************
* 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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#ifndef FLASH_H
#define FLASH_H
#include <stdint.h>
#include <stdbool.h>
#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 */

Wyświetl plik

@ -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.

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)