[nRF52840 DK] SPI transaction interrupted by ISR ?

Hi,



I've got a display driven over SPI at 8MHz by the lib LVGL in a dedicated Zephyr thread and an ISR configured on one gpio pin that triggers a short routine registering the rising edge of the signal (basically incrementing a var).
 
The used Zephyr SPI write method is from <drivers/spi.h> :
static inline int spi_write_dt(const struct spi_dt_spec *spec, const struct spi_buf_set *tx_bufs);



When the ISR is highly solicited (i.e. lots of pulses on gpio pin -> >1k/s ), I've noticed the display starts to show artifacts that isn't cleared if the drawn area position isn't dynamic.

I'm assuming it comes from the case where the ISR is called in the middle of the display SPI update transaction and some SPI data is shifted out during this time as the SCK still continues from hardware.
 

Is there a way to make sure the SPI transaction doesn't "freeze" in this kind of configuration ?



Thanks for your time !
Parents
  • Hello,

    Have you been able to observe how the interrupts affects the SPI transfer on an logic analyzer?

    I do not see any reason why a frequent pin interrupt should affect the SPI transfer, because once SPI transfer is started it will transfer continously the amount of byte in one chunk (through EasyDMA), unless you have disabled EasyDMA, and thereby using interrupt based SPI transfer. Maybe you can comment whether CONFIG_SPI_0_NRF_SPI or CONFIG_SPI_0_NRF_SPIM is used in your project?

    Kenneth

  • I just probed on MOSI and, so far I can tell, it doesn't seem to be affected indeed.

    And I don't have any of CONFIG_SPI_0_NRF_SPIM or CONFIG_SPI_0_NRF_SPI settled in the project. How to be sure EasyDMA is effectively used ?

    Anyway I tried shutting down some non-critical applicative threads and it doesn't change anything, artifacts still there when heavy ISR calls.

    EDIT:

    I also noticed some SPI data may be interpreted as SPI command one (causing random behaviors like inverting the display color, etc.). Looking into the driver, the gpio for data_control pin is handled manually using gpio_pin_set_d before and after spi_write_dt for data command:

     

      gpio_pin_set_dt(&config->dc_gpio, 1);
      errno = spi_write_dt(&config->bus, &tx_bufs_cmd);
      gpio_pin_set_dt(&config->dc_gpio, 0);

    May it cause issues if process is preempted over there?

  • Are you sure you don't have any electrical problems, that you have poor grounding or similiar?

    Do I understand it correctly that your ISR does not trigger any SPI transfer? In other words the ISR does not directly/indirectly affect the transfer of SPI (other than the potential delay it may cause).

    Kenneth

  • Rather than using a gpio pin manually to switch between command/data perhaps use the SPIM DCX functionality which does this for you in hardware:

    spi_config.dcx_pin = data_control_pin;

    6.25.2 D/CX functionality
    Some SPI slaves, for example display drivers, require an additional signal from the SPI master to distinguish between command and data bytes. For display drivers this line is often called D/CX. SPIM provides support for such a D/CX output line. The D/CX line is set low during transmission of command bytes and high during transmission of data bytes. The D/CX pin number is selected using PSELDCX on page 423 and the number of command bytes preceding the data bytes is configured using DCXCNT on page 424. It is not allowed to write to the DCXCNT on page 424 during an ongoing transmission

  •  Yes, my first driver implementation was using nrfx_spim.h and nrf_spim_* functions but now I would like to maximize the compatibility for other platforms using drivers/spi.h.

    I don't think there is the same functionality in this lib, right ?

Reply Children
  • I assume you are using SPIM with DMA (ENABLE=7), and not SPI without DMA (ENABLE=1)  as the latter would make no sense for a display. If the driver doesn't support DCX you can add it after the initialisation; it is a hardware feature that can be  independent of the Nordic driver (in SPIM DMA mode):

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
    // Set pin to an output first then set DCX registers
    
    NRF_SPIM0->PSELDCX=pin; // Pin select for DCX signal
    
    NRF_SPIM0->DCXCNT = 1; // This register specifies the number of command bytes preceding the
                           // data bytes. The PSEL.DCX line will be low during transmission of
                           // command bytes and high during transmission of data bytes. Value 0xF
                           // indicates that all bytes are command bytes.

Related