Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Writing/Reading to Flash and Transmitting Large Amount Data Over BLE

Hello everyone,

I am an intern and new to BLE. I was tasked with developing a simple temperature logger that will placed in rivers/lakes. So far I've had some success.

My development environment is as follows: Custom PCB with a nRF52832 chip, ST-Link on a Nucleo board for flashing and erasing the chip, Eclipse IDE with Cross GCC and I am using the nRF5 SDK 17.

To my question: I am storing a temperature reading and a timestamp +  some other data in a RAM buffer. The whole payload is 12 bytes. Now I know that a single page in flash is 4096 bytes which gives roughly 341 entries per page. How do I write to flash without disrupting the bluetooth communication. And also how do I receive the data from flash, say 10 pages worth of entries, to my central device when I issue a command from my BLE terminal or phone.

I've used the ble_nus module for simple commands: setting the time between measurements, setting the internal clock, receiving current temperature reading etc., but this time the data is quite large - over 40KB. Is this service appropriate or should I use another? And how do I go about setting it up for such a big payload of data.

typedef struct {
    int32_t     temp;
    calendar_t  timestamp;
    place_t     type;
} temperature_flash_data_t;

 

static temperature_flash_data_t ram_to_flash_buffer[MAX_ENTRIES];
static uint32_t entry_count = 0;
void log_data_to_buffer(int32_t temperature, custom_time_t *time, place_t *place)
{
	if(entry_count >= MAX_ENTRIES)
	{
	    flush_data_to_flash();
	}

	ram_to_flash_buffer[entry_count].temperature = temperature;
	ram_to_flash_buffer[entry_count].timestamp.year = time->year;
	ram_to_flash_buffer[entry_count].timestamp.month = time->month;
	ram_to_flash_buffer[entry_count].timestamp.day = time->day;
	ram_to_flash_buffer[entry_count].timestamp.hour = time->hour;
	ram_to_flash_buffer[entry_count].timestamp.minute = time->minute;
	ram_to_flash_buffer[entry_count].timestamp.second = time->second;
	ram_to_flash_buffer[entry_count].place.type = place->river;

	entry_count++;
}

void flush_data_to_flash(void) 
{
	uint32_t total_words = (entry_count * ENTRY_SIZE) / sizeof(uint32_t);

    nrf_nvmc_page_erase(flash_page_address); 
	nrf_nvmc_write_words(flash_page_address, (const uint32_t *)ram_to_flash_buffer, total_words);

	entry_count = 0;
	flash_page_address += 0x00001000; // Increment to next page

	if(flash_page_address >= 0x00080000) 
	{
		flash_page_address = 0x00078000;
	}
}

In the above snippet I log my data into RAM and send it to page 120 in flash. But I am a bit lost on how read it back and then transmit via BLE with ble_nus module.

Any help would be appreciated!

Thanks

Parents
  • Hi,

    I am using the nRF5 SDK 17.

    First of all, I must inform you that the recommendation for new projects is not to use the older and now in maintenance mode nRF5 SDK, but rather the newer nRF Connect SDK. For details, see our nRF Connect SDK and nRF5 SDK statement. For now, I will assume you are still on nRF5 SDK, but would I highly recommend a switch to nRF Connect SDK.

    I am storing a temperature reading and a timestamp +  some other data in a RAM buffer. The whole payload is 12 bytes. Now I know that a single page in flash is 4096 bytes which gives roughly 341 entries per page. How do I write to flash without disrupting the bluetooth communication. And also how do I receive the data from flash, say 10 pages worth of entries, to my central device when I issue a command from my BLE terminal or phone.

    Both nRF5 SDK and nRF Connect SDK have libraries for working with Flash. For nRF5 SDK there is the (more low level and direct access) fstorage library, as well as the (more abstracted, with wear leveling but with some overhead compared to fstorage) Flash Data Storage library.

    Regarding Flash, please note that there is a minimum endurance of 10 000 write/erase cycles. After that, you may start to see bit errors or other malfunctions of the Flash memory. Because of that, and based on what you write about your current use case, I would strongly consider holding the values in RAM, if at all possible, and not go via Flash. Of course, if you need to store a large amount of data and for a longer period of time, then there might be no escaping Flash and Flash storage might be the correct approach. For storing 40 kB, RAM is not much of an option on the nRF52832 with its 64 or 32 kB of RAM. Please however consider the 10 k write/erase cycles, which means you might want wear leveling. (I.e. setting aside a number of 40 kB slots, and rotate between them where you store the data, if you expect to store data more than 10 k times during the lifetime of the product.)

    For writing to and reading from Flash, I would highly recommend using a library, and for your use case (if you stick with nRF5 SDK) fstorage is likely the best (since FDS adds more overhead). However, if you do need wear leveling, using FDS could be better since it provides wear leveling out-of-the-box.

    I've used the ble_nus module for simple commands: setting the time between measurements, setting the internal clock, receiving current temperature reading etc., but this time the data is quite large - over 40KB. Is this service appropriate or should I use another? And how do I go about setting it up for such a big payload of data

    Sending large amounts of data over NUS is relatively straight-forward, since NUS is essentially just a data stream. What you then need to decide on is data format (how do the receiver know that the data blob starts and stops?) While you could go for implementing the Object Transfer Profile or something similar, I think that would be overly complex for your use case, and you seem to be well on your way with NUS already.

    Please note that NUS is available in both nRF5 SDK and in nRF Connect SDK. The latter also have libraries for working with Flash.

    Regards,
    Terje

Reply
  • Hi,

    I am using the nRF5 SDK 17.

    First of all, I must inform you that the recommendation for new projects is not to use the older and now in maintenance mode nRF5 SDK, but rather the newer nRF Connect SDK. For details, see our nRF Connect SDK and nRF5 SDK statement. For now, I will assume you are still on nRF5 SDK, but would I highly recommend a switch to nRF Connect SDK.

    I am storing a temperature reading and a timestamp +  some other data in a RAM buffer. The whole payload is 12 bytes. Now I know that a single page in flash is 4096 bytes which gives roughly 341 entries per page. How do I write to flash without disrupting the bluetooth communication. And also how do I receive the data from flash, say 10 pages worth of entries, to my central device when I issue a command from my BLE terminal or phone.

    Both nRF5 SDK and nRF Connect SDK have libraries for working with Flash. For nRF5 SDK there is the (more low level and direct access) fstorage library, as well as the (more abstracted, with wear leveling but with some overhead compared to fstorage) Flash Data Storage library.

    Regarding Flash, please note that there is a minimum endurance of 10 000 write/erase cycles. After that, you may start to see bit errors or other malfunctions of the Flash memory. Because of that, and based on what you write about your current use case, I would strongly consider holding the values in RAM, if at all possible, and not go via Flash. Of course, if you need to store a large amount of data and for a longer period of time, then there might be no escaping Flash and Flash storage might be the correct approach. For storing 40 kB, RAM is not much of an option on the nRF52832 with its 64 or 32 kB of RAM. Please however consider the 10 k write/erase cycles, which means you might want wear leveling. (I.e. setting aside a number of 40 kB slots, and rotate between them where you store the data, if you expect to store data more than 10 k times during the lifetime of the product.)

    For writing to and reading from Flash, I would highly recommend using a library, and for your use case (if you stick with nRF5 SDK) fstorage is likely the best (since FDS adds more overhead). However, if you do need wear leveling, using FDS could be better since it provides wear leveling out-of-the-box.

    I've used the ble_nus module for simple commands: setting the time between measurements, setting the internal clock, receiving current temperature reading etc., but this time the data is quite large - over 40KB. Is this service appropriate or should I use another? And how do I go about setting it up for such a big payload of data

    Sending large amounts of data over NUS is relatively straight-forward, since NUS is essentially just a data stream. What you then need to decide on is data format (how do the receiver know that the data blob starts and stops?) While you could go for implementing the Object Transfer Profile or something similar, I think that would be overly complex for your use case, and you seem to be well on your way with NUS already.

    Please note that NUS is available in both nRF5 SDK and in nRF Connect SDK. The latter also have libraries for working with Flash.

    Regards,
    Terje

Children
No Data
Related