Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Problems about spidma buffer!!!

Hi, NODRDICSEMI

Now I use PPI + gpiote (spidma) to make the hardware read and write by itself. But after I enabled RX list, I found that when the amount of data read exceeds the RX buffer I set, RX buffer will not be updated.So

1、How do I know if the RX buffer is full,

2、How do I know the number of times SPI reads and writes when using spidma?

In addition, I found in the debugging program that SPI RX buffer received more than one set of data when the event reached gpiote interrupt, that is to say, SPI read and write operations were performed more than once. However, I have set the read-write task trigger condition of SPI to gpiote input event.

I don't understand what's wrong.

Hope to get a reply as soon as possible.

June6

Parents
  • Hello,

    Are you able to share the code you are using to set up the transfers here? Preferably the full project so I can more easily replicate the problem on my side.

    Normally you should get a event once the specified read buffer is full, but it is also possible to configure the driver to not use interrupts (with the NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER flag).

    Best regards,

    Vidar

  • Hi, Vidar

    #define DMA_TX_BUFFER_SIZE 2
    #define DMA_RX_BUFFER_SIZE 80001
    
    typedef struct {
      uint32_t spi_evt_addr;
      uint32_t spi_task_addr;
      uint32_t gpiote_evt_addr;
      uint32_t gpiote_task_addr;
    } ppi_addr_t;
    
    typedef struct ArrayList {
      uint8_t tx_buffer[DMA_TX_BUFFER_SIZE];
      uint8_t rx_buffer[DMA_RX_BUFFER_SIZE];
    } ArrayList_type;
    
    ppi_addr_t ppi_addr;
    ArrayList_type spi_dma_list;
    nrf_drv_spi_t spi_0 = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE_0);
    
    uint32_t ppi_init(void) {
      uint32_t err_code;
      nrf_ppi_channel_t ppi_channel1, ppi_channel2, ppi_channel3;
      uint32_t gpiote_evt_addr, spi_evt_addr, gpiote_task_addr, spi_task_addr;
    
      err_code = nrf_drv_ppi_init();
      APP_ERROR_CHECK(err_code);
    
      gpiote_evt_addr = ppi_addr.gpiote_evt_addr;
      gpiote_task_addr = ppi_addr.gpiote_task_addr;
      spi_evt_addr = ppi_addr.spi_evt_addr;
      spi_task_addr = ppi_addr.spi_task_addr;
    
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel2);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel3);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel4);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_assign(ppi_channel1, gpiote_evt_addr,
                                            gpiote_task_addr);
      APP_ERROR_CHECK(err_code);
    
      err_code =
          nrf_drv_ppi_channel_assign(ppi_channel2, gpiote_evt_addr, spi_task_addr);
      APP_ERROR_CHECK(err_code);
    
      err_code =
          nrf_drv_ppi_channel_assign(ppi_channel3, spi_evt_addr, gpiote_task_addr);
      APP_ERROR_CHECK(err_code);
    
      /* Enable configured PPI channel */
      err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_enable(ppi_channel2);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_enable(ppi_channel3);
      APP_ERROR_CHECK(err_code);
    
      return NRF_SUCCESS;
    }
    
    uint32_t ppi_uninit(void) {
      uint32_t err_code;
      nrf_ppi_channel_t ppi_channel1, ppi_channel2, ppi_channel3;
    
      /* Disable configured PPI channel */
      err_code = nrf_drv_ppi_channel_disable(ppi_channel1);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_disable(ppi_channel2);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_disable(ppi_channel3);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_free(ppi_channel1);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_free(ppi_channel2);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_ppi_channel_free(ppi_channel3);
      APP_ERROR_CHECK(err_code);
    
      memset(&ppi_addr, 0, sizeof(ppi_addr));
    
      err_code = nrf_drv_ppi_uninit();
      APP_ERROR_CHECK(err_code);
    
      return NRF_SUCCESS;
    }
    
    static void spi_event_handler(nrf_drv_spi_evt_t const *p_event,
                                  void *p_context) {
                                  
    }
    
    /**
     * @brief platform specific initialization (platform dependent)
     */
    static uint32_t spi_init(void) {
      nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
      spi_config.ss_pin = SPI_CS_PIN;
      spi_config.miso_pin = SPI_MISO_PIN;
      spi_config.mosi_pin = SPI_MOSI_PIN;
      spi_config.sck_pin = SPI_SCK_PIN;
        
      APP_ERROR_CHECK(
          nrf_drv_spi_init(&spi_0, &spi_config, spi_event_handler, NULL));
        
      ppi_addr.spi_evt_addr = nrf_drv_spi_end_event_get(&spi_0);
      ppi_addr.spi_task_addr = nrf_drv_spi_start_task_get(&spi_0);
    }
    
    void spi_data_dma_set(void) {
      uint8_t reg = 0xA8; 
    
      memset(&spi_dma_list, 0, sizeof(spi_dma_list));
      spi_dma_list.tx_buffer[0] = reg;
      nrf_spim_tx_buffer_set(spi_0.u.spim.p_reg, spi_dma_list.tx_buffer, 1);
      nrf_spim_rx_buffer_set(spi_0.u.spim.p_reg, spi_dma_list.rx_buffer, 3);
      /* TODO Confirm whether it is normal */
      nrf_spim_event_clear(spi_0.u.spim.p_reg, NRF_SPIM_EVENT_END);
    }
    
    void spi_list_set(void) {
      nrf_spim_tx_list_disable(spi_0.u.spim.p_reg);
      nrf_spim_rx_list_enable(spi_0.u.spim.p_reg);
    }
    
    void gpiote_in_evt_enable(void) {
      nrf_drv_gpiote_in_event_enable(SPI_INT_PIN, true);
    }
    
    void gpiote_in_evt_disable(void) {
      nrf_drv_gpiote_in_event_disable(SPI_INT_PIN);
    }
    
    void gpiote_out_task_enable(void) {
      nrf_drv_gpiote_out_task_enable(SPI_CS_PIN);
    }
    
    void gpiote_out_task_disable(void) {
      nrf_drv_gpiote_out_task_disable(SPI_CS_PIN);
    }
    
    static void in_pin_handler(nrf_drv_gpiote_pin_t pin,
                               nrf_gpiote_polarity_t action) {
      if (pin == SPI_ACCEL_INT_PIN)
        ;
    }
    
    ret_code_t gpiote_init(void) {
      ret_code_t err_code;
    
      if (!nrf_drv_gpiote_is_init()) {
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
      }
      nrf_drv_gpiote_in_config_t in_config_0 = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
      in_config_0.pull = NRF_GPIO_PIN_PULLUP;
      /* When configuration conversion occurs, no callback is generated and PPI is
       * used instead */
      err_code =
          nrf_drv_gpiote_in_init(SPI_ACCEL_INT_PIN, &in_config_0, in_pin_handler);
      APP_ERROR_CHECK(err_code);
    
      /* The initial state is high */
      nrf_drv_gpiote_out_config_t out_config_0 =
          GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
      err_code = nrf_drv_gpiote_out_init(SPI_CS_PIN, &out_config_0);
      APP_ERROR_CHECK(err_code);
    
      ppi_addr.gpiote_evt_addr =
          nrf_drv_gpiote_in_event_addr_get(SPI_INT_PIN);
      ppi_addr.gpiote_task_addr =
          nrf_drv_gpiote_out_task_addr_get(SPI_CS_PIN);
          
      gpiote_in_evt_enable();
      gpiote_out_task_enable();
    
      return NRF_SUCCESS;
    }
    
    void gpiote_uninit(void) {
      gpiote_in_evt_disable();
      nrf_drv_gpiote_in_uninit(SPI_INT_PIN);
      gpiote_out_task_disable();
      nrf_drv_gpiote_out_uninit(SPI_CS_PIN);
    }
    
    int main(void) {
      spi_init();
      spi_data_dma_set();
      spi_list_set();
      gpiote_init();
      ppi_init();
    }

    The above is the SPI DMA part of the code, other parts involved too much, temporarily difficult to share.

    Do you think there is any problem with the above code?

    After using SPI DMA, I have successfully exchanged data with the sensor, but at present I still get the data in SPI RX buffer regularly. I hope that I can be informed when the RX buffer is full, so that I can get the data without a timer.

    And I didn't find NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER flag in the structure parameter(*p_event) of SPI interrupt callback function(spi_event_handler).

    Best regards,

    June6

  • Hi,

    Thanks for sharing code snippet. It looks like you want to set up a repated transfer with the NRF_DRV_SPI_FLAG_RX_POSTINC flag, similiar to the scenario described in the driver documentation:

    The following example shows how to set up a sequence of SPI transfers that will be triggered using PPI (for example, using RTC or TIMER compare events). A single transfer consists of a transmission of 1 byte and a reception of 3 bytes. The TX data is repeated for all transfers, but the RX data from all transfers is collected in the buffer. Therefore, NRF_DRV_SPI_FLAG_RX_POSTINC is set so that the buffer address for the received data is incremented. The end of sequence is controlled externally, and the processing of data is postponed until the end of the sequence (the user event handler is disabled). (link)

    But I don't see any calls to nrf_drv_spi_xfer() in the code you posted.

    Best regards,

    Vidar

Reply
  • Hi,

    Thanks for sharing code snippet. It looks like you want to set up a repated transfer with the NRF_DRV_SPI_FLAG_RX_POSTINC flag, similiar to the scenario described in the driver documentation:

    The following example shows how to set up a sequence of SPI transfers that will be triggered using PPI (for example, using RTC or TIMER compare events). A single transfer consists of a transmission of 1 byte and a reception of 3 bytes. The TX data is repeated for all transfers, but the RX data from all transfers is collected in the buffer. Therefore, NRF_DRV_SPI_FLAG_RX_POSTINC is set so that the buffer address for the received data is incremented. The end of sequence is controlled externally, and the processing of data is postponed until the end of the sequence (the user event handler is disabled). (link)

    But I don't see any calls to nrf_drv_spi_xfer() in the code you posted.

    Best regards,

    Vidar

Children
No Data
Related