STM32 HAL_LOCK問題
25034 ワード
STM32 HAL_LOCK問題
STM32 HAL_LOCK問題
STM 32を使用するHALライブラリの开発において、UARTとCANを使用する场合、データを突然受信しなくなる场合があります.デバッグでは、信号はありますが、ソフトウェアは受信が中断することはありません.デバッグによって、问题点は
典型的なuart受信データの例
uart構成後、最後に
そして、データを受信たびに
データを受信してから、データを読み取り、次の受信を再起動します.論理的には、少しも問題はありません.しかし、実際に使用している場合、特にuartは全二重で、データ量が大きい場合、突然
まず
デバッグによると、プログラムは
ステップトレースでは
誰がロックしたの?
送信関数locked了huart
送信データ期間中、
簡単な解決策
より完璧な方法で、割り込み関数を修正します.
HALの割り込み関数インタフェースを使わないで、自分で1段書きます
実はこの中のほとんどのコードは
これこそ一般的なuartワークモードです!
CANにもこのような問題があり、CANが発生する確率が高い.
通信の問題はみな大きな問題だから、根本的に問題を解決しなければならない.
STM32 HAL_LOCK問題
STM 32を使用するHALライブラリの开発において、UARTとCANを使用する场合、データを突然受信しなくなる场合があります.デバッグでは、信号はありますが、ソフトウェアは受信が中断することはありません.デバッグによって、问题点は
__HAL_LOCK()
という関数に位置づけられます.以下、uartを例に、この问题を剖析します.典型的なuart受信データの例
uart構成後、最後に
HAL_UART_Receive_IT()
を呼び出します.HAL_UART_Receive_IT(&huart1, (u8 *)RxBuffer, 1);
そして、データを受信たびに
HAL_UART_RxCpltCallback()
が呼び出される.void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
uart1ReceivedBuffer=RxBuffer;//
HAL_UART_Receive_IT(&huart1,&RxBuffer,1);//
}
}
データを受信してから、データを読み取り、次の受信を再起動します.論理的には、少しも問題はありません.しかし、実際に使用している場合、特にuartは全二重で、データ量が大きい場合、突然
HAL_UART_RxCpltCallback()
が呼び出されなくなったことに気づき、受信が切れました.なぜこのような状況が発生したのですか.__HAL_LOCK()
は何をしましたか.まず
HAL_UART_Receive_IT()
のソースコードを見てみましょう./**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
デバッグによると、プログラムは
__HAL_UNLOCK(huart);
まで実行された後、HAL_UART_RxCpltCallback()
を終了しました.__HAL_UNLOCK(huart);
の中で何をしたのか見てみましょう#if (USE_RTOS == 1U)
/* Reserved for future use */
#error "USE_RTOS should be 0 in the current HAL release"
#else
#define __HAL_LOCK(__HANDLE__) \
do{ \
if((__HANDLE__)->Lock == HAL_LOCKED) \
{ \
return HAL_BUSY; \
} \
else \
{ \
(__HANDLE__)->Lock = HAL_LOCKED; \
} \
}while (0U)
#define __HAL_UNLOCK(__HANDLE__) \
do{ \
(__HANDLE__)->Lock = HAL_UNLOCKED; \
}while (0U)
#endif /* USE_RTOS */
ステップトレースでは
return HAL_BUSY;
というコードが実行されていることがわかり、HAL_UART_Receive_IT()
は実行されずにそのまま終了しました!!!すべての異常は、この予想外の脱退によるものです.HAL_UART_RxCpltCallback()
はデータ割り込みを受信した後に1回しか呼び出されません.HAL_UART_Receive_IT()
は最後まで実行されず、次の受信割り込みを起動できませんでした.そのため、今後HAL_UART_RxCpltCallback()
は呼び出される機会がありません.誰がロックしたの?
送信関数locked了huart
/**
* @brief Sends an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Transmit data register empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
送信データ期間中、
HAL_UART_Transmit_IT()
は__HAL_LOCK(huart);
で共通のhuartを送信受信するので、受信に影響されます.簡単な解決策
__HAL_LOCK(huart)
defineを空の関数にすればいい.簡単で、乱暴だ.より完璧な方法で、割り込み関数を修正します.
HALの割り込み関数インタフェースを使わないで、自分で1段書きます
/**
* Uart common interrupt process. This need add to uart ISR.
*
* @param serial serial device
*/
static void uart_isr(UART_HandleTypeDef *UartHandle,uint8_t type)
{
uint32_t isrflags = READ_REG(UartHandle->Instance->SR);
uint32_t cr1its = READ_REG(UartHandle->Instance->CR1);
uint8_t rec;
UartHandle->pRxBuffPtr = &gUartValue[type];
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
rec=(uint8_t)(UartHandle->Instance->DR & (uint8_t)0x00FF);;
rt_hw_serial_isr(UartHandle,rec);// , hal .
__HAL_UART_CLEAR_FLAG(UartHandle, UART_FLAG_RXNE);// !!!!
}
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
/* Check that a Tx process is ongoing */
if (UartHandle->gState == HAL_UART_STATE_BUSY_TX)
{
uint16_t *tmp;
if (UartHandle->Init.WordLength == UART_WORDLENGTH_9B)
{
tmp = (uint16_t *) UartHandle->pTxBuffPtr;
UartHandle->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
if (UartHandle->Init.Parity == UART_PARITY_NONE)
{
UartHandle->pTxBuffPtr += 2U;
}
else
{
UartHandle->pTxBuffPtr += 1U;
}
}
else
{
UartHandle->Instance->DR = (uint8_t)(*UartHandle->pTxBuffPtr++ & (uint8_t)0x00FF);
}
if (--UartHandle->TxXferCount == 0U)
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(UartHandle, UART_IT_TXE);
/* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(UartHandle, UART_IT_TC);
}
}
}
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(UartHandle, UART_IT_TC);
/* Tx process is ended, restore huart->gState to Ready */
UartHandle->gState = HAL_UART_STATE_READY;
/* */
}
}
実はこの中のほとんどのコードは
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
と同じです.この関数はHAL_UART_IRQHandler
に取って代わって、それから自分で受信と送信を実現します.ここで解決しました.他の問題はすべて解決しました.割り込みエントリの変更:void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
uart_isr(&huart1,1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
これこそ一般的なuartワークモードです!
CANにもこのような問題があり、CANが発生する確率が高い.
通信の問題はみな大きな問題だから、根本的に問題を解決しなければならない.