AnsweredAssumed Answered

Processor Expert bug in AsynchroSerial when interrupts disabled

Question asked by Bronson Philippa on Jun 27, 2017

It seems that Processor Expert's AsynchroSerial generates incorrect code when interrupts are disabled. I am experimenting with a K22F board and implementing a basic serial echo program. The complete project is attached.

 

With interrupts disabled, AS1_RecvChar always returns ERR_RXEMPTY.

 

Digging into the code, it seems that the issue lies with the InterruptRx function in ASerialLdd1.c. The code reads:

static void InterruptRx(ASerialLdd1_TDeviceDataPtr DeviceDataPrv)
{
  register uint16_t Data;              /* Temporary variable for data */
  Data = (uint16_t)UART_PDD_GetChar8(UART1_BASE_PTR); /* Read an 8-bit character from the receiver */
  if (DeviceDataPrv->InpDataNumReq != 0x00U) { /* Is the receive block operation pending? */
    *(DeviceDataPrv->InpDataPtr++) = (uint8_t)Data; /* Put an 8-bit character to the receive buffer */
    DeviceDataPrv->InpRecvDataNum++;   /* Increment received char. counter */
    if (DeviceDataPrv->InpRecvDataNum == DeviceDataPrv->InpDataNumReq) { /* Is the requested number of characters received? */
      DeviceDataPrv->InpDataNumReq = 0x00U; /* If yes then clear number of requested characters to be received. */
    }
  }
}

The issue is that DeviceDataPrv->InpDataNumReq is always zero! Therefore the main code is skipped. InpDataNumReq is set by ASerialLdd1_ReceiveBlock() ... but that function is not run by AS1_RecvChar until a character has already been received (see below). The return ERR_RXEMPTY happens before ASerialLdd1_ReceiveBlock. The crucial setting DeviceDataPrv->InpDataNumReq is never modified.

 

byte AS1_RecvChar(AS1_TComData *Chr)
{
  byte Result = ERR_OK;                /* Return error code */
  LDD_SERIAL_TError SerialErrorMask;   /* Serial error mask variable */

  if (!EnMode) {                       /* Is the device disabled in the actual speed CPU mode? */
    return ERR_SPEED;                  /* If yes then error */
  }
  ASerialLdd1_Main(ASerialLdd1_DeviceDataPtr);
  if (ASerialLdd1_GetError(ASerialLdd1_DeviceDataPtr, &SerialErrorMask) == ERR_OK) { /* Get error state */
    if (SerialErrorMask != 0U) {
      Result = ERR_COMMON;             /* If yes then set common error value */
    } else {
      if (ASerialLdd1_GetReceivedDataNum(ASerialLdd1_DeviceDataPtr) == 0U) { /* Is not received char? */
        return ERR_RXEMPTY;            /* If yes then error is returned */
      }
    }
  }
  *Chr = BufferRead;                   /* Read the char */
  (void)ASerialLdd1_ReceiveBlock(ASerialLdd1_DeviceDataPtr, &BufferRead, 1U); /* Receive one data byte */
  ASerialLdd1_Main(ASerialLdd1_DeviceDataPtr);
  return Result;                       /* Return error code */
}

 

I can work around this by enabling interrupts, but it's confusing to new users when a certain check box in Processor Expert silently breaks the code!

Original Attachment has been moved to: AsynchroSerial_Bug_K22F.zip

Outcomes