[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.

  • When it worked correctly (to transfer 2 bytes of data, what is the time when CS line is triggered and pulled back?)

    Blue line: SS
    Green line: SCK (8MHz)

    I have confirmed that the SS signal works well under the conditions of 'TIME_TO_WAIT_US '

    In my case, The master device SPI interface should be configured with SPI options CPOL=0 and CPHA=0.

    Blue line: SCK (8MHz)

    Green line: MOSI (desired value: 0xFF00)

    Pink line: MISO (desired value: 0x0001)

    - Below is an image that works well. ( TIME_TO_WAIT_US = 20)

    -Below is an image that doesn't work ( TIME_TO_WAIT_US = 6)

  • Are you using correct COPL and CPHA?

    Can you try with 10us delay instead of 6?

    And then you can try reducing it down to see where it breaks / does not work.

    (are you doing anything else as well during this process?)

    Just for testing, maybe you can reduce the speed and test again.

  • Thank you for brainstorming the issue with me.

    Are you using correct COPL and CPHA?

    Yes, The desired result is actually outputted when it is 20us.

    Can you try with 10us delay instead of 6?

    Here is no significant difference between 6us and 10us.
    In both cases, the desired MISO and MOSI values are not outputted as shown in the above picture.

    And then you can try reducing it down to see where it breaks / does not work.

    (are you doing anything else as well during this process?)

    Currently, there are no additional processes. I'm only controlling the TXD and RXD pointers of the SPI. As per the current code, it works well or doesn't work around the 12us mark.

    I plan to add Bluetooth transmission later.


    Considering everything, it seems like the issue arises because the SPIM handler is too heavy. I'm writing this ticket because I'm curious if this is the limit or if there are any other countermeasures.


Reply
  • Thank you for brainstorming the issue with me.

    Are you using correct COPL and CPHA?

    Yes, The desired result is actually outputted when it is 20us.

    Can you try with 10us delay instead of 6?

    Here is no significant difference between 6us and 10us.
    In both cases, the desired MISO and MOSI values are not outputted as shown in the above picture.

    And then you can try reducing it down to see where it breaks / does not work.

    (are you doing anything else as well during this process?)

    Currently, there are no additional processes. I'm only controlling the TXD and RXD pointers of the SPI. As per the current code, it works well or doesn't work around the 12us mark.

    I plan to add Bluetooth transmission later.


    Considering everything, it seems like the issue arises because the SPIM handler is too heavy. I'm writing this ticket because I'm curious if this is the limit or if there are any other countermeasures.


Children
No Data
Related