Blame | Last modification | View Log | RSS feed
#include <xc.h>
#include <plib.h>
#include "defines.h"
#include "SPI4.h"
static SPI4_DATA *spi_data_ptr;
void SPI4_Init(SPI4_DATA *data) {
spi_data_ptr = data;
spi_data_ptr->buffer_out_ind = 0;
spi_data_ptr->buffer_out_len = 0;
spi_data_ptr->buffer_in_ind = 0;
spi_data_ptr->buffer_in_len = 0;
spi_data_ptr->write_blank = 0;
INTDisableInterrupts();
// Note: FIFO enhanced buffer depth is 4/8/16 for 32/16/8 bit widths
// FSCK = FPB / (2 * (SPIxBRG + 1))
IEC1CLR = 0x00000700; // Disable all SPI interrupts
SPI4CON = 0; // Stops and resets the SPI4.
int tmp = SPI4BUF; // Clears the receive buffer
IFS1CLR = 0x00000700; // Clear any existing event
IPC8CLR = 0x0000001F; // Clear the priority
IPC8SET = 0x0000001A; // Set IPL=6, Subpriority 2
SPI4BRG = 0x4; // Use FPB/10 clock frequency
SPI4STATCLR = 0x40; // Clear the Overflow
IEC1SET = 0x00000300; // Enable RX and Error interrupts
// Enhanced buffer, SPI on, 8 bits transfer, SMP=1, Master mode
// SPIxTXIF set on buffer empty, SPIxRXIF set on buffer not empty
SPI4CON = 0x18225;
INTEnableInterrupts();
}
int SPI4_Read(int length, void (*rx_callback)(char, char *)) {
spi_data_ptr->rx_callback = rx_callback;
// Ensure that the receiving buffer is large enough
if (length > SPI4_BUFFER_IN_SIZE)
return 0;
// Ensure that no previous transactions are in progress
if (spi_data_ptr->buffer_in_len != 0)
return 0;
spi_data_ptr->write_blank = 1;
spi_data_ptr->buffer_in_len = length;
spi_data_ptr->buffer_in_ind = 0;
SPI4_Write(NULL, length, NULL);
return 1;
}
int SPI4_Write(char *array, int length, void (*tx_callback)(void)) {
spi_data_ptr->tx_callback = tx_callback;
// We only care about the transmit length if we are sending data
if (length > SPI4_BUFFER_OUT_SIZE && !spi_data_ptr->write_blank)
return 0;
// Ensure that no previous transactions are in progress
if (spi_data_ptr->buffer_out_len != 0)
return 0;
// Put the data to send into the outbound buffer
spi_data_ptr->buffer_out_len = length;
spi_data_ptr->buffer_out_ind = 0;
// Copy only if we are actually going to transmit data
if (!spi_data_ptr->write_blank) {
int i;
for (i = 0; i < length; i++) {
spi_data_ptr->buffer_out[i] = array[i];
}
}
IEC1SET = 0x00000400; // Enable TX interrupt
return 1;
}
void __ISR(_SPI_4_VECTOR, ipl6) __SPI_4_Interrupt_Handler(void) {
// Process SPI4 error flag
if (IFS1bits.SPI4EIF) {
// Clear the receive overflow bit if it is set
if (SPI4STATbits.SPIROV) {
SPI4STATbits.SPIROV = 0;
}
IFS1CLR = 0x00000100; // Clear the error flag
}
// Process SPI4 receive flag
if (IFS1bits.SPI4RXIF) {
int i;
// Read the data received from the last transfer
int rxBufferCount = SPI4STATbits.RXBUFELM;
for (i = 0; i < rxBufferCount; i++) {
char c = SPI4BUF;
// Put the received data into the buffer
if (spi_data_ptr->buffer_in_len != 0) {
spi_data_ptr->buffer_in[spi_data_ptr->buffer_in_ind] = c;
spi_data_ptr->buffer_in_ind++;
// If done acquiring requested length, reset
if (spi_data_ptr->buffer_in_ind == spi_data_ptr->buffer_in_len) {
// Call the RX callback function on the received data
if (spi_data_ptr->rx_callback != NULL)
(*spi_data_ptr->rx_callback)(spi_data_ptr->buffer_in_len, spi_data_ptr->buffer_in);
spi_data_ptr->buffer_in_len = 0;
}
}
}
IFS1CLR = 0x00000200; // Clear the RX flag
}
// Process SPI4 transmit flag
if (IFS1bits.SPI4TXIF && IEC1bits.SPI4TXIE) {
int i;
// Disable the transmit interrupt if all data has been sent
if (spi_data_ptr->buffer_out_len == 0) {
IEC1CLR=0x00000400;
spi_data_ptr->write_blank = 0;
// Call the TX callback function at end of transmission
if (spi_data_ptr->tx_callback != NULL)
(*spi_data_ptr->tx_callback)();
} else {
// Start transmitting the data in the buffer
int txBufferFree = 16 - SPI4STATbits.TXBUFELM;
if (spi_data_ptr->buffer_out_len > txBufferFree) {
for (i = 0; i < txBufferFree; i++) {
if (spi_data_ptr->write_blank) {
SPI4BUF = 0x00;
} else {
SPI4BUF = spi_data_ptr->buffer_out[spi_data_ptr->buffer_out_ind];
spi_data_ptr->buffer_out_ind++;
}
}
spi_data_ptr->buffer_out_len -= txBufferFree;
} else {
for (i = 0; i < spi_data_ptr->buffer_out_len; i++) {
if (spi_data_ptr->write_blank) {
SPI4BUF = 0x00;
} else {
SPI4BUF = spi_data_ptr->buffer_out[spi_data_ptr->buffer_out_ind];
spi_data_ptr->buffer_out_ind++;
}
}
spi_data_ptr->buffer_out_len = 0;
}
}
IFS1CLR = 0x00000400; // Clear the TX flag
}
}