/* 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 = 0; // 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 } }