SPIM doesn't stop forever when Peer is PowerDown.

My environment is
nRF52840 + nRF5 SDK 17

I have nRF52840 and LCD module(ER-TFTM101-1) connected using SPIM2.

When LCD power is on, It's fine work.

But,
When LCD power is off, SPIM never STOP.

Follow is simple test code

	/* SCK */
	nrf_gpio_pin_drive_t pin_drive = NRF_GPIO_PIN_S0S1;
	nrf_gpio_pin_write(SPIM_CLK_PIN, 0);
	nrf_gpio_cfg(SPIM_CLK_PIN,
		NRF_GPIO_PIN_DIR_OUTPUT,
		NRF_GPIO_PIN_INPUT_CONNECT,
		NRF_GPIO_PIN_NOPULL,
		pin_drive,
		NRF_GPIO_PIN_NOSENSE);
	/* MOSI */
	nrf_gpio_pin_write(SPIM_MOSI_PIN, 0);
	nrf_gpio_cfg(SPIM_MOSI_PIN,
		NRF_GPIO_PIN_DIR_OUTPUT,
		NRF_GPIO_PIN_INPUT_DISCONNECT,
		NRF_GPIO_PIN_NOPULL,
		pin_drive,
		NRF_GPIO_PIN_NOSENSE);
	/* MISO */
	nrf_gpio_cfg(SPIM_MISO_PIN,
		NRF_GPIO_PIN_DIR_INPUT,
		NRF_GPIO_PIN_INPUT_CONNECT,
		NRF_GPIO_PIN_NOPULL,
		pin_drive,
		NRF_GPIO_PIN_NOSENSE);
	/* SS */
	nrf_gpio_pin_write(SPIM_SS_PIN, 1);
	nrf_gpio_cfg(SPIM_SS_PIN,
		NRF_GPIO_PIN_DIR_OUTPUT,
		NRF_GPIO_PIN_INPUT_DISCONNECT,
		NRF_GPIO_PIN_NOPULL,
		pin_drive,
		NRF_GPIO_PIN_NOSENSE);

	SpimReg.ENABLE = SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos;
	SpimReg.TASKS_STOP = 1;
	SpimReg.PSEL.SCK = SPIM_CLK_PIN;
	SpimReg.PSEL.MOSI = SPIM_MOSI_PIN;
	SpimReg.PSEL.MISO = SPIM_MISO_PIN;
	SpimReg.FREQUENCY = SPIM_FREQ;
	SpimReg.RXD.PTR = uint32_t(m_recv_buff),
	SpimReg.RXD.MAXCNT = 2;
	SpimReg.RXD.LIST = 0;
	SpimReg.TXD.PTR = uint32_t(m_send_buff),
	SpimReg.TXD.MAXCNT = 2;
	SpimReg.TXD.LIST = 0;
	SpimReg.CONFIG = 0; /* active-high / Leading / MsbFirst */
	SpimReg.ORC = 0x00;
	actCS(true); /* assert CS */
	SpimReg.EVENTS_END = 0;
	SpimReg.TASKS_START = 1;

EVENTS_STARTED is 1
EVENTS_STOPPED/EVENTS_ENDRX/EVENTS_END/EVENTS_ENDTX never be 1.

in the above condition,
when LCD power is turned on, EVENTS_STOPPED/EVENTS_ENDRX/EVENTS_END/EVENTS_ENDTX is 1.

after that, when LCD power is turned off,

Again, When TASKS_START set 1, EVENTS_STARTED  and EVENTS_STOPPED/EVENTS_ENDRX/EVENTS_END/EVENTS_ENDTX is 1.

how is this going?

** SPIM returns EVENT_STOP if the SCLK signal line is determined while the LCD is power down.

Parents
  • Hi 

    Do I understand your problem correctly that you are not getting events before powering LCD, but you get events after powering LCD, and you still get events after powering LCD off again? Or am I misunderstanding?

    What exactly do you mean by LCD power turned on/off? Are you enabling/disabling a module, or are you setting a gpio high/low, or something else?

    Maybe you could scope the lines to get a better idea of what is going on?

    Also, I believe you should config SPIM before you enable it. Right now it looks like you're doing it the other way around which could be a source of errors.

    Best regards,

    Einar

  • I did some more research.

    Apparently, SCLK and GND are short-circuited when LCD power is turned off.

    I changed the way we test.
    1. When CLK of SPIM is connected to GND, EVENTS_END is '0' even if TASK_START is set to 1.
    2. When
    CLK is opend,  EVENTS_END is '1'.

    After 1, do following
    a) DISABLE_SPIM
    b) CLK is opend
    c) ENABLE_SPIM
    Even though I did not set TASKS_START to '1', EVENTS_END became '1'.

    I have two doubts.
    1. If the CLK signal cannot change (such as being shorted to GND), will the SPIM state machine remain stopped(not END)?
    2. If the state machine is not completed (not END), disabling SPIM will not stop the state machine itself?

  • At first, SCLK is connected to GND.

    write '0' to EVENTS_STOPPED / EVENTS_ENDRX / EVENTS_END / EVENTS_ENDTX / EVENTS_STARTED.

    write '1' to TASKS_START

    EVENTS_STARTED change to '1'

    But, EVENTS_STOPPED / EVENTS_ENDRX / EVENTS_END / EVENTS_ENDTX never change to '1'.

    (When write '1' to TASKS_STOP, EVENTS_STOPPED  never change to '1'.)

    After that, SCLK disconnect from GND( be opend.)

    As soon as, EVENTS_ENDRX / EVENTS_END / EVENTS_ENDTX  change to '1'.

    What happen?

  • As I said these events can be used to check that the SPI is ready and not busy, and it makes sense that it is not ready before SCLK is opened and operational, so I don't think it sounds strange that these events get set to 1 when the SPI is ready to be used and not busy.

    Have you tried using the SPI to see if it works?

  • My test code.

    #define	SPIM_SS_PIN			28
    #define	SPIM_CLK_PIN		29
    #define	SPIM_MOSI_PIN		30
    #define	SPIM_MISO_PIN		31
    
    #define	SpimReg				(*NRF_SPIM0)
    
    volatile uint32_t s_counter;
    
    uint8_t m_recv_buff[2];
    uint8_t m_send_buff[2] = { 0xA5, 0x3C };
    
    int main(void)
    {
    	/* SCK */
    	nrf_gpio_pin_drive_t pin_drive = NRF_GPIO_PIN_S0S1;
    	nrf_gpio_pin_write(SPIM_CLK_PIN, 0);
    	nrf_gpio_cfg(SPIM_CLK_PIN,
    		NRF_GPIO_PIN_DIR_OUTPUT,
    		NRF_GPIO_PIN_INPUT_CONNECT,
    		NRF_GPIO_PIN_NOPULL,
    		pin_drive,
    		NRF_GPIO_PIN_NOSENSE);
    	/* MOSI */
    	nrf_gpio_pin_write(SPIM_MOSI_PIN, 0);
    	nrf_gpio_cfg(SPIM_MOSI_PIN,
    		NRF_GPIO_PIN_DIR_OUTPUT,
    		NRF_GPIO_PIN_INPUT_DISCONNECT,
    		NRF_GPIO_PIN_NOPULL,
    		pin_drive,
    		NRF_GPIO_PIN_NOSENSE);
    	/* MISO */
    	nrf_gpio_cfg(SPIM_MISO_PIN,
    		NRF_GPIO_PIN_DIR_INPUT,
    		NRF_GPIO_PIN_INPUT_CONNECT,
    		NRF_GPIO_PIN_NOPULL,
    		pin_drive,
    		NRF_GPIO_PIN_NOSENSE);
    
    	/* SS */
    	nrf_gpio_pin_write(SPIM_SS_PIN, 1);
    	nrf_gpio_cfg(SPIM_SS_PIN,
    		NRF_GPIO_PIN_DIR_OUTPUT,
    		NRF_GPIO_PIN_INPUT_DISCONNECT,
    		NRF_GPIO_PIN_NOPULL,
    		pin_drive,
    		NRF_GPIO_PIN_NOSENSE);
    
    	/**/
    	SpimReg.TASKS_STOP = 1;
    	SpimReg.PSEL.SCK = SPIM_CLK_PIN;
    	SpimReg.PSEL.MOSI = SPIM_MOSI_PIN;
    	SpimReg.PSEL.MISO = SPIM_MISO_PIN;
    	SpimReg.FREQUENCY = SPIM_FREQUENCY_FREQUENCY_K125;
    	SpimReg.RXD.PTR = uint32_t(m_recv_buff),
    	SpimReg.RXD.MAXCNT = 2;
    	SpimReg.RXD.LIST = 0;
    	SpimReg.TXD.PTR = uint32_t(m_send_buff),
    	SpimReg.TXD.MAXCNT = 2;
    	SpimReg.TXD.LIST = 0;
    	SpimReg.CONFIG = 0; /* active-high / Leading / MsbFirst */
    	SpimReg.ORC = 0x00;
    
    	SpimReg.ENABLE = SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos;
    
    	nrf_gpio_pin_clear(SPIM_SS_PIN);
    
    	SpimReg.EVENTS_END = 0;
    	SpimReg.TASKS_START = 1;
    
    	for (;;) {
    		s_counter++;
    	}
    }
    

    When SCLK is open.

    SS and MOSI wave form

    EVENTS

    When write to TASKS_START=1, as soon as, EVENTS_ENDRX/EVENTS_END/EVENTS_ENDTX is '1'.

    When SCLK is connect to GND.

    SS and MOSI wave form(MOSI is not change.)

    EVENTS

    EVENTS_ENDRX/EVENTS_END/EVENTS_ENDTX is never '1'.

    Is this move as expected?

    Even if the SPIM-peer is in such a state, I want the SPIM to always complete. Is there any workaround?

  • Again, have you tried sending messages on the SPI?

    Does it work?

  • Look at the [SCLK is open] waveform.
    0xA5, 0x3C are sent in order.

    No data is sent to MOSI in the [SCLK is connect to GND.] waveform.

Reply Children
  • Well yes, it should not be surprising that no data is sent when SCLK is connected to GND?

    When "LCD power" is turned on and SCLK is open, does SPI work as expected?

  • >When "LCD power" is turned on and SCLK is open, does SPI work as expected?

    Yes.

    The problem is the following two points.
    1. It cannot detect that SPIM is not transmitting. (no error occurs)
    2. Writing 1 to TASKS_STOP never causes EVENTS_STOP.

  • Hi again

    I would really recommend that you try using a driver instead of setting the registers manually.

    You should consider using our nrfx driver, and even if you decide not to use it, at least have a look at how it does things.

    Also, can you please specify how SCLK and GND are short-circuited when LCD power is turned off? This still confuses me.

    I believe SCLK being grounded is the source of a lot of the unwanted behavior you're observing.

    -Einar

  • Do the following test(based on examples/peripheral/nrfx_spim)

    #include "nrfx_spim.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define NRFX_SPIM_SCK_PIN  3
    #define NRFX_SPIM_MOSI_PIN 4
    #define NRFX_SPIM_MISO_PIN 28
    #define NRFX_SPIM_SS_PIN   29
    #define NRFX_SPIM_DCX_PIN  30
    
    #define SPI_INSTANCE  0                                           /**< SPI instance index. */
    static const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    #define TEST_STRING "Nordic123456789012345678901234567890"
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];  /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    int main(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, m_length, m_rx_buf, m_length);
    
        nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
        spi_config.frequency      = NRF_SPIM_FREQ_1M;
        spi_config.ss_pin         = NRFX_SPIM_SS_PIN;
        spi_config.miso_pin       = NRFX_SPIM_MISO_PIN;
        spi_config.mosi_pin       = NRFX_SPIM_MOSI_PIN;
        spi_config.sck_pin        = NRFX_SPIM_SCK_PIN;
        //spi_config.dcx_pin        = NRFX_SPIM_DCX_PIN;
        //spi_config.use_hw_ss      = true;
        spi_config.ss_active_high = false;
        APP_ERROR_CHECK(nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL));
    
        NRF_LOG_INFO("NRFX SPIM example started.");
    
        while (1)
        {
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
    
            APP_ERROR_CHECK(nrfx_spim_xfer(&spi, &xfer_desc, 0));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
            bsp_board_led_invert(BSP_BOARD_LED_0);
            nrf_delay_ms(200);
        }
    }

    result

    SCK/MOSI/MISO/SS is open
    LED is blinking.

    MOSI, MISO or SS is connected to GND.
    LED is blinking.

    SCK is connected to GND.
    LED is not blinking.

    So the result is the same.

    It is a big problem if SPIM stalls due to a problem with the slave device.
    Please provide a solution immediately.

  • Hi

    Can you please specify how SCLK and GND are short-circuited when LCD power is turned off?

    Is this a property of the module, or is it a result of your wiring?

    I'm afraid having a grounded SCK might not be covered by the SPI spec, so there might not be a straight forward solution, but I've asked about this internally and I'll let you know what they have to say about the issue.

    If you don't find another way around this, I would suggest adding a timeout to abort your SPI query in the case of stalling. But I believe best practice would be to avoid using SPI while it's not properly initialized.

    -Einar

Related