cancel
Showing results for 
Search instead for 
Did you mean: 

How can I get SPI NSS pin driven high, and why is SPI transactions sometimes garbled?

PWint
Associate III

I am having great difficulties getting an SPI interface to work on a STM32433 device. I’ve gone back to the ST Nucleo dev board and used STMCube to generate a project and I am able to reproduce all my problems with only the dev board.

I am using SPI1 on PA4 through PA7.

1. NSS not driven.

The NSS line is only driven low when hardware, master mode is enabled. On the dev board it is always low unless the pull-up is enabled on the GPIO, but in this case NSS slowly goes high (and in my case not high enough before next transaction) because it seems it is high-impedance when SPI is disabled.

The code generated by STMCube never disables the SPI, so after calling HAL_SPI_Transmit() it never goes high again.

I did not find any calls in the SPI_HAL ot manually control NSS.

According to RM0394 SPIx_CR1.SSI (Bit 8): “The value of this bit is forced onto the 

NSS pin and the I/O value of the NSS pin is ignored.“ However, when I change SSM to 1 (to select software mode), and then change SSI, it has no effect.

What configuration/method/mode should I use so that NSS is driven high and low?

2. Garbage SPI Data.

The SPI bus transaction is sometimes invalid. When this happens, the debugger also loses the connection and I am unable to program after this. I first have to re-program with an application that does not do a SPI transaction. This fails with a flash verification error. I then have to cycle power, and then I am able to re-program and continue.

Attached is a scope trace showing the garbage SPI transaction. Clock can be seen going low, but it is low for a very long time (compared to actual clock speed) before some clocks that are too short follows. After this, I cannot debug the CPU any longer.

1 ACCEPTED SOLUTION

Accepted Solutions

On the Nucleo64 , the SMPS is controlled by PA4..PA7 pins, you use for SPI.

Did you change the solder bridges accordingly?

JW

View solution in original post

9 REPLIES 9
  1. NSS output in hardware mode is disappointment for all users. You have to manipulate it "manually", set it as GPIO and drive it low and high before and after transmission as needed. (When setting SSM, NSS pin is simply not connected to the SPI peripheral anymore, not as input nor as output).
  2. I don't know, but loss of debugging might indicate some major hardware failure - some short, clock loss, surge in power. Is there anything external connected to the board?

JW

PWint
Associate III

I am also getting the feeling NSS is not working as documented, but surely this should be fixed (either hardware or documentation)? It clearly states that SSI drives NSS when in software mode.

I've parked that for the moment, and changed my code to use a GPIO to drive NSS. I've gone to bare basics with the code below. It crashes 100% reliably on the line that writes to the data register (line 41 below). I can see in the debugger that the instructions following that is not executed (even though the debugger thinks it is - I am instruction stepping and registers are not loaded correctly). My experience with behaviour like that is that a critical exception was triggered (hardware fault) and that the debugger lost synch with the CPU. How can writing to the SPI DR cause such a severe error?

I have absolutely nothing but the USB cable connected to my board.

void DrvSPI_STM32L4::init()
{
  SPI1->CR2 = // SPI_CR2_LDMATX |             // DMA Num TX Bytes is even.
              // SPI_CR2_LDMARX |             // DMA Num RX Bytes is even.
                 SPI_CR2_FRXTH |              // RXNE event is generated if the FIFO level is > 1/4 (8-bit).
                 (0b0111 << SPI_CR2_DS_Pos) | // 8-bit data transfer size.
              // SPI_CR2_TXEIE |              // Disable TXE interrupt.
              // SPI_CR2_RXNEIE |             // Disable RXNE interrupt.
              // SPI_CR2_ERRIE |              // Disable Error interrupt.
              // SPI_CR2_FRF |                // Motorola frame format.
              // SPI_CR2_NSSP |               // No NSS pulses (asserted before transfer, and de-asserted after).
                 SPI_CR2_SSOE |               // SS output enabled in master mode (multimaster not supported).
              // SPI_CR2_TXDMAEN |            // Disable TX DMA.
              // SPI_CR2_RXDMAEN |            // Disable RX DMA.
                 0;
  
  SPI1->CR1 = // SPI_CR1_BIDIMODE |           // 2-line unidirectional data mode.
              // SPI_CR1_BIDIOE |             // Not used if in 2-line unidirectional mode.
              // SPI_CR1_CRCEN |              // CRC calculation disabled.
              // SPI_CR1_CRCNEXT |            // Only used if CRC is enabled.
              // SPI_CR1_CRCL |               // Only used if CRC is enabled.
              // SPI_CR1_RXONLY |             // Full-duplex mode.
                 SPI_CR1_SSM |                // Software slave management.
                 SPI_CR1_SSI |                // NSS (CS) pin is high. (Not used if SSM is zero).
              // SPI_CR1_LSBFIRST |           // MSB transferred first.
                 SPI_CR1_SPE |                // Enable SPI.
                 (0b001 << SPI_CR1_BR_Pos) |  // Baud = f_PCLK/4.
                 SPI_CR1_MSTR |               // Master configuration.
              // SPI_CR1_CPOL |               // Clock Polarity select (see datasheet).
              // SPI_CR1_CPHA |               // Clock Phase select (see datasheet).
                 0;
  
  volatile uint8_t go = 0;
  while (go == 0) {}
 
  volatile uint8_t dummy;
  volatile uint8_t* byteDR = (volatile uint8_t*)&SPI1->DR;
  for(;;)
  {
    GPIOA->ODR &= ~(1 << 4); // Take CS low.
    *byteDR = 0x01;          // Command.
    while ((SPI1->SR & SPI_SR_BSY) != 0) {}  // Wait until not busy.
    GPIOA->ODR |= (1 << 4); // Take CS high;
  }
}

PWint
Associate III

I forgot to mention: I re-connected my scope to look at the SPI transaction when writing to DR and it is also a garbage SPI transaction (see attached).

You can see there are only 7 clock cycles (instead of 8). MOSI (trace 3) changes on the last falling edge (I am writing 0x1, so this is correct) but is then stretched, and changes again without another clock edge. This seems like a bug in the SPI hardware.

> It clearly states that SSI drives NSS when in software mode.

I'm not going to look up the exact wording and I know the manuals are not written very clearly, but the intention of that sentence is to say that the *internal* NSS node of the SPI module (after being disconnected from the pin by setting SSM) is connected to the register bit SSI.

The garbled

> STM32433

STM32L433?

What board is this? Is this a "known good" board such as Nucleo or Disco? What is the clocking? Can you try it with the reset setting of clocks, if it's not already the case?

Is there any other manipulation with SPI register before the above code is called? Are there any interrupts enabled in NVIC?

JW

It is a NUCLEO64 ext-SMPS L433RC_P Rev B01 board.

The plot thickens: I found that when I run my code, instead of stepping through it, then I do not get the error.

My clocks is configured with default values (MSI, 4 MHz, busses same, etc.).

I have interrupts disabled at this point.

> I found that when I run my code, instead of stepping through it, then I do not get the error.

Do you observe SPI registers in debugger? This may be intrusive, although I don't quite understand how would that result in the described behaviour, but then I am no wizard too.

So if yes, try to switch off any "live update" or close the registers windows and step through in that way.

IAR? Keil? Eclipsoid?

JW

PS. Have no experience with the SMPS. Can you please observe the supply pins while stepping through in the "failing" configuration?

JW

On the Nucleo64 , the SMPS is controlled by PA4..PA7 pins, you use for SPI.

Did you change the solder bridges accordingly?

JW

Great, thanks, that was it.

I've removed the jumpers, and no longer see the problem. I completely missed that the ports was used on that page.