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

Transfer more than 255 bytes with SPI master on nrf52

Hi everybody,

I am trying to read a 1024 bytes FIFO buffer from an IMU (Bosh BMI160) using the SPI master driver on nrf52832 and sdk 12.2.

I know others had the same problem and I've read the other posts but since I just started with the nrf52 I couldn't figure out exactly how to implement this so I decided to open a new question.

For what I understood from other posts I should split the transfer into single transactions (4 in my case) and then using PPI count them with a TIMER and when the TIMER reaches 4, stop the SPI transfer, again with PPI. This should use the DMA and transfer the bytes directly into the ram.

Here is the code I am using:

// handler to disable the timer and set CS when the timer reaches 4
void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
            burst_transfer_disable();
            break;

        default:
            //Do nothing.
            break;
    }
}

static void burst_setup()
{
    uint32_t spi_end_evt;
    uint32_t timer_count_task;
    uint32_t timer_cc_event;
    ret_code_t err_code;       

    //Configure timer
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.mode = NRF_TIMER_MODE_COUNTER;
    err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_event_handler);
    APP_ERROR_CHECK(err_code);

    // Compare event after 4 transmissions
    nrf_drv_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, 4, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    timer_count_task = nrf_drv_timer_task_address_get(&timer, NRF_TIMER_TASK_COUNT);
	timer_cc_event = nrf_drv_timer_event_address_get(&timer,  NRF_TIMER_EVENT_COMPARE0);

    // allocate PPI channels
    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_spi);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_timer);
    APP_ERROR_CHECK(err_code);

    spi_start_task = nrf_drv_spi_start_task_get(&spi);
    spi_end_evt = nrf_drv_spi_end_event_get(&spi);

    // Configure the PPI to toggle the CS (high to low) and to start the spi when there is an interrupt
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_spi, spi_end_evt, timer_count_task);
    APP_ERROR_CHECK(err_code);

    // Configure another PPI to toggle again the CS (low to high) when the spi transfer is finished
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_timer, timer_cc_event, NRF_SPIM_TASK_STOP);
    APP_ERROR_CHECK(err_code);
}

static void burst_transfer_enable()
{
    ret_code_t err_code;

    burst_completed = false;

    err_code = nrf_drv_ppi_channel_enable(ppi_channel_spi);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_enable(ppi_channel_timer);
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_enable(&timer);

    // Configure short between spi end event and spi start task
    nrf_spim_shorts_enable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);

    imu_select();
}

static void burst_transfer_disable()
{
    ret_code_t err_code;

    // Configure short between spi end event and spi start task
    nrf_spim_shorts_disable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);

    err_code = nrf_drv_ppi_channel_disable(ppi_channel_spi);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_disable(ppi_channel_timer);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_timer_disable(&timer);

    imu_deselect();

    burst_completed = true;
}

s8 bmi160_bus_burst_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u32 cnt)
{
	m_tx_buf[0] = reg_addr | READ_MASK;
	m_tx_buf[1] = 0;

	nrf_drv_spi_xfer_desc_t xfer = NRF_DRV_SPI_XFER_TRX(m_tx_buf, 1, reg_data, 255);
    uint32_t flags = NRF_DRV_SPI_FLAG_HOLD_XFER |
                     NRF_DRV_SPI_FLAG_REPEATED_XFER |
                     NRF_DRV_SPI_FLAG_RX_POSTINC |
                     NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER;
    nrf_drv_spi_xfer(&spi, &xfer, flags);  

	burst_transfer_enable();

	spi_start_task = 0x1UL;

	while(!burst_completed){
		__WFE();
	}
	spi_xfer_done = false;
	burst_completed = false;

	return SUCCESS;
}

The device crashes after the SPI is started and I get a APP_ERROR:ERROR:Fatal.

Is this the correct way to do this? Do you have an idea of where the problem might be?

Thanks!

Parents
  • Hi Ole, thanks for your comment. I have updated the question by NRF_DRV_SPI_FLAG_TX_POSTINC with NRF_DRV_SPI_FLAG_RX_POSTINC since I want to do multiple reads. That however didn't fix the problem.

    Regarding when to disable the shorts, I disable them at the fourth END event because at that time I also issue a NRF_SPIM_TASK_STOP trough PPI so I thought that would be the right time to do it. My understanding is that when the fourth END arrives it will not start another transfer because it is stopped through PPI. Is that correct? Also, actually I only need to read 1020 bytes, so four transactions of 255 bytes each will be fine.

    For the debugging, I defined DEBUG and wrote the handler below. However, I only get the file number a nothing is printed for the file name and error code, not even the log string at the beginning ("APP:INFO:"). What am I doing wrong?

Reply
  • Hi Ole, thanks for your comment. I have updated the question by NRF_DRV_SPI_FLAG_TX_POSTINC with NRF_DRV_SPI_FLAG_RX_POSTINC since I want to do multiple reads. That however didn't fix the problem.

    Regarding when to disable the shorts, I disable them at the fourth END event because at that time I also issue a NRF_SPIM_TASK_STOP trough PPI so I thought that would be the right time to do it. My understanding is that when the fourth END arrives it will not start another transfer because it is stopped through PPI. Is that correct? Also, actually I only need to read 1020 bytes, so four transactions of 255 bytes each will be fine.

    For the debugging, I defined DEBUG and wrote the handler below. However, I only get the file number a nothing is printed for the file name and error code, not even the log string at the beginning ("APP:INFO:"). What am I doing wrong?

Children
No Data
Related