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

Updating SPI transfer with PPI

Hello, I have a question about using PPI with a SPI transfer.

I’m using a NRF52832 custom board with the Softdevice. I’m reading sensor data every 20ms via TWI and sampling SAADC via a PPI Channel. This data is send to an Android with NUS- nordic uart service.

So far this works perfectly.

Now I’m additionally trying to implement an SPI communication with a DAC to generate a square wave signal. So far I used a timer handle with a flag to toggle between two values. It’s a simple 24 bit transfer only which has to be done every ~25 us.

As expected once everything is running together I’m getting short delays in my square wave signal. I’m guessing because of the interrupt priorities. The DAC output signal can be seen in the oszi image below. The delays are a maximum of 300-500 us long.

This causes some issues with the device I’m trying to operate with the DAC. I thought about using PPI in combination with SPI. The problem is I'm not sure how to implement the toggling to generate a square wave signal. Additionally I need to change the transferred SPI data value every ~20 ms. For example, change the DAC output from +-1 V to +-2 V.

This is the code of my SPI-PPI module so far. Any ideas how I can toggle the SPI values and change them while everything is running? I read in this Q&A that the NRF_DRV_SPI_FLAG_TX_POSTINC flag should be used, but I don't know how to implement it.

void ppi_spi_init(void)
{
	
	uint8_t data[3];

	data[0] = CMD_WRITE_UPDATE_DAC_REG; 
	data[1] = (input & 0xFF00) >> 8; 
	data[2] = (input & 0x00FF) >> 0; 

	
  ret_code_t err_code;

   err_code = nrf_drv_ppi_init();
   APP_ERROR_CHECK(err_code);
		
	/**************************************************config timer **************************************************/
	
		nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
		err_code = nrf_drv_timer_init(&DAC_TIMER, &timer_cfg, dac_timer_handler);

   /* setup DAC_TIMER for compare events*/
		uint32_t time_ticks =	nrf_drv_timer_us_to_ticks(&DAC_TIMER, 23); 
		nrf_drv_timer_extended_compare(&DAC_TIMER, NRF_TIMER_CC_CHANNEL1, time_ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, false);    
		nrf_drv_timer_enable(&DAC_TIMER); 
	

   uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&DAC_TIMER,NRF_TIMER_CC_CHANNEL1);

	
  memset(spi_rx_buf, 0, spi_length);
	spi_xfer_done = 0;
	
		nrf_drv_spi_xfer_desc_t xfer = NRF_DRV_SPI_XFER_TRX(data, 3, spi_rx_buf, 0);
		
		uint32_t flags = NRF_DRV_SPI_FLAG_HOLD_XFER           |
                 NRF_DRV_SPI_FLAG_RX_POSTINC          |
                 NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER |
                 NRF_DRV_SPI_FLAG_REPEATED_XFER;
								 
		nrf_drv_spi_xfer(&spi2, &xfer, flags);

				uint32_t start_tsk_addr = nrf_drv_spi_start_task_get(&spi2);

				uint32_t end_evt_addr = nrf_drv_spi_end_event_get(&spi2);
			
   err_code = nrf_drv_ppi_channel_alloc(&spi_ppi_channel);
   APP_ERROR_CHECK(err_code);

   err_code = nrf_drv_ppi_channel_assign(spi_ppi_channel,timer_compare_event_addr, start_tsk_addr);
   APP_ERROR_CHECK(err_code);
}


void spi_ppi_enable(void)
{
  ret_code_t err_code = nrf_drv_ppi_channel_enable(spi_ppi_channel);

  APP_ERROR_CHECK(err_code);
}

Thank you for the help.

Best regards.

Niklas

 

  • Hi,

    I am not sure this will solve the issue you have. Is the time when you need to toggle between values constant, or does it depend on something else? If it is constant then it should be OK to use fixed length transfers and start the next transfer after the previous has finished via PPI (for instance by a timer like you do). However, the array list is not circular, so you will have to start again via SW when you have iterated through your array list.

    There is no example in the SDK that demonstrates EasyDMA array list, but the driver documentation covers this under Repeated transfers. Essentially you set up an array of transfers, and when you start a new transfer, this increases the array index list so that the next data array is used.

    I have not tested your code, but it looks like you have the main parts you need. However, I notice the following

    • You use NRF_DRV_SPI_FLAG_RX_POSTINC, but it should be NRF_DRV_SPI_FLAG_TX_POSTINC, which is probably what you want?
    • Do you care about RX data? If you can use NRF_DRV_SPI_XFER_TX, or just set the third parameter in NRF_DRV_SPI_XFER_TRX to null.

    If you go this route and have problems after testing it, can you provide updated code and a description of the problems you are seeing?

Related