cspinucleomcu

STM32 Master/Slave SPI communication using HAL_SPI_TransmitReceive()


I'm trying to test out a SPI master using HAL_SPI_TransmitReceive() as I will be communicating with an SPI slave. The SPI slave device is not yet available. I have two STM32F4 NUCLEOs that I am using. One that will be the master and one pretending to be the slave device. I've wired them together and am using the following code:

Master_main.c

SPI_HandleTypeDef hspi2;

static void MX_SPI2_Init(void);

uint8_t spi_tx_data[9];
uint8_t spi_rx_data[9];

int main(void)
{
  MX_SPI2_Init();

  spi_tx_data[0] = 0;
  spi_tx_data[1] = 0;
  spi_tx_data[2] = 0;
  spi_tx_data[3] = 0;
  spi_tx_data[4] = 0;
  spi_tx_data[5] = 0;
  spi_tx_data[6] = 0;
  spi_tx_data[7] = 0;
  spi_tx_data[8] = 1;

  while (1)
  {
      static HAL_StatusTypeDef spi_error = HAL_OK;

      static uint32_t PreviousTicks_GreenLight = 0U;
      uint32_t CurrentTicks_GreenLight = HAL_GetTick();
      if((CurrentTicks_GreenLight - PreviousTicks_GreenLight) >= 500u)
      {
          HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
          PreviousTicks_GreenLight = CurrentTicks_GreenLight;
      }

      static uint8_t runonce = 0;
      if (HAL_GPIO_ReadPin(USER_Btn_GPIO_Port, USER_Btn_Pin) != 0) {
          if (runonce != 1){

              HAL_GPIO_WritePin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin, 0);
              HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
              spi_error = HAL_SPI_TransmitReceive(&hspi2,spi_tx_data, spi_rx_data,18,0x01);
              HAL_Delay(1);
              HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
              HAL_GPIO_WritePin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin, 1);

              runonce = 1;
          }
      } else {
          runonce = 0;
      }

      static uint32_t PreviousTicks_RedLight = 0U;
      uint32_t CurrentTicks_RedLight = HAL_GetTick();
      if((CurrentTicks_RedLight - PreviousTicks_RedLight) >= 500u)
      {
          if ( spi_error == HAL_TIMEOUT || spi_error == HAL_ERROR){
              HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
          } else {
              if ( spi_rx_data[8] == 2){
                  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
              }
          }
          PreviousTicks_RedLight = CurrentTicks_RedLight;
      }
  }
}

static void MX_SPI2_Init(void)
{
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
}

Slave_main.c

uint8_t spi_tx_data[9];
uint8_t spi_rx_data[9];

uint8_t rx_cmplt = 0;

void HAL_SPI_RxCpltCallback (SPI_HandleTypeDef *hspi) {
    static uint8_t rx_counter = 0;

    if ( rx_counter == 8 ){
        rx_cmplt = 1;
    } else {
        rx_counter++;
    }
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}

int main(void)
{
  MX_SPI2_Init();

  spi_tx_data[0] = 0;
  spi_tx_data[1] = 0;
  spi_tx_data[2] = 0;
  spi_tx_data[3] = 0;
  spi_tx_data[4] = 0;
  spi_tx_data[5] = 0;
  spi_tx_data[6] = 0;
  spi_tx_data[7] = 0;
  spi_tx_data[8] = 2;

  while (1)
  {
      static HAL_StatusTypeDef spi_error = HAL_OK;

      static uint32_t PreviousTicks_GreenLight = 0U;
      uint32_t CurrentTicks_GreenLight = HAL_GetTick();
      if((CurrentTicks_GreenLight - PreviousTicks_GreenLight) >= 1000u)
      {
          HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
          PreviousTicks_GreenLight = CurrentTicks_GreenLight;
      }

      static uint8_t runonce = 0;
      if (HAL_GPIO_ReadPin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin) != 1) {
          if (runonce != 1){

              HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
              //spi_error = HAL_SPI_TransmitReceive_IT(&hspi2, spi_tx_data, spi_rx_data, 18);
              spi_error = HAL_SPI_TransmitReceive(&hspi2,spi_tx_data, spi_rx_data,18,0x01);
              HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);

              runonce = 1;
          }
      } else {
          runonce = 0;
      }

      static uint32_t PreviousTicks_RedLight = 0U;
      uint32_t CurrentTicks_RedLight = HAL_GetTick();
      if((CurrentTicks_RedLight - PreviousTicks_RedLight) >= 500u)
      {
          if ( rx_cmplt == 1 ){
              if (spi_rx_data[8] == 1){
                  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, 1);
              } else {
                  HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, 1);
              }
          } else {
              if ( spi_error == HAL_TIMEOUT || spi_error == HAL_ERROR){
                  HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
                  if (spi_error == HAL_TIMEOUT){
                      HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
                  }
              }
          }

          PreviousTicks_RedLight = CurrentTicks_RedLight;
      }
  }
}

static void MX_SPI2_Init(void)
{
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_SLAVE;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
}

I stripped out various MCU initialization for simplicity. I had made an attempt to use the IT version of TransmitRecieve at an earlier time, but it didn't successfully transmit. If I use the USER button on my master several times it does manage to activate the appropriate lights on the slave but not on the master.


Solution

  • I suspect I had some sort of wiring issue. I added a breadboard into the mix and stuck some LEDs in, and somehow after connecting everything up, both master and slave worked correctly. I did change the code around to use some of the STM example for SPI, but that was before the breadboard.

    Slave.c

      static uint8_t runonce = 0;
      if (HAL_GPIO_ReadPin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin) != 1) {
          if (runonce != 1){
    
    
          switch(HAL_SPI_TransmitReceive(&hspi2, spi_tx_data, spi_rx_data, 9, 5000))
            {
            case HAL_OK:
              /* Communication is completed_____________________________________________*/
              /* Compare the sent and received buffers */
              if(spi_rx_data[8] == 1)
              {
                  HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
              }
    
              break;
    
            case HAL_TIMEOUT:
              /* A Timeout occurred_____________________________________________________*/
              /* Call Timeout Handler */
                HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
              break;
    
              /* An Error occurred______________________________________________________*/
            case HAL_ERROR:
              /* Call Timeout Handler */
                HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
              break;
    
            default:
              break;
            }
    
          runonce = 1;
      }
      } else {
          runonce = 0;
      }
    

    Master.c

      static uint8_t runonce = 0;
      if (HAL_GPIO_ReadPin(USER_Btn_GPIO_Port, USER_Btn_Pin) != 0) {
          if (runonce != 1){
    
    
              HAL_GPIO_WritePin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin, 0);
              HAL_Delay(0x01);
    
              switch(HAL_SPI_TransmitReceive(&hspi2, spi_tx_data, spi_rx_data, 9, 5000))
                {
                case HAL_OK:
                  /* Communication is completed_____________________________________________*/
                  /* Compare the sent and received buffers */
                  if(spi_rx_data[8] == 2)
                  {
                      HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, 1);
                  }
    
                  break;
    
                case HAL_TIMEOUT:
                  /* A Timeout occurred_____________________________________________________*/
                  /* Call Timeout Handler */
                    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, 1);
                  break;
    
                  /* An Error occurred______________________________________________________*/
                case HAL_ERROR:
                  /* Call Timeout Handler */
                    HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, 1);
                  break;
    
                default:
                  break;
                }
    
              //HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    
              HAL_GPIO_WritePin(GPIO_ADR1_GPIO_Port, GPIO_ADR1_Pin, 1);
    
              runonce = 1;
          }
      } else {
          runonce = 0;
      }