Subversion Repositories Code-Repo

Rev

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

#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
    }
}