Subversion Repositories Code-Repo

Rev

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

#include <xc.h>
#include <stdio.h>
#include <string.h>
#include "defines.h"
#include "base_SPI.h"
#include "base_UART.h"

static SPI_DATA *spi_data_p;

void SPI2_Init(SPI_DATA *data, char speed) {
    spi_data_p = data;

    // Set up SPI2 with specified pins
    RPINR22 = PPS_SPI2_CLK_IN; // SPI2 CLK Input
    PPS_SPI2_CLK_OUT = 11; // SPI2 CLK Output

#ifndef SPI2_WRITE_ONLY
    RPINR21 = PPS_SPI2_MISO; // SPI2 Data Input
    SPI_MISO_TRIS = 1; // SPI2 data in pin (MISO)
#endif
    
    SPI_CLK_TRIS = 0; // SPI2 clock pin
    PPS_SPI2_MOSI = 10; // SPI2 Data Output (MOSI)
    SPI_MOSI_TRIS = 0; // SPI2 data out pin (MOSI)

    SPI_SLAVE_SELECT_TRIS = 0; // SPI2 slave select
    SPI_SLAVE_SELECT_LAT = 1; // SPI2 SS high (Idle)

    SPI_RESET_TRIS = 0; // SPI2 reset
    SPI_RESET_LAT = 1; // SPI2 reset active low

    SPI_DC_SELECT_TRIS = 0; // SPI2 D/C select
    SPI_DC_SELECT_LAT = 0;

    SSP2STATbits.SMP = 0; // Input is sampled in the middle of data output time
    SSP2STATbits.CKE = 0; // Transmit occurs on transition from Idle to active clock state

    SSP2CON1bits.SSPM = speed;

    SSP2CON1bits.CKP = 1; // Idle state for clock is a high level
    SSP2CON1bits.SSPEN = 1; // Enable MSSP module

#ifdef SPI2_USE_INTERRUPT
    PIE3bits.SSP2IE = 1; // Enable MSSP2 interrupt
#else
    PIE3bits.SSP2IE = 0;
#endif

#ifndef SPI2_WRITE_ONLY
    spi_data_p->buffer_in_len = 0;
    spi_data_p->buffer_in_read_ind = 0;
    spi_data_p->buffer_in_write_ind = 0;
#endif
    spi_data_p->buffer_out_ind = 0;
    spi_data_p->buffer_out_len = 0;
}

void SPI2_Write(char *msg, unsigned int length) {
    unsigned int i = 0;
#ifdef SPI2_USE_INTERRUPT
    spi_data_p->buffer_out_len = length;
    spi_data_p->buffer_out_ind = 1;
    for (i = 0; i < length; i++) {
        spi_data_p->buffer_out[i] = msg[i];
    }
    SPI_SLAVE_SELECT_LAT = 0; // Bring SS line low
    SSP2BUF = spi_data_p->buffer_out[0]; // Transmit first byte
#else
    SPI_SLAVE_SELECT_LAT = 0;
    while (i != length) {
        SSP2BUF = msg[i];
        i++;
        while (!SSP2STATbits.BF);

#ifndef SPI2_WRITE_ONLY
        spi_data_p->buffer_in[spi_data_p->buffer_in_write_ind] = SSP2BUF;
        if (spi_data_p->buffer_in_write_ind == MAXSPIBUF - 1) {
            spi_data_p->buffer_in_write_ind = 0;
        } else {
            spi_data_p->buffer_in_write_ind++;
        }
        spi_data_p->buffer_in_len++;
#else
        // Read data in buffer to clear it
        char tmp = SSP2BUF;
#endif
    }
    SPI_SLAVE_SELECT_LAT = 1;
#endif
}

void SPI2_Write_Repeat(char c, unsigned int length) {
#ifdef SPI2_USE_INTERRUPT
    // TODO Implement interrupts for SPI2
#else
    unsigned int i = 0;
    SPI_SLAVE_SELECT_LAT = 0;
    while (i != length) {
        SSP2BUF = c;
        i++;
        while (!SSP2STATbits.BF);

#ifndef SPI2_WRITE_ONLY
        spi_data_p->buffer_in[spi_data_p->buffer_in_write_ind] = SSP2BUF;
        if (spi_data_p->buffer_in_write_ind == MAXSPIBUF - 1) {
            spi_data_p->buffer_in_write_ind = 0;
        } else {
            spi_data_p->buffer_in_write_ind++;
        }
        spi_data_p->buffer_in_len++;
#else
        // Read data in buffer to clear it
        char tmp = SSP2BUF;
#endif
    }
    SPI_SLAVE_SELECT_LAT = 1;
#endif
}

void SPI2_DMA_Init(void) {
    DMACON1bits.SSCON0 = 0;
    DMACON1bits.SSCON1 = 0; // DYLINTEN is software programmable

    DMACON1bits.TXINC = 1; // TXADDR is automatically incremented
    DMACON1bits.RXINC = 0; // RXADDR is not automatically incremented

    DMACON1bits.DUPLEX0 = 1;
    DMACON1bits.DUPLEX1 = 0; // Half-duplex mode, transmission only

    DMACON1bits.DLYINTEN = 0; // Interrupt is disabled

    DMACON2bits.DLYCYC = 0b0000; // Delay time of 1 cycle between bytes
    DMACON2bits.INTLVL = 0b0000; // Interrupt on transfer complete
}

void SPI2_DMA_Start(unsigned int length, void* TXADDR, void* RXADDR) {
    // Set length of message to transmit
    DMABCH = (char)(length-1 >> 8);
    DMABCL = (char)(length-1);

    // Set sourcing address
    TXADDRH = (char)((int)TXADDR >> 8);
    TXADDRL = (char)((int)TXADDR);

    // Set receiving address
    RXADDRH = (char)((int)RXADDR >> 8);
    RXADDRL = (char)((int)RXADDR);

    DMACON1bits.DMAEN = 1; // Start transmission
}

#ifndef SPI2_WRITE_ONLY
void SPI2_Recv_Interrupt_Handler() {
    char c;

    if (SSP2STATbits.BF) { // Check if data receive flag is set
        if (spi_data_p->buffer_in_len == MAXSPIBUF - 1) {
            char output[64];
            sprintf(output, "SPI2: (ERROR) buffer overflow\r\n");
            DBG_PRINT_SPI(output, strlen(output));
            c = SSP2BUF; // Read SSP2BUF to clear it
        } else {
            // Save received data into buffer
            spi_data_p->buffer_in[spi_data_p->buffer_in_write_ind] = SSP2BUF;
            if (spi_data_p->buffer_in_write_ind == MAXSPIBUF - 1) {
                spi_data_p->buffer_in_write_ind = 0;
            } else {
                spi_data_p->buffer_in_write_ind++;
            }
            spi_data_p->buffer_in_len++;

            // Put next byte in SSP2BUF for transmit
            if (spi_data_p->buffer_out_ind != spi_data_p->buffer_out_len) {
                SSP2BUF = spi_data_p->buffer_out[spi_data_p->buffer_out_ind];
                spi_data_p->buffer_out_ind++;
            } else {
                SPI_SLAVE_SELECT_LAT = 1; // Bring SS line high
                spi_data_p->buffer_out_ind = 0;
                spi_data_p->buffer_out_len = 0;
            }
        }
    }
}

void SPI2_Read(char length) {
#ifdef SPI2_USE_INTERRUPT
    spi_data_p->buffer_out_len = length;
    spi_data_p->buffer_out_ind = 1;
    for (char i = 0; i < length; i++) {
        spi_data_p->buffer_out[i] = 0x0;
    }
    SPI_SLAVE_SELECT_LAT = 0; // Bring SS line low
    SSP2BUF = spi_data_p->buffer_out[0]; // Transmit first byte
#else
    SPI_SLAVE_SELECT_LAT = 0;

    for (char i = 0; i < length; i++) {
        SSP2BUF = 0x0;
        while (!SSP2STATbits.BF);

        spi_data_p->buffer_in[spi_data_p->buffer_in_write_ind] = SSP2BUF;
        if (spi_data_p->buffer_in_write_ind == MAXSPIBUF - 1) {
            spi_data_p->buffer_in_write_ind = 0;
        } else {
            spi_data_p->buffer_in_write_ind++;
        }
        spi_data_p->buffer_in_len++;
    }
    SPI_SLAVE_SELECT_LAT = 1;
#endif
}

char SPI2_Buffer_Len() {
    return spi_data_p->buffer_in_len;
}

char SPI2_Read_Buffer(char* buffer) {
    char i = 0;
    while (spi_data_p->buffer_in_len != 0) {
        buffer[i] = spi_data_p->buffer_in[spi_data_p->buffer_in_read_ind];
        i++;
        if (spi_data_p->buffer_in_read_ind == MAXSPIBUF - 1) {
            spi_data_p->buffer_in_read_ind = 0;
        } else {
            spi_data_p->buffer_in_read_ind++;
        }
        spi_data_p->buffer_in_len--;
    }
    return i;
}
#endif