Context:
I’ve setup running two task with same priority sharing single UART to transmit and receive data on the RS484 bus.
On every data transmission from either of the task the response is expected, UART RX ISR has been setup to receive data.
Issue:
Occasionally, one of the task never gets response for one of transmit as a result eventually the xTaskNotifyWait times out.
what puzzling is the same code give me 100% success rate when device running with single task.
I would like to get my functions verified whether it is set right to handle uart data when sharing with multiple tasks
Any help would be appreciated! Thanks
Code snippets attached for reference:
/**
* @fn DRV_RS485_Ret_t DRV_RS485_SendReceive(const uint8_t* const pTxData, uint16_t sizeTx,
* uint8_t* const pRxData, uint16_t sizeRx,
* uint16_t* const pReceivedBytes, uint16_t timeout)
*
*
* @brief Sends a message over the RS485 network and receives the reply.
* Timeout specifies the timeout in milliseconds for both the transmission and reception.
* Function blocks the calling task until all the communication is performed (success or
* or error).
*
*
* @param[in] pTxData: pointer to the transmit buffer;
* @param[in] sizeTx: number of bytes to be transmitted;
* @param[in] pRxData: pointer to the receive buffer;
* @param[in] sizeRx: size of the receive buffer (maximum size of the received message);
* @param[out] pReceivedBytes: pointer to the variable updated with the number of received bytes;
* @param[in] timeout: timeout in milliseconds for the transmission and reception operation;
*
* @return DRV_RS485_Ret_t.
*
* @note Function uses the calling task events to communicate:
* - RS485_EVENT_RX (bit 1);
* - RS485_EVENT_ERR (bit 0);
*
******************************************************************************/
DRV_RS485_Ret_t DRV_RS485_SendReceive(const uint8_t* const pTxData, uint16_t sizeTx,
uint8_t* const pRxData, uint16_t sizeRx, uint16_t* const pReceivedBytes,
uint16_t timeout)
{
assert_param(pTxData);
assert_param(sizeTx);
assert_param(pRxData);
assert_param(sizeRx);
assert_param(pReceivedBytes);
DRV_RS485_Ret_t ret = DRV_RS485_NO_ERR;
/* take the mutex */
if (pdPASS == xSemaphoreTake(lpMutex, portMAX_DELAY))
{
/* Ensure the calling task does not already have a notification pending by calling
xTaskNotifyWait() with the events RS485_EVENT_RX and RS485_EVENT_ERR cleared at the exit
of the function and a block time of 0 (don't block). The current notification value is
not required, so the pulNotificationValue parameter is set to NULL. */
(void)xTaskNotifyWait(0, (uint32_t)(RS485_EVENT_RX | RS485_EVENT_ERR), NULL, 0);
xTaskToNotify = xTaskGetCurrentTaskHandle();
TickType_t tickDiff = xTaskGetTickCount() - oldTickCount;
if (tickDiff < DRV_RS485_DELAY_MS)
{
vTaskDelay(DRV_RS485_DELAY_MS - tickDiff);
}
ret = DRV_RS485_SendEx(pTxData, sizeTx, pRxData, sizeRx, pReceivedBytes, timeout);
/* release the mutex */
if (pdPASS == xSemaphoreGive(lpMutex))
{
/* Mutex properly released */
}
else /* error during releasing the mutex: this should never happen ! */
{
ret = (DRV_RS485_NO_ERR == ret) ? DRV_RS485_ERR_MUTEX_GIVE : ret;
}
}
else /* error during taking the mutex: should never happen ! */
{
ret = DRV_RS485_ERR_MUTEX_TAKE;
}
return(ret);
}
/**
* @fn static DRV_RS485_Ret_t DRV_RS485_SendEx(const uint8_t* const pTxData, uint16_t sizeTx, uint16_t timeout)
*
* @brief Sends the sizeTx data pointed by pTxData over the RS485 network.
* timeout specifies the timeout in milliseconds.
* CRC16 will be computed and appended at the end of the message
*
* @param[in] pTxData: pointer to the transmit buffer.
* @param[in] sizeTx: number of bytes to be transmitted.
* @param[in] timeout: timeout in milliseconds.
*
* @return DRV_RS485_Ret_t.
*
******************************************************************************/
static DRV_RS485_Ret_t DRV_RS485_SendEx(const uint8_t* const pTxData, uint16_t sizeTx,
uint8_t* const pRxData, uint16_t sizeRx,
uint16_t* const pReceivedByte,
uint16_t timeout)
{
DRV_RS485_Ret_t ret = DRV_RS485_NO_ERR;
bool errCond = (NULL == pTxData) || (NULL == pRxData) || (0 == sizeTx) || (0 == sizeRx) ||
(NULL == pReceivedByte);
if (true == errCond)
{
ret = DRV_RS485_ERR_PARAMETER;
}
else
{
uint32_t event = 0;
if ((sizeTx >= (DRV_RS485_MSG_MIN_LEN - CRC16_SIZE)) &&
(sizeTx <= (DRV_RS485_MSG_MAX_LEN - CRC16_SIZE)) )
{
memcpy (&lRs485.msg[0], pTxData, sizeTx);
/* Compute the CRC and append it to the message */
uint16_t crc = CRC16_Modbus_Compute(pTxData, sizeTx);
lRs485.msg[sizeTx] = (uint8_t)(crc & BYTE_MASK);
lRs485.msg[sizeTx+1] = (uint8_t)(crc >> EIGHT_VALUE);
lRs485.bytesToSend = sizeTx + CRC16_SIZE;
ret = DRV_RS485_Send(&lRs485.msg[0], lRs485.bytesToSend);
if (ret != DRV_RS485_NO_ERR) /* Transmission initialized properly ? */
{
/* Error in HAL layer: return the error code */
}
else
{
lRs485.bytesToReceive = sizeRx + CRC16_SIZE;
ret = DRV_RS485_Receive(&lRs485.msg[0], lRs485.bytesToReceive);
if (ret != DRV_RS485_NO_ERR) /* Reception initialized properly ? */
{
/* Error in HAL layer: return the error code */
}
else
{
bool loop = true;
while(loop) /* loop avoiding to exit due to the wrong event */
{
/* Wait for transmission complete event or error */
BaseType_t xResult = xTaskNotifyWait(0, (uint32_t)(RS485_EVENT_ERR | RS485_EVENT_RX), &event, pdMS_TO_TICKS(timeout));
ret = DRV_RS485_HandleEvent(xResult, event);
switch (ret)
{
case DRV_RS485_ERR_TIMEOUT:
HAL_UART_AbortReceive(&huart2);
HAL_UART_AbortTransmit(&huart2);
loop = false;
break;
case DRV_RS485_NO_ERR:
ret = CheckMsgIntegrity(&lRs485.msg[0]);
if (DRV_RS485_NO_ERR == ret ) /* Is msg CRC correct ? */
{
/* copy the message to the destination buffer without the CRC */
*pReceivedByte = lRs485.bytesReceived - CRC16_SIZE;
memcpy(pRxData, &lRs485.msg[0], *pReceivedByte);
}
loop = false;
break;
case DRV_RS485_ERR_UART_COM:
ret = (DRV_RS485_Ret_t)(DRV_RS485_ERR_HAL_BASE + LIB_BIN_CTZ(lRs485.errCode));
/* intentional fall-through */
case DRV_RS485_ERR_INTERNAL:
loop = false;
break;
default:
/* nothing to do: just wait for the proper event */
break;
}
}
}
}
}
else /* Invalid length of the Tx Message */
{
ret = DRV_RS485_ERR_TX_LENGTH;
}
}
return(ret);
}