This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1352P: Race condition in UARTCC26XX.c?

Part Number: CC1352P

Hello,

I have struggled with a problem on the UART of CC1352P, using Simplelink SDK 2.30 and UARTCC26XX driver. (This driver's source code did not change to SDK 2.40.)

Use case: I am transferring and receiving concurrently and with high duty cycle at 9600 Baud. Transmitting several bytes at once, reading single bytes. Using callback mode for both RX and TX.

Error: After minutes to 1 hour, transmission fails.

This is what happens in error case:

- UARTCC26XX_read() is interrupted while at line

    /* Enable RX */
    HWREG(hwAttrs->baseAddr + UART_O_CTL) |= UART_CTL_RXE;

by UARTCC26XX_swiIntFxn() which disables the UART_CTL_TXE bit.

    /* Disable TX */
    HWREG(hwAttrs->baseAddr + UART_O_CTL) &= ~(UART_CTL_TXE);

- UARTCC26XX_read() continues and it erroneously restores the UART_CTL_TXE bit.

- UARTCC26XX_write() then checks for UART_CTL_TXE cleared and fails with UART_ERROR.

    /* The UART TX is disabled after a successful write, if it is
     * still active another write is in progress, reject. */
    uint32_t writeActive = HWREG(hwAttrs->baseAddr + UART_O_CTL) & (UART_CTL_TXE);
    if (!object->opened || writeActive) {
        HwiP_restore(key);
        DebugP_log1("UART:(%p) Could not write data, uart closed or in use.",
                    ((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr);

        return (UART_ERROR);
    }

There are several of these read-modify-write instructions, using the HWREG() macro, in this driver. And only a few of them are within HwiP_disable()...HwiP_restore() blocks.

Second possible source of these errors could be the UARTIntEnable()/UARTIntDisable() functions which use the HWREG() macro as well.

I have attached a patch that fixes my problem and I hope it is of use for future revisions of the UARTCC26XX driver.

Best regards,
hkr

diff --git a/UARTCC26XX.c b/UARTCC26XX.c
@@ -437,7 +456,9 @@ static void writeTxFifoFlush(UARTCC26XX_Object  *object, UARTCC26XX_HWAttrsV2 co
     /*It is not possible to flush the TX FIFO with simple write to HW, doing workaround:
      * 0. Disable TX interrupt
      */
+    unsigned int key = HwiP_disable();
     UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
+    HwiP_restore(key);
     /* 1. Ensure TX IO will stay high when connected to GPIO */
     PIN_setOutputEnable(object->hPin, hwAttrs->txPin, 1);
     PIN_setOutputValue(object->hPin, hwAttrs->txPin, 1);
@@ -1113,7 +1134,9 @@ int_fast32_t UARTCC26XX_write(UART_Handle handle, const void *buffer,
     threadSafeStdbyDisSet(&uartTxPowerConstraint);
 
     /* Enable TX */
+    key = HwiP_disable();
     HWREG(hwAttrs->baseAddr + UART_O_CTL) |= UART_CTL_TXE;
+    HwiP_restore(key);
 
     uint32_t writtenLast = size;
     /* Fill up TX FIFO */
@@ -1151,7 +1174,9 @@ int_fast32_t UARTCC26XX_write(UART_Handle handle, const void *buffer,
     } else {
 
         /* Enable TX interrupts */
+        key = HwiP_disable();
         UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX);
+        HwiP_restore(key);
 
         /* If writeMode is blocking, block and get the status. */
         if (object->writeMode == UART_MODE_BLOCKING) {
@@ -1263,12 +1288,16 @@ void UARTCC26XX_writeCancel(UART_Handle handle)
         writeTxFifoFlush(object, hwAttrs);
     }
 
+    key = HwiP_disable();
+
     /* Disable TX interrupt */
     UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
 
     /* Disable UART TX */
     HWREG(hwAttrs->baseAddr + UART_O_CTL) &= ~(UART_CTL_TXE);
 
+    HwiP_restore(key);
+
     /* Release constraint since transaction is done */
     threadSafeStdbyDisRelease(&uartTxPowerConstraint);
 
@@ -1355,6 +1384,8 @@ int_fast32_t UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size)
             /* Set constraint for sleep to guarantee transaction */
             threadSafeStdbyDisSet(&uartRxPowerConstraint);
 
+            key = HwiP_disable();
+
             /* Enable RX */
             HWREG(hwAttrs->baseAddr + UART_O_CTL) |= UART_CTL_RXE;
 
@@ -1362,6 +1393,8 @@ int_fast32_t UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size)
             UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT |
                           UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
 
+            HwiP_restore(key);
+
             /* If readMode is blocking, block and get the status. */
             if (object->readMode == UART_MODE_BLOCKING) {
                 /* Pend on semaphore and wait for Hwi to finish. */