UART communication: PIC18F and PC - Page 1
Forum section: electronics / general

author: Lucky-Luka
author_rank: Unknown
timestamp: March 21, 2021, 05:35:59 pm
content: Hi allI am experimenting UART communication between a PIC18F4580 and the PC through USB-TTL Converter Module.I've written a program that performs a loopback test: I write something on the PC using Realterm and the PIC will send it back.I've set up the UART in asynchronous 8-bit mode.It works but if I enable the line "PIE1bits.TXIE = 1; // UART Transmit Interrupt Enable bit" it doesn't work anymore and I can't understand why.I haven't really understood how and why to set that bit after reading the datasheet:QuoteSecond thing that I can't understand: I thought that I could just send 1 ascii character at the time in this manner. I tried to send this string "Hello1Hello2Hello3Hello4" and I received it back.How is it possible that after the first character all the rest is not lost? RCREG is 2 layer FIFO 8 bit register right? Is the string buffered in the PC?ThanksCode:#include <xc.h>#include <stdint.h>#include "stdbool.h"#include "config.h"#define _XTAL_FREQ 8000000 // 8MHz// Function declarationvoid UART_RX_Init(void);// Globalsuint8_t data = 0;bool got_data_bool = false;void UART_send(uint8_t *c);void UART_receiver(uint8_t *c, bool *rx_flag);void main(void) {// 8MHz internal oscillatorOSCCONbits.IRCF = 0x07;// Internal oscillator selectedOSCCONbits.SCS = 0x03;// I wait until the oscillator frequency is stablewhile(OSCCONbits.IOFS != 1);RCONbits.IPEN = 1; // Enable interrupt prioritiesei(); // It's like GIE = 1 to enable all interruptsINTCONbits.GIEL = 1; // Enable LOW priority interrupt//INTCONbits.GIEH = 1; // Enable HIGH priority interruptUART_RX_Init(); // Initialize the UART @ 9600bpswhile(1){if(got_data_bool){UART_send(&data);got_data_bool = false;}}return;}// UART initializationvoid UART_RX_Init(void){// Set the RX-TX pins to be in UART mode, not I/OTRISCbits.RC7 = 1;TRISCbits.RC6 = 0;SPBRG = 51; // 9600bps @ 8MHz, 8bit baud rate generator, high speedRCSTAbits.CREN = 1; // Asyncronous mode continuous receiverRCSTAbits.SPEN = 1; // Serial port enabledBAUDCONbits.BRG16 = 0; // 8bit baud rate generatorTXSTAbits.SYNC = 0; // Asyncronous modeTXSTAbits.BRGH = 1; // High speedTXSTAbits.TXEN = 1; // Transmit enableIPR1bits.RCIP = 1; // Receive interrupt high priority//PIE1bits.TXIE = 1; // UART Transmit Interrupt Enable bit (no software clear needed)PIE1bits.RCIE = 1; // UART receive interrupt enabled}// High priority ISRvoid __interrupt(high_priority) HIGH_ISR_RCIF(void){// Check if the ISR is caused by RCIF// The EUSART receive buffer, RCREG, is full (clear when RCREG is read)// Check interrupt flag bitif(PIR1bits.RCIF){UART_receiver(&data,&got_data_bool);PIR1bits.RCIF = 0; // Clear interrupt flag}}void UART_send(uint8_t *c){// It is more efficient to use TXIF rather than polling TRMT.//while(!TXSTAbits.TRMT); // Wait until TSR register is empty (TMRT = 1 --> TSR empty)while(!PIR1bits.TXIF); // Wait until TXREG is emptyTXREG=*c;}void UART_receiver(uint8_t *c, bool *rx_flag){// Framing error (can be updated by reading RCREG register and// receiving next valid byte)if(RCSTAbits.FERR){uint8_t er = RCREG;// Overrun error (can be cleared by clearing bit CREN)}else if(RCSTAbits.OERR){RCSTAbits.CREN=0;RCSTAbits.CREN=1;}else{*c = RCREG; // Read the received buffer*rx_flag = true;}}

author: Lucky-Luka
author_rank: Unknown
timestamp: March 21, 2021, 06:05:53 pm
content: Reading the datasheet I thought that TXIF hasn't to be cleared by software but it's cleared when TXREG is loaded.Am i wrong?

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 21, 2021, 06:13:01 pm
content: Hmmm...In main:- Interrupt priorities enabled- Low priority interrupt enabled- High priority interrupt disabledCode:void main(void) {RCONbits.IPEN = 1; // Enable interrupt prioritiesei(); // It's like GIE = 1 to enable all interruptsINTCONbits.GIEL = 1; // Enable LOW priority interrupt//INTCONbits.GIEH = 1; // Enable HIGH priority interruptIn UART_RX_Init:- Receive interrupt high priorityCode:// UART initializationvoid UART_RX_Init(void){IPR1bits.RCIP = 1; // Receive interrupt high priority//PIE1bits.TXIE = 1; // UART Transmit Interrupt Enable bit (no software clear needed)PIE1bits.RCIE = 1; // UART receive interrupt enabled}And you only have the high priority ISR, so it will never be called?Code:// High priority ISRvoid __interrupt(high_priority)HIGH_ISR_RCIF(void)First try only one way.Set only TX and send a string to computer every second, and check it works.If it doesn't work in that routine until you find the problem.Then set only Rx, send a string from the PC and store it in the PIC ram.Debug to ensure it getting received correctly.Again, if it doesn't work, keep trying until you solve the issue.Only when both are working, try to make them work together.Quote from: Lucky-Luka on March 21, 2021, 06:05:53 pmYes, PIC datasheets are usually very clear about this (As you quoted from the datasheet).Anyways, check the errata, there could be some surprises there.Your Tx routine should work:Code:void UART_send(uint8_t *c){// It is more efficient to use TXIF rather than polling TRMT.//while(!TXSTAbits.TRMT); // Wait until TSR register is empty (TMRT = 1 --> TSR empty)while(!PIR1bits.TXIF); // Wait until TXREG is emptyTXREG=*c;}Just in case the compiler optimizes to much, I would add a nop before checking the TXIF:Code:asm("nop");while(!PIR1bits.TXIF); // Wait until TXREG is emptYou can remove it later if you get it working. Don't think on optimizing the code yet.To start, I would disable all interrupts and try something like this:Code:// Send a string to the computerwhile(1){Delay(1000);// 1 second delayUART_send('T');UART_send('X');UART_send(' ');UART_send('T');UART_send('E');UART_send('S');UART_send('T');UART_send('\r');UART_send('\n');}That will ensure the TXIF is working as it should and you're not overwriting / overflowing the TXbuffer.And to test RX:Code:char RxBuffer;unsigned char RxPos=0;while(rxPos<32){if(got_data_bool){got_data_bool = 0;RxBuffer[RxPos++] = data ;}}while(1);// Set breakpoint hereThen debug it, send a string from the computer, when it fills up check that the 32 stored chars are correct (No missing or corrupted chars).

author: Lucky-Luka
author_rank: Unknown
timestamp: March 21, 2021, 08:03:57 pm
content: To address the other question of the original post, do you know how it is possible that using Realterm I can send strings and not only one ascii character at the time?

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 21, 2021, 10:29:21 pm
content: I use YAT (https://sourceforge.net/projects/y-a-terminal/), it's great for that.I always had a lot of trouble with Realterm.

author: westfw
author_rank: Super Contributor
timestamp: March 22, 2021, 01:48:17 am
content: QuoteHow do you think those are different?Don't most terminal emulators let you "paste" into them?

author: TomS_
author_rank: Frequent Contributor
timestamp: March 23, 2021, 06:39:36 am
content: A string is just an array of characters. You paste it into your terminal, it queues them up to be transmitted one after the other (usually in a continuous stream), your PIC receives them and echoes them back.The PIC and the terminal software have no particular concept of a string. All they do is send and receive bytes, whether you supply them one at a time or in a chunk doesn't matter.

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 23, 2021, 01:59:15 pm
content: I know it's not correct, but given the context, I perfectly understood the meaning of "sending a string".Sending data trought the serial port without any delay between characters.This is very important to ensure the receiving device is capable at handling the data at max speed .A 1MHz MCU could handle 1Mbit UART if you send a char every 100mS.But when you send 10 together ... buffer overflow for sure.So the pic receives{H}{E}{L}{L}{O}Instead{H}...{E}............{L}......{L}.........{O}

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 31, 2021, 01:06:12 pm
content: pic18 family has indirect addressing, they have few instrucciones over the classic pic16 to add better support for high levels languages like C.I've used them a lot in C, with code optimization it was fairly good