Electronic – PIC: UART transmit corrupted after watchdog sleep

picuart

I have a PIC16 (datasheet here) for which UART transmit works, except right after a watchdog sleep, where the first few characters are corrupted.

I have posted my reduced code below. What could cause corruption of the first few UART transmit characters right after a watchdog sleep?

// Baud rates
#define BAUD_115200 0
#define BAUD_9600 1

// Watchdog sleep times
#define WATCHDOG_SLEEP_4S 0b01100

/* Note: The watchdog operating mode configuration is done in configuration word 1 */
void watchdog_configure(char interval) {
    // Configure the watchdog interval (e.g. 10010 for 256 seconds)
    WDTCONbits.WDTPS = interval & 0b11111;
}

void watchdog_sleep(void) {
    WDTCONbits.SWDTEN = 0b1;
    SLEEP();
    WDTCONbits.SWDTEN = 0b0;
}

void UART_setBaudRate(const unsigned char type) {
    // See table 25-5
    if(type == BAUD_115200) {
        SPBRG = 68;
    } else {
        SPBRGH = (832 >> 8);
        SPBRGL = 832 & 0b11111111;
    }
}

/* Configure the UART for full-duplex asynchronous transmission */
void UART_initialise(void) {
    UART_setBaudRate(BAUD_115200);

    // Configure the RX/DT pin as an input
    TRISCbits.TRISC4 = 0b1;

    // Enable the asynchronous transceiver
    TXSTAbits.TXEN = 0b1;
    TXSTAbits.SYNC = 0b0;
    RCSTAbits.SPEN = 0b1;
    RCSTAbits.CREN = 0b1;
    TXSTAbits.BRGH = 0b1;

    // Use 16 bits for the baud rate
    BAUDCONbits.BRG16 = 0b1;
}

void UART_write(const unsigned char character) {
    // Wait while the transmit shift register empties
    while(!PIR1bits.TXIF) {}

    // Indicate the character to be written to the Transmit Shift Register
    TXREG = character;

    // Add a one cycle delay to ensure that the TXIF flag is valid
    _delay(1);
}

void UART_writeString(const unsigned char *string) {
    unsigned char i = 0;

    while(*(string + i) != '\0') {
        UART_write(*(string + i));
        i += 1;
    }
}

void main(void) {
    // Perform initialisations
    watchdog_configure(WATCHDOG_SLEEP_4S);
    UART_initialise();

    watchdog_sleep();
    UART_writeString("UART TESTING");
}

Best Answer

I would guess that the problem is not actually occurring when the PIC wakes up, but rather when it sleeps. If the PIC goes to sleep between the time the code enqueues a character for transmission and the time the UART finishes sending it, some bits of that character will get sent before the PIC sleeps and some will get sent after it wakes up. The first falling edge that occurs after the PIC wakes up will likely be interpreted by the receiver as a start bit rather than a data bit. If a start bit occurs within 8 bit times of that, the receiver will not detect that as a start bit, but will instead detect the next falling edge (which may well be some other data bit). This condition is referred to as a "framing error"; note that nearly all framing errors will cause incorrect data to be received, but only some will cause the "FE" bit to be set.

It's worthwhile to note that when sending a byte value of 00, 80, C0, E0, F0, F8, FC, FE, or FF, it's possible for a misdetected start bit to cause an incorrect value to be received for that byte, but the byte following one of the above values should be received correctly in any case (since will be no falling edge between the start bit of any of the indicated values and the start bit of the next byte). By contrast, if a framing error occurs on byte value in the range 40-7F, it's likely that the next byte will be corrupted as well, since there's a falling edge between bits 6 and 7.