173 lines
4.8 KiB
C

/*
* spi.c
*
* Copyright 2014 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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);
}