[SPIM+TIMER+PPI] Issue regarding the handlers for SPIM and TIMER.

Hello,

I am programming BLE with the nRF52840-DK. [Toolchain Manager: v1.3.0, IDE: Visual Studio Code (VSCode), SDK: ncs v2.6.0, window11 pro]

< Simple Code Explanation >

1. The ADC (SLAVE) and nRF52840 DK (MASTER) communicate via SPIM.

2. A command is sent to the ADC at regular intervals defined by 'TIME_TO_WAIT_US'.

  • The TIMER is used to measure the intervals and PPI is used to start SPIM.
  • The command buffer includes tx_buf_array and tx_buf_array_2. (nRF52840 DK -> ADC)
  • tx_buf_array is a command for ADC initialization.
  • tx_buf_array_2 is a command to retrieve ADC data and is intended to be sent repeatedly.
  • The SPIM handler exists to modify Tx_PTR and to signal the end of SPIM.
  • The TIMER handler exists to signal the end of the TIMER.

< my issue>

If TIME_TO_WAIT_US is less than 10, SPIM communication does not work properly. (ADC spec: Maximum SCLK frequency is 25 MHz)

I think a lot of time is being consumed in the handler. I'm not sure exactly what the problem is.

I want SPIM to work properly when 'TIME_TO_WAIT_US' is 5~6.

Could you give me some advice?

- Below is my code for the handler part:

void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) {   
	//LOG_INF("spim1_handler[%d] - TXD.PTR: 0x%08X", spi_counter, spim1_inst.p_reg->TXD.PTR);
	if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array_2[17] + 2) {
        spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0];
    } else if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array[30] ) {
        spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0];
    }
	if(spi_counter == MAX_SPI_COUNT){
		spi_disable(spim1_inst.p_reg);
        k_sem_give(&sem_condition1);
    }
    spi_counter++;
}

void timer0_handler(nrf_timer_event_t event_type, void * p_context){   
	if(spi_counter == MAX_SPI_COUNT){
		timer_disable(&timer0_inst);
        k_sem_give(&sem_condition2); 
    }
} 

- Below is my code for the ppi part:

    /*   PPI  Setting  */
    uint32_t gpiote_task_addr = nrfx_gpiote_out_task_address_get(&gpiote_inst ,SS_PIN_MASTER);    
    uint32_t timer_start_compare_event_addr = nrfx_timer_compare_event_address_get(&timer0_inst, NRF_TIMER_CC_CHANNEL0);
    uint32_t spi_start_task_addr   = nrfx_spim_start_task_address_get(&spim1_inst);
    uint32_t spi_end_evt_addr = nrfx_spim_end_event_address_get(&spim1_inst);

    // Timer reaches the desired tick -> GPIOTE toggle(off), SPI start
    error = nrfx_gppi_channel_alloc(&ppi_channel_spi_start);
    nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_start, timer_start_compare_event_addr, gpiote_task_addr);
    nrfx_gppi_fork_endpoint_setup(ppi_channel_spi_start, spi_start_task_addr);

    // SPI tx-rx transmission ends -> GPIOTE toggle(on)
    error = nrfx_gppi_channel_alloc(&ppi_channel_spi_end);
    nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_end, spi_end_evt_addr, gpiote_task_addr);


Parents
  • Hi,

    Let's say TIME_TO_WAIT_US is 10, then after every 10us SPI transaction is being executed?

    How many bytes you are transmitting?
    How many bytes you are receiving?
    What is the frequency of operation?
    How much time it would require to tx/rx using a spim transaction?
    There will always be sometime after the CSN has been pulled low and the clock (CLK) is generated, and similarly at the end of transaction there will be time after CLK is disabled to the point when CSN is pulled back.

    So you need to see if your requirement is realistic and design / manage accordingly.

    Regards,
    Naeem

  • Hello!

    I used an oscilloscope to measure the MISO, MOSI, SCK, and SS signals. When 'TIME_TO_WAIT_US' was set to 20, the SPIM operated normally, as confirmed by log debugging and electrical signal values.

    However, when 'TIME_TO_WAIT_US' was set to 6, it did not work properly. The results of the oscilloscope measurements can be summarized as follows:

    1. The SS and SCK signals are operating normally.
    2. The MOSI signal is not operating correctly.
      • It does not transmit the desired values. I think the issue might be that the TXD.PTR modification in the handler is not being done correctly.
      • For example, I tried to send the value 0xFF00 in an infinite loop, but this value is not being transmitted.

    Below is the modified handler code.

    void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) {   
    
        if ((spi_counter == 29) || (spi_counter > 29 && (spi_counter - 29) % 18 == 0)) {
            spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0];
        } 
        if ( (spi_counter > 29) && (spi_counter % 1000 == 0)) {
            spim1_inst.p_reg->RXD.PTR = (uint32_t)rx_buf_array[0];
        }
        spi_counter++;
    }
    
    void timer0_handler(nrf_timer_event_t event_type, void * p_context){   
    
    } 
    

    Could you provide some advice on this? I would also appreciate it if you could recommend similar tickets!

  • Can you share the snapshot of those signals you have captured when it is working correctly and when it is not working correctly?

    When it worked correctly (to transfer 2 bytes of data, what is the time when CS line is triggered and pulled back?) That should be the minimum time required for your transitions and there would be some delay in between.

  • These are few tickets that discuss timing issues with SPI:

    SPIM delay 6us

    SPI Delay between transfers

    It might be a good idea to start with some sample and first confirm the output as desired, and then change the sample as per needs.

Reply Children
No Data
Related