NRF52832 - Slow SPI, no difference in using synchronous or asynchronous driver functions

Hey Slight smile

I think I miss something here.

I got a nrf52832 Chip on the MDBT42Q – 512KV2 Module by Raytac. Now I try to communicate with an ADC from TI via SPi, which works fine. I'm using Zephyr for this. The ADC triggers an GPIO Interrupt with a 1000Hz frequency. In the Interrupt handler I receive the data via SPI. Receiving the data in the work queue does not change anything.

Measuring the time consumption for calling the spi_read() function shows ~400us for 120Bytes (8Mhz since is max.). Cause I need to receive data every 1ms, this is a lot. The timing is measured with a gpio toggled high/low.

Now I tried an asynchronous approach, activated:

CONFIG_SPI_ASYNC=y
CONFIG_POLL=y
and used:
gpio_pin_toggle()
spi_read_signal()
gpio_pin_toggle()
AND
gpio_pin_toggle()
spi_transceive_cb()
gpio_pin_toggle()
functions.
But both of them take the same time as the spi_read. How does that make sense? Is spi_read using EasyDma? And, can I solve that to speed things up and free some CPU cycles?
Thanks!
Parents
  • Hello,

    Could you elaborate further on how you have configured the SPI to run on 8 MHz, and how you have configured the GPIO to toggle during the event handling?
    Chances are that the GPIO measurements will not be correct since the processing of the event can be delayed due to other threads or higher-priority interrupts.
    However, if you set up a GPIO task to toggle as a reaction to a SPI event through PPI then the GPIO will be toggled instantly when the event occurs, without needing CPU intervention.

    Lastly, do you have access to a logic analyzer? It would be good to confirm that the communication is happening as you expect it to, through the use of a logic analyzer.

    Best regards,
    Karl

  • Hey, of course here is my config:

    &spi2 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	pinctrl-0 = <&spi2_default>;
    	pinctrl-1 = <&spi2_sleep>;
    	cs-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
    	pinctrl-names = "default", "sleep";
    	clock-frequency = <8000000>;
    	spidev: spi-device@0 {
    		reg = <0>;
    	};
    };

    &pinctrl {
    	spi2_default: spi2_default {
    		group1 {
    			nordic,drive-mode = <NRF_DRIVE_H0H1>;
    			psels = <NRF_PSEL(SPIM_SCK, 0, 16)>,
    				<NRF_PSEL(SPIM_MOSI, 0, 11)>,
    				<NRF_PSEL(SPIM_MISO, 0, 17)>;
    		};
    	};
    
    	spi2_sleep: spi2_sleep {
    		group1 {
    			psels = <NRF_PSEL(SPIM_SCK, 0, 16)>,
    				<NRF_PSEL(SPIM_MOSI, 0, 11)>,
    				<NRF_PSEL(SPIM_MISO, 0, 17)>;
    			low-power-enable;
    		};
    	};
    }

    CONFIG_SPI=y
    CONFIG_SPI_ASYNC=y
    CONFIG_POLL=y

    #define MY_SPI DT_NODELABEL(spi2)
    
    
    const struct spi_cs_control spi_cs = {
        .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spidev)),
        .delay = 0,
    };
    
    const struct spi_config spi_cfg = {
        .frequency = DT_PROP(MY_SPI, clock_frequency),
        .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPHA,
        .slave = 50,
        .cs = &spi_cs,
    };
    
    spi_dev = DEVICE_DT_GET(MY_SPI);
    

    About the gpio:

    leds {
    	compatible = "gpio-leds";
    	led0: led_0 {
    		gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
    		label = "Red LED 0";
    	};
    };
    	
    &gpio0 {
    	status = "okay";
    };
    
    
    //Init
    if (!gpio_is_ready_dt(&ledRed)) {
        printk("gpio not ready\n");
    }
      
    ret = gpio_pin_configure_dt(&ledRed, GPIO_OUTPUT_HIGH);
        if (ret < 0) {
        printk("config failed\n");
    }
    
    
    
    //Code I'm running
    gpio_pin_set_dt(&ledRed, 1); 
    err = spi_read(spi_dev, &spi_cfg, &adsRX);
    gpio_pin_set_dt(&ledRed, 0);
    
    

    Your point about other threads or interrupts sounds plausible. I think I really need to digg deaper into Zephyr, Threadings, Scheduling and stuff.

    The best way to really find out what the MCU is doing is probably by using an Hardware Trace Interface? Is there an cheaper alternative instead of buying those expensive probes? Unfortunately I don't have one available.

    Thanks for pointing out the PPI feature, i'll give it a shot and try to digg into it.

    And yes I got an Logic Analyzer but since I'm working on a custom board it is not really possible to connect the channels to the Board, though it would be really interessting. Thinking Strangely enough if I increase SPI frequency to 8Mhz my TI ADS (up to 20Mhz) is no longer responding. There must be something wrong. Already tried the high drive mode.

    I could maybe use my nrf52840 DK, try to run the code there and check it out.

    Anyway thanks a lot for your help!! I'll try to find some new insights.

    Regard

  • Hello,

    Thank you for providing the config and clarifications.
    Briefly looking through the config I do not see any reason why this should run so slow, and so I suspect that the issue here could be how the timings is measured with the GPIO.
    Toggling the GPIO through PPI or setting up a logic analyzer would quickly confirm for us whether this could be the case :) 

    Benni said:

    The best way to really find out what the MCU is doing is probably by using an Hardware Trace Interface? Is there an cheaper alternative instead of buying those expensive probes? Unfortunately I don't have one available.

    Thanks for pointing out the PPI feature, i'll give it a shot and try to digg into it.

    If you use the debug feature of the nRF Connect SDK Visual Studio Code you can see the threads of your program, and if you would like to read more about threading in Zephyr in general you could take a look here.

    Benni said:
    And yes I got an Logic Analyzer but since I'm working on a custom board it is not really possible to connect the channels to the Board, though it would be really interessting.

    Ah, I understand.
    Then I think the easiest approach would be to use the same GPIO that you are already using for the timing measurements, but set it up to toggle by the SPI events through PPI instead of as part of the event handler.
    This way you will easily be able to measure the time elapsed between each full transfer, which you then could use to verify that it is happening at the expected rate.
    Using your nRF52840 DK connected to your logic analyzer to verify that the SPI is behaving as you would expect is also a very good approach. 
    My bet is on the measurement of the 400 µs period for a 120 byte transfer being inaccurate in this case.

    Benni said:
    Strangely enough if I increase SPI frequency to 8Mhz my TI ADS (up to 20Mhz) is no longer responding. There must be something wrong. Already tried the high drive mode.

    That does seem strange indeed - is there any unusual loggings, or other unexpected behavior?
    Does the TI ADS report anything on its side? I am unfortunately not familiar with the TI ADS personally, but sometimes there could be a configuration to allow for specific interfaces to be used at different speeds - I would check its datasheet for this, just to make sure that that is not an issue.

    Benni said:
    Anyway thanks a lot for your help!! I'll try to find some new insights.

    No problem at all - I am happy to help!
    Please do not hesitate to ask if you should have any questions or issues during this work! :) 

    Best regards,
    Karl

Reply
  • Hello,

    Thank you for providing the config and clarifications.
    Briefly looking through the config I do not see any reason why this should run so slow, and so I suspect that the issue here could be how the timings is measured with the GPIO.
    Toggling the GPIO through PPI or setting up a logic analyzer would quickly confirm for us whether this could be the case :) 

    Benni said:

    The best way to really find out what the MCU is doing is probably by using an Hardware Trace Interface? Is there an cheaper alternative instead of buying those expensive probes? Unfortunately I don't have one available.

    Thanks for pointing out the PPI feature, i'll give it a shot and try to digg into it.

    If you use the debug feature of the nRF Connect SDK Visual Studio Code you can see the threads of your program, and if you would like to read more about threading in Zephyr in general you could take a look here.

    Benni said:
    And yes I got an Logic Analyzer but since I'm working on a custom board it is not really possible to connect the channels to the Board, though it would be really interessting.

    Ah, I understand.
    Then I think the easiest approach would be to use the same GPIO that you are already using for the timing measurements, but set it up to toggle by the SPI events through PPI instead of as part of the event handler.
    This way you will easily be able to measure the time elapsed between each full transfer, which you then could use to verify that it is happening at the expected rate.
    Using your nRF52840 DK connected to your logic analyzer to verify that the SPI is behaving as you would expect is also a very good approach. 
    My bet is on the measurement of the 400 µs period for a 120 byte transfer being inaccurate in this case.

    Benni said:
    Strangely enough if I increase SPI frequency to 8Mhz my TI ADS (up to 20Mhz) is no longer responding. There must be something wrong. Already tried the high drive mode.

    That does seem strange indeed - is there any unusual loggings, or other unexpected behavior?
    Does the TI ADS report anything on its side? I am unfortunately not familiar with the TI ADS personally, but sometimes there could be a configuration to allow for specific interfaces to be used at different speeds - I would check its datasheet for this, just to make sure that that is not an issue.

    Benni said:
    Anyway thanks a lot for your help!! I'll try to find some new insights.

    No problem at all - I am happy to help!
    Please do not hesitate to ask if you should have any questions or issues during this work! :) 

    Best regards,
    Karl

Children
No Data
Related