This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nRF52832 SPI 4-Wire Master Issue with SPI Sample

I have been trying to adapt the following example project to work with my SPI peripheral device (LIS2DE12 Accelerometer): nRF5_SDK_11.0.0_89a8197\examples\peripheral\spi\pca10040\arm5_no_packs

My device has been flashed with S132 2.0.

Info on this peripheral is here: www.st.com/.../en.DM00153214.pdf

I am using a custom device with the following nRF to ST pin connections:

PO.02 (SS) to Pin 2 (CS)

PO.03 (MOSI) to Pin 4 (SDI)

PO.04 (SCK) to Pin 1 (SLC)

PO.05 (MISO) to Pin 3 (SDO)

I have defined these pins within nrf_drv_config.h as per docs.

#define SPI0_ENABLED 1

#if (SPI0_ENABLED == 1)
#define SPI0_USE_EASY_DMA 1		

#define SPI0_CONFIG_SCK_PIN 4
#define SPI0_CONFIG_MOSI_PIN 3
#define SPI0_CONFIG_MISO_PIN 5
#define SPI0_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW

Note that the only other peripheral enabled is UART0 and it is not using any pins that the SPI interface is using.

#define UART0_ENABLED 1

#if (UART0_ENABLED == 1)
#define UART0_CONFIG_HWFC         NRF_UART_HWFC_DISABLED
#define UART0_CONFIG_PARITY       NRF_UART_PARITY_EXCLUDED
#define UART0_CONFIG_BAUDRATE     NRF_UART_BAUDRATE_115200
#define UART0_CONFIG_PSEL_TXD 10	// RxN Tag Config Tx
#define UART0_CONFIG_PSEL_RXD 8		// RxN Tag Config Rx
#define UART0_CONFIG_PSEL_CTS 9		// RxN Tag Config Unused
#define UART0_CONFIG_PSEL_RTS 14	// RxN Tag Config Unused
#define UART0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#ifdef NRF52
#define UART0_CONFIG_USE_EASY_DMA false

Also note that I had tried disabling DMA using:

#define SPI0_USE_EASY_DMA 0

... but found that I was only able to get a clock output during my MOSI buffer transfer but the clock was not continuing to support incoming MISO bytes. Enabling DMA seemed to fix this.

Code used for SPI init and read/write is here:

#define SPI_CS_PIN   2  	
#define SPI_INSTANCE  0 
#if (SPI0_ENABLED == 1)
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); 
#endif
static volatile bool spi_xfer_done; 

static uint8_t		m_tx_buf[2];	// Control/Addr byte plus optionally used data byte for reg writes.
static uint8_t		m_rx_buf[1];	// Always just 1 data byte returned.

void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{
	nrf_delay_ms(10);
	
    spi_xfer_done = true;
    NRF_LOG_PRINTF(" Transfer completed.\r\n");
	NRF_LOG_PRINTF(" Received: 0x%02X\r\n",m_rx_buf[0]);
}

int main(void)
{
	ret_code_t err_code;
	
	err_code = NRF_LOG_INIT();
    APP_ERROR_CHECK(err_code);
    NRF_LOG_PRINTF("Altered SPI example\r\n");

    nrf_drv_spi_config_t spi_config;
    spi_config.ss_pin = SPI_CS_PIN;
	spi_config.mosi_pin = SPI0_CONFIG_MOSI_PIN;
	spi_config.sck_pin = SPI0_CONFIG_SCK_PIN;
	spi_config.miso_pin = SPI0_CONFIG_MISO_PIN;
	spi_config.frequency = NRF_DRV_SPI_FREQ_8M;			// Default 4M
	spi_config.mode = NRF_DRV_SPI_MODE_3;				// Default mode 0 
	spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; // Matches Default.
	spi_config.irq_priority = SPI0_CONFIG_IRQ_PRIORITY;
	
	err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler);
	APP_ERROR_CHECK(err_code);

    while(1)
    {
        // Reset rx buffer and transfer done flag
        memset(m_rx_buf, 0, 1);
        spi_xfer_done = false;
	
		m_tx_buf[0] = 0x8F;	// 1 = Read, 0 = No Addr Inc, 001111 = WhoAmI Reg Add
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, 1, m_rx_buf, 1));

        while (!spi_xfer_done)
        {
            __WFE();
        }

        nrf_delay_ms(100);
    }
}

There are 2 issues that I am having when issuing a read of peripheral register 0x0F (using cmd 0x8F):

  1. Response data printed within the callback should always be 0x33 (the fixed value in register 0x0F), but is often erroneous.

  2. Voltage levels on the clock, MISO and MOSI lines look incorrect during peripheral responses.

Relating to "1." - I repeatably read a register value of 0xFF and then the correct 0x33 (and then 0xFF again and the cycle repeats) when using the fastest Nordic SPI rate of 8 Mbps. At lower rates, inconsistent register values are read.

Relating to "2." (which may be the cause of "1."), I believe that there may be contention on the lines as indicated in scope caps.

Please ignore the apparent offset from ground as there is an outstanding scope setup issue.

In this first capture, the yellow line shows my clock and the blue line shows chip select. It is driven low by the Nordic SPI driver as required. image description TagSPI_6.bmp

In this second capture, the blue line now shows the MOSI signal. It seems good until a response comes in from the peripheral and then it is driven to a strange state instead of O Vdc. The command is 0x8F (10001111) denoting read from register 0x0F. image descriptionTagSPI_7.bmp

In this last capture, the blue line now shows the MISO signal. It's timing and indicated value is correct (byte value 0x33), but its levels seem strange. image descriptionTagSPI_5.bmp

Could this indicate contention on the clock and MISO lines - only when the peripheral is responding to a read command over MOSI? The driver init seems to leave the MISO pin floating.

// - MISO (optional) - input,
    if (p_config->miso_pin != NRF_DRV_SPI_PIN_NOT_USED)
    {
        miso_pin = p_config->miso_pin;
        nrf_gpio_cfg_input(miso_pin, NRF_GPIO_PIN_NOPULL);
    }

Is this ok, or perhaps would a pull up help?

Changing data rates to below 8 Mbps does not seem to affect the traces, so maybe there a two distinct issues here.

Any help and suggestions are appreciated.

  • Last time I had levels doing something silly like that I had a grounding issue, are you sure your dev board and your sensor have the same VDD and their grounds connected directly and firmly together? When I didn't have that right, the whole sensor chip floated up and down as GPIOs went high and low.

    You should also fix your outstanding scope setup issue because it makes the results at least a little suspect.

    SPI is a driven protocol, so pullups/pulldowns aren't required.

  • RK - thanks for the response.

    No DK used. This is a custom device with solid trace supporting VDD and Gnd connections between an nRF52832 and accelerometer.

    Since posting, I have had some success using the driver. I am now reading 2 bytes (even though 1 is returned) and I am consistently getting 0xFF and then the byte that contains peripheral register data. I am also able to write peripheral register data and read back modifications. To get this, I changed the mode to "...Mode_0", set the speed to 8 Mbps and I am throwing out the first byte returned from the driver (always 0xFF).

    I am still very concerned that I am seeing the scope output shown and will hope that someone from Nordic can offer a suggestion. Our hardware engineer has suggested that there appears to be contention on the MISO, MOSI and Clock lines.

  • "there appears to be contention on the MISO, MOSI and Clock lines." is really totally meaningless, it just doesn't say anything beyond "I don't understand the signals". The peripheral just doesn't produce signals with 1/2 voltages so either there's a connection issue on the board, and it would have to be a very odd one, or the scope's not showing the signal properly. The SPI module doesn't produce signals which look like that, whatever you do to it.

    As to the rest, since SPI clocks data in at the same time it clocks data out, throwing away the first few received bytes is not unusual because the first few bytes are clocked in from the slave before it's received the bytes with the request, and those bytes are often either 0xFF or 0x00, ie with no data to send the slave just clocks out 1s or 0s. So that sounds completely usual to me.

  • RK - great feedback.

    Mark - I am also confused by this 'contention' concept; it's the slave's job to drive the MISO pin. Also, as RK pointed out, most SPI slave devices will either clock out a status byte or garbage for the first byte of a transaction because they don't know what you want to do until they've read at least a byte of data. From the datasheet linked above:

    """ bit 8-15 : data DO(7:0) (read mode). This is the data that is read from the device (MSb first). """

    Bits 0-7 in read mode are garbage for this device.

  • Thanks Daniel. The reception of the leading 0xFF is clear to me now. The strange scope signals remain a mystery and are most likely just an issue with the scope or my setup of it (I am a software guy who hasn't used one for a few decades). I will get a hardware engineer more involved in an effort to resolve.

Related