Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use hardware NSS (SPI) on stm32f4?

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?

like image 653
mkom Avatar asked Mar 03 '16 18:03

mkom


People also ask

What is NSS pulse mode?

The Slave Select signal can operate in a pulse mode where the master generates pulses on NSS output signal between data frames for a duration of one SPI clock period when there is a continuous transfer of data. The data is then interleaved by two SPI clock periods. The clock phase is fixed in this mode.

What is NSS microcontroller?

When the device in slave mode, the NSS pin works as standard “chip select” input and lets the slave communicates with the master. When the device is in master mode, the NSS pin either used as input or output. So as an input pin, NSS will avoid multi-master bus collision.


1 Answers

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.

like image 101
peets Avatar answered Sep 17 '22 20:09

peets