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

BLE connection lost after Flash write

Hi: 

I use the SDK 13.0 and nRF52 DK to develop software for the project. Based on BLE UART (NUS), the software do SAADC sample and transfer the data out in real time, The ADC sampling rate is 250 Sa/s. The data is received by a nRF52 dongle board, and transferred to the local PC through UART. The system works fine. 

Now, I try to save the ADC sampling data to the BLE chip flash memory first, and then after triggered, data is read from flash and transferred out through bluetooth. The trigger now is "after finishing the flash write".

For flash write and Read, it's in a packet size of 64 samples. The problem is if I write 4 packets, and read/transfer 4 packets ( total data volume is 64*4 =256 samples), the software works fine. If I write and read/transfer more than 4 packets. the BLE software can be restarted/reset frequently. Double check the data pattern using a terminal software find, the restart/reset happens after/in the last packet write. Because of that, the slave and master device can not build stable connection, and no data transmission can be made.

My thought is the BLE connection parameters (connection interval) are not well tuned. But even tried with different settings on that, it still not work. 

The main function that do the flash write/read and data transfer is attached here. Need some insight to this problem. thanks 

#define MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(180, UNIT_1_25_MS)         /**< Determines minimum connection interval in millisecond. */
#define MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(220, UNIT_1_25_MS)         /**< Determines maximum connection interval in millisecond. */
#define SLAVE_LATENCY           0                                       /**< Determines slave latency in counts of connection events. */
#define SUPERVISION_TIMEOUT     MSEC_TO_UNITS(4000, UNIT_10_MS)  

#define SAADC_SAMPLES_IN_BUFFER         64

static uint16_t FS_WR_DATA_L = 32; 
static uint16_t FS_WR_N = 6; 

int main(void)
{
    uint32_t err_code;
    bool     erase_bonds;
	  int32_t volatile temp;

		///////////////////////
		NRF_POWER->DCDCEN = 1;
		///////////////////////
//		nrf_gpio_cfg_output(13);
//		nrf_gpio_pin_set(13);
//		nrf_gpio_cfg_output(12);
//		nrf_gpio_pin_clear(12);
	
    // Initialize.
		nrf_temp_init(); //////////////////////
		NRF_TEMP->TASKS_START = 1;
		///////////////////////////////////////
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    uart_init();
    log_init();

    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();
	/////////////////////////
	//nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, 247+4);
	fstorage_init();
    
    saadc_sampling_event_init();
    saadc_init();
    saadc_sampling_event_enable();
		
		//////////////////////////////////20180925 Added
		pwm_setup();
		///////////////////////////////////
    printf("\r\nUART Start1!\r\n");		
    NRF_LOG_INFO("UART Start2!\r\n");
    err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);

		////////////////////////////
		//nrf_gpio_cfg_output(19);
    // Enter main loop.
    for (;;)
    {
			if(fs_write_en == 1)
			{	
					uint16_t cc_r;
					uint8_t bytes_to_send;
					uint32_t value_from_f;
					uint8_t value_to_send[(SAADC_SAMPLES_IN_BUFFER)*2 +2];
					uint8_t value[SAADC_SAMPLES_IN_BUFFER*2 +5];
		
					cc_r = m_adc_evt_counter % FS_WR_N;
					
					printf("%x\r\n", cc_r);
					fstorage_write(cc_r * FS_WR_DATA_L, value_to_f, FS_WR_DATA_L);
//					fstorage_read(0, FS_WR_DATA_L);
					
					if (cc_r == (FS_WR_N - 1))
					{
						
						for (int j=0; j < FS_WR_N; j++)
						{
//							printf("%x\r\n", m_adc_evt_counter);
							printf("Data read from flash address 0x%X: \r\n", (uint32_t)fs_config.p_start_addr + j*32); 
							for(int i=0; i<(SAADC_SAMPLES_IN_BUFFER)/2; i++)
							{
								value_from_f = fstorage_read2(j*32 + i);
//								printf("%X \r\n", value_from_f);   
								value[i*4] 		 = value_from_f;
								value[(i*4)+1] = value_from_f >>  8;
								value[(i*4)+2] = value_from_f >> 16;
								value[(i*4)+3] = value_from_f >> 24;
							}  
								///////////////////////////////
								// read temperature sensor
								int32_t volatile temp;
								int32_t t;
								sd_temp_get(&t);
								temp = t;
					
								value[SAADC_SAMPLES_IN_BUFFER*2] = temp;
								value[SAADC_SAMPLES_IN_BUFFER*2 + 1] = temp >> 8;
								value[SAADC_SAMPLES_IN_BUFFER*2 + 2] = m_adc_evt_counter;
								value[SAADC_SAMPLES_IN_BUFFER*2 + 3] = 0x7A;
								value[SAADC_SAMPLES_IN_BUFFER*2 + 4] = 0x7A;
								// Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
								if((SAADC_SAMPLES_IN_BUFFER*2) <= NRF_BLE_GATT_MAX_MTU_SIZE - 3) 
								{
										bytes_to_send = (SAADC_SAMPLES_IN_BUFFER*2 + 5);
								}
								else 
								{
										bytes_to_send = 20;
								}
//								if( m_conn_handle != BLE_CONN_HANDLE_INVALID ) 
//								{
									err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
									if (err_code != NRF_ERROR_INVALID_STATE) 
									{
											APP_ERROR_CHECK(err_code);
									}	
//								}
							}
						}
					m_adc_evt_counter++; 
						
					if ( cc_r == (FS_WR_N - 1))
					{
						fstorage_erase();
					}
					fs_write_en = 0;
					power_manage();
				}
				else
				{
						power_manage();
				}
					// Put SDN# in HIGH mode
				nrf_gpio_cfg_output(8);
				nrf_gpio_pin_set(8);
    }
}

Parents
  • It sounds to me that you have an assert in your application, which will by default reset the chip to recover. However during development it is useful to catch the assert, this can be done by define DEBUG in your project (preprocessor symbols), then you can find that in app_error_fault_handler() the code should run app_error_save_and_stop() instead of NVIC_SystemReset(). 

    In app_error_save_and_stop() you should be able to identify the file name, line number and error code for the assert.

  • Hi Kenneth:

    Thanks for prompt reply. 

    Can you kindly provide more information on how to catch the assert, and how to add DEBUG?

    Thanks

  • Hi Kenneth:

    Thanks for continuously supporting on this case. 

    I did do some search and read many cases online for this error. I tried adding the following or similar code to my project: 

    In on_ble_evt(ble_evt_t * p_ble_evt)

    					case BLE_GATTS_EVT_HVN_TX_COMPLETE:
    					tx_complete = true;
    				//Add by Wei Lu
    					break;

    In main.c, coding like this:

    						
    						while(!tx_complete);
    						err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
    						if ((err_code != NRF_ERROR_INVALID_STATE)&& (err_code != NRF_ERROR_BUSY))
    							{
    								
    								APP_ERROR_CHECK(err_code);
    							}
    						tx_complete = false;

    Even do this way, the program still not not work. Further check shows the tx_complete not be set back to "True" after the first sending out setting to "False".

    What's the possible reason for this? Do I use the BLE_GATTS_EVT_HVN_TX_COMPLETE correctly?

    Thanks

  • I don't understand the flow here and I don't like infinite while loops, so maybe try something like this instead:

    static volatile bool tx_in_progress;
    
    in on_ble_evt():
    
    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
    	tx_in_progress = false;
    
    in main():
    
    if(tx_in_progress == false)
    	tx_in_progress = true
    	ble_nus_string_send() 
    	if error 
    		tx_in_progress = false

  • Hi Kenneth:

    thanks for the reply. 

    First, I tried your code. But it still not work. 

    My problem is I need read from flash memory, and send the large bulk data out though BLE. The packet size 64 samples, 128 bytes. As I continuously read from flash, and send out. I add the BLE_GATTS_EVT_HVN_TX_COMPLETE to check the transfer complete, like using your code. But in my application, the BLE_GATTS_EVT_HVN_TX_COMPLETE event is not triggered. and the tx_in_progress is always TRUE. 

    What's the possible reason for this? How can I debug it?

    Add new code here. 

    Thanks

    					case BLE_GATTS_EVT_HVN_TX_COMPLETE:
    					tx_complete = true;
    					tx_in_progress = false;
    					break;
    					
    					
    in main.c
    									printf("%x\r\n", tx_in_progress);
    								if(tx_in_progress == false)
    								{
    									tx_in_progress = true;
    									
    									err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
    									if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY))
    									{
    										APP_ERROR_CHECK(err_code);
    										tx_in_progress = false;
    									}	
    								}

  • I was thinking more like this, in main.c:

    if(tx_in_progress == false)
    {
    	tx_in_progress = true;
        err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
        
        if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_RESOURCES))
        {
        	APP_ERROR_CHECK(err_code);
        }
        if (err_code != NRF_SUCCESS)
        {
            tx_in_progress = false;
        }
    }

  • Hi Kenneth:

    thanks for continuously support on this topic.

    In my application, I need transfer out bulk data in one time. Like in the tested application,  it need transfer out 6 packets of 128 bytes in one time. 

    I tried your code, it can connect with the master without break, but it only transfer 1 packet, while lost the other 5 packets. 

    I happen to try this code:

    									if(tx_in_progress == false)
    									{	}
    										tx_in_progress = true;										
    										err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);										
    										if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_RESOURCES))
    										{
    											APP_ERROR_CHECK(err_code);
    										} 
    										if (err_code != NRF_SUCCESS)
    										{
    												tx_in_progress = false;
    										}
    This code can transfer 4 packets, while lost the other 2 packets. 

    In my previous code, 4 packets is the maximum number I can get for the one time transfer.

    thanks

    Wei

Reply
  • Hi Kenneth:

    thanks for continuously support on this topic.

    In my application, I need transfer out bulk data in one time. Like in the tested application,  it need transfer out 6 packets of 128 bytes in one time. 

    I tried your code, it can connect with the master without break, but it only transfer 1 packet, while lost the other 5 packets. 

    I happen to try this code:

    									if(tx_in_progress == false)
    									{	}
    										tx_in_progress = true;										
    										err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);										
    										if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_RESOURCES))
    										{
    											APP_ERROR_CHECK(err_code);
    										} 
    										if (err_code != NRF_SUCCESS)
    										{
    												tx_in_progress = false;
    										}
    This code can transfer 4 packets, while lost the other 2 packets. 

    In my previous code, 4 packets is the maximum number I can get for the one time transfer.

    thanks

    Wei

Children
  • It's only when you receive err_code = NRF_SUCCESS that the packet is queued to be sent as notification. Do you take into account that when you receive the BLE_GATTS_EVT_HVN_TX_COMPLETE event you also need to check the counter value to know how many packets were sent? 

    p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count


  • No, I did not do that. 

    What's that, and should I do that? See some example codes, do not see they do this. Or do you more information about this?

    Wei

  • I think it is easier to help you if you can describe what you want to do.

    Most just send notification by calling sd_ble_gatts_hvx() until NRF_ERROR_RESOURCES, wait for BLE_GATTS_EVT_HVN_TX_COMPLETE event, and then call sd_ble_gatts_hvx() until NRF_ERROR_RESOURCES again. This can be repeated indefinitely. 

    Just be aware that you will get one BLE_GATTS_EVT_HVN_TX_COMPLETE for many sd_ble_gatts_hvx() calls.

    If you want to know how many notifications that was actually sent you need to check p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count on BLE_GATTS_EVT_HVN_TX_COMPLETE event.

  • By the way, can I change the tx buffer length ?

    Thx

  • Hi Kenneth:

    Now, I try to save the ADC sampling data (250Sa/s) to the BLE chip flash memory first, and then after triggered, data is read from flash and transferred out through bluetooth. The trigger now is "after finishing the flash write".

    For flash write and Read, it's in a packet size of 64 samples. The problem is if I write 4 packets, and read/transfer 4 packets ( total data volume is 64*4 =256 samples), the software works fine. If I write and read/transfer more than 4 packets. the BLE software can be restarted/reset frequently. Double check the data pattern using a terminal software find, the restart/reset happens after/in the last packet write. this is because of the APP_ERROR_CHECK(err_code). 

    This is my application request. How can I check the BLE_GATTS_EVT_HVN_TX_COMPLETE event? So I can transfer as many packets as possible in one time transfer? So I can read the saved data from flash memory and transfer them out in one time, like may be with the data size of 64packets * 128 bytes, or bigger.

    Thanks

    Wei 

Related