Files
MySensors/hardware/MySensors/samd/libraries/SPI/SPI.h
T
Thomas Mørch c62aca4125 Added ethernet module to local hardware instance, since we have to hack it a bit in order to move it to alternative SPI port
Removed Wire and SAMD_AnalogCorrection libraries from HW section, as we didn't change anything in those, so let's keep it to the standard ones

Modified SPI library, initializing extra SPI ports, also HW mux changes in the setup of individual SPI ports to match the GW setup

Added MyHWSAMD files so they are included in the core headers (MyConfig.h / MySensors.h)
2015-12-06 23:16:44 +01:00

156 lines
4.3 KiB
C++

/*
* SPI Master library for Arduino Zero.
* Copyright (c) 2015 Arduino LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED
#include <Arduino.h>
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()
// - usingInterrupt()
// - SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1
#define SPI_MODE0 0x02
#define SPI_MODE1 0x00
#define SPI_MODE2 0x03
#define SPI_MODE3 0x01
#if defined(__SAMD21G18A__)
// Even if not specified on the datasheet, the SAMD21G18A MCU
// doesn't operate correctly with clock dividers lower than 4.
// This allows a theoretical maximum SPI clock speed of 12Mhz
#define SPI_MIN_CLOCK_DIVIDER 4
// Other SAMD21xxxxx MCU may be affected as well
#else
#define SPI_MIN_CLOCK_DIVIDER 2
#endif
class SPISettings {
public:
SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {
if (__builtin_constant_p(clock)) {
init_AlwaysInline(clock, bitOrder, dataMode);
} else {
init_MightInline(clock, bitOrder, dataMode);
}
}
// Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }
private:
void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {
init_AlwaysInline(clock, bitOrder, dataMode);
}
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock);
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
switch (dataMode)
{
case SPI_MODE0:
this->dataMode = SERCOM_SPI_MODE_0; break;
case SPI_MODE1:
this->dataMode = SERCOM_SPI_MODE_1; break;
case SPI_MODE2:
this->dataMode = SERCOM_SPI_MODE_2; break;
case SPI_MODE3:
this->dataMode = SERCOM_SPI_MODE_3; break;
default:
this->dataMode = SERCOM_SPI_MODE_0; break;
}
}
uint32_t clockFreq;
SercomSpiClockMode dataMode;
SercomDataOrder bitOrder;
friend class SPIClass;
};
class SPIClass {
public:
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI);
byte transfer(uint8_t data);
inline void transfer(void *buf, size_t count);
// Transaction Functions
void usingInterrupt(int interruptNumber);
void beginTransaction(SPISettings settings);
void endTransaction(void);
// SPI Configuration methods
void attachInterrupt();
void detachInterrupt();
void begin();
void end();
void setBitOrder(BitOrder order);
void setDataMode(uint8_t uc_mode);
void setClockDivider(uint8_t uc_div);
private:
void init();
void config(SPISettings settings);
SERCOM *_p_sercom;
uint8_t _uc_pinMiso;
uint8_t _uc_pinMosi;
uint8_t _uc_pinSCK;
bool initialized;
uint8_t interruptMode;
char interruptSave;
uint32_t interruptMask;
};
void SPIClass::transfer(void *buf, size_t count)
{
// TODO: Optimize for faster block-transfer
uint8_t *buffer = reinterpret_cast<uint8_t *>(buf);
for (size_t i=0; i<count; i++)
buffer[i] = transfer(buffer[i]);
}
#if SPI_INTERFACES_COUNT > 0
extern SPIClass SPI;
extern SPIClass SPI_ETH;
extern SPIClass SPI_USER;
#endif
// For compatibility with sketches designed for AVR @ 16 MHz
// New programs should use SPI.beginTransaction to set the SPI clock
#if F_CPU == 48000000
#define SPI_CLOCK_DIV2 6
#define SPI_CLOCK_DIV4 12
#define SPI_CLOCK_DIV8 24
#define SPI_CLOCK_DIV16 48
#define SPI_CLOCK_DIV32 96
#define SPI_CLOCK_DIV64 192
#define SPI_CLOCK_DIV128 255
#endif
#endif