/* * spi.c * * Copyright 2016 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 "ports_definition.h" #include "spi.h" // global variables for sending big buffer static U16 sendbuflen = 0; static U8 *sendbuf = NULL, *inbuff = NULL; /* * SPI registers * SPI_CR1 (page 271): | LSBFIRST | SPE | BR[2:0] | MSTR | CPOL | CPHA | * BR: xxx - f/2^{xxx+1} * 01111100 * SPI_CR2 (page 272): | BDM | BDOE | CRCEN | CRCNEXT | - | RXONLY | SSM | SSI | * 00000000 * SPI_ICR (page 273): | TXIE | RXIE | ERRIE | WKIE | - | - | - | - | * SPI_SR (page 274): | BSY | OVR | MODF | CRCERR | WKUP | - | TXE | RXNE | * set it to zero before send new byte */ void spi_init(){ // pins config: MISO is pullup in, MOSI & SCK are pp out PORT(SPI_PORT, DDR) |= SPI_MOSI_PIN | SPI_SCK_PIN; PORT(SPI_PORT, CR1) |= SPI_MOSI_PIN | SPI_SCK_PIN | SPI_MISO_PIN; // setup line: f/256, enable, master SPI_CR1 = SPI_CR1_SPE | SPI_CR1_BRMASK | SPI_CR1_MSTR; //SPI_CR1 = SPI_CR1_SPE | (SPI_CR1_BRMASK&0x10) | SPI_CR1_MSTR; SPI_CR2 = 0; } /** * static routine waiting SPI free */ static void spi_wait(){ while(!(SPI_SR & SPI_SR_TXE)) while(SPI_SR & SPI_SR_BSY); } /** * send given data buffer * WARNING! Buffer should have livetime at least while !spi_buf_sent() * set _get == 1 to put received data into the same buffer */ void spi_send_buffer(U8 *buff, U16 len, U8 *inb){ inbuff = inb; sendbuflen = len; sendbuf = buff; spi_wait(); SPI_DR = *sendbuf; // interrupts: RXNE SPI_ICR = SPI_ICR_RXIE; } /** * send next byte from sendbuf (called by interrupt routine) */ void spi_send_next(){ if(!sendbuf) return; if(inbuff){ *inbuff++ = SPI_DR; } if(--sendbuflen == 0){ sendbuf = NULL; SPI_ICR = 0; return; } SPI_DR = *(++sendbuf); } /** * blocking send 1 byte & return ansver */ U8 spi_send_byte(U8 data){ spi_wait(); SPI_ICR = 0; SPI_DR = data; while(!(SPI_SR & SPI_SR_RXNE)); return SPI_DR; } void spi_send_buffer_blocking(U8 *buff, U16 len, U8 *inb){ U16 i; U8 r; for(i = 0; i < len; ++i){ r = spi_send_byte(buff[i]); if(inb) inb[i] = r; } } /** * return 1 if there's no data in queue to send */ U8 spi_buf_sent(){ if(!sendbuf) return 1; else return 0; }