Reboot problem when using NVS
Posted: Thu May 31, 2018 9:36 am
HI,
I have been using ESP-IDF and its component libraries for a few weeks now.
The first application I built with it was a test application which used only the Wifi component and it worked just fine: operate for a few seconds, go to sleep for 5 seconds, wake up again, work, ....
The second one is the base for our final application, all it does for now is use the NVS library to initialise a parameter storage area, sleep for 60 seconds and start again, ....
it is based on the following enum table to identify each parameter:
There is also an associated area in RAM to hold copies of the parameter data in RAM, which also contain default values for each parameter:
Note: the data shown as "************" is not the real deal of course.
To bind it all together there is a table providing some essential data such as the NVS key strings to use, the parameter's data types and the pointers to the parameter values listed just above:
The idea is to see if the ParameterdataVersion is in the flash, check if it corresponds to what it should be and if not initialise the values in flash to the defined default values in RAM.
The function to do the work is called for each parameter in reverse order ( to guarantee that the ParameterDataVersion value is written to flash last ) and it looks like this:
From the attached serial port output file ( sensitive data converted to "*" symbols ) it is clear to see that it actually works until it suddenly stops while executing the nvs_set function for the ParameterDataVersion ( using key string "ParDataVersion "). From that point onward there is no more serial port output whatsoever. It appears to crash but oddly enough it does perform the 60 second sleep period at the end of the top level program.
One things is certain: the actual ParameterDataVersion does not get written into the flash because the code always performs the same way. That can only be caused by the value not being written so it tries to perform the exact same initialisation procedure over and over.
Some Extra observations:
I have been using ESP-IDF and its component libraries for a few weeks now.
The first application I built with it was a test application which used only the Wifi component and it worked just fine: operate for a few seconds, go to sleep for 5 seconds, wake up again, work, ....
The second one is the base for our final application, all it does for now is use the NVS library to initialise a parameter storage area, sleep for 60 seconds and start again, ....
it is based on the following enum table to identify each parameter:
Code: Select all
enum Parameters
{
ParameterDataVersion, // parameter type: uint32_t
RequiredRxRssiLevel, // parameter type: int8_t
AccessPointSSID_1, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointSSID_2, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointSSID_3, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointSSID_4, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointSSID_5, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointPassword_1, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointPassword_2, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointPassword_3, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointPassword_4, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
AccessPointPassword_5, // parameter type: char [ MAX_STRING_PARAMETER_SIZE ]
OtaServerRootCertificate,// parameter type: char [ MAX_CERTIFICATE_PARAMETER_SIZE ]
DefinedParameters // dummy parameter enum to generate the number of parameters value
};
Code: Select all
static uint32_t _ParameterDataVersion_ = PARAMETER_DATA_VERSION;
static int8_t _RequiredRxRssiLevel_ = -75; //unit = dB
static char _AccessPointSSID_1_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointSSID_2_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointSSID_3_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointSSID_4_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointSSID_5_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointPassword_1_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointPassword_2_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointPassword_3_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointPassword_4_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _AccessPointPassword_5_ [ MAX_STRING_PARAMETER_SIZE ] = "************";
static char _OtaServerRootCertificate_ [ MAX_CERTIFICATE_PARAMETER_SIZE ] = OTA_SERVER_ROOT_CA_PEM;
To bind it all together there is a table providing some essential data such as the NVS key strings to use, the parameter's data types and the pointers to the parameter values listed just above:
Code: Select all
static ParameterListEntry_t ParameterList[ DefinedParameters ]=
{
{ "ParDataVersion ", Type_uint32, &_ParameterDataVersion_ }, // enum index: ParameterDataVersion
{ "ReqRxRssiLevel ", Type_int8, &_RequiredRxRssiLevel_ }, // enum index: RequiredRxRssiLevel
{ "AccessPntSSID_1", Type_string, &_AccessPointSSID_1_ }, // enum index: AccessPointSSID_1
{ "AccessPntSSID_2", Type_string, &_AccessPointSSID_2_ }, // enum index: AccessPointSSID_2
{ "AccessPntSSID_3", Type_string, &_AccessPointSSID_3_ }, // enum index: AccessPointSSID_3
{ "AccessPntSSID_4", Type_string, &_AccessPointSSID_4_ }, // enum index: AccessPointSSID_4
{ "AccessPntSSID_5", Type_string, &_AccessPointSSID_5_ }, // enum index: AccessPointSSID_5
{ "AccessPntPwrd_1", Type_string, &_AccessPointPassword_1_ }, // enum index: AccessPointPassword_1
{ "AccessPntPwrd_2", Type_string, &_AccessPointPassword_2_ }, // enum index: AccessPointPassword_2
{ "AccessPntPwrd_3", Type_string, &_AccessPointPassword_3_ }, // enum index: AccessPointPassword_3
{ "AccessPntPwrd_4", Type_string, &_AccessPointPassword_4_ }, // enum index: AccessPointPassword_4
{ "AccessPntPwrd_5", Type_string, &_AccessPointPassword_5_ }, // enum index: AccessPointPassword_5
{ "OtaServRootCert", Type_string, &_OtaServerRootCertificate_ }, // enum index: OtaServerRootCertificate
};
The function to do the work is called for each parameter in reverse order ( to guarantee that the ParameterDataVersion value is written to flash last ) and it looks like this:
Code: Select all
switch (dataType)
{
case Type_uint8: espError = nvs_set_u8 ( NvsHandle, key, *( uint8_t * ) dataLocation ); break;
case Type_int8: espError = nvs_set_i8 ( NvsHandle, key, *( int8_t * ) dataLocation ); break;
case Type_uint16: espError = nvs_set_u16 ( NvsHandle, key, *( uint16_t * ) dataLocation ); break;
case Type_int16: espError = nvs_set_i16 ( NvsHandle, key, *( int16_t * ) dataLocation ); break;
case Type_uint32: espError = nvs_set_u32 ( NvsHandle, key, *( uint32_t * ) dataLocation ); break;
case Type_int32: espError = nvs_set_i32 ( NvsHandle, key, *( int32_t * ) dataLocation ); break;
case Type_uint64: espError = nvs_set_u64 ( NvsHandle, key, *( uint64_t * ) dataLocation ); break;
case Type_int64: espError = nvs_set_i64 ( NvsHandle, key, *( int64_t * ) dataLocation ); break;
case Type_string: espError = nvs_set_str ( NvsHandle, key, ( char * ) dataLocation ); break;
case Type_certificate: espError = nvs_set_str ( NvsHandle, key, ( char * ) dataLocation ); break;
}
From the attached serial port output file ( sensitive data converted to "*" symbols ) it is clear to see that it actually works until it suddenly stops while executing the nvs_set function for the ParameterDataVersion ( using key string "ParDataVersion "). From that point onward there is no more serial port output whatsoever. It appears to crash but oddly enough it does perform the 60 second sleep period at the end of the top level program.
One things is certain: the actual ParameterDataVersion does not get written into the flash because the code always performs the same way. That can only be caused by the value not being written so it tries to perform the exact same initialisation procedure over and over.
Some Extra observations:
- It always fails/stops after 78.7 milliseconds
The default log level in this case is DEBUG_LEVEL
Adding vTaskDelay(5) does not help much either: it just slows it down a bit and does manage to send the debug message for the ParameterDataVersion parameter.