Rev 215 | Go to most recent revision | Blame | Last modification | View Log | RSS feed
#include <xc.h>
#include <plib.h>
#include "defines.h"
#include "SPI1.h"
static SPI1_DATA *spi_data_ptr;
void SPI1_Init(SPI1_DATA *data, void (*rx_callback)(char)) {
spi_data_ptr = data;
spi_data_ptr->buffer_out_ind = 0;
spi_data_ptr->buffer_out_len = 0;
spi_data_ptr->rx_callback = rx_callback;
INTDisableInterrupts();
// Note: FIFO enhanced buffer depth is 4/8/16 for 32/16/8 bit widths
// Alternative Configuration:
// The third value is the SPI bitrate which is 1/2 the frequency of the
// desired clock frequency. Thus 40Mhz / (20Mhz / 2) = 4.
// Note: SPI_OPEN_TBE_NOT_FULL should only be used at >10Mhz speeds
// SpiChnOpen(SPI_CHANNEL1, SPI_OPEN_MSTEN | SPI_OPEN_ENHBUF | SPI_OPEN_TBE_NOT_FULL | SPI_OPEN_RBF_NOT_EMPTY, 4);
// INTSetVectorPriority(INT_SPI_1_VECTOR, INT_PRIORITY_LEVEL_6);
// INTSetVectorSubPriority(INT_SPI_1_VECTOR, INT_SUB_PRIORITY_LEVEL_1);
// INTClearFlag(INT_SPI1E);
// INTClearFlag(INT_SPI1TX);
// INTClearFlag(INT_SPI1RX);
// FSCK = FPB / (2 * (SPIxBRG + 1))
IEC0CLR = 0x03800000; // Disable all SPI interrupts
SPI1CON = 0; // Stops and resets the SPI1.
int tmp = SPI1BUF; // Clears the receive buffer
IFS0CLR = 0x03800000; // Clear any existing event
IPC5CLR = 0x1F000000; // Clear the priority
IPC5SET = 0x19000000; // Set IPL=6, Subpriority 1
SPI1BRG = 0x1; // Use FPB/4 clock frequency
SPI1STATCLR = 0x40; // Clear the Overflow
#ifndef SPI_WRITE_ONLY
IEC0SET = 0x01800000; // Enable RX and Error interrupts
#endif
// Enhanced buffer, SPI on, 8 bits transfer, SMP=1, Master mode
// SPIxTXIF set on buffer empty, SPIxRXIF set on buffer not empty
SPI1CON = 0x18225;
INTEnableInterrupts();
}
int SPI1_Write(char *array, int length, void (*tx_callback)(void)) {
spi_data_ptr->tx_callback = tx_callback;
if (length > SPI1_BUFFER_OUT_SIZE)
return 0;
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 = length-1;
int i;
for (i = 0; i < length; i++) {
spi_data_ptr->buffer_out[i] = array[i];
}
IEC0SET = 0x02000000; // Enable TX interrupt
return 1;
}
void __ISR(_SPI_1_VECTOR, ipl6) __SPI_1_Interrupt_Handler(void) {
#ifndef SPI_WRITE_ONLY
// Process SPI1 error flag
if (IFS0bits.SPI1EIF) {
// Clear the receive overflow bit if it is set
if (SPI1STATbits.SPIROV) {
SPI1STATbits.SPIROV = 0;
}
IFS0CLR = 0x00800000; // Clear the error flag
}
// Process SPI1 receive flag
if (IFS0bits.SPI1RXIF) {
int i;
// Read the data received from the last transfer
int rxBufferCount = SPI1STATbits.RXBUFELM;
for (i = 0; i < rxBufferCount; i++) {
char c = SPI1BUF;
// Call the RX callback function on the received data
if (spi_data_ptr->rx_callback != NULL)
(*spi_data_ptr->rx_callback)(c);
}
IFS0CLR = 0x01000000; // Clear the RX flag
}
#endif
// Process SPI1 transmit flag
if (IFS0bits.SPI1TXIF && IEC0bits.SPI1TXIE) {
int i;
// Disable the transmit interrupt if all data has been sent
if (spi_data_ptr->buffer_out_len == 0) {
IEC0CLR=0x02000000;
if (spi_data_ptr->tx_callback != NULL)
(*spi_data_ptr->tx_callback)();
} else {
// Start transmitting the data in the buffer
int txBufferFree = 16 - SPI1STATbits.TXBUFELM;
if (spi_data_ptr->buffer_out_len > txBufferFree) {
for (i = 0; i < txBufferFree; i++) {
SPI1BUF = 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++) {
SPI1BUF = spi_data_ptr->buffer_out[spi_data_ptr->buffer_out_ind];
spi_data_ptr->buffer_out_ind--;
}
spi_data_ptr->buffer_out_len = 0;
}
}
IFS0CLR = 0x02000000; // Clear the TX flag
}
}