cancel
Showing results for 
Search instead for 
Did you mean: 

Must I implement the read of the CS signal to receive data in a SPI slave?

jg_spitfire
Senior

Hi,

project details:

  • master: FPGA zynq board, clk freq = 25MHz
  • slave: STM32F411VE board, pull up in CS
  • full duplex tx/rx in both boards
  • slave code generated with cubemx
  • sw4stm32 IDE
  • 20cm jumper cables to connect both boards
  • GND connection beteween the boards

I have understand that in the master (I am using a FPGA) I must select low or high the CS to select the slave (STM32F411VE board), but what about the slave?, do I need to implement something like this to receive the data?

//first way
    while(1)
    {
     
    if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == 0) //CS pin
    		{
     
                        HAL_SPI_TransmitReceive(&hspi5,txbuffer,rxbuffer, 12, 5000);
     
    		}
    }

or the function transmitreceive detects internally if the CS is low to start the communication?, I mean, receive the data just doing this:

//second way
    while(1)
    {
       HAL_SPI_TransmitReceive(&hspi5,txbuffer,rxbuffer, 12, 5000);
    }

I have this query because I am doing tests (second way) in the slave but always receive data when I connect the CS pin to GND or 3.3V, and in the TransmitReceive function I dont´t find any line of code that checks if CS is enabled or disabled to start the tx/rx of data

thanks

3 REPLIES 3
PMath.4
Senior III

Use the SPI_NSS pin configured in input mode - let the H/W do it for you 🙂

Hi, I have configured the NSS in this way, so you tell me that when the nss is configured by hardware the function detects it automatically?, I thought this was only when I configure nss in software mode (disabled in cubemx)

0693W000000Un3xQAC.jpg

PMath.4
Senior III
void SPI1_IRQHandler(void)
{
    /* Check OVR/UDR flag value in ISR register */
    if(LL_SPI_IsActiveFlag_OVR(SPI1) || LL_SPI_IsActiveFlag_UDR(SPI1))
    {
    	SET_BIT(SPI1->IFCR, SPI_IFCR_OVRC); //clear over and under run errors
    	SET_BIT(SPI1->IFCR, SPI_IFCR_UDRC);
    	return;
    }
    /* Check RXP flag value in ISR register */
    if(LL_SPI_IsActiveFlag_RXP(SPI1) && LL_SPI_IsEnabledIT_RXP(SPI1))
    {
      /* Call function Reception Callback */
		SPIRxBuf[SPIRxBufHead]  = LL_SPI_ReceiveData8(SPI1);   // store the byte in the ring buffer
		SPIRxBufHead = (SPIRxBufHead + 1) % CONSOLE_RX_BUF_SIZE;     // advance the head of the queue
		return;
    }
    /* Check EOT flag value in ISR register */
    if(LL_SPI_IsActiveFlag_EOT(SPI1) && LL_SPI_IsEnabledIT_EOT(SPI1))
    {
      /* Call function Reception Callback */
    	  SET_BIT(SPI1->IFCR, SPI_IFCR_EOTC);
    	  LL_SPI_SetTransferSize(SPI1, 1024);
      return;
    }
void GPIOPins_SPI1_Config(void)
{
  /* (1) Enables GPIO clock and configures the SPI1 pins *******************/
  /* Enable the peripherals clocks of GPIOs */
	  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB);
	  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
 
  /* SPI1 SCK GPIO pin configuration*/
  GPIO_InitStruct.Pin       = SPIx_MASTER_SCK_PIN;
  GPIO_InitStruct.Mode      = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Pull      = LL_GPIO_PULL_DOWN;
  GPIO_InitStruct.Speed     = LL_GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = SPIx_MASTER_SCK_AF;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI1 MISO GPIO pin configuration*/
  GPIO_InitStruct.Pin       = SPIx_MASTER_MISO_PIN;
  GPIO_InitStruct.Alternate = SPIx_MASTER_MISO_AF;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI1 MOSI GPIO pin configuration*/
  GPIO_InitStruct.Pin       = SPIx_MASTER_MOSI_PIN;
  GPIO_InitStruct.Alternate = SPIx_MASTER_MOSI_AF;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /* SPI1 NSS GPIO pin configuration*/
GPIO_InitStruct.Pin       = LL_GPIO_PIN_4;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
GPIO_InitStruct.Pull      = LL_GPIO_PULL_UP;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* (2) Configure NVIC for SPI1 transfer complete/error interrupts **********/
  /* Set priority for SPI1_IRQn */
  NVIC_SetPriority(SPI1_IRQn,0);
  /* Enable SPI1_IRQn */
  NVIC_EnableIRQ(SPI1_IRQn);
}
 
void SPI1_Config (void)
{
  /* Configure SPI SLAVE *****************************************************/
  /* Enable SPI1 Clock */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
 
  /* Configure the SPI1 parameters */
  SPI_InitStruct.BaudRate          = LL_SPI_BAUDRATEPRESCALER_DIV2;
  SPI_InitStruct.TransferDirection = LL_SPI_SIMPLEX_RX;
  SPI_InitStruct.ClockPhase        = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.ClockPolarity     = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.BitOrder          = LL_SPI_MSB_FIRST;
  SPI_InitStruct.DataWidth         = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.NSS               = LL_SPI_NSS_HARD_INPUT;
  SPI_InitStruct.CRCCalculation    = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.Mode              = LL_SPI_MODE_SLAVE;
 
  LL_SPI_Init(SPI1, &SPI_InitStruct);
 
  /* Lock GPIO for master to avoid glitches on the clock output */
  LL_SPI_DisableGPIOControl(SPI1);
  LL_SPI_DisableMasterRxAutoSuspend(SPI1);
 
  /* Set number of date to transmit */
  LL_SPI_SetTransferSize(SPI1, 1024);
 
  /* Enable SPI1 */
  LL_SPI_Enable(SPI1);
 
  /* Enable TXP Interrupt */
//  LL_SPI_EnableIT_TXP(SPI1);
 
  /* Enable RXP Interrupt */
  LL_SPI_EnableIT_RXP(SPI1);
 
  /* Enable SPI Errors Interrupt */
  LL_SPI_EnableIT_CRCERR(SPI1);
  LL_SPI_EnableIT_UDR(SPI1);
  LL_SPI_EnableIT_OVR(SPI1);
  LL_SPI_EnableIT_EOT(SPI1);
}
 

Certainly seems to work. I'm using SPI in receive simplex mode with interrupts buffering the incoming data into a circular buffer and when I disconnect NSS the receive stops as you would expect.