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

Problem with sampling rate when sending a long data using NUS (for nrf51 DK)

In my project, I aim to send an ADC value (10 bits ADC)  and 6 data (16 bits/each data) from MPU6050 by using nrf51 DK to Android app ( modified from https://github.com/NordicPlayground/Android-nRF-UART). I created two timers for ADC channel and MPU6050 to aim for getting sampling rate of 500 samples/second. Since the buffer of the NUS just has only 8 bits,  I partitioned the value of ADC and 6 data of MPU6050 into values with 8 bits long, which ended up having 2 bytes for an ADC value and 12 bytes for 6 data of MPU. It means that I need to send to Android app total 14 bytes for each time. In Android app, I did a simple technique to combine the data partitioned into real data.

The data of MPU collected on Android app seem correct as I tried to send 6 constant number before getting real data from MPU function; however, there are something wrong in ADC value with sampling rate. I tried to send a sinusoidal wave with the frequency of 10Hz as an analog input, but after receiving data on App, I just got a signal with only 0.71Hz. Without sending 6 data of MPU6050, I can receive sine signal with the same frequency. 

Is that because of sending too long data (14 bytes) caused the mismatch of frequency between analog signal and signal after digitalizing?

I notice that we can set up the length of buffer of NUS like this. Could I change the buffer size up to 16 bits so that I can reduce the length of data transmitted to App each time?

#define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE                256                                         /**< UART RX buffer size. */

Here is code I used to send 14 bytes. I create a buffer with the size of 14. First two bytes are for ADC value and the rest is for MPU data

static void adc_event_handler(nrf_drv_adc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_ADC_EVT_DONE)
    {
				
        adc_event_counter++;
       // printf("    ADC event counter: %d\r\n", adc_event_counter);			
        uint32_t i;
				printf("Data size: %d\r\n",p_event->data.done.size);
        for (i = 0; i < p_event->data.done.size; i++)
        {
            printf("%d\r\n",p_event->data.done.p_buffer[i]);   //Print ADC result on hardware UART
            adc_result[(2*i)] = p_event->data.done.p_buffer[i] >> 8;
            adc_result[(2*i)+1] = p_event->data.done.p_buffer[i];					
        }
	
				APP_ERROR_CHECK(nrf_drv_adc_buffer_convert(adc_buffer,ADC_BUFFER_SIZE));   //Allocate buffer for ADC
        //LEDS_INVERT(BSP_LED_3_MASK);				                                          //Indicate sampling complete on LED 4
    }
}

This code is for partitioning the ADC value and store in first two bytes of variable name adc_results.

static void sensor_measurement_handler(void * p_context)
{
		uint32_t err_code;
		UNUSED_PARAMETER(p_context);
		int16_t MPU6050_data[6];// = {100, 200, 300, 400, 500, 600};
		int16_t angles[6];
		//int8_t MPU6050_send[12];
		int16_t len_send_data = 12, i = 0;
		// Read ACC value
		MPU6050_Get_Accel_Angles(&MPU6050_data[0],&MPU6050_data[1],&MPU6050_data[2], &angles[0],&angles[1],&angles[2]);
		// Read Gyro value
		MPU6050_Get_Gyro_Angles(&MPU6050_data[3],&MPU6050_data[4],&MPU6050_data[5],&angles[3],&angles[4],&angles[5]);
		//MPU6050_data[6] = 0.96 * angles[0] + 0.04 * angles[3];  //filter góc t? gyro và accel
		//MPU6050_data[7] = 0.96 * angles[1]  + 0.04 * angles[4];  //filter góc t? gyro và accel
		//MPU6050_data[8] = 0.96 * angles[2] + 0.04 * angles[5];  //filter góc t? gyro và accel
		/*
		MPU6050_data[6] = angles[0]; 
		MPU6050_data[7] = angles[1];
		MPU6050_data[8] = angles[2]; 
		MPU6050_data[9] = (int16_t) ble_sensor_get_status();      // l?y status c?a led
		*/
		/*
		// using this function to send MPU6050 data to BLE and smartphone
		err_code = ble_sensor_measurement_send(&ble_sensor_handle, MPU6050_data, sizeof(MPU6050_data));
		
		if ((err_code != NRF_SUCCESS) &&
		(err_code != NRF_ERROR_INVALID_STATE) &&
		(err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
		)
		{
					 APP_ERROR_HANDLER(err_code);
		}
		*/
		for (i = 1; i < len_send_data/2+1; i++){
			printf("Sensor value: %d\r\n",MPU6050_data[i]);
			adc_result[(2*i)] = MPU6050_data[i-1] >>8;
			adc_result[(2*i)+1] = MPU6050_data[i-1];
	}
	   ble_nus_string_send(&m_nus, &adc_result[0], 14); 
	}

This code is for getting data from MPU and put it in the next 12 bytes of variable adc_results. After that, I call function ble_nus_string_send(&m_nus, &adc_result[0], 14) to send data to Android app. 

Thank you!

Parents
  • Hi,

    I'm not sure I understand what you mean by the following statement:

    I tried to send a sinusoidal wave with the frequency of 10Hz as an analog input, but after receiving data on App, I just got a signal with only 0.71Hz. Without sending 6 data of MPU6050, I can receive sine signal with the same frequency

    Could you please provide some more explanation, with numbers and diagrams?

    Note that nRF51 series do not have DMA features from ADC and SPI/TWI peripherals, like nRF52 series does. The sample rate will be limited by the CPUs availability to handle events. If you have high BLE/radio activity, or frequently read/write TWI/SPI, the ADC will have a lower maximum sample rate.

    Best regards,
    Jørgen

  • Have you tried sending a "dummy signal" over NUS to determine if the issue stems from sampling or from the BLE transfer? You might have to optimize your connection parameters in order to get a high enough throughput (set connection interval to 7.5 ms, and BW config to HIGH. Thgeis should give you the possibility to transmitt 6 packets per connection interval, a total og 800 packets per second. If you have your settings set to lower than this, you might not be able to transmitt the 500 samples/second of ADC data.

Reply Children
No Data
Related