This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SPI Master pin set and clear

I am trying to run the SPI code on an NRF52382 based custom board. I am using the NRF 52 DK,  Keil uVision 5.0 , SDK 15.2.

I cannot set and clear the SPI relevant pins on my custom board as gpios. The pins I am using are:

SPI_SS_PIN = P0.6
SPI_MISO_PIN = P0.8
SPI_MOSI_PIN = P0.9
SPI_SCK_PIN = P0.7 

and the schematic showing these pins is: 

I was successfully able to toggle all four pins above, (as well as the RESET P0.21) as GPIOs after I did following: 

1. went to sdk_config.h and changed  NRF_LOG_BACKEND_UART_TX_PIN    to pin 5 instead of 6

2. went to OPTIONS FOR TARGET -> C/C++ -> Preprocessor Symbols -> Define and added " CONFIG_NFCT_PINS_AS_GPIOS" after nrf52382.... and removed the line " CONFIG_GPIO_AS_PINRESET"

But as soon as I run the SPI example code in SDK15 I am unable to toggle these pins and use them as gpios. Especially the SPI_SS_PIN which is pin 6, as soon as I run the SPI code this pin fixes to high value and will not clear/go low.  

My thinking is there something wrong with the way the SPI example configures the spi relevant pins? 

https://devzone.nordicsemi.com/f/nordic-q-a/18546/gpio-not-set-or-clear-with-spi-code this guy seemed to have had the same problem running SPI and with the CS pin...

Thank you! 

Parents
  • Depends perhaps on when you are doing a set/clear test; try setting the SPI_SS_PIN pin to NRF_DRV_SPI_PIN_NOT_USED before initialising the spi, and see if that allows manually set/clear of the /CS pin. Note in this case a manual configuration of the pin to Output must be made as the SPI driver is no longer controlling the pin. The reason for doing this is to ensure nothing else is interfering with the pin; the spi driver does not control the /CS pin with hardware spi but instead runs a set or clear instruction encapsulating the hardware spi transmission. That means the user can just as easily do the set/clear before and after the spi transfer, or allow the handler to do it as in your case.

    Other devices have hardware control over the /CS pin (similar to SCK, MOSI and MISO), but not the nRF52832.

    Also you are probably aware, but if you are testing on a DK then pin 6 is connected in hardware ..

  • Updated:   Now I am configuring the CS pin after I initialize the SPI and it seems to work because the pin goes down to 0.7 V from the earlier Vdd HIGH 3.3V. However, even though the voltage value reduced I do not think this means the SPI_SS_PIN is LOW because the LOW value on my board is typically in millivolts. 

    I am thinking the 0.7V for the CS pin is a floating value. And I do not get why I cannot clear the SPI_SS_PIN?  
    Could this be because the SPI_SS_PIN needs to have a falling edge (and not clear 0) for the SPI peripheral device to be connected? 

    Thanks again

  • When SPI is enabled did you set the pin to NRF_DRV_SPI_PIN_NOT_USED as I mentioned above when manually driving the pin? ie spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED. Otherwise the spi still drives the pin ..

  • Yes I did do that. I set it to NOT_USED in the nrf_drv_spi.h file before I configured it as high low drive. 

    There is another thing I tried after that. I tried enabling my peripheral with pin 6 as a gpio instead of as the SPI slave select pin. I set spi.config.ss_pin to NRF_DRV_SPI_PIN_NOT_USED. And then I did not set Pin 6 to spi.config.ss_pin. Instead I set Pin 6 to LOW as a simple GPIO and said that SPI_SS_PIN is not used (there is no hardware pin connected to SS). 

    But surprisingly I got the same result. 
    The peripheral I am using is the ADS1220 (analog to digital conv). Maybe it sets its slave select to 0.7 V whenever it is provided clock and there is sth withe the ADC?  

  • I have used the ADS1220, albeit on a Dialog BLE radio, and not had any issues; the /CS worst-case leakage on that device is only 10uA and so there must be some other hardware or software item interfering with operation of the pin. Since that only happens with your spi code enabled, either there is something still in contention in the code or maybe there is a fault on the ADS1220; can you try a second board, just in case? Maybe also post the spi init code ..

  • Here is my SPI code : 

    I hope the images are visible in a comment...
    Thank you for your help! I appreciate it

  • Ah, I think your code will not work as NULL for tx buffer and length is not valid and will cause an assert. I imagine that setting a command byte but not transmitting it was not what you intended; here is a typical invocation:

    mAfePacketTransferComplete = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&mAfeSpiInstance, mTxBuf, mRxTxBufLength, mRxBuf, mRxTxBufLength));
    

    Compare this with the nrf_drv_spi_transfer() you are using in your code image, and you will note that the transmit command and length are both NULL, or zero, which is not acceptable.

    Also, just as an aside, what pins are the LEDs on?

Reply
  • Ah, I think your code will not work as NULL for tx buffer and length is not valid and will cause an assert. I imagine that setting a command byte but not transmitting it was not what you intended; here is a typical invocation:

    mAfePacketTransferComplete = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&mAfeSpiInstance, mTxBuf, mRxTxBufLength, mRxBuf, mRxTxBufLength));
    

    Compare this with the nrf_drv_spi_transfer() you are using in your code image, and you will note that the transmit command and length are both NULL, or zero, which is not acceptable.

    Also, just as an aside, what pins are the LEDs on?

Children
  • This is the assert trap:

        ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
        ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
        ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
    

  •  So I fixed this ^ that you pointed out. I now initialize m_tx_buf [0] = 0x08 and rest of m_tx_buf array to 0 ; and then do nrf_drv_spi_transfer(&spi, m_tx_buf, tx_length, m_rx_buf, rx_length). But the problem is same as before. I also noticed that there are NO LEDs on my custom PCB device that I am programming so I commented out all the BSP and LED relevant code and run the program again. But that did not fix the issue either. If I use P0.6 as a simple GPIO in the same project with the SPI parts commented out, it works fine and sets to clear if I want to. 

    I even redefiened " #define NRF_DRV_SPI_PIN_NOT_USED  0x00   from 0xFF" in the nrf_drv_spi header file to make the default spi_not_used value 0 but that did not work either. 

    Another thing that I noticed: Even though I am not initializing, or using the DRDY pin ((P0.10) on my nrf) anywhere in the entire project, just it being connected to the DRDY on the ADS1220 (the ADC) chip on my PCB makes it go to 3.3V (Vdd) instead of a float value (as it should be if it is unused and unconfigured).  Also, when I set the CS pin to HIGH it goes up to 2.6 V (not upto 3.3V like the other pins do when they are HIGH). Do these things say sth about how the ADC is working? 

    Thank you once again. 

    Since I am working with a custom PCB changing the CS pin would mean making another layout and board. Would you recommend I short pin 6 to pin 5 externally on the nrf52 on the PCB and then use pin 5 to control CS? When you were using ADS1220 , did you get problems with its CS pin at all, and were you externally tying it down to DGND? I remember running SPI on another ADS1220 chip using nrf52 DK first and was getting problems running SPI master successfully earlier as well. This is why I shifted to the custom PCB.  

  • On the ADS1220 the dedicated /DRDY signal is not open-drain and will drive to a high level (3.3 volts) except when pulsing low to indicate data ready; therefore P0.10 will have 3.3 volts as you observe (ie correct behavior).

    The pin 6 issues you see imply either a short to another pin on the ADS1220 or pin 6 being used somewhere else in the code on another nRF52 peripheral. It is also possible (unlikely) that the ADS1220 GND is sitting at +1.0 volts and the schottky clamp diodes in the ADS1220 therefore hold pin 6 at 0.7 volts. Are you switching the voltage supplies to the ADS1220 with port pins, or have any series resistance in the GND line? Note 2.7 volts + 0.7 volts is also suspiciously close to 3.3 volts, though that may be a red herring. Connecting pin 5 to pin 6 would be a hack and may hide the true issue you are looking for.

    The ADS1220 has no requirement for any pull-up or pull-down resistors on any of the SPI lines, including /CS and /DRDY, and I have never had any issues in driving these lines. I suggest you post the actual code text of the spi code init and handler you are using with an Insert Code box. I will look out settings I have used on this chip and post them later this weekend. Pins 7, 10, and 11 should be at 3.3 volts. Pins 1,2,3,4,6 and 17 should all be at Gnd (0v wrt nRF52) unless you are doing something special.

    One last comment, have you left any serial uart code enabled? The default for the PCA10040 which I think you started with has the following conflict with pin P0.6:

    #define RX_PIN_NUMBER  8
    #define TX_PIN_NUMBER  6
    #define CTS_PIN_NUMBER 7
    #define RTS_PIN_NUMBER 5
    #define HWFC           true
    

  • Yes, some of my serial uart is enabled. I need to read data from my ADC and send it to the computer via the uart (i.e. I am using NRF_LOG_INFO ). I did change the UART_TX pin number from 6 to 5 in the sdk_config.h file before I even started. That should be okay since pin 5 is unused on my custom board. I am sure pin 6 is not being used anywhere else in the sdk_config.h of my project. Where else should I be checking to make sure where else it is being used? To stop its UART_TX functionality, is removing it from the sdk file enough? 
    P.S. I tried removing all NRF_LOG and LOG initialization code (all the data logging code) in my main file and running the code but the problem persists. 

    My ADS1220 pins are: 
    pin 11 - 3.3V, pin 10 at 5V,    
    Pin 6 and 7 are both at 1.8V.  All the rest of the pins on ADS1220 are as you said should be. 


    Here is my code. What I get from this code is FATAL ERROR on my putty terminal, and I believe the values of the RX and TX registers are showing the addresses of some registers, not data because although these values are persistent (do not change/aren't garbage), they are not corresponding to my voltage data input. 

    /**
     * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include "nrf_drv_spi.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 SPI_INSTANCE  0 /**< SPI instance index. */
    #define S0 21
    #define S1 22
    #define S2 23
    #define S3 24
    #define CS 6
    
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    
    static uint8_t       m_tx_buf[4];           /**< TX buffer. */
    static uint8_t       m_rx_buf[4];    /**< RX buffer. */
    static const uint8_t tx_length = sizeof(m_tx_buf);        /**< Transfer length. */
    static const uint8_t rx_length = sizeof(m_rx_buf); 
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
        spi_xfer_done = true;
         NRF_LOG_INFO("Transfer completed.");
        //if (m_rx_buf[0] != 1)
        //{
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
    			  nrf_delay_ms(10); 
    			  NRF_LOG_INFO ("Received:  %d  Transmitted:  %d  \n", m_rx_buf, m_tx_buf); 
        //}
    }
    
    
    void init_pins () {
    	
    	nrf_gpio_cfg_output(S0); 
    	nrf_gpio_cfg_output(S1); 
    	nrf_gpio_cfg_output(S2); 
    	nrf_gpio_cfg_output(S3); 
    	 
    	nrf_gpio_pin_set (S3); 
    	nrf_gpio_pin_clear (S1);
    	nrf_gpio_pin_clear (S2);
    	nrf_gpio_pin_set (S0);
    		
    
    	
    	
    }
    
    int main(void)
    {
       // bsp_board_init(BSP_INIT_LEDS);
    		
    	
    	
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
       // NRF_LOG_DEFAULT_BACKENDS_INIT();
    		
    	
    		nrf_delay_ms(50); 
    	
    NRF_LOG_FLUSH();
    	NRF_LOG_INFO ("Hi...");
    	nrf_delay_ms(5); 
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;
    		spi_config.frequency = NRF_DRV_SPI_FREQ_4M; 
    		spi_config.mode     = NRF_DRV_SPI_MODE_1; 
    		//spi_config.irq_priority = APP_IRQ_PRIORITY_HIGHEST;
    	
    		
    		nrf_gpio_cfg_output(SPI_SCK_PIN); 
    		nrf_gpio_cfg_output(SPI_MOSI_PIN);
    		nrf_gpio_cfg_input (SPI_MISO_PIN, NRF_GPIO_PIN_NOPULL); 
    	
    		
    	
    	
        APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
        nrf_delay_ms(20); 
    		
    		
    		
    		nrf_delay_ms(20);
    		init_pins();    // configure CS as output and set it to HIGH 
    
    nrf_gpio_cfg(CS,
                     NRF_GPIO_PIN_DIR_OUTPUT,
                     NRF_GPIO_PIN_INPUT_CONNECT,
                     NRF_GPIO_PIN_NOPULL,
                     NRF_GPIO_PIN_H0H1,
                     NRF_GPIO_PIN_NOSENSE);
    
    //nrf_gpio_cfg_output(CS);
    //nrf_gpio_pin_clear(CS); 
    								 
    		memset(m_tx_buf, 0, tx_length);
    		memset(m_tx_buf, 0, rx_length);
    		m_tx_buf[0] = 0x08;  //START/SYNC HEX COMMAND FOR ADS1220  
    		
    		NRF_LOG_INFO("SPI example started. TX : %d   RX:  %d  \n", m_tx_buf, m_rx_buf);
    	 
    		nrf_gpio_pin_clear(CS); 
    		nrf_delay_ms(1); 
    		APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, tx_length, m_rx_buf, rx_length));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    			
    				nrf_delay_ms(10); 
    				
    				
    	
    		memset(m_tx_buf, 0, tx_length);
    		m_tx_buf[0] = 0x08;  //START/SYNC 
    				
        for (;;)
        {
    			
    				
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, rx_length);
            spi_xfer_done = false;
    				
    				nrf_delay_ms(15); 
    				NRF_LOG_INFO (" Before Transfer , after memset _ rxbuf = %d, txBuf = %d", m_rx_buf[0], m_tx_buf[0]);
    				
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, tx_length, m_rx_buf, rx_length));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
            //bsp_board_led_invert(BSP_BOARD_LED_0);
            nrf_delay_ms(800);
    				
    				
        }
    }
    

  • See .\nRF5_SDK_15.2.0_9412b96\components\boards/pca10040.h for the serial port pin definitions using pin 6.

    Fatal Error .. is that coming from an assert()?

    I would suggest moving the following code until after the loop in main; ie logging only when spi_xfer_done is set otherwise the huge delay in that interrupt handler can cause all sorts of issues which will cloud what is going on:

         NRF_LOG_INFO("Transfer completed.");
        //if (m_rx_buf[0] != 1)
        //{
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
    			  nrf_delay_ms(10); 
    			  NRF_LOG_INFO ("Received:  %d  Transmitted:  %d  \n", m_rx_buf, m_tx_buf); 
        //}
    

Related