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 Reply Children
No Data
Related