AnsweredAssumed Answered

Removing dead code from HAL Library and optimising for size breaks functionality

Question asked by B Zikhali on Jul 15, 2016
Latest reply on Jul 18, 2016 by B Zikhali
I am working on optimising an application to minimise code size and also increase speed. I noticed that even though CubeMX will initialize the peripheral with certain features disabled the code in the driver will still include useless checks ie. CRC calculation is disabled but the HAL_SPI_TransmitReceive function will still check every single time if the CRC is enabled. My idea was to remove these if-else blocks and not only did I get a size decrease but also a 1ms speed increase (the function is used in a nested loop). The problem is when I optimise for size -Os, SPI functionality breaks - I get garbage. 

Here is the code in question; 

/* SPI3 init function */
void MX_SPI3_Init(void) {
  
    hspi3.Instance = SPI3;
    hspi3.Init.Mode = SPI_MODE_MASTER;
    hspi3.Init.Direction = SPI_DIRECTION_2LINES;
    hspi3.Init.DataSize = SPI_DATASIZE_16BIT;
    hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi3.Init.NSS = SPI_NSS_HARD_OUTPUT;
    hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi3.Init.TIMode = SPI_TIMODE_DISABLED;
    hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
    hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLED;
    HAL_SPI_Init(&hspi3);
  
}


001./**
002.  * @brief  Transmit and Receive an amount of data in blocking mode
003.  * @param  hspi: SPI handle
004.  * @param  pTxData: pointer to transmission data buffer
005.  * @param  pRxData: pointer to reception data buffer to be
006.  * @param  Size: amount of data to be sent
007.  * @param  Timeout: Timeout duration
008.  * @retval HAL status
009.  */
010.HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
011.{
012.  __IO uint16_t tmpreg = 0;
013.  uint32_t tickstart = 0;
014.   
015.  assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction));
016.   
017.  if(hspi->State != HAL_SPI_STATE_READY)
018.  {
019.    return HAL_BUSY;
020.  }
021.   
022.  if((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
023.  {
024.    return HAL_ERROR;
025.  }
026. 
027.  tickstart = HAL_GetTick();
028.   
029.  /* Process Locked */
030.  __HAL_LOCK(hspi);
031.   
032.  hspi->State       = HAL_SPI_STATE_BUSY_TX_RX;
033.  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
034.  hspi->pRxBuffPtr  = pRxData;
035.  hspi->RxXferCount = Size;
036.  hspi->RxXferSize  = Size;
037.  hspi->pTxBuffPtr  = pTxData;
038.  hspi->TxXferCount = Size;
039.  hspi->TxXferSize  = Size;
040.   
041.  /* Reset CRC Calculation */
042.  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED)
043.  {
044.    __HAL_SPI_RESET_CRC(hspi);
045.  }
046.   
047.  /* Set the Rx Fido threshold */
048.  if((hspi->Init.DataSize > SPI_DATASIZE_8BIT) || (hspi->RxXferCount > 1))
049.  {
050.    /* set fiforxthreshold according the reception data lenght: 16bit */
051.    CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
052.  }
053.  else
054.  {
055.    /* set fiforxthreshold according the reception data lenght: 8bit */
056.    SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
057.  }
058.   
059.  /* Check if the SPI is already enabled */
060.  if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
061.  {
062.    /* Enable SPI peripheral */   
063.    __HAL_SPI_ENABLE(hspi);
064.  }
065.   
066.  /* Transmit and Receive data in 16 Bit mode */
067.  if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
068.  
069.    while ((hspi->TxXferCount > 0 ) || (hspi->RxXferCount > 0))
070.    {
071.      /* Wait until TXE flag */
072.      if((hspi->TxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_TXE) == SPI_FLAG_TXE))
073.      {
074.        hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
075.        hspi->pTxBuffPtr += sizeof(uint16_t);
076.        hspi->TxXferCount--;
077.         
078.        /* Enable CRC Transmission */
079.        if((hspi->TxXferCount == 0) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED))
080.        {
081.          SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
082.        }
083.      }
084.       
085.      /* Wait until RXNE flag */
086.      if((hspi->RxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_RXNE) == SPI_FLAG_RXNE))
087.      {
088.        *((uint16_t *)hspi->pRxBuffPtr) = hspi->Instance->DR;
089.        hspi->pRxBuffPtr += sizeof(uint16_t);
090.        hspi->RxXferCount--;
091.      }
092.      if(Timeout != HAL_MAX_DELAY)
093.      {
094.        if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
095.        {
096.          hspi->State = HAL_SPI_STATE_READY;
097.          __HAL_UNLOCK(hspi);
098.          return HAL_TIMEOUT;
099.        }
100.      }
101.    
102.  }
103.  /* Transmit and Receive data in 8 Bit mode */
104.  else
105.  {
106.    while((hspi->TxXferCount > 0) || (hspi->RxXferCount > 0))
107.    {
108.      /* check if TXE flag is set to send data */
109.      if((hspi->TxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_TXE) == SPI_FLAG_TXE))
110.      {
111.        if(hspi->TxXferCount > 2)
112.        {
113.          hspi->Instance->DR = *((uint16_t*)hspi->pTxBuffPtr);
114.          hspi->pTxBuffPtr += sizeof(uint16_t);
115.          hspi->TxXferCount -= 2;
116.        }
117.        else
118.        {
119.          *(__IO uint8_t *)&hspi->Instance->DR = (*hspi->pTxBuffPtr++);
120.          hspi->TxXferCount--;
121.        }
122.         
123.        /* Enable CRC Transmission */
124.        if((hspi->TxXferCount == 0) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED))
125.        {
126.          SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
127.        }
128.      }
129.             
130.      /* Wait until RXNE flag is reset */
131.      if((hspi->RxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_RXNE) == SPI_FLAG_RXNE))
132.      {
133.        if(hspi->RxXferCount > 1)
134.        {
135.          *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
136.          hspi->pRxBuffPtr += sizeof(uint16_t);
137.          hspi->RxXferCount -= 2;
138.          if(hspi->RxXferCount <= 1)
139.          {
140.            /* set fiforxthresold before to switch on 8 bit data size */
141.            SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
142.          }
143.        }
144.        else
145.        {
146.          (*hspi->pRxBuffPtr++) =  *(__IO uint8_t *)&hspi->Instance->DR;
147.          hspi->RxXferCount--;
148.        }
149.      }
150.      if(Timeout != HAL_MAX_DELAY)
151.      {
152.        if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
153.        {
154.          hspi->State = HAL_SPI_STATE_READY;
155.          __HAL_UNLOCK(hspi);
156.          return HAL_TIMEOUT;
157.        }
158.      }
159.    }
160.  }
161.   
162.  /* Read CRC from DR to close CRC calculation process */
163.  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED)
164.  {
165.    /* Wait until TXE flag */
166.    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SPI_FLAG_RXNE, Timeout) != HAL_OK)
167.    
168.      /* Erreur on the CRC reception */
169.      hspi->ErrorCode|= HAL_SPI_ERROR_CRC;
170.    }
171.     
172.    if(hspi->Init.DataSize == SPI_DATASIZE_16BIT)
173.    {
174.      tmpreg = hspi->Instance->DR;
175.    }
176.    else
177.    {
178.      tmpreg = *(__IO uint8_t *)&hspi->Instance->DR;
179.      if(hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT)
180.      {
181.        if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SPI_FLAG_RXNE, Timeout) != HAL_OK)
182.        
183.          /* Erreur on the CRC reception */
184.          hspi->ErrorCode|= HAL_SPI_ERROR_CRC;
185.        }   
186.        tmpreg = *(__IO uint8_t *)&hspi->Instance->DR;
187.      }
188.    }
189.  }
190. 
191.  /* Check the end of the transaction */
192.  if(SPI_EndRxTxTransaction(hspi,Timeout) != HAL_OK)
193.  {
194.    return HAL_TIMEOUT;
195.  }
196. 
197.  hspi->State = HAL_SPI_STATE_READY;
198.   
199.  /* Check if CRC error occurred */
200.  if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET)
201.  {
202.    hspi->ErrorCode|= HAL_SPI_ERROR_CRC;
203.    /* Clear CRC Flag */
204.    __HAL_SPI_CLEAR_CRCERRFLAG(hspi);
205.     
206.    /* Process Unlocked */
207.    __HAL_UNLOCK(hspi);
208.     
209.    return HAL_ERROR;
210.  }
211.   
212.  /* Process Unlocked */
213.  __HAL_UNLOCK(hspi);
214.   
215.  if(hspi->ErrorCode != HAL_SPI_ERROR_NONE)
216.  {  
217.    return HAL_ERROR;
218.  }
219.  else
220.  {
221.    return HAL_OK;
222.  }
223.}
224. 
225./**
226.  * @brief  Transmit an amount of data in no-blocking mode with Interrupt
227.  * @param  hspi: SPI handle
228.  * @param  pData: pointer to data buffer
229.  * @param  Size: amount of data to be sent
230.  * @retval HAL status
231.  */
232.HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
233.{
234.  assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));
235.   
236.  if(hspi->State == HAL_SPI_STATE_READY)
237.  {
238.    if((pData == NULL) || (Size == 0))
239.    {
240.      return  HAL_ERROR;                                   
241.    }
242.     
243.    /* Process Locked */
244.    __HAL_LOCK(hspi);
245.     
246.    hspi->State       = HAL_SPI_STATE_BUSY_TX;
247.    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
248.    hspi->pTxBuffPtr  = pData;
249.    hspi->TxXferSize  = Size;
250.    hspi->TxXferCount = Size;
251.    hspi->pRxBuffPtr  = NULL;
252.    hspi->RxXferSize  = 0;
253.    hspi->RxXferCount = 0;
254. 
255.    /* Set the function for IT treatement */
256.    if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
257.    {
258.      hspi->RxISR = NULL;
259.      hspi->TxISR = SPI_TxISR_16BIT;
260.    }
261.    else
262.    {
263.      hspi->RxISR = NULL;
264.      hspi->TxISR = SPI_TxISR_8BIT;
265.    }
266.     
267.    /* Configure communication direction : 1Line */
268.    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
269.    {
270.      __HAL_SPI_1LINE_TX(hspi);
271.    }
272.     
273.    /* Reset CRC Calculation */
274.    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED)
275.    {
276.      __HAL_SPI_RESET_CRC(hspi);   
277.    }
278.     
279.    /* Enable TXE and ERR interrupt */
280.    __HAL_SPI_ENABLE_IT(hspi,(SPI_IT_TXE));
281. 
282.    /* Process Unlocked */
283.    __HAL_UNLOCK(hspi);
284. 
285.    /* Note : The SPI must be enabled after unlocking current process
286.              to avoid the risk of SPI interrupt handle execution before current
287.              process unlock */
288.         
289.    /* Check if the SPI is already enabled */
290.    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
291.    {
292.      /* Enable SPI peripheral */   
293.      __HAL_SPI_ENABLE(hspi);
294.    }
295.         
296.    return HAL_OK;
297.  }
298.  else
299.  {
300.    return HAL_BUSY;
301.  }
302.}

In this example lines 42 -  45 can be removed because the CRC is disabled, the if-else block at line 45 can be removed, I'm using 16 bit TX/RX. The if at line 67 can be removed and the entire else block (line 104 - 160) is unnecessary, again I am using 16 bit TX/RX. Lines 163 _ 189 can be removed as can lines 200 - 210 (no CRC). But as I noted above doing so and turning on -Os breaks the function - I get garbage via SPI. Does anyone have an idea why before I try removing useless code from other HAL functions. 

 

Outcomes