This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

WRITE AND READ SAADC DATA WITH FDS

nrf52832  S132  v6.1.1

i want to write saadc data in flash, so i call "write_to_flash" function in "void saadc_callback(nrf_drv_saadc_evt_t const * p_event)"

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{    
	  int product;
		uint16_t val;
	  uint8_t value;
	  ret_code_t err_code;
	  product = channel3_enabled*8 + channel2_enabled*4 + channel1_enabled*2 + channel0_enabled;
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {

        static uint8_t data_array[SAMPLES_IN_BUFFER*2];
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        uint8_t i;
        printf("\r\nADC event number:%d \r\n", (int)m_adc_evt_counter);
        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
               data_array2[i]=p_event->data.done.p_buffer[i];
					     val = p_event->data.done.p_buffer[i];				
						   printf("%d\r\n",val);					
               //8MSB data				
					     value=val>>4;//right shift	4 bit			
					     value |= 1;//XXXX_XXX1,1 means MSB
							 value &= 247;//XXXX_0XX1,0 means saadc data
							 value = dataencode(i, product, value);
					     data_array[(i*2)]=value;
							 value=0;
							 
							 //8LSB data,XXXX_XXX0
							 value=val;
					     value&=254;
					     data_array[i*2+1]=value;
               value=0;
				}
        uint16_t length = (uint16_t)(i*2);
				memcpy(data_array3,data_array,length);
				if(!writeflash_en)
				{err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);}
				else
				{write_to_flash();}	
				if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_NOT_FOUND) )
				{
					APP_ERROR_CHECK(err_code);
				}
        m_adc_evt_counter++;
    }
}


void write_to_flash(void)
{
			fds_record_desc_t desc = {0};
			ret_code_t rc;
			rc = fds_record_write(&desc, &m_dummy_record);
			if(rc == FDS_ERR_NO_SPACE_IN_FLASH)
			{			
				stop_saadc();
				writeflash_en = 0;
				ret_code_t err_code;
				uint16_t length;
				length = 2;
				uint8_t flash_full[2];
				flash_full[0] = 105;
				flash_full[1] = 105;
				err_code = ble_nus_data_send(&m_nus, flash_full, &length, m_conn_handle);
				if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_NOT_FOUND) )
				{
					APP_ERROR_CHECK(err_code);
				}
				NRF_LOG_INFO("NO SPACE IN FLASH, FDS OPERATION WILL BE OVER")			
			}
			if( rc== FDS_ERR_NO_SPACE_IN_QUEUES)
			{
				writeflash_en = 0;
				stop_saadc();	
				NRF_LOG_INFO("NO SPACE IN QUEUES, FDS OPERATION WILL BE OVER");
			}
		}

sizeof(data_array3)  is 240, so every record in flash is 60 words,

virtual page is 3;

virtual page size 1024;

then i stop adc and read data when flash is full, i get 32 records ,every record only contains 16 or 19  or ......words ,less than 60 words.

if everythng is correct, i can get 32 records and 60 words in every record;

the following is my read_from_flash() function

void read_from_flash()
{
		//±£´æÃØÔ¿µÄÁîÅÆÇåÁã
		fds_find_token_t  tok  = {0};
		ret_code_t rc;
		rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);//¶ÔÓ¦KEY¼Ç¼²éÕÒÊý¾Ý
		NRF_LOG_INFO("record_id:%8x",desc.record_id);
		NRF_LOG_INFO("p_record:%8x",desc.p_record);
		if (rc == FDS_SUCCESS)
		{
			/* A config file is in flash. Let's update it. */
			fds_flash_record_t config = {0};

			/* Open the record and read its contents. */
      rc = fds_record_open(&desc, &config);
      APP_ERROR_CHECK(rc);
								
			NRF_LOG_INFO("Found Record ID = %d",desc.record_id);
			NRF_LOG_INFO("Data = ");
			data = (uint32_t *)config.p_data;
			static uint8_t data_array_send[4];
			for (uint16_t i=0; i<config.p_header->length_words; i++)//i<config.p_header->length_words(60)
			{
				NRF_LOG_INFO("0x%8x",data[i]);
				data_array_send[0] = data[i];
				data_array_send[1] = data[i]>>8;
				data_array_send[2] = data[i]>>16;
				data_array_send[3] = data[i]>>24;
				uint16_t length1= 4;
				ble_nus_data_send(&m_nus, data_array_send, &length1, m_conn_handle);
			}
			NRF_LOG_INFO("\r\n");
			/* Close the record when done reading. */
			while(fds_record_close(&desc) != FDS_SUCCESS)
			{NRF_LOG_INFO("flash close fail");}	
			while(fds_record_delete(&desc) != FDS_SUCCESS)
			{NRF_LOG_INFO("flash delete fail")}
		}		
		else
		{
			NRF_LOG_INFO("can't find record or no more record to be read");		
			while(app_timer_stop(m_timer_id) != NRF_SUCCESS)
			{NRF_LOG_INFO("stop timer fail");}
			rc = fds_gc();
			if(rc == FDS_SUCCESS)
			{
				NRF_LOG_INFO("GC SUCCESS");
				uint16_t length;
				length = 2;
				uint8_t flash_read_end[2];
				flash_read_end[0] = 121;
				flash_read_end[1] = 121;
				ble_nus_data_send(&m_nus, flash_read_end, &length, m_conn_handle);
			}
			stat();
		}
}

it's called by a timer.

so what's the problem about "read data less than written data" ?

Any suggestion will be appreciated.

  • Hi,

    There are a few missing parts here, for instance how you populate the m_dummy_record data structure that you write to FDS using fds_record_write() in write_to_flash()? Note also that FDS operations are asynchronous, and they are not finished before you get an event that tells you either that the operation is finished successfully or that an error occured.

    Queueing a flash operation on every saadc measurement is not necessarily a good idea, as flash operations are probably much slower than the rate of measurements. That in turn may lead to problems. If you store the data to be written in the same static memory location for all queued writes, and have multiple writes in the queue, then you may get into a situation where the same data is written multiple times. You may also get data races where a record is written to flash while you are half-way updating the record structure.

    Depending on the use case, it may be a much better idea to buffer data in RAM instead of going via flash. Especially if the data rate is such that you have to write a record every few minutes. Also, you should only do garbage collection when flash is full (or near full). The flash is limited to 10k write/erase cycles, which means if you continuously write and erase flash you will quickly wear down the flash (and it will not work any more.)

    Regards,
    Terje

  • thanks for your reply

    my m_dummy_data structure:

    static uint8_t data_array3[240]={0};
    static fds_record_t const m_dummy_record =
    {
        .file_id           = CONFIG_FILE,
        .key               = CONFIG_REC_KEY,
        .data.p_data       = &data_array3,
        /* The length of a record is always expressed in 4-byte units (words)*/
        .data.length_words = (sizeof(data_array3)+3) / sizeof(uint32_t),
    };

    "Queueing a flash operation on every saadc measurement is not necessarily a good idea, as flash operations are probably much slower than the rate of measurements. " "You may also get data races where a record is written to flash while you are half-way updating the record structure." i think you are rigtht.

    i set "uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, frequency_sel)"  frequecy_sel 1ms, the saadc rate may be much higher than fds operation.

    In my instance, i can get event that  tells the operation is finished successfully and "no space in flash" when flash is full, i run gc when flash is full.

    the reason why i use fds to store saadc data is that i can't get high throughout(my another question), so i want to store data when data rate is high ,then stop saadc and send it slowly to master. ram size is much smaller than flash, even the falsh size is not enough with such high data rate. so it is not a good idea to store hight rate  adc data in flash? i will try to increase  "frequecy_sel " to low down data rate.

    thanks again!

  • Hi,

    Using flash for buffering data is generally not a good idea, because of the relatively slow speed compared to RAM and because it wears down (10.000 write/erase cycles).

    Flash is a good idea for persistent data, that is data that must survive a device reset (turning it off and on again.)

    You should still be able to store data in a buffer in RAM, if you use the 64 kB RAM variant of the nRF52832. Especially so if you move to the nRF52840 with 256 kB RAM.

    Regards,
    Terje

Related