How can I use hardware NSS (SPI) on STM32F4?
Asked Answered
C

5

9

I tried to use the hardware NSS signal with the HAL library, but I can't find any function to make the NSS pin have a low or high level. I also tried to find the answer in the HAL documentation, but there isn't any information there either. All examples on the Internet contain only software NSS.

How is one supposed to use hardware NSS?

Cleromancy answered 3/3, 2016 at 18:39 Comment(4)
if you use hardware NSS, then the pin state is managed by the peripheral. You don't need to explicitly drive it in software. To do so, you just configure your SPI_InitTypeDef.NSS with either SPI_NSS_HARD_INPUT if your device is a slave, or SPI_NSS_HARD_OUTPUT if your device is a master.Sparrow
I have yet to find a SPI slave that would safely allow driving NSS in hardware. The requirements for CS are usually only satisfied by driving this pin with software GPIO.Cocotte
It just doesn't work like classic CS in SPI master mode. From reference manual: "The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled."Incarnadine
I've got the same issue; using STM32F417 as a SPI master; when configured as HARD_OUTPUT the output is always low (i.e. selecting the slave). Works fine in SOFT mode but that's not what I'm after. No errors reported by the HAL nor by the hardware.Gennie
S
7

Somewhere I read that NSS is driven low as long as the SPI Master is enabled and driven high again if the SPI Master is disabled. I tried it using the HAL library (Cube/STM32CubeMX) from ST with an STM32L476 and polling SPI1. Initialization before and de-initialization after transmission did not set the NSS pin, but it took a lot of time:

Init structure:

hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

Transmit sequence:

HAL_SPI_Init( &hspi1 );
HAL_SPI_TransmitReceive( &hspi1, btx, brx, l, 5 ); // timeout 5msec;
while( hspi1.State == HAL_SPI_STATE_BUSY );  // wait for xmission complete
HAL_SPI_DeInit( &hspi1 );

So I decided setting the pin manually using GPIO (using SPI_NSS_SOFT in init):

HAL_GPIO_WritePin( NSS1_GPIO_Port, NSS1_Pin, GPIO_PIN_RESET ); // NSS1 low
HAL_SPI_TransmitReceive( &hspi1, btx, brx, l, 5 ); // timeout 5msec;
while( hspi1.State == HAL_SPI_STATE_BUSY );  // wait xmission complete
HAL_GPIO_WritePin( NSS1_GPIO_Port, NSS1_Pin, GPIO_PIN_SET ); // NSS1 high

I used blocking transmission (no DMA or Interrupt), because it was fast enough and no other tasks waiting. DMA setup proved to take unacceptably longer time to send only 24 bytes at 20 MHz. It would be an acceptable alternative.

As far as I can see in the STM32L4xx manual Chapter 38.4.12/13, the automatic NSS goes high after each byte/word transmission and thus is not well usable for longer streams holding NSS low for the whole transmission.

Sheathe answered 10/7, 2016 at 7:10 Comment(1)
It looks like the NSS signal is designed to work as an open-drain output with a pull-up resistor; I think the pin goes hi-Z instead of high when the peripheral controls it. Configuring the pin as alternate function, open-drain, with internal pull-up seems to make the pin go low when the peripheral is enabled and high when it isn't. An external pull-up resistor also works.Aribold
A
2

You can use the NSS pin as a standard GPIO and drive it with an interrupt routine. You should do that part by software. First set the NSS low and then send your frame (HAL_SPI_Transmit).

After the slave gets all the frame, use the HAL_SPI_RxCpltCallback function and set the NSS pin high in that interrupt.

Don’t forget to connect the GPIO pin to the NSS pin on the slave.

Annulet answered 4/3, 2016 at 7:12 Comment(0)
F
2

Look at the reference manual for your STM32 chip. I don't know if they're all the same but according to the one for mine (STM32WB55xx) and one I was able to find a public web link to (STM32F0)...

See the SPI functional description for NSS pin management (section 28.5.5 for the STM32F0 document I linked to), where it describes three modes:

  • Software NSS management (SPIx_CR1 register SSM bit = 1). The internal slave select information is driven internally by the SSI bit in register SPIx_CR1. The external NSS pin is free for applications to use.

  • Hardware NSS management (SSM bit = 0). This has two possible configurations depending on the SSOE bit in register SPIx_CR1:

    • NSS output enable (SSOE = 1). Only used when the MCU is master. The NSS signal is driven low as soon as SPI is enabled in master mode (SPE=1) and is kept low until SPI is disabled (SPE=0). A pulse can be generated between continuous communications if NSS pulse mode is activated. The SPI can not work in multimaster configuration with this NSS setting
    • NSS output disable (SSOE = 0). If the MCU is master, this allows multimaster capability. If NSS is pulled low, SPI enters master mode fault state and the device is automatically reconfigured in slave mode. In slave mode, the NSS pin works as a standard "chip select" input and the slave is selected while the NSS line is at low level.

Looking at the headers for my SoC, soft mode is SSM=1 (software NSS management). Hard output mode is SSM=0 and SSOE=1 (NSS output enable). Hard input mode is all zeros (NSS output disable).

If you're using hard output mode, you may also want to look at NSS pulse mode (section 28.5.12 in the STM32F0 document I linked to). It describes (with a timing diagram) how the system will leave NSS low most of the time, pulsing it high between data frames. If your device uses NSS/CS to synchronize the data frames, then this may be useful. Or maybe not, if your device reacts to NSS going high by aborting the current operation, since the text seems to indicate that it will pulse NSS between every word you transfer, not between buffers.

Unfortunately, this doesn't look like the most flexible implementation. Depending on your application, you may find it easier to leave it in soft mode and just toggle the NSS pin via GPIOs.

Forgather answered 23/8, 2019 at 21:41 Comment(0)
S
2

The NSS pin may need a pull-up resistor if HiZ (not documented).

Sweatband answered 20/12, 2019 at 3:37 Comment(2)
Available internally? That is, a matter of hardware configuration?Vanny
Not available internally, unfortunately. A physical pull-up resistor is required.Sweatband
M
0

Internal pull-up resistor configuration for Hardware NSS Output Signal: STM32CubeIDE screenshot

Mastiff answered 21/11, 2023 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.