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

S210 & twi - timing / speed

Dear all,

I use nrf51422 with S210 soft device. I need to read an attached sensor via TWI. The sensor returns 32 bits of data. I need to read that 100 times a second. I defined a timer running off the low speed clock source ( which is needed for the soft device anyway) to trigger the sensor reads:

// APP_TIMER_INIT already done in main.c with prescaler value 0
APP_TIMER_DEF(LDC_Sample_timer);	    // define another timer for the LDC sampling frequency 
APP_ERROR_CHECK(app_timer_create(&LDC_Sample_timer,APP_TIMER_MODE_REPEATED,ldc_sample_handler));		// create the new timer
app_timer_start(LDC_Sample_timer(int)32768/10,NULL);			// 0.1 second

I then read the sensor in the timer ISR:

void ldc_sample_handler(void * p_context){
	UNUSED_PARAMETER(p_context);
	NRF_TWI1->POWER  = 1;
	NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
	ldc_read_all();
	NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
	NRF_TWI1->POWER  = 0;
}


void ldc_read_all(void){
	ldc_register_address = LDC_DATA_MSB_CH1;					// TODO : make this a parameter
  static app_twi_transfer_t const transfers[] =			// transfer definition
  {
    APP_TWI_WRITE(ldc_device_address, &ldc_register_address, 1, APP_TWI_NO_STOP),
    APP_TWI_READ (ldc_device_address, ldc_p_buffer, 4, 0)
  };
	static app_twi_transaction_t const transaction =
  {
     .callback            = ldc_twi_callback_func,
     .p_user_data         = NULL,
     .p_transfers         = transfers,
     .number_of_transfers = 2
  };
	APP_ERROR_CHECK(app_twi_schedule(&m_app_twi, &transaction));	// read the MSB
	ldc_register_address = ldc_register_address + 1;							// next register address for the LSB
	APP_ERROR_CHECK(app_twi_schedule(&m_app_twi, &transaction));	// read the LSB. We can modify the register address without creating a new instance as it is accessed by a pointer.
}

Now, what happens is this:

  1. Whenever I set the LDC_sample_timer to less than 32768/15, the ANT+ communication breaks down and it seems the NRF resets all the time.

  2. If I keep the sample timer interval above 67 msec,the TWI functions but has some strange behavior, see attached images:

TWI block1: write register address to TWI device

TWI block2: read 32 bytes from TWI device

The datasheet of the device states it can do 400kHz TWI and all the timings are easily fast enough to not cause this ( so, the TWI device does for sure not cause this behaviour by using clock stretching ):

datasheet of connected TWI device

As you can see in the code, I defined the entire 48 bit transaction as one "app_twi" transaction. But in fact the individual bytes show up on the bus with different delays in between them (the TWI clock pauses). Some of these delays are pretty big like the one after sending the first two bytes to the sensor. Strangely, there is zero delay between sending byte #3 ( device read command) and the first received byte from the slave, but all subsequent received bytes do have a delay.

So, I have these questions:

  • Is there any documentation showing TWI (or in general peripherals) timing restrictions if a soft device is running ? I found the "between 1 and 6 msec CPU blocking" for BLE softdevices, but nothing for S210/S310.
  • Why does the thing reset if I set my sample timer to be faster than approx 67 msec ? The M0 core should be way,way fast enough to do 100 TWI transfers per second.
  • What does influence the delays between the individual bytes of the multi-byte TWI transfer ? These delays are NOT related to TWI clock speed, they stay the same if I run the TWI with 400kHz..

Thanks, Wolfgang Ebersbach

  • OK, I put the TWI transfers out of the timer ISR. Now I just set a flag in the ISR and do the TWI transaction within the main loop. This allows for the 100 TWI transactions per second. Every now and then the transaction is paused by 5.something msec. This likely is the s210 processing the ANT stuff. Remains the question why the TWI transaction itself has these delays in it.

  • I think you have answered most of your question in your comment. I will try to add some more details.

    The TWI transmitter and receiver are single buffered so the CPU has to do some work between every byte. As stated in Section 28.4 of the reference manual for write:

    If the CPU is prevented from writing to TXD when the TWI master is ready to clock out a byte, the TWI master will stretch the clock until the CPU has written a byte to the TXD register.

    and read:

    After receiving a byte, the TWI master will delay sending the ACK/NACK bit by stretching the clock until the CPU has extracted the received byte, that is, by reading the RXD register.

    Section 11.2 of the SoftDevice Specification describes the processor availability and latencies for the interrupts/priorities available to the application. This seems to match with the pauses you sometimes see in the TWI transfers.

  • Hi Einar,

    thanks for the response. What you refer to is HW related delays, like copying 8 bits from a register to somewhere. Anyhow, I see delays of 70usec between the write transfer and the read transfer. And about 25usec between the first read byte and the 2nd one. And > 100usec between the end of one read transfer and the start of the next write transfer. These numbers are WAY too big to be caused by hardware. I have seen the softdevice document, according to that the TWI is free to be used. Also, interrupt latency additions caused by the soft device are all 1-digit numbers.

    Sadly (at least to me) the SDK is extremely scattered into a million files, #defines and macros all over the place so that it is really really hard to understand the example codes.

    So, if I use app_twi, does that actually use hardware TWI ? Or is that bit-banged software TWI ?

    In any case there is some delays hidden somewhere. Maybe they are required for whatever reason, maybe not. I just try to get the TWI transfers done as quick as possible to save energy. My TWI sensor has quite high power consumption, so any usec more sleep on the sensor side pays off a lot...

    According to the NRF51 datasheet there is hardware TWI. On page 58 of the DS you can see that the longest delay required by hardware is 5,2 usec for start / stop conditions. So, there is no hardware reason for 2 or even 3 digit delay times.

    I'll put some more time in this as soon as I managed to gain control over the GPIO's in the ant_bpwr_tx example code - which is hard due to the way the board support and app_button stuff is buried everywhere in the example code. I would much more prefer example code that is as minimal as possible. Yes, including having register addresses and such directly in the code instead of hidden behind 15 #include/#ifdef/#macro things.

    Regards, Wolfgang.

  • Regarding the first quote, I copy-pasted the wrong section. I have updated the answer with what I indented to include. Thanks for noticing.

    You are using the hardware peripheral. What I wanted to point out with the quotes is that the CPU has to write and read each byte separately to the TWI peripheral registers, and if the CPU cannot do this in time, the transfer will be delayed.

    If you look at the Processor availability section (11.2) of the SoftDevice Specification, you will see that you can expect high priority interrupts some times when using ANT, and the duration of these events are of the order you are seeing (See Table 18 of the S210 Soft Device Spec).

    The nRF52 however has a new set of TWI peripherals (TWIM/TWIS) which has DMA. So with the nRF52 should be able to do the transfers consistently without the delay even while doing ANT communication (or processing any other high priority interrupts).

  • Einar, I have seen this. So, yes, by documentation it may be that the master stretches the clock. But > 100usec ? Anyhow, thanks for the help, I'll close this now as I have other, more urgent things to solve before I come back to this fine tuning issue.

Related