nRF52 DK - SPI with PPI

Hello all,

I'm trying to send SPI signal from nRF52-DK to other circuit component.

nRF52 doesn't receive data, and send 16 bit data at one transfer.

I want to send data every 20 us, so I wrote the code like this, using PPI. (This is not entire code)

static uint8_t       m_tx_buf[2];           /**< TX buffer. */
static uint8_t       m_rx_buf[2];    /**< RX buffer. */
static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
static const nrf_drv_timer_t m_timer_1 = NRF_DRV_TIMER_INSTANCE(1); 
#define TIMER_DAC_TIMEOUT_US      25

static void timer_init(void)
{
	ret_code_t err_code;

	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;

	err_code = nrf_drv_timer_init(&m_timer_1, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);

	uint32_t ticks_input_dac = nrf_drv_timer_us_to_ticks(&m_timer_1, TIMER_DAC_TIMEOUT_US);
	nrf_drv_timer_extended_compare(&m_timer_1,
		NRF_TIMER_CC_CHANNEL0,
		ticks_input_dac,
		NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
		false);
}

static void enable_timers(void)
{
	nrf_drv_timer_enable(&m_timer_1);
}

static void ppi_init(void)
{
	ret_code_t err_code;

	err_code = nrf_drv_ppi_init();
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_0);
	APP_ERROR_CHECK(err_code);
}

static void DAC_init(void) 
{
	ret_code_t err_code;

        nrf_drv_spi_xfer_desc_t xfer = NRF_DRV_SPI_XFER_TRX(m_tx_buf, m_length, m_rx_buf, 0);  
        err_code = nrf_drv_spi_xfer(&spi, &xfer, NRF_DRV_SPI_FLAG_HOLD_XFER); //Flg: transfer is triggered externally by PPI.

	uint32_t timer_compare_event_addr = nrf_drv_timer_event_address_get(&m_timer_1, NRF_TIMER_EVENT_COMPARE0);
    uint32_t dac_task_addr = nrf_drv_spi_start_task_get(&spi);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_0, timer_compare_event_addr, dac_task_addr);
	APP_ERROR_CHECK(err_code);
}

void DAC_event_enable(void)
{
	APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(ppi_channel_0));
}

void spi_event_handler(nrf_drv_spi_evt_t const * p_event, void * p_context) 
{        
    if(DAC_status == 1){ //rising
       m_tx_buf[0] = DAC_number/256;
       m_tx_buf[1] = DAC_number%256;
       DAC_number = DAC_number + 176;  
       if(DAC_number == 61180){ 
          DAC_status = 2;
          DAC_number = 60828; 
       }
       APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, 0)); 
    }

    else if(DAC_status == 2){ //decreasing
        m_tx_buf[0] = DAC_number/256;
        m_tx_buf[1] = DAC_number%256;
        DAC_number = DAC_number - 176; 
        if(DAC_number == 23868){ 
           DAC_status = 3;
           DAC_number = 24044;  
        }
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, 0)); 
    }

    else{ //resting potential
        m_tx_buf[0] = DAC_number/256; 
        m_tx_buf[1] = DAC_number%256; 
        DAC_counter++; 
        if(DAC_counter == 4662){
            DAC_counter = 0;
            DAC_status = 1;
        }
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, 0));
    }
}

static void spi_init(void) 
{       
        ret_code_t err_code;
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; 

        spi_config.frequency = NRF_SPI_FREQ_4M;
        spi_config.mode = NRF_SPI_MODE_0;
        spi_config.bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST;

        spi_config.ss_pin   = SPI_SS_PIN;  
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;

	err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL);
	APP_ERROR_CHECK(err_code);
}

DAC_number and DAC_counter is used to decide the data that I try to send.

Anyway, when I run the code, I can't get the desired result.

Roughly, it deliver right data. However, time scale is not correct.

I think PPI doesn't work, maybe? I thought like this because the result was same when I changed TIMER_DAC_TIMEOUT_US(target SPI interval) to 100.

When I measured signal with oscilloscope, SPI interval was almost 20us, and sometimes there were delay.

If you guys have an idea, please let me know!

  • Hi,

    I see that in the code you have set TIMER_DAC_TIMEOUT_US to 25 while in the text you write 20 us. Is that the issue? If not, can you elaborate on how the "time scale is not correct"? Please elaborate on your measurments and what you have found when debugging.

    I think PPI doesn't work, maybe?

    PPI itself should not fail as it is quite simple and the timer part of this triggering the SPI transfer for every compare0 event seems correct, so I would look elsewhere first.

  • Hi, it was my mistake in the text, My target is 25us but actually it looks like 20us.
    I connected nRF52-DK with DAC, and I measured DAC output by oscilloscope.

    From oscilloscope, I could see that value is updated every ~20us (but not accurately 20us), and it maintained similar value although I changed TIMER_DAC_TIMEOUT_US to 100 or 150.

    I think it is because of "nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, 0)" in spi_event_handler function. Because after spi transfer, event_handler is called and there is transfer function again, so this loop continues without PPI I guess...

    But when I erase "nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, 0)" in spi_event_handler, I could not see any outputs (SPI transfer)...

  • Hi,

    I see. You set up the transaction one time in your DAC_init() where you call nrf_drv_spi_xfer() with the NRF_DRV_SPI_FLAG_HOLD_XFER flag. This will configure everything for a transaction that can be triggered by PPI, which it looks like you have done correctly. It will only happen once, though. To repeat it you need to set up a new transaction with nrf_drv_spi_xfer() before triggering it with PPI again. I would suggest doing this in the SPI interrupt/event handler, so that you always set up a new transaction when the previous has completed.

    (It is also possible to set up several transactions in a row that can be triggered by PPI without CPU intervention using array list, which is described in this thread).

  • Wow, your advice helped me a lot!

    Now it works. Thank you so much

Related