STM32 gotchas
21.SPI master NSS unusable

SPI is a simple and popular serial protocol to connect peripherals communicating at a relatively high speed. It is based on a simple shift registers, so it consists of one data line per direction (MOSI, MISO) and a common clock line (SCK).

There is usually at least one more signal, providing framing, but as SPI is more a defacto than a formal standard, different devices treat this signal differently. Usually, it is generated by master, it is active low, usually starts and stops slave's communication, i.e. resets bit counters and also provides higher-level framing, and often also control's slave's threestateable MISO signal, so that MOSI of multiple slaves can simple be tied together.

In STM32's SPI, this signal is called NSS (N stands for Negative i.e. active low, SS stands for Slave Select). When SPI is set as slave, it indeed is an input providing framing/bitcounter reset and threestating of MISO. When set as master, NSS can be set as input and then it provides a means for an external device to switch the module to slave. This is intended for multmaster communication; but the mechanism is not very robust (there's no provision to prevent masters to collide in starting communication at the same time) so it's not very usable in this way.

The more usual mode of operation is, when SPI master uses NSS as output and generates framing on it. Users sometimes expect that when NSS in STM32 SPI is set to output (SPI_CR2.SSOE=1), the SPI will generate framing signal on this NSS. However, there's no such hardware in the SPI. If SSOE=1, NSS is simply set to low as long as the SPI module is enabled (SPI_CR1.SPE=1). If SPI module is disabled (SPI_CR1.SPE=0), the NSS pin is not driven actively. If a pullup is switched on for this pin in GPIOx_PUPDR, the pin will be pulled up, but this may take time, depending on the capacitive loading on the pin, given the pullup is relatively weak (nominally 40kΩ).

Since the 'F0/F3 families, a new feature has been introduced in SPI, NSS pulse mode (see SPIx_CR2.NSSP). While this generates bit-counter-reset-framing automatically on NSS, this usually is not what most of the users expects, i.e. higher, protocol-level framing is still not provided. Moreover, NSS pulsing generates gaps between frames, resulting in discontinuous clock and effectively slowing down the communication.

So the general recommendation is, for framing/NSS towards a slave requiring framing, use any pin as GPIO Output, and handle it "manually"1. If more automation is needed, users with good command of the STM32 peripherals may attempt to use timers to generate framing (and sometimes also clock, at the cost of one extra pin for external interconnect between TIMx_CHx and SPIx_SCK).


1. When doing so, it may be not a good idea to time the end of NSS based on the BSY signal.