Subversion Repositories Code-Repo

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
199 Kevin 1
#include <xc.h>
2
#include <plib.h>
3
#include "defines.h"
4
#include "SPI1.h"
5
 
201 Kevin 6
static SPI1_DATA *spi_data_ptr;
199 Kevin 7
 
8
void SPI1_Init(SPI1_DATA *data) {
201 Kevin 9
    spi_data_ptr = data;
10
    spi_data_ptr->outBufferInd = 0;
11
    spi_data_ptr->outBufferLen = 0;
199 Kevin 12
#ifndef SPI1_WRITE_ONLY
201 Kevin 13
    spi_data_ptr->inBufferInd = 0;
14
    spi_data_ptr->inBufferLen = 0;
199 Kevin 15
#endif
16
 
17
    INTDisableInterrupts();
18
 
19
    // Note: FIFO enhanced buffer depth is 4/8/16 for 32/16/8 bit widths
20
 
21
    // Alternative Configuration:
22
    // The third value is the SPI bitrate which is 1/2 the frequency of the
23
    //  desired clock frequency. Thus 40Mhz / (20Mhz / 2) = 4.
24
    // Note: SPI_OPEN_TBE_NOT_FULL should only be used at >10Mhz speeds
25
//    SpiChnOpen(SPI_CHANNEL1, SPI_OPEN_MSTEN | SPI_OPEN_ENHBUF | SPI_OPEN_TBE_NOT_FULL | SPI_OPEN_RBF_NOT_EMPTY, 4);
26
//    INTSetVectorPriority(INT_SPI_1_VECTOR, INT_PRIORITY_LEVEL_6);
27
//    INTSetVectorSubPriority(INT_SPI_1_VECTOR, INT_SUB_PRIORITY_LEVEL_1);
28
//    INTClearFlag(INT_SPI1E);
29
//    INTClearFlag(INT_SPI1TX);
30
//    INTClearFlag(INT_SPI1RX);
31
 
32
    // FSCK = FPB / (2 * (SPIxBRG + 1))
33
    IEC0CLR     = 0x03800000;   // Disable all SPI interrupts
34
    SPI1CON     = 0;            // Stops and resets the SPI1.
35
    int tmp     = SPI1BUF;      // Clears the receive buffer
36
    IFS0CLR     = 0x03800000;   // Clear any existing event
37
    IPC5CLR     = 0x1F000000;   // Clear the priority
38
    IPC5SET     = 0x19000000;   // Set IPL=6, Subpriority 1
39
    SPI1BRG     = 0x1;          // Use FPB/4 clock frequency
40
    SPI1STATCLR = 0x40;         // Clear the Overflow
41
#ifndef SPI1_WRITE_ONLY
42
    IEC0SET = 0x01800000;       // Enable RX and Error interrupts
43
#endif
44
    // Enhanced buffer, SPI on, 8 bits transfer, SMP=1, Master mode
45
    // SPIxTXIF set on buffer empty, SPIxRXIF set on buffer not empty
46
    SPI1CON     = 0x18225;
47
 
48
    INTEnableInterrupts();
49
}
50
 
51
#ifndef SPI1_WRITE_ONLY
52
int SPI1_Read_Buffer(unsigned char *array, unsigned int count) {
53
    if (count > SPI1_BUFFER_SIZE)
54
        return 0;
201 Kevin 55
    if (spi_data_ptr->inBufferLen == 0)
199 Kevin 56
        return 0;
57
 
58
    // Save previous interrupt state
59
    int prev = IEC0 & 0x03800000;
60
     // Temporarily disable interrupts
61
    IEC0CLR = 0x03800000;
201 Kevin 62
    int ret = spi_data_ptr->inBufferLen;
199 Kevin 63
    int i;
64
    for (i = 0; i < count; i++) {
201 Kevin 65
        array[i] = spi_data_ptr->inBuffer[i];
199 Kevin 66
    }
67
    // Reset buffer pointers
201 Kevin 68
    spi_data_ptr->inBufferInd = 0;
69
    spi_data_ptr->inBufferLen = 0;
199 Kevin 70
    // Restore saved interrupt state
71
    IEC0SET = prev;
72
    // Return the number of valid bytes in the buffer
73
    return ret;
74
}
75
#endif
76
 
77
int SPI1_Write(unsigned char *array, unsigned int count, void (*callback)(void)) {
201 Kevin 78
    spi_data_ptr->callback_function = callback;
199 Kevin 79
 
80
    if (count > SPI1_BUFFER_SIZE)
81
        return 0;
201 Kevin 82
    if (spi_data_ptr->outBufferLen != 0)
199 Kevin 83
        return 0;
84
 
201 Kevin 85
    spi_data_ptr->outBufferLen = count;
86
    spi_data_ptr->outBufferInd = count-1;
199 Kevin 87
    int i;
88
    for (i = 0; i < count; i++) {
201 Kevin 89
        spi_data_ptr->outBuffer[i] = array[i];
199 Kevin 90
    }
91
    IEC0SET = 0x02000000; // Enable TX interrupt
92
    return 1;
93
}
94
 
95
void __ISR(_SPI_1_VECTOR, ipl6) __SPI_1_Interrupt_Handler(void) {
96
#ifndef SPI1_WRITE_ONLY
97
    // Process SPI1 error flag
98
    if (IFS0bits.SPI1EIF) {
99
        // Clear the receive overflow bit if it is set
100
        if (SPI1STATbits.SPIROV) {
101
            SPI1STATbits.SPIROV = 0;
102
        }
103
        IFS0CLR = 0x00800000; // Clear the error flag
104
    }
105
 
106
    // Process SPI1 receive flag
107
    if (IFS0bits.SPI1RXIF) {
108
        int i;
109
        // Read the data received from the last transfer
110
        int rxBufferCount = SPI1STATbits.RXBUFELM;
201 Kevin 111
        if (spi_data_ptr->inBufferLen + rxBufferCount < SPI1_BUFFER_SIZE) {
199 Kevin 112
            for (i = 0; i < rxBufferCount; i++) {
201 Kevin 113
                spi_data_ptr->inBuffer[spi_data_ptr->inBufferInd] = SPI1BUF;
114
                spi_data_ptr->inBufferInd++;
115
                spi_data_ptr->inBufferLen++;
199 Kevin 116
            }
117
        } else {
118
            // If buffer is full, discard data in enhanced buffer
119
            for (i = 0; i < rxBufferCount; i++) {
120
                int tmp = SPI1BUF;
121
            }
122
        }
123
        IFS0CLR = 0x01000000; // Clear the RX flag
124
    }
125
#endif
126
 
127
    // Process SPI1 transmit flag
128
    if (IFS0bits.SPI1TXIF) {
129
        int i;
130
        // Disable the transmit interrupt if all data has been sent
201 Kevin 131
        if (spi_data_ptr->outBufferLen == 0) {
199 Kevin 132
            IEC0CLR=0x02000000;
201 Kevin 133
            if (spi_data_ptr->callback_function != NULL)
134
                (*spi_data_ptr->callback_function)();
199 Kevin 135
        } else {
136
            // Start transmitting the data in the buffer
137
            int txBufferFree = 16 - SPI1STATbits.TXBUFELM;
201 Kevin 138
            if (spi_data_ptr->outBufferLen > txBufferFree) {
199 Kevin 139
                for (i = 0; i < txBufferFree; i++) {
201 Kevin 140
                    SPI1BUF = spi_data_ptr->outBuffer[spi_data_ptr->outBufferInd];
141
                    spi_data_ptr->outBufferInd--;
199 Kevin 142
                }
201 Kevin 143
                spi_data_ptr->outBufferLen -= txBufferFree;
199 Kevin 144
            } else {
201 Kevin 145
                for (i = 0; i < spi_data_ptr->outBufferLen; i++) {
146
                    SPI1BUF = spi_data_ptr->outBuffer[spi_data_ptr->outBufferInd];
147
                    spi_data_ptr->outBufferInd--;
199 Kevin 148
                }
201 Kevin 149
                spi_data_ptr->outBufferLen = 0;
199 Kevin 150
            }
151
        }
152
        IFS0CLR = 0x02000000; // Clear the TX flag
153
    }
154
}