Subversion Repositories Code-Repo

Rev

Rev 201 | 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(unsigned char *array, unsigned int count, void (*tx_callback)(void)) {
    spi_data_ptr->tx_callback = tx_callback;

    if (count > SPI1_BUFFER_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 = count;
    spi_data_ptr->buffer_out_ind = count-1;
    int i;
    for (i = 0; i < count; 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) {
        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
    }
}