How to use hardware NSS (SPI) on stm32f4?

44,076

Solution 1

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/CubeMX) from ST with a STM32L476 and polling SPI1. Initialization before and de-initialization after transmission did NOT set the NSS Pin - but took much 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 20MHz. 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.

Solution 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 put the Nss low and then send your frame (HAL_SPI_Transmit) After the slave gets all frame, use the HAL_SPI_RxCpltCallback and put the Nss high in that interrupt.

Dont forget to connect GPIO pin to Nss pin on slave.

Solution 3

NSS pin may need pull-up resistor if HiZ [not documented]

Share:
44,076
mkom
Author by

mkom

Updated on July 11, 2022

Comments

  • mkom
    mkom almost 2 years

    So I tried to use hardware NSS signal with HAL library, but I can't find any function to make NSS pin have low or high level. I also tried to find the answer in HAL documentation, but there is no information too. All examples in the Internet contain only software NSS. How one is supposed to use hardware NSS?

  • Will
    Will over 5 years
    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.