/* 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
}
}