From c25693e14cfbae38baf502786a9ef53b573937b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Mon, 18 Jan 2016 15:51:02 +0100 Subject: [PATCH] add SPI support (using interrupts) --- lib/spi.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/spi.h | 57 ++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 lib/spi.c create mode 100644 lib/spi.h diff --git a/lib/spi.c b/lib/spi.c new file mode 100644 index 0000000..81e8dbe --- /dev/null +++ b/lib/spi.c @@ -0,0 +1,157 @@ +/* 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 3 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, see . + * + */ +/* Copyright (c) 2015 King Kévin */ +/* This library handles the Serial Peripheral Interface (SPI) + * it uses the SPI port and can but used with or without interrupt (non-block or blocking) + */ +#include // Standard Integer Types +#include // General utilities +#include // Boolean + +#include // AVR device-specific IO definitions +#include // Interrupts +#include // Power Management and Sleep Modes + +#include // SPI configuration + +volatile uint8_t* spi_b = NULL; // the byte address to transmit/receive +volatile size_t spi_i = NULL; // how many remaining bytes to transmit + +/* receive SPI byte and transmit next on previous transmit completion when transfer is interrupt based (non-blocking) */ +ISR(SPI_STC_vect) +{ /* SPI transfer complete interrupt */ + *spi_b = SPDR; // save received byte + spi_i--; // decrement remaining bytes to transmit/receive + if (spi_i==0) { // no remaining bytes to transmit/receive + SPI_PORT |= (1<=128) { + SPSR &= ~(1<=64) { + SPSR |= (1<=32) { + SPSR |= (1<=16) { + SPSR &= ~(1<=8) { + SPSR |= (1<=4) { + SPSR &= ~(1< for bytes + * the read bytes are saved back in + * this function returns only when communication finished + */ +void spi_transfer_blocking(uint8_t* data, size_t length) +{ + if ((data==NULL) || (length==0)) { // verify is there is data to transmit + return; + } + SPCR &= ~(1< for bytes + * the read bytes are saved back in + * global interrupts are required to be enabled + * the function returns immediatly, while data is transfered + * to ensure the transfer is complete, use spi_transfer_wait() + * if data is already being transfered it will idle until the last transfer is completed + */ +void spi_transfer_nonblocking(uint8_t* data, size_t length) +{ + if ((data==NULL) || (length==0)) { // verify is there is data to transfer + return; + } + spi_transfer_wait(NULL, 0); // wait for transfer to complete + spi_b = data; // save data pointer + spi_i = length; // save length pointer + SPCR |= (1< for bytes + * the read bytes are saved back in + * global interrupts are required to be enabled + * the function returns when all the data is transfered + * while the data is transfered it goes into idle mode + * if is NULL or is 0 it just ensures the previous transfer is complete + */ +void spi_transfer_wait(uint8_t* data, size_t length) +{ + // wait until the previous transfer is finished + while (spi_i>0) { + // go to sleep and wait for next interrupt (SPI will interrupt a one point) + set_sleep_mode(SLEEP_MODE_IDLE); + sleep_mode(); + } + if (data != NULL && length!=0) { // verify is there is data to transfer + spi_transfer_nonblocking(data, length); // start new transfer + spi_transfer_wait(NULL, 0); // wait for transfer to complete + } +} diff --git a/lib/spi.h b/lib/spi.h new file mode 100644 index 0000000..13160f1 --- /dev/null +++ b/lib/spi.h @@ -0,0 +1,57 @@ +/* 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 3 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, see . + * + */ +/* Copyright (c) 2015 King Kévin */ +/* This library handles the Serial Peripheral Interface (SPI) */ + +/* SPI pins */ +#define SPI_PORT PORTB +#define SPI_DDR DDRB +#define SPI_PIN PINB +#define SCK_IO PB5 +#define MISO_IO PB4 +#define MOSI_IO PB3 +#define SS_IO PB2 + +/* SCK frequency divider (F_osc/, with within 2-128) */ +#define SCK_DIV 16 + +/* initialize SPI */ +void spi_init(void); +/* receive SPI byte and transmit next on previous transmit completion when transfer is interrupt based (non-blocking) */ +ISR(SPI_STC_vect); +/* transmit and receive data over SPI + * transmits than receives each byte from for bytes + * the read bytes are saved back in + * this function returns only when communication finished + */ +void spi_transfer_blocking(uint8_t* data, size_t length); +/* transmit and receive data over SPI + * transmits than receives each byte from for bytes + * the read bytes are saved back in + * global interrupts are required to be enabled + * the function returns immediatly, while data is transfered + * to ensure the transfer is complete, use spi_transfer_wait() + * if data is already being transfered it will idle until the last transfer is completed + */ +void spi_transfer_nonblocking(uint8_t* data, size_t length); +/* transmit and receive data over SPI + * transmits than receives each byte from for bytes + * the read bytes are saved back in + * global interrupts are required to be enabled + * the function returns when all the data is transfered + * while the data is transfered it goes into idle mode + * if is NULL or is 0 it just ensures the previous transfer is complete + */ +void spi_transfer_wait(uint8_t* data, size_t length);