Hi, I have written an interrupt routine to receive binary messages over SCI for an MC9S08 CPU. This does not work when the byte 0x00 is included in the message.
The messages all starts with a Start Of Message byte (SOM) equal to 0xAA and ends with a End Of Message byte (EOM) equal to 0x55. If the SOM or EOM is included in the message as ordinary data they are stuffed with a stuff byte equal to 0x70 and the most significant bit in the byte is inverted.
This works very well in all cases as long as the messages do not include one or more bytes equal to 0x00. For instance receiving the message “SOM, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, EOM” works as expected. If I try to receive a message like this: “SOM, 0x10, 0x00, 0x00, EOM” the messages is received as “SOM, 0x10, 0x00, EOM”, one of the 0x00 is not received. If I try to receive a message like this: “SOM, 0x10, 0x00, 0x55” this is received as “SOM, 0x10, 0x00, 0xd5”. All testing shows me that the problem is related to receiving messages containing the character 0x00.
The code below shows how the SCI2 is configured in the InitSCI routine. The interrupt routine itself is also included. L is a typedef struct declared globally in the project.
#define SOM 0xaa
#define EOM 0x55
#define STUFF 0x70
void InitSCI ( void )
{
SCI2C2 = 0x00;
SCI2C1 = 0x00;
SCI2C2 = 0x2C;
SCI2C3 = 0x00;
}
__interrupt void isrVsci2rx(void)
{
UINT8 ucStatus, ucData;
ucStatus = SCI2S1;
ucData = SCI2D;
if ( L.WaitForSOM == TRUE )
{
if ( ucData == SOM )
{
L.WaitForSOM = FALSE;
g_ucRxUART2ReadIndex = 0;
L.MsgReceivedLen = 0;
L.StuffReceived = FALSE;
}
}
else
{
switch ( ucData )
{
case 0x2a: //SOM with inverted most significant bit
case 0xd5: //EOM with inverted most significant bit
case 0xf0: //STUFF with inverted most significant bit
if ( L.StuffReceived == TRUE )
{
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex++] = ucData ^ 0x80;
L.MsgReceivedLen++;
L.StuffReceived = FALSE;
}
else
{
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex++] = ucData;
L.MsgReceivedLen++;
}
break;
case STUFF:
if ( L.StuffReceived == TRUE )
{
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex++] = ucData;
L.MsgReceivedLen++;
L.StuffReceived = FALSE;
}
else
{
L.StuffReceived = TRUE;
}
break;
case EOM:
if ( L.StuffReceived == TRUE )
{
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex++] = ucData;
L.MsgReceivedLen++;
L.StuffReceived = FALSE;
}
else
{
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex] = ucData;
L.WaitForSTX = TRUE;
L.MsgReceived = TRUE;
}
break;
default:
g_ucRxUART2Buffer [g_ucRxUART2ReadIndex++] = ucData;
L.MsgReceivedLen++;
L.StuffReceived = FALSE;
}
}
}
Hello,
I cannot see any reason why the received data would become corrupted. The SCI module should be able to correctly receive a null character. Have you already checked that the correct sequence is being sent to the MCU? You might independently monitor the serial line using a PC-based terminal program having hexadecimal debug capability.
To transfer a variable length data packet containing non-ASCII data, including null bytes, I have previously used a slightly simpler scheme than the one you are using. The details are as follows -
All packets commence with the ASCII control character "data link escape" <DLE> (value 0x10), and finish with the pair of ASCII control characters <DLE> followed by "end of text" <ETX> (value 0x03). Immediately prior to the final pair of characters, will be a single checksum byte, calculated by modulo‑2 addition (exclusive‑OR) of all data bytes, excluding the above control characters.
If any data byte value within the body of the packet should have the value 0x10, corresponding to <DLE>, the byte will be immediately followed by a further <DLE> character. In this case, only one of the characters would be incuded in the checksum calculation
The only restriction is that the first data byte within the packet cannot be <DLE> or <ETX>. For the application in which this was used, the first data byte within each packet was an alphabetic character to identify the packet type.
Regards,
Mac