AnsweredAssumed Answered

Bug in HAL_SPI_Receive

Question asked by A.Alex.002 on Oct 7, 2016
Latest reply on Nov 3, 2016 by nervi.stefano
setup
/* SPI1 init function */
static void MX_SPI1_Init(void)
{
 
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
 
}
Bug description
In 3-wire SPI mode at the end of receive operation MCU gives 8 extra impulses on SPI_CLK line, after CS rises. Here are code example and it's image, rhet was cought by logic analyzer.
//writing data to device
reg = 0x06;
HAL_GPIO_WritePin(GPIOA,CS_Pin,0);
HAL_SPI_Transmit(&hspi1,&reg,1,0x1);
HAL_SPI_Transmit(&hspi1,IDdata,4,0x1);
HAL_GPIO_WritePin(GPIOA,CS_Pin,1);
 
//reading data from device
reg=0x06|0x40;
HAL_GPIO_WritePin(GPIOA,CS_Pin,0);
HAL_SPI_Transmit(&hspi1,&reg,1,0x1);
HAL_SPI_Receive(&hspi1,val,4,0x1);
HAL_GPIO_WritePin(GPIOA,CS_Pin,1);
Link: https://pp.vk.me/c636028/v636028142/2b3f1/FITRHYtKxXI.jpg

Solution
I fixed this issue by editing HAL_SPI_Receive function.: moved __HAL_SPI_DISABLE(hspi);  before /* Wait until RXNE flag is set */
Old version:
001.HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
002.{
003.  __IO uint16_t tmpreg = 0;
004. 
005.  if(hspi->State == HAL_SPI_STATE_READY)
006.  {
007.    if((pData == NULL ) || (Size == 0))
008.    {
009.      return  HAL_ERROR;
010.    }
011. 
012.    /* Process Locked */
013.    __HAL_LOCK(hspi);
014. 
015.    /* Configure communication */
016.    hspi->State       = HAL_SPI_STATE_BUSY_RX;
017.    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
018. 
019.    hspi->pRxBuffPtr  = pData;
020.    hspi->RxXferSize  = Size;
021.    hspi->RxXferCount = Size;
022. 
023.    /*Init field not used in handle to zero */
024.    hspi->RxISR = 0;
025.    hspi->TxISR = 0;
026.    hspi->pTxBuffPtr  = NULL;
027.    hspi->TxXferSize  = 0;
028.    hspi->TxXferCount = 0;
029. 
030.    /* Configure communication direction : 1Line */
031.    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
032.    {
033.      SPI_1LINE_RX(hspi);           //запускается меандр
034.    }
035. 
036.    /* Reset CRC Calculation */
037.    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
038.    {
039.      SPI_RESET_CRC(hspi);
040.    }
041.     
042.    if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES))
043.    {
044.      /* Process Unlocked */
045.      __HAL_UNLOCK(hspi);
046. 
047.      /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
048.      return HAL_SPI_TransmitReceive(hspi, pData, pData, Size, Timeout);
049.    }
050. 
051.    /* Check if the SPI is already enabled */
052.    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
053.    {
054.      /* Enable SPI peripheral */
055.      __HAL_SPI_ENABLE(hspi);
056.    }
057. 
058.    /* Receive data in 8 Bit mode */
059.    if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
060.    {
061.      while(hspi->RxXferCount > 1)
062.      {
063.        /* Wait until RXNE flag is set */
064.        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
065.        {
066.          return HAL_TIMEOUT;
067.        }
068. 
069.        (*hspi->pRxBuffPtr++) = hspi->Instance->DR;
070.        hspi->RxXferCount--;
071.      }
072.      /* Enable CRC Reception */
073.      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
074.      {
075.        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
076.      }
077.    }
078.    /* Receive data in 16 Bit mode */
079.    else
080.    {
081.      while(hspi->RxXferCount > 1)
082.      {
083.        /* Wait until RXNE flag is set to read data */
084.        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
085.        {
086.          return HAL_TIMEOUT;
087.        }
088. 
089.        *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
090.        hspi->pRxBuffPtr+=2;
091.        hspi->RxXferCount--;
092.      }
093.      /* Enable CRC Reception */
094.      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
095.      {
096.        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
097.      }
098.    }
099. 
100.    /* Wait until RXNE flag is set */
101.    if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
102.    {
103.      return HAL_TIMEOUT;
104.    }
105. 
106.    /* Receive last data in 8 Bit mode */
107.    if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
108.    {
109.      (*hspi->pRxBuffPtr++) = hspi->Instance->DR;
110.    }
111.    /* Receive last data in 16 Bit mode */
112.    else
113.    {
114.      *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
115.      hspi->pRxBuffPtr+=2;
116.    }
117.    hspi->RxXferCount--;
118. 
119.    /* If CRC computation is enabled */
120.    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
121.    {
122.      /* Wait until RXNE flag is set: CRC Received */
123.      if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
124.      {
125.        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
126.        return HAL_TIMEOUT;
127.      }
128. 
129.      /* Read CRC to clear RXNE flag */
130.      tmpreg = hspi->Instance->DR;
131.      UNUSED(tmpreg);
132.    }
133.     
134.    if((hspi->Init.Mode == SPI_MODE_MASTER)&&((hspi->Init.Direction == SPI_DIRECTION_1LINE)||(hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
135.    {
136.      /* Disable SPI peripheral */
137.      __HAL_SPI_DISABLE(hspi);
138.    }
139. 
140.    hspi->State = HAL_SPI_STATE_READY;
141. 
142.    /* Check if CRC error occurred */
143.    if((hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET))
144.    
145.      /* Check if CRC error is valid or not (workaround to be applied or not) */
146.      if (SPI_ISCRCErrorValid(hspi) == SPI_VALID_CRC_ERROR)
147.      {
148.        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
149. 
150.        /* Reset CRC Calculation */
151.        SPI_RESET_CRC(hspi);
152. 
153.        /* Process Unlocked */
154.        __HAL_UNLOCK(hspi);
155. 
156.        return HAL_ERROR;
157.      }
158.      else
159.      {
160.        __HAL_SPI_CLEAR_CRCERRFLAG(hspi);
161.      }
162.    }
163. 
164.    /* Process Unlocked */
165.    __HAL_UNLOCK(hspi);
166. 
167.    return HAL_OK;
168.  }
169.  else
170.  {
171.    return HAL_BUSY;
172.  }
173.}
174. 
175./**

My version:(look at line # 99 in both files, 134 in old file and 140 in my file)
001.HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
002.{
003.  __IO uint16_t tmpreg = 0;
004. 
005.  if(hspi->State == HAL_SPI_STATE_READY)
006.  {
007.    if((pData == NULL ) || (Size == 0))
008.    {
009.      return  HAL_ERROR;
010.    }
011. 
012.    /* Process Locked */
013.    __HAL_LOCK(hspi);
014. 
015.    /* Configure communication */
016.    hspi->State       = HAL_SPI_STATE_BUSY_RX;
017.    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
018. 
019.    hspi->pRxBuffPtr  = pData;
020.    hspi->RxXferSize  = Size;
021.    hspi->RxXferCount = Size;
022. 
023.    /*Init field not used in handle to zero */
024.    hspi->RxISR = 0;
025.    hspi->TxISR = 0;
026.    hspi->pTxBuffPtr  = NULL;
027.    hspi->TxXferSize  = 0;
028.    hspi->TxXferCount = 0;
029. 
030.    /* Configure communication direction : 1Line */
031.    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
032.    {
033.      SPI_1LINE_RX(hspi);           //запускается меандр
034.    }
035. 
036.    /* Reset CRC Calculation */
037.    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
038.    {
039.      SPI_RESET_CRC(hspi);
040.    }
041.     
042.    if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES))
043.    {
044.      /* Process Unlocked */
045.      __HAL_UNLOCK(hspi);
046. 
047.      /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
048.      return HAL_SPI_TransmitReceive(hspi, pData, pData, Size, Timeout);
049.    }
050. 
051.    /* Check if the SPI is already enabled */
052.    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
053.    {
054.      /* Enable SPI peripheral */
055.      __HAL_SPI_ENABLE(hspi);
056.    }
057. 
058.    /* Receive data in 8 Bit mode */
059.    if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
060.    {
061.      while(hspi->RxXferCount > 1)
062.      {
063.        /* Wait until RXNE flag is set */
064.        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
065.        {
066.          return HAL_TIMEOUT;
067.        }
068. 
069.        (*hspi->pRxBuffPtr++) = hspi->Instance->DR;
070.        hspi->RxXferCount--;
071.      }
072.      /* Enable CRC Reception */
073.      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
074.      {
075.        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
076.      }
077.    }
078.    /* Receive data in 16 Bit mode */
079.    else
080.    {
081.      while(hspi->RxXferCount > 1)
082.      {
083.        /* Wait until RXNE flag is set to read data */
084.        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
085.        {
086.          return HAL_TIMEOUT;
087.        }
088. 
089.        *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
090.        hspi->pRxBuffPtr+=2;
091.        hspi->RxXferCount--;
092.      }
093.      /* Enable CRC Reception */
094.      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
095.      {
096.        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
097.      }
098.    }
099.    if((hspi->Init.Mode == SPI_MODE_MASTER)&&((hspi->Init.Direction == SPI_DIRECTION_1LINE)||(hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
100.    {
101.      /* Disable SPI peripheral */
102.      __HAL_SPI_DISABLE(hspi);
103.    }
104.    /* Wait until RXNE flag is set */
105.    if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
106.    {
107.      return HAL_TIMEOUT;
108.    }
109. 
110.    /* Receive last data in 8 Bit mode */
111.    if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
112.    {
113.      (*hspi->pRxBuffPtr++) = hspi->Instance->DR;
114.    }
115.    /* Receive last data in 16 Bit mode */
116.    else
117.    {
118.      *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
119.      hspi->pRxBuffPtr+=2;
120.    }
121.    hspi->RxXferCount--;
122. 
123.    /* If CRC computation is enabled */
124.    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
125.    {
126.      /* Wait until RXNE flag is set: CRC Received */
127.      if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout) != HAL_OK)
128.      {
129.        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
130.        return HAL_TIMEOUT;
131.      }
132. 
133.      /* Read CRC to clear RXNE flag */
134.      tmpreg = hspi->Instance->DR;
135.      UNUSED(tmpreg);
136.    }
137.     
138. 
139.    hspi->State = HAL_SPI_STATE_READY;
140. 
141.    /* Check if CRC error occurred */
142.    if((hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET))
143.    
144.      /* Check if CRC error is valid or not (workaround to be applied or not) */
145.      if (SPI_ISCRCErrorValid(hspi) == SPI_VALID_CRC_ERROR)
146.      {
147.        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
148. 
149.        /* Reset CRC Calculation */
150.        SPI_RESET_CRC(hspi);
151. 
152.        /* Process Unlocked */
153.        __HAL_UNLOCK(hspi);
154. 
155.        return HAL_ERROR;
156.      }
157.      else
158.      {
159.        __HAL_SPI_CLEAR_CRCERRFLAG(hspi);
160.      }
161.    }
162. 
163.    /* Process Unlocked */
164.    __HAL_UNLOCK(hspi);
165. 
166.    return HAL_OK;
167.  }
168.  else
169.  {
170.    return HAL_BUSY;
171.  }
172.}
173. 
174./**
and timing diagrams https://pp.vk.me/c636028/v636028142/2b3fa/OB5Hv55BEaE.jpg
This moving helps to make it work, but I guess it is not best solution. I think in this case last byte could be lost. 
But it works.

Hope, that it would be helpful.
Best regards
Alex

Outcomes