From 8433b4dcc4318f77fef5114f38411b64b26ca293 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Thu, 22 May 2025 00:00:24 -0400 Subject: [PATCH 1/8] add pic18 ltt uart driver --- include/uart.h | 41 ++++++++++++++ pic18f26k83/uart.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 include/uart.h create mode 100644 pic18f26k83/uart.c diff --git a/include/uart.h b/include/uart.h new file mode 100644 index 0000000..7b96d2e --- /dev/null +++ b/include/uart.h @@ -0,0 +1,41 @@ +#ifndef UART_H_ +#define UART_H_ + +#include +#include + +/* + * Initialize UART module. Set up rx and tx buffers, set up module, + * and enable the requisite interrupts + */ +void uart_init(void); + +/* + * A lot like transmitting a single byte, except there are multiple bytes. tx does + * not need to be null terminated, that's why we have the len parameter + * + * tx: pointer to an array of bytes to send + * len: the number of bytes that should be sent from that array + */ +void uart_transmit_buffer(uint8_t *tx, uint8_t len); + +/* + * returns true if there's a byte waiting to be read from the UART module + */ +bool uart_byte_available(void); + +/* + * pops a byte from the receive buffer and returns it. Don't call this + * function unless uart_byte_available is returning true. Don't call this + * function from an interrupt context. + */ +uint8_t uart_read_byte(void); + +/* + * handler for all UART1 module interrputs. That is, PIR3:U1IF, U1EIF, U1TXIF, and U1RXIF + * this function clears the bits in PIR3 that it handles. + */ +void uart_interrupt_handler(void); + +#endif /* UART_H */ + diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c new file mode 100644 index 0000000..5175e9a --- /dev/null +++ b/pic18f26k83/uart.c @@ -0,0 +1,138 @@ +#include + +#include "uart.h" +#include "canlib.h" +#include "canlib/util/safe_ring_buffer.h" + +// safe ring buffers for sending and receiving +static srb_ctx_t rx_buffer; +static srb_ctx_t tx_buffer; + +// memory pools to use for those srbs. 100 is a completely arbitrary number +uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; + +void uart_init(void) +{ + TRISB3 = 1; + TRISB2 = 1; + ANSELB3 = 0; + ANSELB2 = 0; + // set RX pin location + U1RXPPS = (0b001 << 3) | // port B + (0b011); // pin 30 + // set CTS pin location + U1CTSPPS = (0b001 << 3) | // port B + (0b010); // pin 2 + + TRISB4 = 0; + TRISB1 = 0; + // Set B4 to TX + RB4PPS = 0b010011; // UART1 TX + // Set B1 to RTS + RB1PPS = 0b010101; // UART1 RTS + + // enable flow control. + U1CON2bits.FLO = 0b10; + // low speed + U1CON0bits.BRGS = 0; + // don't autodetect baudrate + U1CON0bits.ABDEN = 0; + // normal mode (8 bit, no parity, no 9th bit) + U1CON0bits.MODE = 0; + // enable transmit + U1CON0bits.TXEN = 1; + // enable receive + U1CON0bits.RXEN = 1; + + // keep running on overflow, never stop receiving + U1CON2bits.RUNOVF = 1; + + // baud rate stuff, divide by 25 to get 115200 baud + U1BRGL = 25; + U1BRGH = 0; + + // we are go for UART + U1CON1bits.ON = 1; + + // initialize the rx and tx buffers + srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); + srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); + + // enable receive interrupt + IPR3bits.U1RXIP = 1; + PIE3bits.U1RXIE = 1; + // Do not enable transmit interrupt, that interrupt enable signals that + // there is data to be sent, which at init time is not true +} + +void uart_transmit_buffer(uint8_t *tx, uint8_t len) +{ + // just call uart_transmit_byte with each byte they want us to send + while (len--) + { + srb_push(&tx_buffer, tx); + tx++; + }\ + // If the module isn't enabled, give it a byte to send and enable it + if (PIE3bits.U1TXIE == 0) + { + srb_pop(&tx_buffer, &tx); + U1TXB = tx; + U1CON0bits.TXEN = 1; + // also enable the interrupt for when it's ready to send more data + PIE3bits.U1TXIE = 1; + } +} + +bool uart_byte_available(void) +{ + return !srb_is_empty(&rx_buffer); +} + +uint8_t uart_read_byte(void) +{ + uint8_t rcv; + srb_pop(&rx_buffer, &rcv); + return rcv; +} + +void uart_interrupt_handler(void) +{ + if (PIR3bits.U1TXIF) + { + // check if there are any bytes we still want to transmit + if (!srb_is_empty(&tx_buffer)) + { + // if so, transmit them + uint8_t tx; + srb_pop(&tx_buffer, &tx); + U1TXB = tx; + } + else + { + // If we have no data to send, disable this interrupt + PIE3bits.U1TXIE = 0; + // if not, disable the TX part of the uart module so that TXIF + // isn't triggered again and so that we reenable the module on + // the next call to uart_transmit_byte + U1CON0bits.TXEN = 0; + } + PIR3bits.U1TXIF = 0; + } + else if (PIR3bits.U1RXIF) + { + // we received a byte, need to push into RX buffer and return + uint8_t rcv = U1RXB; + srb_push(&rx_buffer, &rcv); + PIR3bits.U1RXIF = 0; + } + else if (PIR3bits.U1EIF) + { + // Some sort of error, ignore for now (TODO?) + PIR3bits.U1EIF = 0; + } + else if (PIR3bits.U1IF) + { + PIR3bits.U1IF = 0; + } +} From e8bc2ba024d1b56fec894752f673db703800c053 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Wed, 28 May 2025 19:11:07 -0400 Subject: [PATCH 2/8] removed pps init, added bool controlled flow control and dynamic baud rate --- pic18f26k83/uart.c | 59 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index 5175e9a..c3bbe1d 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -1,9 +1,12 @@ #include +#include +#include #include "uart.h" #include "canlib.h" #include "canlib/util/safe_ring_buffer.h" + // safe ring buffers for sending and receiving static srb_ctx_t rx_buffer; static srb_ctx_t tx_buffer; @@ -11,28 +14,30 @@ static srb_ctx_t tx_buffer; // memory pools to use for those srbs. 100 is a completely arbitrary number uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; -void uart_init(void) -{ - TRISB3 = 1; - TRISB2 = 1; - ANSELB3 = 0; - ANSELB2 = 0; - // set RX pin location - U1RXPPS = (0b001 << 3) | // port B - (0b011); // pin 30 - // set CTS pin location - U1CTSPPS = (0b001 << 3) | // port B - (0b010); // pin 2 - - TRISB4 = 0; - TRISB1 = 0; - // Set B4 to TX - RB4PPS = 0b010011; // UART1 TX - // Set B1 to RTS - RB1PPS = 0b010101; // UART1 RTS - - // enable flow control. - U1CON2bits.FLO = 0b10; +void uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) + + +// TRISB3 = 1; +// TRISB2 = 1; +// ANSELB3 = 0; +// ANSELB2 = 0; +// // set RX pin location +// U1RXPPS = (0b001 << 3) | // port B +// (0b011); // pin 30 +// // set CTS pin location +// U1CTSPPS = (0b001 << 3) | // port B +// (0b010); // pin 2 +// +// TRISB4 = 0; +// TRISB1 = 0; +// // Set B4 to TX +// RB4PPS = 0b010011; // UART1 TX +// // Set B1 to RTS +// RB1PPS = 0b010101; // UART1 RTS + + // bool controlled flow control. + U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; + // low speed U1CON0bits.BRGS = 0; // don't autodetect baudrate @@ -47,9 +52,13 @@ void uart_init(void) // keep running on overflow, never stop receiving U1CON2bits.RUNOVF = 1; - // baud rate stuff, divide by 25 to get 115200 baud - U1BRGL = 25; - U1BRGH = 0; + // dynamic baud rate (478) + uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; + + uint16_t brg = (fosc / (divisor * baud_rate)) - 1; + U1BRGH = (brg >> 8) & 0xFF; + U1BRGL = brg & 0xFF; + // we are go for UART U1CON1bits.ON = 1; From 4a1aea698290802004d24725f88acae276adaf3f Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Wed, 28 May 2025 23:57:58 -0400 Subject: [PATCH 3/8] added param checks and updated .h --- include/uart.h | 3 +- pic18f26k83/uart.c | 128 +++++++++++++++++++++------------------------ 2 files changed, 62 insertions(+), 69 deletions(-) diff --git a/include/uart.h b/include/uart.h index 7b96d2e..2374f6a 100644 --- a/include/uart.h +++ b/include/uart.h @@ -3,12 +3,13 @@ #include #include +#include "common.h" /* * Initialize UART module. Set up rx and tx buffers, set up module, * and enable the requisite interrupts */ -void uart_init(void); +w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control); /* * A lot like transmitting a single byte, except there are multiple bytes. tx does diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index c3bbe1d..66b67d1 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -5,6 +5,7 @@ #include "uart.h" #include "canlib.h" #include "canlib/util/safe_ring_buffer.h" +#include "common.h" // safe ring buffers for sending and receiving @@ -14,9 +15,8 @@ static srb_ctx_t tx_buffer; // memory pools to use for those srbs. 100 is a completely arbitrary number uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; -void uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) +w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) - // TRISB3 = 1; // TRISB2 = 1; // ANSELB3 = 0; @@ -35,56 +35,61 @@ void uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) // // Set B1 to RTS // RB1PPS = 0b010101; // UART1 RTS - // bool controlled flow control. - U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; - - // low speed - U1CON0bits.BRGS = 0; - // don't autodetect baudrate - U1CON0bits.ABDEN = 0; - // normal mode (8 bit, no parity, no 9th bit) - U1CON0bits.MODE = 0; - // enable transmit - U1CON0bits.TXEN = 1; - // enable receive - U1CON0bits.RXEN = 1; - - // keep running on overflow, never stop receiving - U1CON2bits.RUNOVF = 1; - - // dynamic baud rate (478) - uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; - - uint16_t brg = (fosc / (divisor * baud_rate)) - 1; - U1BRGH = (brg >> 8) & 0xFF; - U1BRGL = brg & 0xFF; - - - // we are go for UART - U1CON1bits.ON = 1; - - // initialize the rx and tx buffers - srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); - srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); - - // enable receive interrupt - IPR3bits.U1RXIP = 1; - PIE3bits.U1RXIE = 1; - // Do not enable transmit interrupt, that interrupt enable signals that - // there is data to be sent, which at init time is not true +//only 12 or 48 MHz for pic +if (fosc != 12000000UL && fosc != 48000000UL) return W_INVALID_PARAM; + +// bool controlled flow control. +U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; + +// low speed +U1CON0bits.BRGS = 0; +uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; + +//checks if baud rate param within range +if (baud_rate == 0 || baud_rate > (fosc / divisor)) return W_INVALID_PARAM; + +// don't autodetect baudrate +U1CON0bits.ABDEN = 0; +// normal mode (8 bit, no parity, no 9th bit) +U1CON0bits.MODE = 0; +// enable transmit +U1CON0bits.TXEN = 1; +// enable receive +U1CON0bits.RXEN = 1; + +// keep running on overflow, never stop receiving +U1CON2bits.RUNOVF = 1; + +// dynamic baud rate +uint16_t brg = (fosc / (divisor * baud_rate)) - 1; +U1BRGH = (brg >> 8) & 0xFF; +U1BRGL = brg & 0xFF; + + +// we are go for UART +U1CON1bits.ON = 1; + +// initialize the rx and tx buffers +srb_init(&rx_buffer, rx_buffer_pool, sizeof (rx_buffer_pool), sizeof (uint8_t)); +srb_init(&tx_buffer, tx_buffer_pool, sizeof (tx_buffer_pool), sizeof (uint8_t)); + +// enable receive interrupt +IPR3bits.U1RXIP = 1; +PIE3bits.U1RXIE = 1; +// Do not enable transmit interrupt, that interrupt enable signals that +// there is data to be sent, which at init time is not true + +return W_SUCCESS; } -void uart_transmit_buffer(uint8_t *tx, uint8_t len) -{ +void uart_transmit_buffer(uint8_t *tx, uint8_t len) { // just call uart_transmit_byte with each byte they want us to send - while (len--) - { + while (len--) { srb_push(&tx_buffer, tx); tx++; - }\ + } // If the module isn't enabled, give it a byte to send and enable it - if (PIE3bits.U1TXIE == 0) - { + if (PIE3bits.U1TXIE == 0) { srb_pop(&tx_buffer, &tx); U1TXB = tx; U1CON0bits.TXEN = 1; @@ -93,32 +98,25 @@ void uart_transmit_buffer(uint8_t *tx, uint8_t len) } } -bool uart_byte_available(void) -{ +bool uart_byte_available(void) { return !srb_is_empty(&rx_buffer); } -uint8_t uart_read_byte(void) -{ +uint8_t uart_read_byte(void) { uint8_t rcv; srb_pop(&rx_buffer, &rcv); return rcv; } -void uart_interrupt_handler(void) -{ - if (PIR3bits.U1TXIF) - { +void uart_interrupt_handler(void) { + if (PIR3bits.U1TXIF) { // check if there are any bytes we still want to transmit - if (!srb_is_empty(&tx_buffer)) - { + if (!srb_is_empty(&tx_buffer)) { // if so, transmit them uint8_t tx; srb_pop(&tx_buffer, &tx); U1TXB = tx; - } - else - { + } else { // If we have no data to send, disable this interrupt PIE3bits.U1TXIE = 0; // if not, disable the TX part of the uart module so that TXIF @@ -127,21 +125,15 @@ void uart_interrupt_handler(void) U1CON0bits.TXEN = 0; } PIR3bits.U1TXIF = 0; - } - else if (PIR3bits.U1RXIF) - { + } else if (PIR3bits.U1RXIF) { // we received a byte, need to push into RX buffer and return uint8_t rcv = U1RXB; srb_push(&rx_buffer, &rcv); PIR3bits.U1RXIF = 0; - } - else if (PIR3bits.U1EIF) - { + } else if (PIR3bits.U1EIF) { // Some sort of error, ignore for now (TODO?) PIR3bits.U1EIF = 0; - } - else if (PIR3bits.U1IF) - { + } else if (PIR3bits.U1IF) { PIR3bits.U1IF = 0; } } From 5e99f232607cadbaf25a4d5dfa789a36a03e65c5 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Thu, 29 May 2025 00:05:54 -0400 Subject: [PATCH 4/8] fixed clang format --- include/uart.h | 8 +++---- pic18f26k83/uart.c | 54 +++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/uart.h b/include/uart.h index 2374f6a..0ffc5df 100644 --- a/include/uart.h +++ b/include/uart.h @@ -1,9 +1,9 @@ #ifndef UART_H_ -#define UART_H_ +#define UART_H_ -#include -#include #include "common.h" +#include +#include /* * Initialize UART module. Set up rx and tx buffers, set up module, @@ -38,5 +38,5 @@ uint8_t uart_read_byte(void); */ void uart_interrupt_handler(void); -#endif /* UART_H */ +#endif /* UART_H */ diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index 66b67d1..19d42dd 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -2,11 +2,10 @@ #include #include -#include "uart.h" #include "canlib.h" #include "canlib/util/safe_ring_buffer.h" #include "common.h" - +#include "uart.h" // safe ring buffers for sending and receiving static srb_ctx_t rx_buffer; @@ -17,26 +16,26 @@ uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) -// TRISB3 = 1; -// TRISB2 = 1; -// ANSELB3 = 0; -// ANSELB2 = 0; -// // set RX pin location -// U1RXPPS = (0b001 << 3) | // port B -// (0b011); // pin 30 -// // set CTS pin location -// U1CTSPPS = (0b001 << 3) | // port B -// (0b010); // pin 2 -// -// TRISB4 = 0; -// TRISB1 = 0; -// // Set B4 to TX -// RB4PPS = 0b010011; // UART1 TX -// // Set B1 to RTS -// RB1PPS = 0b010101; // UART1 RTS - -//only 12 or 48 MHz for pic -if (fosc != 12000000UL && fosc != 48000000UL) return W_INVALID_PARAM; + // TRISB3 = 1; + // TRISB2 = 1; + // ANSELB3 = 0; + // ANSELB2 = 0; + // // set RX pin location + // U1RXPPS = (0b001 << 3) | // port B + // (0b011); // pin 30 + // // set CTS pin location + // U1CTSPPS = (0b001 << 3) | // port B + // (0b010); // pin 2 + // + // TRISB4 = 0; + // TRISB1 = 0; + // // Set B4 to TX + // RB4PPS = 0b010011; // UART1 TX + // // Set B1 to RTS + // RB1PPS = 0b010101; // UART1 RTS + + // only 12 or 48 MHz for pic + if (fosc != 12000000UL && fosc != 48000000UL) return W_INVALID_PARAM; // bool controlled flow control. U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; @@ -45,8 +44,10 @@ U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; U1CON0bits.BRGS = 0; uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; -//checks if baud rate param within range -if (baud_rate == 0 || baud_rate > (fosc / divisor)) return W_INVALID_PARAM; +// checks if baud rate param within range +if (baud_rate == 0 || baud_rate > (fosc / divisor)) { + return W_INVALID_PARAM; +} // don't autodetect baudrate U1CON0bits.ABDEN = 0; @@ -65,13 +66,12 @@ uint16_t brg = (fosc / (divisor * baud_rate)) - 1; U1BRGH = (brg >> 8) & 0xFF; U1BRGL = brg & 0xFF; - // we are go for UART U1CON1bits.ON = 1; // initialize the rx and tx buffers -srb_init(&rx_buffer, rx_buffer_pool, sizeof (rx_buffer_pool), sizeof (uint8_t)); -srb_init(&tx_buffer, tx_buffer_pool, sizeof (tx_buffer_pool), sizeof (uint8_t)); +srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); +srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); // enable receive interrupt IPR3bits.U1RXIP = 1; From 9012f55b9a9266e9ae30dd779fd8dd28b96e5ced Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Thu, 29 May 2025 18:29:52 -0400 Subject: [PATCH 5/8] fix syntax and format --- include/uart.h | 9 ++-- pic18f26k83/uart.c | 101 ++++++++++++++++++--------------------------- 2 files changed, 46 insertions(+), 64 deletions(-) diff --git a/include/uart.h b/include/uart.h index 0ffc5df..104afb7 100644 --- a/include/uart.h +++ b/include/uart.h @@ -1,10 +1,11 @@ -#ifndef UART_H_ -#define UART_H_ +#ifndef ROCKETLIB_UART_H +#define ROCKETLIB_UART_H -#include "common.h" #include #include +#include "common.h" + /* * Initialize UART module. Set up rx and tx buffers, set up module, * and enable the requisite interrupts @@ -38,5 +39,5 @@ uint8_t uart_read_byte(void); */ void uart_interrupt_handler(void); -#endif /* UART_H */ +#endif /* ROCKETLIB_UART_H */ diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index 19d42dd..aaa6995 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -14,72 +14,53 @@ static srb_ctx_t tx_buffer; // memory pools to use for those srbs. 100 is a completely arbitrary number uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; -w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) - - // TRISB3 = 1; - // TRISB2 = 1; - // ANSELB3 = 0; - // ANSELB2 = 0; - // // set RX pin location - // U1RXPPS = (0b001 << 3) | // port B - // (0b011); // pin 30 - // // set CTS pin location - // U1CTSPPS = (0b001 << 3) | // port B - // (0b010); // pin 2 - // - // TRISB4 = 0; - // TRISB1 = 0; - // // Set B4 to TX - // RB4PPS = 0b010011; // UART1 TX - // // Set B1 to RTS - // RB1PPS = 0b010101; // UART1 RTS - +w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) { // only 12 or 48 MHz for pic if (fosc != 12000000UL && fosc != 48000000UL) return W_INVALID_PARAM; -// bool controlled flow control. -U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; + // bool controlled flow control. + U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; -// low speed -U1CON0bits.BRGS = 0; -uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; + // low speed + U1CON0bits.BRGS = 0; + uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; -// checks if baud rate param within range -if (baud_rate == 0 || baud_rate > (fosc / divisor)) { - return W_INVALID_PARAM; -} + // checks if baud rate param within range + if (baud_rate == 0 || baud_rate > (fosc / divisor)) { + return W_INVALID_PARAM; + } -// don't autodetect baudrate -U1CON0bits.ABDEN = 0; -// normal mode (8 bit, no parity, no 9th bit) -U1CON0bits.MODE = 0; -// enable transmit -U1CON0bits.TXEN = 1; -// enable receive -U1CON0bits.RXEN = 1; - -// keep running on overflow, never stop receiving -U1CON2bits.RUNOVF = 1; - -// dynamic baud rate -uint16_t brg = (fosc / (divisor * baud_rate)) - 1; -U1BRGH = (brg >> 8) & 0xFF; -U1BRGL = brg & 0xFF; - -// we are go for UART -U1CON1bits.ON = 1; - -// initialize the rx and tx buffers -srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); -srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); - -// enable receive interrupt -IPR3bits.U1RXIP = 1; -PIE3bits.U1RXIE = 1; -// Do not enable transmit interrupt, that interrupt enable signals that -// there is data to be sent, which at init time is not true - -return W_SUCCESS; + // don't autodetect baudrate + U1CON0bits.ABDEN = 0; + // normal mode (8 bit, no parity, no 9th bit) + U1CON0bits.MODE = 0; + // enable transmit + U1CON0bits.TXEN = 1; + // enable receive + U1CON0bits.RXEN = 1; + + // keep running on overflow, never stop receiving + U1CON2bits.RUNOVF = 1; + + // dynamic baud rate + uint16_t brg = (fosc / (divisor * baud_rate)) - 1; + U1BRGH = (brg >> 8) & 0xFF; + U1BRGL = brg & 0xFF; + + // we are go for UART + U1CON1bits.ON = 1; + + // initialize the rx and tx buffers + srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); + srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); + + // enable receive interrupt + IPR3bits.U1RXIP = 1; + PIE3bits.U1RXIE = 1; + // Do not enable transmit interrupt, that interrupt enable signals that + // there is data to be sent, which at init time is not true + + return W_SUCCESS; } void uart_transmit_buffer(uint8_t *tx, uint8_t len) { From 3b2ab1a0f79a719a5d56fb5549988b021a2d3fa4 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Thu, 29 May 2025 18:34:37 -0400 Subject: [PATCH 6/8] fixed clang-format --- pic18f26k83/uart.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index aaa6995..4f35d71 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -16,7 +16,9 @@ uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) { // only 12 or 48 MHz for pic - if (fosc != 12000000UL && fosc != 48000000UL) return W_INVALID_PARAM; + if (fosc != 12000000UL && fosc != 48000000UL) { + return W_INVALID_PARAM; + } // bool controlled flow control. U1CON2bits.FLO = enable_flow_control ? 0b10 : 0b00; From f1d9a62f3a7c836ba6443c3cb1ed485a3eb1675e Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Tue, 17 Jun 2025 23:17:31 -0400 Subject: [PATCH 7/8] rough update based on pr review --- include/uart.h | 41 +++++++------ pic18f26k83/uart.c | 149 ++++++++++++++++++++++++++++----------------- 2 files changed, 116 insertions(+), 74 deletions(-) diff --git a/include/uart.h b/include/uart.h index 104afb7..f93ea6d 100644 --- a/include/uart.h +++ b/include/uart.h @@ -6,38 +6,41 @@ #include "common.h" -/* - * Initialize UART module. Set up rx and tx buffers, set up module, - * and enable the requisite interrupts - */ -w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control); /* - * A lot like transmitting a single byte, except there are multiple bytes. tx does - * not need to be null terminated, that's why we have the len parameter + * Initializes the UART1 module. * - * tx: pointer to an array of bytes to send - * len: the number of bytes that should be sent from that array + * baud_rate: Desired baud rate (e.g., 9600, 115200) + * fosc: Clock frequency (must be 12 MHz or 48 MHz) + * enable_flow_control: true to enable RTS flow control, false to disable + * + * Returns: W_SUCCESS if setup is successful, otherwise W_INVALID_PARAM */ -void uart_transmit_buffer(uint8_t *tx, uint8_t len); +w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control); /* - * returns true if there's a byte waiting to be read from the UART module + * Transmits a single byte over UART (blocking). + * + * waits until the transmit buffer is empty, then sends the byte. */ -bool uart_byte_available(void); +void uart_transmit_byte(uint8_t byte); +//void uart_transmit_buffer(uint8_t *tx, uint8_t len); /* - * pops a byte from the receive buffer and returns it. Don't call this - * function unless uart_byte_available is returning true. Don't call this - * function from an interrupt context. + * Interrupt handler for UART1. + * + * Handles RX and optional TX, + * and calls user-defined uart_rx_callback() on received bytes. */ -uint8_t uart_read_byte(void); +void uart_interrupt_handler(void); /* - * handler for all UART1 module interrputs. That is, PIR3:U1IF, U1EIF, U1TXIF, and U1RXIF - * this function clears the bits in PIR3 that it handles. + * Callback function called when a byte is received. + * + * To use: define your own implementation of this function in your code. + * If not defined by the user, the weak default will be used (does nothing). */ -void uart_interrupt_handler(void); +void uart_rx_callback(uint8_t byte); //override this, optional #endif /* ROCKETLIB_UART_H */ diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index 4f35d71..7644b19 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -1,18 +1,24 @@ -#include +//#include +#include #include #include -#include "canlib.h" -#include "canlib/util/safe_ring_buffer.h" +//#include "canlib.h" //remove -> no canlib dependancy +//#include "canlib/util/safe_ring_buffer.h" #include "common.h" #include "uart.h" -// safe ring buffers for sending and receiving -static srb_ctx_t rx_buffer; -static srb_ctx_t tx_buffer; +// safe ring buffers for sending and receiving (DELETE) +//static srb_ctx_t rx_buffer; +//static srb_ctx_t tx_buffer; // memory pools to use for those srbs. 100 is a completely arbitrary number -uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; +//uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; + +//CALLBACK FXN HERE +__attribute__ ((weak)) void uart_rx_callback (uint8_t byte) { + //user override fxn +} w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) { // only 12 or 48 MHz for pic @@ -52,9 +58,9 @@ w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control // we are go for UART U1CON1bits.ON = 1; - // initialize the rx and tx buffers - srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); - srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); + // initialize the rx and tx buffers DONT USE BUFFER + //srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); + //srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); // enable receive interrupt IPR3bits.U1RXIP = 1; @@ -65,58 +71,91 @@ w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control return W_SUCCESS; } -void uart_transmit_buffer(uint8_t *tx, uint8_t len) { - // just call uart_transmit_byte with each byte they want us to send - while (len--) { - srb_push(&tx_buffer, tx); - tx++; - } - // If the module isn't enabled, give it a byte to send and enable it - if (PIE3bits.U1TXIE == 0) { - srb_pop(&tx_buffer, &tx); - U1TXB = tx; - U1CON0bits.TXEN = 1; - // also enable the interrupt for when it's ready to send more data - PIE3bits.U1TXIE = 1; - } -} - -bool uart_byte_available(void) { - return !srb_is_empty(&rx_buffer); -} - -uint8_t uart_read_byte(void) { - uint8_t rcv; - srb_pop(&rx_buffer, &rcv); - return rcv; +void uart_transmit_byte(uint8_t byte) { + while (!PIR3bits.U1TXIF); // blocking wait + U1TXB = byte; } +//void uart_transmit_buffer(uint8_t *tx, uint8_t len) { //Implement transmit buffer without canlib dependency +// //make into transmit byte fxn +////Make this into a uart transmit byte function +// // just call uart_transmit_byte with each byte they want us to send +// while (len--) { +// //srb_push(&tx_buffer, tx); +// tx++; +// } +// // If the module isn't enabled, give it a byte to send and enable it +// if (PIE3bits.U1TXIE == 0) { +// //delete +// //srb_pop(&tx_buffer, &tx); +// U1TXB = tx; +// U1CON0bits.TXEN = 1; +// // also enable the interrupt for when it's ready to send more data +// PIE3bits.U1TXIE = 1; +// } +//} +//DELETE +//bool uart_byte_available(void) { +// return !srb_is_empty(&rx_buffer); +//} +//DELETE +//uint8_t uart_read_byte(void) { + // uint8_t rcv; + // srb_pop(&rx_buffer, &rcv); + // return rcv; +//} void uart_interrupt_handler(void) { + //TX interrupt if (PIR3bits.U1TXIF) { - // check if there are any bytes we still want to transmit - if (!srb_is_empty(&tx_buffer)) { - // if so, transmit them - uint8_t tx; - srb_pop(&tx_buffer, &tx); - U1TXB = tx; - } else { - // If we have no data to send, disable this interrupt - PIE3bits.U1TXIE = 0; - // if not, disable the TX part of the uart module so that TXIF - // isn't triggered again and so that we reenable the module on - // the next call to uart_transmit_byte - U1CON0bits.TXEN = 0; - } PIR3bits.U1TXIF = 0; - } else if (PIR3bits.U1RXIF) { - // we received a byte, need to push into RX buffer and return - uint8_t rcv = U1RXB; - srb_push(&rx_buffer, &rcv); + } + + //RX interrupt + if (PIR3bits.U1RXIF) { PIR3bits.U1RXIF = 0; - } else if (PIR3bits.U1EIF) { - // Some sort of error, ignore for now (TODO?) + uint8_t rcv = U1RXB; + uart_rx_callback(rcv); // invoke user callback + } + + //UART error interrupt + //ignored for now + if (PIR3bits.U1EIF) { PIR3bits.U1EIF = 0; - } else if (PIR3bits.U1IF) { + // Optionally handle framing/parity/overflow errors + } + + //global UART interrupt + if (PIR3bits.U1IF) { PIR3bits.U1IF = 0; } } +//for receive, implement a callback option +//void uart_interrupt_handler(void) { +// if (PIR3bits.U1TXIF) { +// // check if there are any bytes we still want to transmit +// if (!srb_is_empty(&tx_buffer)) { +// // if so, transmit them +// uint8_t tx; +// srb_pop(&tx_buffer, &tx); +// U1TXB = tx; +// } else { +// // If we have no data to send, disable this interrupt +// PIE3bits.U1TXIE = 0; +// // if not, disable the TX part of the uart module so that TXIF +// // isn't triggered again and so that we reenable the module on +// // the next call to uart_transmit_byte +// U1CON0bits.TXEN = 0; +// } +// PIR3bits.U1TXIF = 0; +// } else if (PIR3bits.U1RXIF) { +// // we received a byte, need to push into RX buffer and return +// uint8_t rcv = U1RXB; +// srb_push(&rx_buffer, &rcv); +// PIR3bits.U1RXIF = 0; +// } else if (PIR3bits.U1EIF) { +// // Some sort of error, ignore for now (TODO?) +// PIR3bits.U1EIF = 0; +// } else if (PIR3bits.U1IF) { +// PIR3bits.U1IF = 0; +// } +//} From f14431b9e62354ebc9abf9b0d76d3141ee7c0536 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Mon, 23 Jun 2025 05:50:31 -0400 Subject: [PATCH 8/8] removed canlib dependancy etc --- include/uart.h | 11 +++-- pic18f26k83/uart.c | 110 +++++++++------------------------------------ 2 files changed, 25 insertions(+), 96 deletions(-) diff --git a/include/uart.h b/include/uart.h index f93ea6d..eba9d7f 100644 --- a/include/uart.h +++ b/include/uart.h @@ -6,7 +6,6 @@ #include "common.h" - /* * Initializes the UART1 module. * @@ -24,7 +23,7 @@ w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control * waits until the transmit buffer is empty, then sends the byte. */ void uart_transmit_byte(uint8_t byte); -//void uart_transmit_buffer(uint8_t *tx, uint8_t len); +// void uart_transmit_buffer(uint8_t *tx, uint8_t len); /* * Interrupt handler for UART1. @@ -35,12 +34,12 @@ void uart_transmit_byte(uint8_t byte); void uart_interrupt_handler(void); /* - * Callback function called when a byte is received. + * Internal callback function called when a byte is received via UART1. * - * To use: define your own implementation of this function in your code. - * If not defined by the user, the weak default will be used (does nothing). + * This is implemented in uart.c and currently echoes the received byte back. + * It is not intended to be overridden by user code due to MPLAB limitations. */ -void uart_rx_callback(uint8_t byte); //override this, optional +void uart_rx_callback(uint8_t byte); #endif /* ROCKETLIB_UART_H */ diff --git a/pic18f26k83/uart.c b/pic18f26k83/uart.c index 7644b19..1cddfe8 100644 --- a/pic18f26k83/uart.c +++ b/pic18f26k83/uart.c @@ -1,27 +1,18 @@ -//#include -#include #include #include +#include -//#include "canlib.h" //remove -> no canlib dependancy -//#include "canlib/util/safe_ring_buffer.h" #include "common.h" #include "uart.h" -// safe ring buffers for sending and receiving (DELETE) -//static srb_ctx_t rx_buffer; -//static srb_ctx_t tx_buffer; - -// memory pools to use for those srbs. 100 is a completely arbitrary number -//uint8_t rx_buffer_pool[100], tx_buffer_pool[100]; - -//CALLBACK FXN HERE -__attribute__ ((weak)) void uart_rx_callback (uint8_t byte) { - //user override fxn +void uart_rx_callback(uint8_t byte) { + uart_transmit_byte(byte); // echos back recieved byte } w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control) { - // only 12 or 48 MHz for pic + // make sure to Configure UART1 pins before running!!! + + // only 12 or 48 MHz support for pic if (fosc != 12000000UL && fosc != 48000000UL) { return W_INVALID_PARAM; } @@ -33,12 +24,12 @@ w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control U1CON0bits.BRGS = 0; uint32_t divisor = (U1CON0bits.BRGS == 1) ? 4 : 16; - // checks if baud rate param within range + // checks for valid baud rate if (baud_rate == 0 || baud_rate > (fosc / divisor)) { return W_INVALID_PARAM; } - // don't autodetect baudrate + // disable autodetect baudrate U1CON0bits.ABDEN = 0; // normal mode (8 bit, no parity, no 9th bit) U1CON0bits.MODE = 0; @@ -55,107 +46,46 @@ w_status_t uart_init(uint32_t baud_rate, uint32_t fosc, bool enable_flow_control U1BRGH = (brg >> 8) & 0xFF; U1BRGL = brg & 0xFF; - // we are go for UART + // enable UART module U1CON1bits.ON = 1; - // initialize the rx and tx buffers DONT USE BUFFER - //srb_init(&rx_buffer, rx_buffer_pool, sizeof(rx_buffer_pool), sizeof(uint8_t)); - //srb_init(&tx_buffer, tx_buffer_pool, sizeof(tx_buffer_pool), sizeof(uint8_t)); - // enable receive interrupt IPR3bits.U1RXIP = 1; PIE3bits.U1RXIE = 1; - // Do not enable transmit interrupt, that interrupt enable signals that - // there is data to be sent, which at init time is not true + + // do not enable TX interrupt initially; only needed when there's queued data return W_SUCCESS; } void uart_transmit_byte(uint8_t byte) { - while (!PIR3bits.U1TXIF); // blocking wait + while (!PIR3bits.U1TXIF) + ; // blocking wait U1TXB = byte; } -//void uart_transmit_buffer(uint8_t *tx, uint8_t len) { //Implement transmit buffer without canlib dependency -// //make into transmit byte fxn -////Make this into a uart transmit byte function -// // just call uart_transmit_byte with each byte they want us to send -// while (len--) { -// //srb_push(&tx_buffer, tx); -// tx++; -// } -// // If the module isn't enabled, give it a byte to send and enable it -// if (PIE3bits.U1TXIE == 0) { -// //delete -// //srb_pop(&tx_buffer, &tx); -// U1TXB = tx; -// U1CON0bits.TXEN = 1; -// // also enable the interrupt for when it's ready to send more data -// PIE3bits.U1TXIE = 1; -// } -//} -//DELETE -//bool uart_byte_available(void) { -// return !srb_is_empty(&rx_buffer); -//} -//DELETE -//uint8_t uart_read_byte(void) { - // uint8_t rcv; - // srb_pop(&rx_buffer, &rcv); - // return rcv; -//} void uart_interrupt_handler(void) { - //TX interrupt + // TX interrupt if (PIR3bits.U1TXIF) { PIR3bits.U1TXIF = 0; } - //RX interrupt + // RX interrupt if (PIR3bits.U1RXIF) { PIR3bits.U1RXIF = 0; uint8_t rcv = U1RXB; - uart_rx_callback(rcv); // invoke user callback + uart_rx_callback(rcv); // invoke user callback } - //UART error interrupt - //ignored for now + // UART error interrupt if (PIR3bits.U1EIF) { PIR3bits.U1EIF = 0; - // Optionally handle framing/parity/overflow errors + // optionally handle framing/parity/overflow errors } - //global UART interrupt + // global UART interrupt if (PIR3bits.U1IF) { PIR3bits.U1IF = 0; } } -//for receive, implement a callback option -//void uart_interrupt_handler(void) { -// if (PIR3bits.U1TXIF) { -// // check if there are any bytes we still want to transmit -// if (!srb_is_empty(&tx_buffer)) { -// // if so, transmit them -// uint8_t tx; -// srb_pop(&tx_buffer, &tx); -// U1TXB = tx; -// } else { -// // If we have no data to send, disable this interrupt -// PIE3bits.U1TXIE = 0; -// // if not, disable the TX part of the uart module so that TXIF -// // isn't triggered again and so that we reenable the module on -// // the next call to uart_transmit_byte -// U1CON0bits.TXEN = 0; -// } -// PIR3bits.U1TXIF = 0; -// } else if (PIR3bits.U1RXIF) { -// // we received a byte, need to push into RX buffer and return -// uint8_t rcv = U1RXB; -// srb_push(&rx_buffer, &rcv); -// PIR3bits.U1RXIF = 0; -// } else if (PIR3bits.U1EIF) { -// // Some sort of error, ignore for now (TODO?) -// PIR3bits.U1EIF = 0; -// } else if (PIR3bits.U1IF) { -// PIR3bits.U1IF = 0; -// } -//} +