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

TWI Switch between easyDMA and normal read

Hi,

I am reading a BMX055 via I2C which consists of three sensors with three addresses. I got the easyDMA running to read 10 times the gyro using the PPI and the data ready interrupt. Now after 10 readings I want to read once the accelerometer and the magnetometer. But if I try to read with

nrf_drv_twi_tx(&m_twi_instance, address, &reg, 1, false); nrf_drv_twi_rx(&m_twi_instance, address, p_data, length);

I get the NRF_ERROR_BUSY which means that the TWIM is still in use. So here is my question how can I switch from easyDMA reading to normal reading.

Thanks and kind regards,

C.

  • Do you setup the TWIM transfers using the TWI driver as well? The error code NRF_ERROR_BUSY will only be returned if the driver is busy, it will not check the state of the peripheral. Did the error code come from nrf_drv_twi_tx or nrf_drv_twi_rx call? Note that unless you initialize the driver in blocking mode, you need to make sure the first transfer is finished before calling the receive function.

  • No it is the following problem: I start a easydma transfer for 10 gyro samples with:

    // Disable the TWIM module while we reconfigure it
    NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos;
    NRF_TWIM0->SHORTS = 0;
    NVIC_DisableIRQ(SPI0_TWI0_IRQn);
    NVIC_ClearPendingIRQ(SPI0_TWI0_IRQn);
    
    // Configure a gpiote channel to generate an event on a polarity change from
    // low to high generated the BMX interrupt pin.
    uint8_t gpiote_ch_bmx_int_event = 0;
    NRF_GPIOTE->CONFIG[gpiote_ch_bmx_int_event] = ( (GPIOTE_CONFIG_MODE_Event   << GPIOTE_CONFIG_MODE_Pos) |
                                                    (BMX_INT_PIN                << GPIOTE_CONFIG_PSEL_Pos) |
                                                    (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos));
    
    NRF_TWIM0->PSEL.SCL = BMX_TWI_SCL_PIN;
    NRF_TWIM0->PSEL.SDA = BMX_TWI_SDA_PIN;
    NRF_TWIM0->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K400;
    
    // Load TWI TX buffer into TWI module. Set number of bytes to write pr transfer, max count, to one.
    // Disable the EasyDMA list functionality for TWI TX.
    NRF_TWIM0->TXD.PTR = (uint32_t)&p_tx_gyro_buffer;
    NRF_TWIM0->TXD.MAXCNT = 1;
    NRF_TWIM0->TXD.LIST = TWIM_TXD_LIST_LIST_Disabled << TWIM_TXD_LIST_LIST_Pos;
    
    // Point to TWI RX buffer. Set number of bytes to read pr transfer, max count, to TWIM_RX_BUF_WIDTH.
    // Disable the EasyDMA list functionality for TWI TX
    NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_gyro_buffer;
    NRF_TWIM0->RXD.MAXCNT = TWIM_RX_BUF_WIDTH_GYRO_ONLY;
    NRF_TWIM0->RXD.LIST = TWIM_RXD_LIST_LIST_ArrayList << TWIM_RXD_LIST_LIST_Pos;
    
    // Make sure that BMX address is set
    NRF_TWIM0->ADDRESS = BMX055_GYRO_ADDRESS;
    // Enable shortcuts that starts a read right after a write and sends a stop condition after last TWI read
    NRF_TWIM0->SHORTS = (TWIM_SHORTS_LASTTX_STARTRX_Enabled << TWIM_SHORTS_LASTTX_STARTRX_Pos) |
                        (TWIM_SHORTS_LASTRX_STOP_Enabled << TWIM_SHORTS_LASTRX_STOP_Pos);
    
    // Configure PPI channel
    // Use BMX interrupt pin as event
    // Start timer 0 on event to count number of transfers
    // Also start TWI transfers on event
    // Enable PPI channel
    NRF_PPI->CH[0].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_ch_bmx_int_event];
    NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TIMER0->TASKS_COUNT;
    NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TWIM0->TASKS_STARTTX;
    
    // Enable the TWIM module
    NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
    

    then when I get the interrupt of the timer I do the following:

    // Clear timer event
    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
    // Reset the TWIM RX pointer to initial address of RX buffer
    NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_gyro_buffer;
    // Toggle a LED for show
    nrf_gpio_pin_toggle(LED_1);
    // Set flag to notify main context of the new data available
    twi_gyro_transfers_complete = true;
    

    Now I want at the same interrupt read the accelerometer and magnetometer only once and then return with the gyro reading. But if I try either reading or writing during the interrupt routine or in the main after reading the flag I get NRF_ERROR_BUSY.

  • The use of the TWIM peripheral directly through the registers should not cause the return of the error code NRF_ERROR_BUSY. Where do you initialize the TWI driver? If you initialize it before you run the TWIM transfers, are you sure the driver is setup to use TWI peripheral and not TWIM peripheral?

  • As you can see in my post before I am using TWIM transfer. But I want after 10 dma transaction one TWI communication taking place. Is this possible? And yes I can see the TWIM communication on the logic analyzer. But If I try to start a nrf_drv_twi_tx during the interrupt routine I get the NRF_BUSY_ERROR

  • Yes, I see that, but in your original question you write that you call nrf_drv_twi_tx/nrf_drv_twi_rx to do the TWI transfers. The driver can be setup to use both TWIM and TWI peripheral. Have you checked the configuration in sdk_config.h to make sure TWI does not use EasyDMA (set TWI0_USE_EASY_DMA to 0). If you initialize the driver before starting the TWIM transfers, and the driver is configured to use EasyDMA (TWIM peripheral), you might end up in a state where the transfers cannot be started. Since TWIM0 and TWI0 share the same base address, you can also not have both enabled at the same time. If you want to use both, you either have to disable TWIM before initializing the TWI driver (without EasyDMA), or use TWIM1/TWI1 instance for one of the transfers.

Related