/* * spi.c * * Copyright 2014 Edward V. Emelianov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "main.h" #include "spi.h" #include "hardware_ini.h" // Rx/Tx buffer volatile uint8_t SPI_TxBuffer[SPI_BUFFERSIZE]; volatile uint8_t SPI_RxBuffer[SPI_BUFFERSIZE]; #ifndef SPI_USE_DMA volatile uint8_t SPI_RxIndex = 0; // omit first byte volatile uint8_t SPI_TxIndex = 0; volatile uint8_t SPI_datalen = 0; #endif volatile uint8_t SPI_EOT_FLAG = 1; // end of transmission flag, set by interrupt uint32_t Current_SPI = SPI1; // this is SPI interface which would b /** * Set current SPI to given value */ void switch_SPI(uint32_t SPI){ Current_SPI = SPI; } void SPI_init(){ switch(Current_SPI){ case SPI1: SPI1_init(); break; case SPI2: SPI2_init(); break; default: return; // error } } //uint32_t read_end; // read timeout /** * Write data to current SPI * @param data - buffer with data * @param len - buffer length (<= DMA_BUFFERSIZE) * @return 0 in case of error (or 1 in case of success) */ uint8_t write_SPI(uint8_t *data, uint8_t len){ //DBG("Write SPI.."); //return 1; uint8_t i; uint32_t tend = Timer + 10; // we will wait for end of previous transmission not more than 10ms //DBG("check\n"); while(!SPI_EOT_FLAG && Timer < tend); // wait for previous DMA interrupt if(!SPI_EOT_FLAG){ DBG("SPI error: no EOT flag!\n"); return 0; // error: there's no receiver??? } if(len > SPI_BUFFERSIZE) len = SPI_BUFFERSIZE; SPI_EOT_FLAG = 0; //DBG("OK\n"); //read_end = Timer + 100; // we will wait for end of previous transmission not more than 0.1s for(i = 0; i < len; i++) SPI_TxBuffer[i] = data[i]; #ifdef SPI_USE_DMA DMA_Cmd(SPIx_TX_DMA_STREAM, ENABLE); #else // !SPI_USE_DMA SPI_RxIndex = 0; SPI_TxIndex = 0; SPI_datalen = len; // set length of data to transmit // start transmission - enable interrupts SPI_CR2(Current_SPI) |= SPI_CR2_TXEIE | SPI_CR2_RXNEIE; //spi_enable_rx_buffer_not_empty_interrupt(SPI1); spi_enable_tx_buffer_empty_interrupt(SPI1); // Enable the SPI peripheral spi_enable(Current_SPI); #endif // SPI_USE_DMA return 1; } /** * read data from SPI * @param data - buffer to which data will be copied * @param len - length of waiting data * @return buffer with data or NULL */ uint8_t *read_SPI(uint8_t *data, uint8_t len){ //DBG("read SPI.. "); //return NULL; uint8_t i; uint32_t tend = Timer + 100; // we will wait for end of previous transmission not more than 0.1s //DBG("check\n"); while((!SPI_EOT_FLAG || len != SPI_RxIndex) && Timer < tend); if(len != SPI_RxIndex){ //DBG("SPI error: bad data length\n"); return NULL; } //DBG("OK\n"); for(i = 0; i < len; i++){ data[i] = SPI_RxBuffer[i]; //print_int(SPI_RxBuffer[i], usb_send); } //read_end = 0; // clear timeout: it mean that now we shouldn't wait any data return data; } /** * Check SPI read complete * @return reading status: * SPI_NO_DATA - data isn't ready yet * SPI_DATA_READY - all OK, we can read buffer * SPI_READ_ERROR - there have been error in data receiving * SPI_read_status check_SPI(){ if(!read_end) return SPI_NO_DATA; // there's nothing to read if(!SPI_EOT_FLAG){ if(Timer > read_end){// read timeout read_end = 0; return SPI_READ_ERROR; // timeout }else return SPI_NO_DATA; } return SPI_DATA_READY; // all OK: timeout haven't been reached yet } */ // SPI interrupt void spi_isr(uint32_t spi){ // RX not empty if(SPI_SR(spi) & SPI_SR_RXNE){ if(SPI_RxIndex < SPI_datalen){ // we haven't receive all data yet // Receive Transaction data SPI_RxBuffer[SPI_RxIndex++] = SPI_DR(spi); }else{ // disable RXNE interrupt & turn off SPI spi_disable_rx_buffer_not_empty_interrupt(spi); spi_disable(spi); } } // TX empty if(SPI_SR(spi) & SPI_SR_TXE){ if(SPI_TxIndex < SPI_datalen){ // buffer still not sent fully // Send Transaction data SPI_DR(spi) = SPI_TxBuffer[SPI_TxIndex++]; }else{ // disable TXE interrupt + set EOT flag spi_disable_tx_buffer_empty_interrupt(spi); SPI_EOT_FLAG = 1; } } SPI_SR(spi) = 0; // clear all interrupt flags } // interrupts for SPI1 & SPI2 void spi1_isr(){ spi_isr(SPI1); } void spi2_isr(){ spi_isr(SPI2); }