0,0 → 1,155 |
#include <xc.h> |
#include <plib.h> |
#include "defines.h" |
#include "SPI1.h" |
|
static SPI1_DATA *data_ptr; |
static void (*callback_function)(void); |
|
void SPI1_Init(SPI1_DATA *data) { |
data_ptr = data; |
data_ptr->outBufferInd = 0; |
data_ptr->outBufferLen = 0; |
#ifndef SPI1_WRITE_ONLY |
data_ptr->inBufferInd = 0; |
data_ptr->inBufferLen = 0; |
#endif |
|
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 SPI1_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(); |
} |
|
#ifndef SPI1_WRITE_ONLY |
int SPI1_Read_Buffer(unsigned char *array, unsigned int count) { |
if (count > SPI1_BUFFER_SIZE) |
return 0; |
if (data_ptr->inBufferLen == 0) |
return 0; |
|
// Save previous interrupt state |
int prev = IEC0 & 0x03800000; |
// Temporarily disable interrupts |
IEC0CLR = 0x03800000; |
int ret = data_ptr->inBufferLen; |
int i; |
for (i = 0; i < count; i++) { |
array[i] = data_ptr->inBuffer[i]; |
} |
// Reset buffer pointers |
data_ptr->inBufferInd = 0; |
data_ptr->inBufferLen = 0; |
// Restore saved interrupt state |
IEC0SET = prev; |
// Return the number of valid bytes in the buffer |
return ret; |
} |
#endif |
|
int SPI1_Write(unsigned char *array, unsigned int count, void (*callback)(void)) { |
callback_function = callback; |
|
if (count > SPI1_BUFFER_SIZE) |
return 0; |
if (data_ptr->outBufferLen != 0) |
return 0; |
|
data_ptr->outBufferLen = count; |
data_ptr->outBufferInd = count-1; |
int i; |
for (i = 0; i < count; i++) { |
data_ptr->outBuffer[i] = array[i]; |
} |
IEC0SET = 0x02000000; // Enable TX interrupt |
return 1; |
} |
|
void __ISR(_SPI_1_VECTOR, ipl6) __SPI_1_Interrupt_Handler(void) { |
#ifndef SPI1_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; |
if (data_ptr->inBufferLen + rxBufferCount < SPI1_BUFFER_SIZE) { |
for (i = 0; i < rxBufferCount; i++) { |
data_ptr->inBuffer[data_ptr->inBufferInd] = SPI1BUF; |
data_ptr->inBufferInd++; |
data_ptr->inBufferLen++; |
} |
} else { |
// If buffer is full, discard data in enhanced buffer |
for (i = 0; i < rxBufferCount; i++) { |
int tmp = SPI1BUF; |
} |
} |
IFS0CLR = 0x01000000; // Clear the RX flag |
} |
#endif |
|
// Process SPI1 transmit flag |
if (IFS0bits.SPI1TXIF) { |
int i; |
// Disable the transmit interrupt if all data has been sent |
if (data_ptr->outBufferLen == 0) { |
IEC0CLR=0x02000000; |
if (callback_function != NULL) |
(*callback_function)(); |
} else { |
// Start transmitting the data in the buffer |
int txBufferFree = 16 - SPI1STATbits.TXBUFELM; |
if (data_ptr->outBufferLen > txBufferFree) { |
for (i = 0; i < txBufferFree; i++) { |
SPI1BUF = data_ptr->outBuffer[data_ptr->outBufferInd]; |
data_ptr->outBufferInd--; |
} |
data_ptr->outBufferLen -= txBufferFree; |
} else { |
for (i = 0; i < data_ptr->outBufferLen; i++) { |
SPI1BUF = data_ptr->outBuffer[data_ptr->outBufferInd]; |
data_ptr->outBufferInd--; |
} |
data_ptr->outBufferLen = 0; |
} |
} |
IFS0CLR = 0x02000000; // Clear the TX flag |
} |
} |