cancel
Showing results for 
Search instead for 
Did you mean: 

SPI using SPI_NSS_HARD_OUTPUT not working

mbristol
Associate II

Using a stm32f412zg:

I want a simple master / slave full duplex config, using hardware gpio toggle PA4.

I believe I am doing the necessary to init it right but 1) problem, the GPIO goest to 0 before the transaction, and never come back up. 2) commenting the GPIO write before the transaction wont stop the transaction to happen, making me thinking it is still in NSS mode.

Those are bunch of th init code and calls, but feel free to ask more info.

On the master side:

static void MX_SPI1_Init(void)
{
	  /* Set the SPI parameters */
	  SpiHandle.Instance               = SPIx;
	  SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
	  SpiHandle.Init.Direction         = SPI_DIRECTION_2LINES;
	  SpiHandle.Init.CLKPhase          = SPI_PHASE_1EDGE;
	  SpiHandle.Init.CLKPolarity       = SPI_POLARITY_LOW;
	  SpiHandle.Init.DataSize          = SPI_DATASIZE_8BIT;
	  SpiHandle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
	  SpiHandle.Init.TIMode            = SPI_TIMODE_DISABLE;
	  SpiHandle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
	  SpiHandle.Init.CRCPolynomial     = 7;
	  SpiHandle.Init.NSS               = SPI_NSS_HARD_OUTPUT;
	  SpiHandle.Init.Mode 			   = SPI_MODE_MASTER;
 
	  if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
	  {
	    Error_Handler();
	  }
}
 
int main(void)
{
  HAL_Init();
 
  /* Configure the system clock to 100 MHz */
  SystemClock_Config();
 
  /* Configure SPI1 */
  MX_SPI1_Init();
 
  /* Set SPI1 pins */
  __GPIOA_CLK_ENABLE();
  GPIO_InitTypeDef  GPIO_InitStruct;
 
  /* CLK */
  GPIO_InitStruct.Pin       = GPIO_PIN_5;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* MOSI */
  GPIO_InitStruct.Pin       = GPIO_PIN_7;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* MISO */
  GPIO_InitStruct.Pin  		= GPIO_PIN_6;
  GPIO_InitStruct.Mode 		= GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull      = GPIO_NOPULL;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* CS */
  GPIO_InitStruct.Pin  		= GPIO_PIN_4;
  GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLUP;
//  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* Set it to HIGH (disable the SPI slave) */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
 
  uint8_t aTxBuffer[] = "1234";
  uint8_t aRxBuffer[BUFFERSIZE];
 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_StatusTypeDef rc = HAL_ERROR;
  rc = HAL_SPI_Transmit(&SpiHandle, (uint8_t*)aTxBuffer, BUFFERSIZE, 2000);
 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
...
...
...

rc = HAL_SPI_TransmitReceive(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE, 5000);On the Slave side:

static void MX_SPI1_Init(void)
{
	  /* Set the SPI parameters */
	  SpiHandle.Instance               = SPIx;
	  SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
	  SpiHandle.Init.Direction         = SPI_DIRECTION_2LINES;
	  SpiHandle.Init.CLKPhase          = SPI_PHASE_1EDGE;
	  SpiHandle.Init.CLKPolarity       = SPI_POLARITY_LOW;
	  SpiHandle.Init.DataSize          = SPI_DATASIZE_8BIT;
	  SpiHandle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
	  SpiHandle.Init.TIMode            = SPI_TIMODE_DISABLE;
	  SpiHandle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
	  SpiHandle.Init.CRCPolynomial     = 7;
	  SpiHandle.Init.NSS               = SPI_NSS_HARD_INPUT;
	  SpiHandle.Init.Mode 			   = SPI_MODE_SLAVE;
 
	  if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
	  {
	    Error_Handler();
	  }
}
 
int main(void)
{
  HAL_Init();
 
  /* Configure the system clock to 100 MHz */
  SystemClock_Config();
 
  /* Configure SPI1 */
  MX_SPI1_Init();
 
  /* Set SPI1 pins */
  __GPIOA_CLK_ENABLE();
  GPIO_InitTypeDef  GPIO_InitStruct;
 
  /* CLK */
  GPIO_InitStruct.Pin       = GPIO_PIN_5;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull      = GPIO_NOPULL;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* MOSI */
  GPIO_InitStruct.Pin       = GPIO_PIN_7;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull      = GPIO_NOPULL;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* MISO */
  GPIO_InitStruct.Pin  		= GPIO_PIN_6;
  GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* CS */
  GPIO_InitStruct.Pin  		= GPIO_PIN_4;
  GPIO_InitStruct.Mode 		= GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull      = GPIO_NOPULL;
//  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  uint8_t received_from_master[] = "0";
  uint8_t send_to_master[] = "3456";
 
  HAL_StatusTypeDef rc = HAL_ERROR;
  rc = HAL_SPI_TransmitReceive(&SpiHandle, (uint8_t *)&send_to_master, (uint8_t*)&received_from_master, BUFFERSIZE, HAL_MAX_DELAY);
 
...
...
...

4 REPLIES 4
mbristol
Associate II

update, I seem to get it working by declaring

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; on the master side and NOT GPIO_MODE_AF_OD

Slightly confusing as I thought the NSS Alternate function would do the job.

On the Slave side

 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; or

 GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; will do the same thing.

TDK
Guru

The NSS pin is not a chip select. It is low if the peripheral is in master mode (aka not a slave) and high otherwise. In other words, it’s not very useful for the master.

One solution is to control the CS pin manually in normal Gpio output mode.

If you feel a post has answered your question, please click "Accept as Solution".

I have read that NSS, in SPI hardware slave select mode, is an open collector output. As such, it can only actively drive the signal low (reset), but requires a resistor to bring the line high (set). This odd topology is so that multiple masters can control the signal. If it was a full totem-pole output, one master could be holding the output high (not selected) and another brings it low. This will cause a dead short between the two processors as there is now a potential difference with one high and one low (don't tie outputs together unless they are designed to handle that).

By using a pull-up resistor, any time one processor selects the peripheral and the line goes low, a small amount of current is drawn through the resistor and sunk by the processor according to V/R. But since the source of the current isn't a processor and is going through a resistor, you don't blow your processor.

So, tie NSS high with something like a 1K resistor (I can't remember what the value was in the book but 3.3v/1k = 3.3mA).

I have not actually tried this but it does make sense, and the person that wrote the book DID try it and it supposedly works.

Andrei from The Great White North.

XTorr.1
Associate II
  • One solution is to control the CS pin manually in normal Gpio output mode.
  • Example / Solution:

in normal Gpio output mode: in the file: stm32f2xx_hal_msp.c Remove GPIO_PIN_4

  /**SPI1 GPIO Configuration

  PA4   ------> SPI1_NSS -- BY GPIO

  PA5   ------> SPI1_SCK

  PA6   ------> SPI1_MISO

  PB5   ------> SPI1_MOSI

  */

  //GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;

  GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

******************* in file Main.c **********************

void Spi1_Write(void)

{

   HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4, GPIO_PIN_RESET); // CS pin PA4

  HAL_SPI_Transmit(&hspi1, (uint8_t*)st_SPI1.SPI_TxBuffer, st_SPI1.SPI_TX_CONT_LEN, 5000); // Write Data

for (uint8_t i=0;i<20;i++)// Wait 7uSeg to end TX Data

{

HAL_IWDG_Refresh(&hiwdg);

}

   HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4, GPIO_PIN_SET); // CS Pin

}

static void MX_GPIO_Init(void)

{

..... other Inits......

 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET); // CS=1

 GPIO_InitStruct.Pin = GPIO_PIN_4;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}