2015-11-10 02:08 AM
Synopsis: HAL_CAN_Transmit_IT & HAL_CAN_Receive_IT can't be used simultaneously effective without data loss risks.
Details:When you build receive/transmit cycle like below (simplified)main() { HAL_CAN_Receive_IT(); HAL_CAN_Transmit_IT();}HAL_CAN_RxCpltCallback() { HAL_CAN_Receive_IT(); // rearm receive}HAL_CAN_TxCpltCallback() { HAL_CAN_Transmit_IT(); // rearm transmit}In some situations HAL_CAN_Receive_IT/HAL_CAN_Transmit_IT drops with busy state.This occurs because both of Transmit & Receive uses lock via __HAL_LOCK(hcan) When you call HAL_CAN_Transmit_IT and interrupt HAL_CAN_RxCpltCallback occurs, state is locked by HAL_CAN_Transmit_IT and rearm rx failed.What solution to solve?I can't find easy way now. In my opinion general mistake is unified ''HAL_CAN_StateTypeDef State'' used for three indenpended flags - General can state, rx state & tx state.I think solution is split State for {State, rxState & txState} and never lock same thing in both of Receive/Transmit.For example current structuretypedef enum{ HAL_CAN_STATE_RESET = 0x00, /*!< CAN not yet initialized or disabled */ HAL_CAN_STATE_READY = 0x01, /*!< CAN initialized and ready for use */ HAL_CAN_STATE_BUSY = 0x02, /*!< CAN process is ongoing */ HAL_CAN_STATE_BUSY_TX = 0x12, /*!< CAN process is ongoing */ HAL_CAN_STATE_BUSY_RX = 0x22, /*!< CAN process is ongoing */ HAL_CAN_STATE_BUSY_TX_RX = 0x32, /*!< CAN process is ongoing */ HAL_CAN_STATE_TIMEOUT = 0x03, /*!< CAN in Timeout state */ HAL_CAN_STATE_ERROR = 0x04 /*!< CAN error state */ }HAL_CAN_StateTypeDef;typedef struct{ ... __IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */ ...}CAN_HandleTypeDef;split totypedef enum{ HAL_CAN_STATE_RESET = 0x00, /*!< CAN not yet initialized or disabled */ HAL_CAN_STATE_READY = 0x01, /*!< CAN initialized and ready for use */ HAL_CAN_STATE_BUSY = 0x02, /*!< CAN process is ongoing */ }HAL_CAN_StateTypeDef;typedef enum{ HAL_CAN_TXRX_STATE_READY = 0x01, HAL_CAN_TXRX_STATE_BUSY = 0x02, HAL_CAN_TXRX_STATE_TIMEOUT = 0x03, HAL_CAN_TXRX_STATE_ERROR = 0x04 }HAL_CAN_TxRxStateTypeDef;typedef struct{ ... __IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */ __IO HAL_CAN_TxRxStateTypeDef RxState; /*!< CAN RX communication state */ __IO HAL_CAN_TxRxStateTypeDef TxState; /*!< CAN TX communication state */ ...}CAN_HandleTypeDef;But that is awesome library modification. Maybe you know any better solution?Same problem affects USART library, i think2015-11-10 03:15 AM
void UART_RxAgain(UART_HandleTypeDef *huart) {
// use the code from HAL_UART_Receive_IT() to repost interrupt
huart->pRxBuffPtr = &wifiState.rxChar;
huart->RxXferSize = 1;
huart->RxXferCount = 1;
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Check if a transmit process is ongoing or not */
if(huart->State == HAL_UART_STATE_BUSY_TX)
{
huart->State = HAL_UART_STATE_BUSY_TX_RX;
}
else
{
huart->State = HAL_UART_STATE_BUSY_RX;
}
/* 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);
/* Process Unlocked */
//__HAL_UNLOCK(huart);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
}
I should say that I am only using polling for UART tx and so this may not be suitable if you want to use interrupts for tx.
Cheers,
Mark
2015-11-10 03:36 AM
That solution contains previously fixed by HAL_LOCK problem with State.
If that code interrupt another call of Transmit_IT inif(huart->State == HAL_UART_STATE_BUSY_RX)
section, State can be overriden after return from interrupt.
UPD: Oops, didn't see your last message. Confirmed