Toggle gpio certain number of times with PPI

Using nRF5_SDK_15.3.0, soft device 132 (Rigado BMD-300 eval kit), segger embedded studio

I'm trying to control ADS1231 by listening for DRDY to go low and pulse an output to SCLK 25 times (shift 24bits and one more to get the data line to go high as per documentation).

I was planning on using the PPI library to accomplish this.  I have a timer compare event that is hooked up with a gpio toggle task:

/**@brief Initialize ads1231
static void ads_init()
uint32_t compare_evt_addr;
uint32_t gpiote_task_addr;
nrf_ppi_channel_t ppi_channel;
ret_code_t err_code;

// initialize gpiote if not already
if (!nrfx_gpiote_is_init())
err_code = nrfx_gpiote_init();

// configure timer using defaults in sdk_config. Takes a timer, timer config, and handler
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
err_code = nrfx_timer_init(&ads_sclk_timer, &timer_cfg, adsclk_handler);

// configure gpiote with the task to toggle the bit. Takes the pin to toggle and the task config
nrfx_gpiote_out_config_t config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
err_code = nrfx_gpiote_out_init(ADS_SCLK, &config);

// set a compare channel 0 with value 2000UL. Timer will clear based on compare 0. Interrupt for compare channel is disabled
nrfx_timer_extended_compare(&ads_sclk_timer, (nrf_timer_cc_channel_t)0, 1000UL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

// allocate a ppi (programmable peripheral interconnect)
err_code = nrfx_ppi_channel_alloc(&ppi_channel);

// get the event address of compare 0. Get the gpiote address associated with the ADS_SCLK pin
compare_evt_addr = nrfx_timer_event_address_get(&ads_sclk_timer, NRF_TIMER_EVENT_COMPARE0);
gpiote_task_addr = nrfx_gpiote_out_task_addr_get(ADS_SCLK);

// hook up the compare event to trigger the toggle task
err_code = nrfx_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);

// enable the ppi channel
err_code = nrfx_ppi_channel_enable(ppi_channel);

In the timer callback I keep a count of how many times I've interrupted and disable the timer and gpio task when I've pulsed 25 times.  

int numBits = 24;

void adsclk_handler(nrf_timer_event_t event_type, void * p_context){
// internal counter
static int count = 0;

NRF_LOG_INFO("%d", count);

if (count > 2*numBits) {
// TODO: read bit

// shift out one more time to reset drdy
if(count > 2*(numBits+1)) {
// reset count and disable the gpio output pin task
count = 0;


When the DRDY line goes low, I enable the gpiote task and timer:

nrfx_gpiote_out_task_enable(ADS_SCLK); // start sclk to shift data out

This produces the following waveform:

There's a little blip at the end of the pulse train that is 12us compared to the rest that are ~60us.  

I'm new to the nrf sdk, is this even the right way to accomplish this?  Would appreciate any advice from the community.  Thanks!

  • You might try SPI; you would still have to use /DRDY as the trigger by changing the pin to the input sense and then changing it back to the SPI MISO function. Unless you require to poll /DRDY at other places in the code then the 25th clock is superfluous; just use 3-byte 24-bit transfer then revert /DRDY to wait for the next transition. The change from the L or H state - depending on last data bit - would be handled by the AFE when it generates the next falling edge, as it automatically pusghes /DRDY high before issuing falling edge.