It is very requisite for internet of thing (IoT) application to have a non-volatile memory, it could keep the status when the battery runs out.
In nRF51/52 series, the flash is called as "Persistent storage", the APIs of this kind are begin from pstorage.
There are examples and guild for how to exploit the pstorag, but I found those are not concise enough. So in here, I would demonstrate how to call the pstorage api in practice case.
Continue from my previous post, I want to add code of pstorage in that.
Add Below code about line 603 :
static void power_manage(void) { uint32_t err_code = sd_app_evt_wait(); APP_ERROR_CHECK(err_code); } #ifndef FALSE #define FALSE (0) #define TRUE (1) #endif #define UART_TX_BUF_SIZE (256) #define UART_RX_BUF_SIZE (256) #define APP_BLOCK_SIZE (32) pstorage_handle_t m_app_storage_base_handle; static uint8_t m_is_need_to_wait_pstorage_operation = FALSE; static pstorage_block_t m_pstorage_operation_block_id = 0; unsigned char m_pstorage_buffer[APP_BLOCK_SIZE]; void app_storage_save_data(void); void app_storage_print_stored_data(void); /** * @brief UART events handler. */ void uart_events_handler(app_uart_evt_t * p_event) { switch (p_event->evt_type) { case APP_UART_DATA_READY: { unsigned char received_char; UNUSED_VARIABLE(app_uart_get(&received_char)); if('~' == received_char) { app_storage_print_stored_data(); NVIC_SystemReset(); } { sprintf((char*)&m_pstorage_buffer[0], " received char = %c\r\n", received_char); pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); /* m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; */ uint32_t err_code; err_code = pstorage_update(&block_handle, &m_pstorage_buffer[0], APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); printf("storing str :\"%s\" into flash\r\n", (char*)&m_pstorage_buffer[0]); }/*store data to flash block*/ } break; case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; case APP_UART_TX_EMPTY: break; case APP_UART_DATA: break; default: break; } } /** * @brief UART initialization. */ void uart_config(void) { uint32_t err_code; const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, TX_PIN_NUMBER, RTS_PIN_NUMBER, CTS_PIN_NUMBER, APP_UART_FLOW_CONTROL_DISABLED, false, UART_BAUDRATE_BAUDRATE_Baud38400 }; APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_events_handler, APP_IRQ_PRIORITY_LOW, err_code); APP_ERROR_CHECK(err_code); }/*uart_config*/ // Event Notification Handler. static void app_storage_callback_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len) { if(handle->block_id == m_pstorage_operation_block_id) m_is_need_to_wait_pstorage_operation = FALSE; switch(op_code) { case PSTORAGE_STORE_OP_CODE: if(NRF_SUCCESS != result) printf("pstorage STORE ERROR callback received \r\n"); break; case PSTORAGE_LOAD_OP_CODE: if(NRF_SUCCESS != result) printf("pstorage LOAD ERROR callback received \r\n"); break; case PSTORAGE_CLEAR_OP_CODE: if(NRF_SUCCESS != result) printf("pstorage CLEAR ERROR callback received \r\n"); break; case PSTORAGE_UPDATE_OP_CODE: if(NRF_SUCCESS != result) printf("pstorage UPDATE ERROR callback received \r\n"); break; default: printf("pstorage ERROR callback received \r\n"); break; } }/*app_storage_callback_handler*/ /** * @brief pstorage initializing and block register */ void app_storage_init() { uint32_t err_code; err_code = pstorage_init(); APP_ERROR_CHECK(err_code); pstorage_module_param_t pstorage_param; pstorage_param.block_size = APP_BLOCK_SIZE; pstorage_param.block_count = 1; pstorage_param.cb = app_storage_callback_handler; err_code = pstorage_register(&pstorage_param, &m_app_storage_base_handle); APP_ERROR_CHECK(err_code); #if(0) { pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; err_code = pstorage_clear(&block_handle, APP_BLOCK_SIZE); APP_ERROR_CHECK(err_code); while(FALSE != m_is_need_to_wait_pstorage_operation) power_manage(); }/*clear data block*/ #endif }/*pstorage_init_store_and_update*/ void app_storage_save_data(void) { uint32_t err_code; #if(0) { pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; err_code = pstorage_clear(&block_handle, APP_BLOCK_SIZE); APP_ERROR_CHECK(err_code); while(FALSE != m_is_need_to_wait_pstorage_operation) power_manage(); }/*clear data block*/ #endif { pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; //err_code = pstorage_store(&block_handle, &m_pstorage_buffer[0], // APP_BLOCK_SIZE, 0); err_code = pstorage_update(&block_handle, &m_pstorage_buffer[0], APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); while(FALSE != m_is_need_to_wait_pstorage_operation) power_manage(); }/*store code block*/ }/*app_storage_save_data*/ void app_storage_print_stored_data(void) { uint32_t err_code; unsigned char storedData[APP_BLOCK_SIZE]; pstorage_handle_t block_handle; err_code = pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); APP_ERROR_CHECK(err_code); err_code = pstorage_load(&storedData[0], &block_handle, APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); { printf("%s\r\n", &storedData[0]); } }/*app_storage_print_stored_data*/ /**@brief Function for application main entry. */ int main(void) { uint32_t err_code; bool erase_bonds; uart_config(); printf("Start...\r\n"); // Initialize. timers_init(); buttons_leds_init(&erase_bonds); ble_stack_init(); app_storage_init(); app_storage_print_stored_data(); sprintf((char*)&m_pstorage_buffer[0], "new boot string\n\r"); { pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; //err_code = pstorage_store(&block_handle, &m_pstorage_buffer[0], // APP_BLOCK_SIZE, 0); err_code = pstorage_update(&block_handle, &m_pstorage_buffer[0], APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); while(FALSE != m_is_need_to_wait_pstorage_operation) power_manage(); }/*store code block*/ app_storage_print_stored_data(); device_manager_init(erase_bonds); gap_params_init();
You could use serial tool (like sscom..etc) to write data (a character) to pstorage.
for example, when I send 'a' via uart, the flash would be written the string" received char = a".
When you send '~' the nRF51/52 would reboot, you could find that the string in pstorage would be kept.
Here is the knacks for using pstorage:
零. The block size should be align of 4, of course.
一. The initialization function pstorage_init (in my case, within the function pstorage_init), should be called after function ble_stack_init. If you call it before ble_stack_init, the function pstorage_init might lead the system reboot ceaselessly. It is not necessary to call pstorage_init after ble_stack_init Immediately, you could call it after the advertise has been started.
二. Before calling the function pstorage_store, it is necessary to call function pstorage_clear, Or the storing action should not be done : the flash contain would not be update. The alternative way is to call function pstorage_update, which is the combination of pstorage_clear and pstorage_store.
三. When the functions pstorage_store/pstorage_update/pstorage_clear, it costs time to complete the action after the functions have returned. In the main "thread", I adopt a global flag (m_is_need_to_wait_pstorage_operation) , while loop and function power_manage to wait the pstorage has been updated indeed, that is like:
{ pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; //err_code = pstorage_store(&block_handle, &m_pstorage_buffer[0], // APP_BLOCK_SIZE, 0); err_code = pstorage_update(&block_handle, &m_pstorage_buffer[0], APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); while(FALSE != m_is_need_to_wait_pstorage_operation) power_manage(); }/*store code block*/
In the pstorage handler callback function :
// Event Notification Handler. static void app_storage_callback_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len) { if(handle->block_id == m_pstorage_operation_block_id) m_is_need_to_wait_pstorage_operation = FALSE; switch(op_code) { case PSTORAGE_STORE_OP_CODE:
that could ensure the data be stored into pstorage.
But inside the interrupt callback, calling power_manage would lead system hanging. Therefore, in the uart event handler callback, i do not call the power_manage function:
/** * @brief UART events handler. */ void uart_events_handler(app_uart_evt_t * p_event) { switch (p_event->evt_type) { case APP_UART_DATA_READY: { unsigned char received_char; UNUSED_VARIABLE(app_uart_get(&received_char)); if('~' == received_char) { app_storage_print_stored_data(); NVIC_SystemReset(); } { sprintf((char*)&m_pstorage_buffer[0], " received char = %c\r\n", received_char); pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_app_storage_base_handle, 0, &block_handle); /* m_pstorage_operation_block_id = block_handle.block_id; m_is_need_to_wait_pstorage_operation = TRUE; */ uint32_t err_code; err_code = pstorage_update(&block_handle, &m_pstorage_buffer[0], APP_BLOCK_SIZE, 0); APP_ERROR_CHECK(err_code); printf("storing str :\"%s\" into flash\r\n", (char*)&m_pstorage_buffer[0]); }/*store data to flash block*/ } break;
四. Do not update your pstorage too frequently, It would cost much electric power, and the written times is limited : it be written 10000 times before broken typically.
沒有留言:
張貼留言