nvm: measurement storage

tatry_variant
Mateusz Lubecki 2022-11-10 18:16:56 +01:00
rodzic 88fd2987cb
commit acddab74e3
9 zmienionych plików z 373 dodań i 14 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="ilg.gnumcueclipse.debug.gdbjtag.openocd.launchConfigurationType">
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;peripherals&gt;&#10; &lt;peripheral name=&quot;GPIOA&quot;/&gt;&#10; &lt;peripheral name=&quot;RTC&quot;/&gt;&#10; &lt;peripheral name=&quot;ADC2&quot;/&gt;&#10;&lt;/peripherals&gt;&#10;"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;peripherals&gt;&#10; &lt;peripheral name=&quot;FLASH&quot;/&gt;&#10;&lt;/peripherals&gt;&#10;"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doContinue" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doDebugInRam" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doFirstReset" value="true"/>
@ -57,6 +57,6 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;/&gt;&#10;"/>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#10; &lt;memoryBlockExpression address=&quot;134742016&quot; label=&quot;0x8080000&quot;/&gt;&#10; &lt;memoryBlockExpression address=&quot;134762496&quot; label=&quot;0x8085000&quot;/&gt;&#10; &lt;memoryBlockExpression address=&quot;134764544&quot; label=&quot;0x8085800&quot;/&gt;&#10;&lt;/memoryBlockExpressionList&gt;&#10;"/>
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
</launchConfiguration>

Wyświetl plik

@ -101,6 +101,8 @@ void main_service_cpu_load_ticks(void);
void main_reload_internal_wdg(void);
uint32_t main_get_nvm_timestamp(void);
#if defined(STM32L471xx)
extern uint32_t rte_main_rx_total;
extern uint32_t rte_main_tx_total;

Wyświetl plik

@ -10,6 +10,8 @@
#include <stdint.h>
#define NVM_RECORD_SIZE 8 // in bytes!!
typedef struct __attribute__((packed)) nvm_measurement_t {
/**
* Date-time timestamp in timezone local for a place where station is installed.
@ -22,16 +24,19 @@ typedef struct __attribute__((packed)) nvm_measurement_t {
uint32_t timestamp;
/**
* Temperature represented as 0.1 degrees increment and
* Temperature represented as 0.2 degrees increment and
* humidity in 2% steps
* bit 0 - bit 9 === raw temperature, physical: raw / 10 - 50 (from -50.0 to +52.3)
* bit 0 - bit 9 === raw temperature, physical: raw / 5 - 50 (from -50.0 to +52.3)
* bit 10 - bit 15 === raw humidity, physical: raw * 2 (from 0% to 100%)
*/
uint16_t temperature_humidity;
/**
* Average windspeed and gust windspeed stored in 0.2m/s increments
* bit 0 - bit 7 === raw average windspeed, physical: raw / 5 (from 0m/s up to 50m/s)
* bit 0 - bit 7 === raw average windspeed, physical: raw / 5 (from 0m/s up to 50m/s)
* bit 9 - bit 12 === raw maximum windspeed, physical: physical_average + raw / 3
* bit 13 - bit 16 === wind direction. lookup table:
* 0 -
*/
uint16_t wind;
@ -47,5 +52,8 @@ typedef enum nvm_state_result_t {
void nvm_measurement_init(void);
nvm_state_result_t nvm_measurement_store(nvm_measurement_t * data);
void nvm_erase_all(void);
void nvm_test_prefill(void); ///<! Only for test purposes!
#endif /* NVM_H_ */

Wyświetl plik

@ -25,6 +25,7 @@ void wx_get_all_measurements(const config_data_wx_sources_t * const config_sourc
int32_t wx_get_bme280_temperature_pressure_humidity(float * const temperature, float * const pressure, int8_t * const humidity);
void wx_pool_anemometer(const config_data_wx_sources_t * const config_sources, const config_data_mode_t * const config_mode, const config_data_umb_t * const config_umb, const config_data_rtu_t * const config_rtu);
void wx_check_force_i2c_reset(void);
uint16_t wx_get_nvm_record_temperature(void);
uint16_t wx_get_nvm_record_wind(void);
#endif /* WX_HANDLER_H_ */

Wyświetl plik

@ -165,6 +165,9 @@ const config_data_gsm_t * main_config_data_gsm = 0;
// global variable incremented by the SysTick handler to measure time in miliseconds
uint32_t master_time = 0;
// current timestamp from RTC in NVM format
uint32_t main_nvm_timestamp = 0;
// this global variable stores numbers of ticks of idling CPU
uint32_t main_idle_cpu_ticks = 0;
@ -396,6 +399,12 @@ int main(int argc, char* argv[]){
main_crc_result = 0;
configuration_set_register(0);
#if defined(STM32L471xx)
nvm_erase_all();
nvm_test_prefill();
#endif
}
// if first section has wrong CRC and it hasn't been restored before
@ -1043,6 +1052,8 @@ int main(int argc, char* argv[]){
#endif
}
main_nvm_timestamp = main_get_nvm_timestamp();
// Infinite loop
while (1)
{
@ -1351,6 +1362,8 @@ int main(int argc, char* argv[]){
main_set_monitor(4);
main_nvm_timestamp = main_get_nvm_timestamp();
#ifndef _MUTE_OWN
packet_tx_handler(main_config_data_basic, main_config_data_mode);
#endif
@ -1561,6 +1574,66 @@ void main_reload_internal_wdg(void){
#endif
}
uint32_t main_get_nvm_timestamp(void) {
uint32_t out = 0;
/**
* Date-time timestamp in timezone local for a place where station is installed.
* Mixture of BCD and integer format, this is just sligtly processed RTC registers
* content.
* bit 0 - bit 12 === number of minutes starting from midnight (max 1440)
* bit 16 - bit 24 === days from new year (max 356)
* bit 25 - bit 31 === years (from 00 to 99, from 2000 up to 2099)
*/
#ifdef STM32L471xx
uint16_t temp = 0;
// minutes
temp = 600 * ((RTC->TR & RTC_TR_HT) >> RTC_TR_HT_Pos) +
60 * ((RTC->TR & RTC_TR_HU) >> RTC_TR_HU_Pos) +
10 * ((RTC->TR & RTC_TR_MNT) >> RTC_TR_MNT_Pos) +
1 * ((RTC->TR & RTC_TR_MNU) >> RTC_TR_MNU_Pos);
out = out | (temp & 0x7FF);
// current month
temp = 1 * ((RTC->DR & RTC_DR_MU) >> RTC_DR_MU_Pos) +
10 * ((RTC->DR & RTC_DR_MT) >> RTC_DR_MT_Pos);
switch (temp) {
case 1: temp = 0; break;
case 2: temp = 31; break;
case 3: temp = 31 + 28; break;
case 4: temp = 31 + 28 + 31; break;
case 5: temp = 31 + 28 + 31 + 30; break;
case 6: temp = 31 + 28 + 31 + 30 + 31; break;
case 7: temp = 31 + 28 + 31 + 30 + 31 + 30; break;
case 8: temp = 31 + 28 + 31 + 30 + 31 + 30 + 31; break;
case 9: temp = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31; break;
case 10:temp = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30; break;
case 11:temp = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31; break;
case 12:temp = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30; break;
}
// then add number of days from current month
temp = temp +
1 * ((RTC->DR & RTC_DR_DU) >> RTC_DR_DU_Pos) +
10 * ((RTC->DR & RTC_DR_DT) >> RTC_DR_DT_Pos);
out = out | ((temp & 0x1FF) << 16);
// years
temp = 10 * ((RTC->DR & RTC_DR_YT) >> RTC_DR_YT_Pos) +
1 * ((RTC->DR & RTC_DR_YU) >> RTC_DR_YU_Pos);
out = out | ((temp & 0x7F) << 25);
#endif
return out;
}
#pragma GCC diagnostic pop

186
src/nvm.c
Wyświetl plik

@ -20,7 +20,10 @@
#endif
#define NVM_MEASUREMENT_OFFSET 0
#define NVM_MEASUREMENT_MAXIMUM_SIZ (NVM_PAGE_SIZE * 96)
#define NVM_MEASUREMENT_PAGES_USED 96
#define NVM_MEASUREMENT_MAXIMUM_SIZ (NVM_PAGE_SIZE * NVM_MEASUREMENT_PAGES_USED)
#define START_OF_LAST_NVM_PAGE (nvm_base_address + NVM_MEASUREMENT_MAXIMUM_SIZ - NVM_PAGE_SIZE)
uint32_t nvm_base_address = 0;
@ -63,11 +66,11 @@ void nvm_measurement_init(void) {
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
nvm_base_address = 0x08040000;
nvm_base_address = 0x08080000;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
nvm_base_address = 0x08080000;
nvm_base_address = 0x08040000;
}
else {
// unknown device ??
@ -136,6 +139,9 @@ void nvm_measurement_init(void) {
nvm_general_state = NVM_OK;
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
FLASH_Lock();
}
else {
@ -147,16 +153,190 @@ void nvm_measurement_init(void) {
nvm_state_result_t nvm_measurement_store(nvm_measurement_t * data) {
nvm_state_result_t out = NVM_OK;
#if defined(STM32L471xx)
volatile uint32_t * src = (uint32_t *)data;
uint32_t next_page_addr = 0;
// flash operation result
FLASH_Status flash_status = 0;
// check if there is a room for storage
if (nvm_general_state == NVM_NO_SPACE_LEFT) {
// erase first page of NVM flash area
nvm_data_ptr = (uint8_t*)nvm_base_address;
flash_status = FLASH_ErasePage(nvm_data_ptr);
if (flash_status == FLASH_COMPLETE) {
nvm_general_state = NVM_OK;
}
else {
nvm_general_state = NVM_PGM_ERROR;
}
}
else {
// check if currently last page is used
if ((uint32_t)nvm_data_ptr < START_OF_LAST_NVM_PAGE) {
// if not check if next page of flash memory is erased or not
if (*(nvm_data_ptr + NVM_PAGE_SIZE) != 0xFF) {
// an address somewhere within the next page of memory
next_page_addr = (uint32_t)nvm_data_ptr + NVM_PAGE_SIZE;
// a start of next flash page
next_page_addr = (next_page_addr / NVM_PAGE_SIZE) * NVM_PAGE_SIZE;
flash_status = FLASH_ErasePage(next_page_addr);
if (flash_status != FLASH_COMPLETE) {
nvm_general_state = NVM_PGM_ERROR;
}
}
}
}
FLASH_Unlock();
// check if NVM has been initialized and it is ready to work
if (nvm_general_state != NVM_UNINITIALIZED) {
// check if there is a room to store this measurement
if (nvm_general_state != NVM_NO_SPACE_LEFT) {
// enable programming
FLASH->CR |= FLASH_CR_PG;
// progam this measurement
for (int i = 0 ; i < NVM_RECORD_SIZE / 4; i++) {
*((uint32_t*)(nvm_data_ptr) + i) = *(src + i);
WAIT_FOR_PGM_COMPLETION
if (flash_status != FLASH_COMPLETE) {
break;
}
}
// move data pointer
nvm_data_ptr += NVM_WRITE_BYTE_ALIGN;
// and check if an end has
if ((uint32_t)nvm_data_ptr < nvm_base_address + NVM_MEASUREMENT_MAXIMUM_SIZ) {
;
}
else {
out = NVM_NO_SPACE_LEFT;
nvm_general_state = NVM_NO_SPACE_LEFT;
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
}
}
FLASH_Lock();
#endif
return out;
}
void nvm_erase_all(void) {
#if defined(STM32L471xx)
uint32_t base_address = 0;
FLASH_Unlock();
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = 0x08080000;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = 0x08040000;
}
else {
return;
}
for (int i = 0; i < NVM_MEASUREMENT_PAGES_USED; i++) {
FLASH_ErasePage(base_address + (i * NVM_PAGE_SIZE));
}
FLASH_Lock();
#endif
}
void nvm_test_prefill(void) {
#if defined(STM32L471xx)
uint32_t * base_address = 0;
// flash operation result
FLASH_Status flash_status = 0;
FLASH_Unlock();
// enable programming
FLASH->CR |= FLASH_CR_PG;
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = (uint32_t *)0x08080000;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = (uint32_t *)0x08040000;
}
else {
return;
}
// program first 10 pages of flash with 0xABCDABCD / 0x99889988
for (int i = 0; i < 10; i++) {
// flash programming must be 64 bit (8 bytes) aligned
for (int j = 0; j < NVM_PAGE_SIZE / 8; j++) {
*(base_address++) = 0xABCDABCD;
WAIT_FOR_PGM_COMPLETION
*(base_address++) = 0x99889988;
WAIT_FOR_PGM_COMPLETION
}
}
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = (uint32_t *)(0x08080000 + 11 * NVM_PAGE_SIZE);
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = (uint32_t *)(0x08040000 + 11 * NVM_PAGE_SIZE);
}
else {
return;
}
for (int i = 11; i < NVM_MEASUREMENT_PAGES_USED; i++) {
// flash programming must be 64 bit (8 bytes) aligned
for (int j = 0; j < NVM_PAGE_SIZE / 8; j++) {
*(base_address++) = 0x12345678;
WAIT_FOR_PGM_COMPLETION
*(base_address++) = 0x99999999;
WAIT_FOR_PGM_COMPLETION
}
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
FLASH_Lock();
#endif
}

Wyświetl plik

@ -22,6 +22,7 @@
#include "aprsis.h"
#include "api/api.h"
#include "pwr_save.h"
#include "nvm.h"
#endif
#include "main.h"
@ -60,6 +61,7 @@ uint8_t packet_tx_trigger_tcp = 0;
#define APRSIS_TRIGGER_METEO (1 << 3)
#define RECONNECT_APRSIS (1 << 7)
nvm_measurement_t packet_tx_nvm;
#endif
void packet_tx_send_wx_frame(void) {
@ -234,6 +236,15 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con
// check if there is a time to send meteo packet through RF
if (packet_tx_meteo_counter >= packet_tx_meteo_interval && packet_tx_meteo_interval != 0) {
#ifdef STM32L471xx
packet_tx_nvm.temperature_humidity = wx_get_nvm_record_temperature();
packet_tx_nvm.wind = wx_get_nvm_record_wind();
packet_tx_nvm.timestamp = main_get_nvm_timestamp();
// write to NVM if it is enabled
nvm_measurement_store(&packet_tx_nvm);
#endif
// this function is required if more than one RF frame will be send from this function at once
// it waits for transmission completion and add some delay to let digipeaters do theris job
packet_tx_multi_per_call_handler();

Wyświetl plik

@ -349,4 +349,72 @@ void wx_pool_anemometer(const config_data_wx_sources_t * const config_sources, c
}
uint16_t wx_get_nvm_record_temperature(void) {
uint16_t out = 0;
uint16_t scaled_temperature = 0;
uint16_t scaled_humidity = 0;
if (rte_wx_temperature_average_external_valid > -50.0f && rte_wx_temperature_average_external_valid < 50.0f) {
scaled_temperature = (uint16_t)((rte_wx_temperature_average_external_valid + 50.0f) * 5.0f);
}
scaled_humidity = rte_wx_humidity_valid / 2;
out = (scaled_temperature & 0x1FF) | ((scaled_humidity & 0x1F) << 10);
return out;
}
uint16_t wx_get_nvm_record_wind(void) {
uint16_t out = 0;
uint8_t scaled_average_windspeed = 0;
uint8_t scaled_windgusts = 0;
uint8_t wind_direction = 0;
scaled_average_windspeed = rte_wx_average_windspeed / 2;
if ((rte_wx_max_windspeed - scaled_average_windspeed) < 52) {
scaled_windgusts = (uint8_t)lroundf((rte_wx_max_windspeed - scaled_average_windspeed) / 3.0f);
}
if (wind_direction <= 11 && wind_direction >= 349)
wind_direction = 0;
else if (wind_direction <= 34 && wind_direction > 11)
wind_direction = 1;
else if (wind_direction <= 56 && wind_direction > 34)
wind_direction = 2;
else if (wind_direction <= 79 && wind_direction > 56)
wind_direction = 3;
else if (wind_direction <= 101 && wind_direction > 79)
wind_direction = 4;
else if (wind_direction <= 124 && wind_direction > 101)
wind_direction = 5;
else if (wind_direction <= 146 && wind_direction > 124)
wind_direction = 6;
else if (wind_direction <= 169 && wind_direction > 146)
wind_direction = 7;
else if (wind_direction <= 191 && wind_direction > 169)
wind_direction = 8;
else if (wind_direction <= 214 && wind_direction > 191)
wind_direction = 9;
else if (wind_direction <= 236 && wind_direction > 214)
wind_direction = 10;
else if (wind_direction <= 259 && wind_direction > 236)
wind_direction = 11;
else if (wind_direction <= 281 && wind_direction > 259)
wind_direction = 12;
else if (wind_direction <= 304 && wind_direction > 281)
wind_direction = 13;
else if (wind_direction <= 327 && wind_direction > 304)
wind_direction = 14;
else if (wind_direction <= 349 && wind_direction > 327)
wind_direction = 15;
else;
out = (scaled_average_windspeed | (scaled_windgusts & 0xF) << 8 | (wind_direction & 0xF) << 12 );
return out;
}

Wyświetl plik

@ -8,6 +8,9 @@
#include "./drivers/l4/flash_stm32l4x.h"
#include "stm32l4xx.h"
#define KB *1024
#define FLASH_KEY1 0x45670123U /*!< Flash key1 */
#define FLASH_KEY2 0xCDEF89ABU /*!< Flash key2: used with FLASH_KEY1
to unlock the FLASH registers access */
@ -74,14 +77,27 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
uint32_t Banks = 0;
// calculate the bank number
if (Page_Address < 0x08080000) {
Banks = FLASH_BANK_1;
if (FLASH_SIZE == 1024 KB) {
// calculate the bank number
if (Page_Address < 0x08080000) {
Banks = FLASH_BANK_1;
}
else {
Banks = FLASH_BANK_2;
}
}
else {
Banks = FLASH_BANK_2;
else if (FLASH_SIZE == 512 KB) {
// calculate the bank number
if (Page_Address < 0x08040000) {
Banks = FLASH_BANK_1;
}
else {
Banks = FLASH_BANK_2;
}
}
FLASH_Unlock();
Page = Page_Address - 0x08000000 - (0x80000 * (Banks - 1));