Last active
February 24, 2017 22:26
-
-
Save ircmaxell/6ff5cea15357aaf4186c6c03488d31f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "pins_arduino.h" | |
#include "SPI_USART.h" | |
uint8_t SPIUsartClass::ss[SPIUSART_COUNT]; | |
void SPIUsartClass::begin(uint8_t _usart, uint8_t _ss) { | |
if (_usart > SPIUSART_COUNT) { | |
return; | |
} | |
ss[_usart] = _ss; | |
digitalWrite(ss[_usart], HIGH); | |
pinMode(ss[_usart], OUTPUT); | |
#define SPIUSART_INIT_CASE(_n) \ | |
UBRR ## _n = 0; \ | |
UCSR ## _n ## A = _BV(TXC ## _n); \ | |
UCSR ## _n ## C = _BV(UMSEL ## _n ## 0) | _BV(UMSEL ## _n ## 1); \ | |
UCSR ## _n ## B = _BV(TXEN ## _n) | _BV(RXEN ## _n); | |
SPIUSART_SWITCH(_usart, SPIUSART_INIT_CASE); | |
SPIUsart.beginTransaction(_usart, SPIUsartSettings()); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _SPIUSART_H_INCLUDED | |
#define _SPIUSART_H_INCLUDED | |
#include <Arduino.h> | |
#include <avr/pgmspace.h> | |
#include <SPI.h> | |
#define SPIUSART_SET_BIT(_dest, _bit) _dest |= _BV(_bit) | |
#define SPIUSART_CLEAR_BIT(_dest, _bit) _dest &= ~_BV(_bit) | |
#if defined(UBRR3) | |
#define SPIUSART0 0 | |
#define SPIUSART1 1 | |
#define SPIUSART2 2 | |
#define SPIUSART3 3 | |
#define SPIUSART_COUNT 4 | |
#define SPIUSART_SWITCH(_v, _c) switch(_v) { \ | |
case 0: \ | |
_c(0); \ | |
break; \ | |
case 1: \ | |
_c(1); \ | |
break; \ | |
case 2: \ | |
_c(2); \ | |
break; \ | |
case 3: \ | |
_c(3); \ | |
break; \ | |
} | |
#elif defined(UBRR2) | |
#define SPIUSART0 0 | |
#define SPIUSART1 1 | |
#define SPIUSART2 2 | |
#define SPIUSART_COUNT 3 | |
#define SPIUSART_SWITCH(_v, _c) switch(_v) { \ | |
case 0: \ | |
_c(0); \ | |
break; \ | |
case 1: \ | |
_c(1); \ | |
break; \ | |
case 2: \ | |
_c(2); \ | |
break; \ | |
} | |
#elif defined(UBRR1) | |
#define SPIUSART0 0 | |
#define SPIUSART1 1 | |
#define SPIUSART_COUNT 2 | |
#define SPIUSART_SWITCH(_v, _c) switch(_v) { \ | |
case 0: \ | |
_c(0); \ | |
break; \ | |
case 1: \ | |
_c(1); \ | |
break; \ | |
} | |
#elif defined(UBRR0) | |
#define SPIUSART0 0 | |
#define SPIUSART_COUNT 1 | |
#define SPIUSART_SWITCH(_v, _c) switch(_v) { \ | |
case 0: \ | |
_c(0); \ | |
break; \ | |
} | |
#else | |
#define SPIUSART_COUNT 0 | |
#define SPIUSART_SWITCH(_v, _c) {} | |
#endif | |
#define SPIUSART_UCSRnC_MASK (_BV(UDORD0) | _BV(UCPOL0) | _BV(UCPHA0)) | |
class SPIUsartSettings { | |
public: | |
SPIUsartSettings() { | |
SPIUsartSettings(4000000, MSBFIRST, SPI_MODE0); | |
} | |
SPIUsartSettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { | |
ubbr_value = (F_CPU / (2 * clock)) - 1; | |
if (clock > F_CPU / 2) { | |
ubbr_value = 0; // clamp to max | |
} | |
ucsrc_or_mask = 0; | |
if (bitOrder == LSBFIRST) { | |
ucsrc_or_mask |= _BV(UDORD0); | |
} | |
switch (dataMode) { | |
case SPI_MODE0: | |
break; // all pins are cleared | |
case SPI_MODE1: | |
ucsrc_or_mask |= _BV(UCPHA0); | |
break; | |
case SPI_MODE2: | |
ucsrc_or_mask |= _BV(UCPOL0); | |
break; | |
case SPI_MODE3: | |
ucsrc_or_mask |= _BV(UCPOL0) | _BV(UCPHA0); | |
break; | |
} | |
} | |
private: | |
uint8_t ucsrc_or_mask = 0; | |
uint16_t ubbr_value = 0; | |
friend class SPIUsartClass; | |
}; | |
class SPIUsartClass { | |
public: | |
inline uint8_t transfer(uint8_t); | |
inline uint8_t transfer(uint8_t, uint8_t); | |
inline uint8_t transfer16(uint8_t _usart, uint16_t _value) { | |
uint16_t result = _value; | |
SPIUsartClass::transferRev(_usart, &result, sizeof(result)); | |
return result; | |
} | |
inline static void transfer(uint8_t, void*, size_t); | |
inline static void transferRev(uint8_t, void*, size_t); | |
inline static void beginTransaction(uint8_t _usart, SPIUsartSettings settings) { | |
#define SPIUSART_BEGIN_TRANSACTION_CASE(_n) \ | |
UCSR ## _n ## C = (UCSR ## _n ## C & SPIUSART_UCSRnC_MASK) | settings.ucsrc_or_mask; \ | |
UBRR ## _n = settings.ubbr_value; | |
SPIUSART_SWITCH(_usart, SPIUSART_BEGIN_TRANSACTION_CASE); | |
} | |
inline static void endTransaction(uint8_t _usart) { | |
} | |
static void begin(uint8_t, uint8_t); // SS | |
static void end(uint8_t); | |
private: | |
static uint8_t ss[SPIUSART_COUNT]; | |
static inline uint8_t transfer_raw(uint8_t, uint8_t); | |
}; | |
extern SPIUsartClass SPIUsart; | |
inline uint8_t SPIUsartClass::transfer(uint8_t _usart, uint8_t _data) { | |
uint8_t val; | |
digitalWrite(SPIUsartClass::ss[_usart], LOW); | |
val = SPIUsartClass::transfer_raw(_usart, _data); | |
digitalWrite(SPIUsartClass::ss[_usart], HIGH); | |
return val; | |
} | |
inline void SPIUsartClass::transfer(uint8_t _usart, void *buf, size_t count) { | |
register uint8_t *p = (uint8_t *) buf; | |
digitalWrite(SPIUsartClass::ss[_usart], LOW); | |
// duff's device | |
register size_t n = (count + 7) / 8; | |
switch (count % 8) { | |
do { | |
case 0: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 7: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 6: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 5: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 4: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 3: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 2: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
case 1: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p++; | |
} while (--n > 0); | |
} | |
digitalWrite(SPIUsartClass::ss[_usart], HIGH); | |
} | |
inline void SPIUsartClass::transferRev(uint8_t _usart, void *buf, size_t count) { | |
register uint8_t *p = (uint8_t *) buf + count - 1; | |
digitalWrite(SPIUsartClass::ss[_usart], LOW); | |
// duff's device | |
register size_t n = (count + 7) / 8; | |
switch (count % 8) { | |
do { | |
case 0: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 7: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 6: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 5: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 4: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 3: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 2: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
case 1: | |
*p = SPIUsartClass::transfer_raw(_usart, *p); | |
p--; | |
} while (--n > 0); | |
} | |
digitalWrite(SPIUsartClass::ss[_usart], HIGH); | |
} | |
inline uint8_t SPIUsartClass::transfer_raw(uint8_t _usart, uint8_t _data) { | |
#define SPIUSART_TRANSFER_RAW_CASE(_n) \ | |
UDR ## _n = _data; \ | |
asm volatile("nop"); \ | |
loop_until_bit_is_set(UCSR ## _n ## A, RXC ## _n); \ | |
return UDR ## _n; | |
SPIUSART_SWITCH(_usart, SPIUSART_TRANSFER_RAW_CASE); | |
return 0; | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "SPI_USART.h" | |
#include <Arduino.h> | |
void setup() { | |
SPIUsart.begin(SPIUSART0, 5); | |
pinMode(13, OUTPUT); | |
digitalWrite(13, LOW); | |
SPIUsart.transfer16(SPIUSART0, ((B10101010 << 8) | (B01010101))); | |
delay(200); | |
SPIUsart.transfer16(SPIUSART0, ((B10101010) | (B01010101 << 8))); | |
delay(200); | |
} | |
void loop() { | |
uint32_t i; | |
SPIUsart.beginTransaction(SPIUSART0, SPIUsartSettings()); | |
for (i = 0; i < (1u<<15); i++) { | |
SPIUsart.transfer16(SPIUSART0, (uint16_t) i); | |
} | |
SPIUsart.endTransaction(SPIUSART0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment