Mesh 5.0.0 high frequency timer inaccurate

Hello,

I'm running the nRF Mesh SDK 5.0.0 with the light CTL LC server example. I have also developed an implementation of a DALI master. DALI is a manchester encoded signal which runs at 1200baud. This means that the signal has a period of 416us. A dali command consists out of 2 bytes with some start and stop bits. To implement this DALI signal I use timer3 which I initialize as follows:

nrfx_timer_config_t tx_tmr_cfg = {
  .frequency          = (nrf_timer_frequency_t) NRFX_TIMER_DEFAULT_CONFIG_FREQUENCY,
  .mode               = (nrf_timer_mode_t) NRFX_TIMER_DEFAULT_CONFIG_MODE,          
  .bit_width          = (nrf_timer_bit_width_t) NRFX_TIMER_DEFAULT_CONFIG_BIT_WIDTH,
  .interrupt_priority = 2,                    
  .p_context          = NULL                                                       
};

err_code = nrfx_timer_init(&DALI_TX_TIMER, &tx_tmr_cfg, _dali_tx_tick_handler);
if(err_code != NRF_SUCCESS) {
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "[DALI] Could not initialize TX timer: %d\n", err_code);
  return err_code;
}

uint32_t time_ticks = nrfx_timer_us_to_ticks(&DALI_TX_TIMER, 416);
nrfx_timer_extended_compare(&DALI_TX_TIMER, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

The tick handler looks as follows:

static void _dali_tx_tick_handler(nrf_timer_event_t event_type, void* p_contex)
{
  if(event_type != NRF_TIMER_EVENT_COMPARE0) {
    return;
  }
  
  //bitbanging stuff
  //when ready the timer is disabled
  if(frame_complete) {
    nrfx_timer_disable(&DALI_TX_TIMER);
  }
}

The above code works perfectly when bluetooth is not enabled. But when Bluetooth is on and there is active mesh communication the timer interrupt is not consistent anymore. Sometimes the 416us period is only in the tens of microseconds but other times it is more than 20ms. 

I think that the timer interrupt is interrupted by the softdevice. This breaks my DALI signal and the DALI drivers stop responding.

I have tried the following things:

  • I tried every priority between 0 and 6.
  • I tried using the app_timer (RTC based) but this was even worse.

Is there any option to solve this issue. In my head an option would be that there is an API in which we reserve a window of for example 5ms in which we know we will not be interrupted. 

  • Hi 

    It sounds odd that you would get interrupts for as much as 20ms. Do you know if there is flash activity in your application?

    Normally the only thing that would cause such long interrupts is a flash page erase. 

    A long time ago we had a project internally to create an additional UART interface for situations where you didn't have a dedicated UART peripheral available. 
    This example used the ADC to handle the UART RX line, by sampling the RX line at a fixed interval set by the UART baudrate (the ADC sampling rate was set around 3x the baudrate). 
    You might be able to use the same code to to receive your DALI signal, even if you have to make some changes to the code to handle the manchester decoding, and any differences in byte lengths etc that you have on the DALI bus compared to a normal UART (with 1 start and 1 stop bit). 

    This example was shared in this case, if you want to take a look at it. 

    A simpler solution would be to configure a timer in free running mode, and use two GPIOTE channels to automatically store the timer value in dedicated CC registers each time a high or low flank is detected (by connecting the GPIOTE events to capture tasks over PPI). This will not work if you are interrupted for as long as 20ms unfortunately...

    Best regards
    Torbjørn

Related