PIC16F1619 XC8 2.0 UART trouble

Thread Starter

odm4286

Joined Sep 20, 2009
250
Hello everyone. I'm having a strange problem with the baud rate generator on this chip. For some reason, even when I enter in values straight from the datasheet I am off by a factor of ten. For example, if I set up everything for 19200 baud I'll end up with 1920 baud. Set for 9600 baud? I end up with 960 baud. Also, when I use realterm I get nothing but 00s as my data. No matter what I transmit. I've played around with this most of the day and I can't seem to find my error. Any ideas?

oscillator config
Code:
// Oscillator Config
    OSCCONbits.SPLLEN = 0;                                            // no PLL
    OSCCONbits.IRCF = 0b1110;                                       // running at 8Mhz.
UART config (Please ignore the parameter in enable_comm(). I've "hardcoded" the function for now to help troubleshoot)
Code:
// UART Config
    TX1STAbits.BRGH = 1;                                          // low speed baud. Baudrate = fosc/16(SPBRGH:SPBRGL + 1)
    BAUD1CONbits.BRG16 = 0;                                   // 8 bit baudrate generator
    TX1STAbits.SYNC =0;                                            // Asynchronous comm
    enable_comm(9600);                                             // start comm port 19200 baud

void enable_comm(unsigned int baudrate)
{
    SP1BRGL = 25;
    TX1STAbits.TXEN = 1;                    // enable data out
    RC1STAbits.CREN = 1;                  // enable continuous receive
    RC1STAbits.SPEN = 1;                   // enable serial port
    RC1STAbits.RX9 = 0;                      // disable 9bit reception
    TX1STAbits.TX9 = 0;                       // disable 9bit transmission
}
I/O section
Code:
// I/O Config
    TRISAbits.TRISA5 = 0;                                                    // heartbeat I/O
    TRISCbits.TRISC5 = 1;                                                   // RS232 Rx
    RXPPS = 0b10101;                                                         // Setting up rs232 input on RC5
    TRISCbits.TRISC0 = 0;                                                   // RS232 Tx
    RC0PPS = 0b10010;                                                      // set as peripheral output
    TRISAbits.TRISA2 = 0;                                                   // used for debug out
    TRISCbits.TRISC7 = 1;                                                   // PWM out. Set to input for now. Switching to output later
    RC7PPS = 0b01110;                                                      // Using PWM module 3
Code:
void transmit_data(unsigned char data)
{
    TX1REG = data;
}
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
Something I just found, I worked the formula backward. Given my current SP1BRGL value and the generated baudrate output on my scope my Fosc is 800Khz. I plugged this new Fosc into the formula and now I get the baud rates I would expect. Still not sure what my issue is.
 

Ian Rogers

Joined Dec 12, 2012
871
Try waiting until the buffers empty or it won't send..

Code:
void transmit_data(unsigned char data)
{
    while(!TRMT)
       TX1REG = data;
}
 

AlbertHall

Joined Jun 4, 2014
11,221
Try waiting until the buffers empty or it won't send..

Code:
void transmit_data(unsigned char data)
{
    while(!TRMT)
       TX1REG = data;
}
TRMT tells you whether all bits have been sent but there is an error in this code. There should be a semicolon after the while line: while(!TRMT);
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
What is the config bit setting for FOSC?
Please include the whole of the code here.
Code:
// PIC16F1619 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = ON    // Clock Out Enable (CLKOUT function is enabled on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switch Over (Internal External Switch Over mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit cannot be cleared once it is set by software)
#pragma config ZCD = OFF        // Zero Cross Detect Disable Bit (ZCD disable.  ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PLLEN = OFF      // PLL Enable Bit (4x PLL is enabled when software sets the SPLLEN bit)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

// CONFIG3
#pragma config WDTCPS = WDTCPS1F// WDT Period Select (Software Control (WDTPS))
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config WDTCWS = WDTCWSSW// WDT Window Select (Software WDT window size control (WDTWS bits))
#pragma config WDTCCS = SWC     // WDT Input Clock Selector (Software control, controlled by WDTCS bits)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 8000000
#include <xc.h>
#include <pic16f1619.h>

#define HEARTBEAT_OUT LATAbits.LATA5
#define HEARTBEAT_READ PORTAbits.RA5
#define DEBUG_OUT LATAbits.LATA2

#define ONE_SEC 1000
#define START_BYTE 0xFF
#define END_BYTE 0xFE
#define TIMER_ZERO_PREFILL 6
#define PACKET_SIZE 6
//#define RX_DEBUG
#define TX_DEBUG
//#define VALIDATE_DEBUG


// prototypes
void enable_comm(unsigned int baudrate);
void transmit_data(unsigned char);
void heartbeat(volatile unsigned int* mS_count);
int validate_packet(volatile unsigned char* packet);
void change_duty(unsigned int duty);
unsigned char receive_data(void);

// Master ISR
volatile unsigned int mS_count = 0;
volatile unsigned char receive_mode = 0;
volatile unsigned char packet[PACKET_SIZE];

void __interrupt() master_isr()                                         // Single interrupt vector on this chip I think
{
    if(INTCONbits.T0IF)
    {
        INTCONbits.T0IF = 0;
        ++mS_count;
        heartbeat(&mS_count);
    }
 
    if(PIR1bits.RCIF) {
        PIR1bits.RCIF = 0;                                                      // clear flag
        receive_mode = 1;                                                      // set receive mode
        packet[0] = receive_data();                                         // get data
#ifdef RX_DEBUG
        DEBUG_OUT = 1;
#endif
    }
}


void main(void)
{
    // I/O Config
    TRISAbits.TRISA5 = 0;                                                    // heartbeat I/O
    TRISCbits.TRISC5 = 1;                                                   // RS232 Rx
    RXPPS = 0b10101;                                                         // Setting up rs232 input on RC5
    TRISCbits.TRISC0 = 0;                                                   // RS232 Tx
    RC0PPS = 0b10010;                                                      // set as peripheral output
    TRISAbits.TRISA2 = 0;                                                   // used for debug out
    TRISCbits.TRISC7 = 1;                                                   // PWM out. Set to input for now. Switching to output later
    RC7PPS = 0b01110;                                                      // Using PWM module 3
 
 
    // Oscillator Config
    OSCCONbits.SPLLEN = 0;                                            // no PLL
    OSCCONbits.IRCF = 0b1110;                                       // running at 8Mhz.
 
    // Timer0 Config
    OPTION_REGbits.TMR0CS = 0;                                    // increment fosc/4
    OPTION_REGbits.PSA = 0;                                            // prescaler assigned to timer0
    OPTION_REGbits.PS = 0b010;                                      // 1:8 prescaler
 
 
    // Interrupt Config
    INTCONbits.GIE = 1;                                                       // enable interrupts
    INTCONbits.T0IE = 1;                                                      // timer0 interrupt enable
    INTCONbits.PEIE = 1;                                                     // enable peripheral interrupts
    PIE1bits.RCIE = 0;                                                          // enable uart Rx interrupt(disabled for now)
 
 
    // UART Config
    enable_comm(9600);                                             // hardcoded for now. Troubleshooting. Arguement has no effect
 
    // PWM Module 3 Config
    PWM3CONbits.PWM3POL = 0;                              // active high
    PR2 = 0xFF;                                                           // gives us a 32uS period
    PWM3DCH = 0;                                                      // clearing for now
    PWM3DCL = 0;                                                      // same here
    PIR1bits.TMR2IF = 0;                                             // clearing timer2 interrupt flag
    T2CONbits.CKPS = 0b101;                                    // 1:32 prescaler
    T2CONbits.ON = 1;                                                // turn on timer2
    while(!PIR1bits.TMR2IF);                                       // wait until timer2 rolls once
    TRISCbits.TRISC7 = 0;                         
 
    PWM3CONbits.PWM3EN = 1;                                 // enable
     
 
    // don't forget enable
 
 
    DEBUG_OUT = 0;
    change_duty(1023);
    // Forever loop
#ifdef TX_DEBUG
 
        transmit_data(255);
     
#endif
    while(1)
    {
        if(receive_mode)
        {
            PIE1bits.RCIE = 0;                                          // disable rx interrupt for now
         
            for(int i = 1; i < PACKET_SIZE; i++)
            {
                while(!RCIF);                                               // waiting for the next byte
                RCIF = 0;
                packet[i] = receive_data();
            }
            //validate_packet(packet);
            #ifdef VALIDATE_DEBUG
                DEBUG_OUT = 1;
             
            #endif
                PIE1bits.RCIE = 1;                                         // re-enable the rx interrupt
        } else {
            // not sure what I'll do here yet.
            #ifdef TX_DEBUG
            transmit_data(0xFF);
            #endif
        }
    }
}

void heartbeat(volatile unsigned int* mS_count)
{
     if(*mS_count >= ONE_SEC)
        {
            HEARTBEAT_OUT = !HEARTBEAT_READ;
            *mS_count = 0;
        }
}

void enable_comm(unsigned int baudrate)
{
    SP1BRGL = 51;
    TX1STAbits.BRGH = 1;                   // high speed baud. Baudrate = fosc/16(SPBRGH:SPBRGL + 1)
    BAUD1CONbits.BRG16 = 0;           // 8 bit baudrate generator
    TX1STAbits.SYNC =0;                    // Asynchronous comm
    RC1STAbits.SPEN = 1;                   // enable serial port
    RC1STAbits.RX9 = 0;                      // disable 9bit reception
    TX1STAbits.TX9 = 0;                       // disable 9bit transmission
    TX1STAbits.TXEN = 1;                    // enable data out
    RC1STAbits.CREN = 1;                  // enable continuous receive 
}

void transmit_data(unsigned char data)
{
    while(!TX1STAbits.TRMT);
    TX1REG = data;
}

unsigned char receive_data(void)
{
    if(RC1STAbits.OERR)                      // clear any errors
    {
        RC1STAbits.CREN = 0;
        __delay_us(1);
        RC1STAbits.CREN = 1;
    }
    return RC1REG;
}

int validate_packet(volatile unsigned char* data)
{
    if(data[0] == START_BYTE && data[5] == END_BYTE)
         return 1;
    return -1;
}

unsigned int two_bytes_to_int(char MSB, char LSB)
{
    int buffer;
    buffer = MSB;
    buffer <<= 8;
    buffer |= LSB;
    return buffer;
}

void change_duty(unsigned int duty)
{
    char LSB = 0;
    char MSB = 0;
    LSB |= duty;                                     
    duty >>= 8;
    MSB |= duty;
    PWM3DCH = MSB;                                                   
    PWM3DCL = LSB;
}
At a loss here, for whatever reason I cannot generate a proper baud rate. Thanks for the help!
 

AlbertHall

Joined Jun 4, 2014
11,221
  • // Oscillator Config
  • OSCCONbits.SPLLEN = 0; // no PLL
  • OSCCONbits.IRCF = 0b1110; // running at 8Mhz.
To check the oscillator frequency is correct, change this code as below. Make sure that HEARTBEAT_OUT has a 1Hz square wave. The program won't do anything else with this addition.
Code:
    // Oscillator Config
    OSCCONbits.SPLLEN = 0;                                            // no PLL
    OSCCONbits.IRCF = 0b1110;                                       // running at 8Mhz.
    while(1)
    [
        _delay_ms(500);
        HEARTBEAT_OUT = 0;
        _delay_ms(500);
        HEARTBEAT_OUT = 1;
    ]
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
To check the oscillator frequency is correct, change this code as below. Make sure that HEARTBEAT_OUT has a 1Hz square wave. The program won't do anything else with this addition.
Code:
    // Oscillator Config
    OSCCONbits.SPLLEN = 0;                                            // no PLL
    OSCCONbits.IRCF = 0b1110;                                       // running at 8Mhz.
    while(1)
    [
        _delay_ms(500);
        HEARTBEAT_OUT = 0;
        _delay_ms(500);
        HEARTBEAT_OUT = 1;
    ]
I will check this tonight. I did check my clkout pin. 2Mhz there, fosc/4. Possibly a bad micro? I'm using a curiosity dev board but I have spare chips. I wonder if I should try a new one?
 

AlbertHall

Joined Jun 4, 2014
11,221
There are 10 bits in a transmitted byte (start, 8 data, and stop). You need to measure the width of a data bit not the frequency of whole bytes.
Transmit 0xAA which has a 10101010 pattern to make the bit width as obvious as possible.
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
There are 10 bits in a transmitted byte (start, 8 data, and stop). You need to measure the width of a data bit not the frequency of whole bytes.
Transmit 0xAA which has a 10101010 pattern to make the bit width as obvious as possible.
Ah, I'll try that tonight. Also, I have a few Arduinos laying around I'll use those to test my ftdi cable.
 

Ian Rogers

Joined Dec 12, 2012
871
I have stuffed this into the sim.... If I send 12345 packet does indeed hold the same... Seems to be okay.

Oh!! I did have to include
ANSELC = 0;


EDIT!!! One other issue.... The code didn't compile as the interrupt routine is wrong

"void interrupt master_isr()" is how it should look...
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
I have stuffed this into the sim.... If I send 12345 packet does indeed hold the same... Seems to be okay.

Oh!! I did have to include
ANSELC = 0;


EDIT!!! One other issue.... The code didn't compile as the interrupt routine is wrong

"void interrupt master_isr()" is how it should look...
Thanks, I'll check the ansel register tonight. I don't think rc0 has analog capability but it's worth trying. Also, isrs are written differently in xc8 2.0
 

Thread Starter

odm4286

Joined Sep 20, 2009
250
Fair enough.... ANSELC=0 is for the RC5 you are using.. You won't get your program moving unless the RX has found something...
Thank you for this, I wouldn't have noticed it otherwise. Turns out my FTDI cable was defective. Figured why not just put the cable up directly to the scope and see whats going on...the Tx line was swinging negative for some strange reason. About -2.5V when I wasn't transmitting and about 2 volts when I was. Grabbed an old ardunio uno I had laying around to test out the transmit code on the PIC...works perfectly. A new cable is on the way, lesson learned. Thanks again, everyone.
 
Top