Subversion Repositories Code-Repo

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <xc.h>
#include "main.h"
#include "UART.h"

static UART_DATA *data_ptr;

void UART_Init(UART_DATA *data) {
    data_ptr = data;

    APFCON0bits.RXDTSEL = 1;    // Change RX from RB5 to RC5
    APFCON0bits.TXCKSEL = 1;    // Change TX from RB7 to RC4
    UART_RX_TRIS = 1;
    UART_TX_TRIS = 0;

    SPBRG = 16;                 // Set baud rate to 115200 @ 32MHz
    BAUDCONbits.BRG16 = 0;      // 8-bit baud rate generator
    TXSTAbits.BRGH = 1;         // High baud rate select

    TXSTAbits.SYNC = 0;         // Async operation
    RCSTAbits.CREN = 1;         // Enable reception module
    TXSTAbits.TXEN = 1;         // Enable transmission module
    RCSTAbits.SPEN = 1;         // Enable EUSART module

    PIE1bits.RCIE = 1;          // UART RX interrupt starts enabled
    PIE1bits.TXIE = 0;          // UART TX interrupt starts disabled

    // Initialize local variables
    data_ptr->buffer_in_read_ind = 0;
    data_ptr->buffer_in_write_ind = 0;
    data_ptr->buffer_in_len = 0;
    data_ptr->buffer_out_ind = 0;
    data_ptr->buffer_out_len = 0;
}

void UART_TX_Interrupt_Handler(void) {
    // Send more data when transmit buffer is empty
    if (data_ptr->buffer_out_ind != data_ptr->buffer_out_len) {
        TXREG = data_ptr->buffer_out[data_ptr->buffer_out_ind];
        data_ptr->buffer_out_ind++;
    } else {
        // Stop processing TX interrupts if there is no more data to send
        while (!TXSTAbits.TRMT);
        PIE1bits.TXIE = 0;
        data_ptr->buffer_out_ind = 0;
        data_ptr->buffer_out_len = 0;
    }
}

void UART_RX_Interrupt_Handler(void) {
    char c = RCREG;

    // Read received data into buffer
    data_ptr->buffer_in[data_ptr->buffer_in_write_ind] = c;
    if (data_ptr->buffer_in_write_ind == UART_BUFFER_SIZE - 1) {
        data_ptr->buffer_in_write_ind = 0;
    } else {
        data_ptr->buffer_in_write_ind++;
    }

    // Increment read counter to keep only the latest data
    if (data_ptr->buffer_in_len < UART_BUFFER_SIZE) {
        data_ptr->buffer_in_len++;
    } else {
        if (data_ptr->buffer_in_read_ind == UART_BUFFER_SIZE - 1) {
            data_ptr->buffer_in_read_ind = 0;
        } else {
            data_ptr->buffer_in_read_ind++;
        }
    }

    // Reset receiver module on overrun error
    if (RCSTAbits.OERR == 1) {
        RCSTAbits.CREN = 0;
        RCSTAbits.CREN = 1;
    }
}

void UART_Write(char *data, char length) {
    // Ensure that no transmission is currently running
    while (PIE1bits.TXIE);

    data_ptr->buffer_out_len = length;
    data_ptr->buffer_out_ind = 0;
    for (char i = 0; i < length; i++) {
        data_ptr->buffer_out[i] = data[i];
    }

    // Start transmission
    PIE1bits.TXIE = 1;
}

char UART_Read(char *buffer) {
    PIE1bits.RCIE = 0; // Disable receiver interrupt
    char length = data_ptr->buffer_in_len;
    for (char i = 0; i < length; i++) {
        buffer[i] = data_ptr->buffer_in[data_ptr->buffer_in_read_ind];
        if (data_ptr->buffer_in_read_ind == UART_BUFFER_SIZE - 1) {
            data_ptr->buffer_in_read_ind = 0;
        } else {
            data_ptr->buffer_in_read_ind++;
        }
    }
    data_ptr->buffer_in_len -= length;
    PIE1bits.RCIE = 1; // Re-enable receiver interrupt
    return length;
}