Skip to content

Commit

Permalink
updated to latest arduino version with transaction support
Browse files Browse the repository at this point in the history
  • Loading branch information
ekettenburg committed Jun 23, 2015
1 parent 4e2f6ff commit 92c97e3
Show file tree
Hide file tree
Showing 3 changed files with 463 additions and 65 deletions.
211 changes: 173 additions & 38 deletions digistump-avr/libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2010 by Cristian Maglie <[email protected]>
* Copyright (c) 2010 by Cristian Maglie <[email protected]>
* Copyright (c) 2014 by Paul Stoffregen <[email protected]> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <[email protected]> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <[email protected]> (atomicity fixes)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
Expand All @@ -8,59 +11,191 @@
* published by the Free Software Foundation.
*/

#include "pins_arduino.h"
#include "SPI.h"

SPIClass SPI;

void SPIClass::begin() {
uint8_t SPIClass::initialized = 0;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPIClass::inTransactionFlag = 0;
#endif

// Set SS to high so a connected chip will be "deselected" by default
digitalWrite(SS, HIGH);

// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);
void SPIClass::begin()
{
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
if (!initialized) {
// Set SS to high so a connected chip will be "deselected" by default
uint8_t port = digitalPinToPort(SS);
uint8_t bit = digitalPinToBitMask(SS);
volatile uint8_t *reg = portModeRegister(port);

// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);
// if the SS pin is not already configured as an output
// then set it high (to enable the internal pull-up resistor)
if(!(*reg & bit)){
digitalWrite(SS, HIGH);
}

// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
}
// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);

// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);

void SPIClass::end() {
SPCR &= ~_BV(SPE);
// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
}
initialized++; // reference count
SREG = sreg;
}

void SPIClass::setBitOrder(uint8_t bitOrder)
{
if(bitOrder == LSBFIRST) {
SPCR |= _BV(DORD);
} else {
SPCR &= ~(_BV(DORD));
void SPIClass::end() {
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
// Decrease the reference counter
if (initialized)
initialized--;
// If there are no more references disable SPI
if (!initialized) {
SPCR &= ~_BV(SPE);
interruptMode = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
inTransactionFlag = 0;
#endif
}
SREG = sreg;
}

void SPIClass::setDataMode(uint8_t mode)
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif

void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
interruptMode = 2;
break;
}
interruptMask |= mask;
if (!interruptMode)
interruptMode = 1;
SREG = sreg;
}

void SPIClass::setClockDivider(uint8_t rate)
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
{
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
// Once in mode 2 we can't go back to 0 without a proper reference count
if (interruptMode == 2)
return;
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
break;
// this case can't be reached
}
interruptMask &= ~mask;
if (!interruptMask)
interruptMode = 0;
SREG = sreg;
}

Loading

0 comments on commit 92c97e3

Please sign in to comment.