Files
MySensors/hardware/MySensors/samd/libraries/SPI/SPI.cpp
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

203 lines
4.8 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
*/
#include "SPI.h"
#include <Arduino.h>
#include <wiring_private.h>
#include <assert.h>
#define SPI_IMODE_NONE 0
#define SPI_IMODE_EXTINT 1
#define SPI_IMODE_GLOBAL 2
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI)
{
initialized = false;
assert(p_sercom != NULL);
_p_sercom = p_sercom;
_uc_pinMiso = uc_pinMISO;
_uc_pinSCK = uc_pinSCK;
_uc_pinMosi = uc_pinMOSI;
}
void SPIClass::begin()
{
init();
// PIO init
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
config(DEFAULT_SPI_SETTINGS);
}
void SPIClass::init()
{
if (initialized)
return;
interruptMode = SPI_IMODE_NONE;
interruptSave = 0;
interruptMask = 0;
initialized = true;
}
void SPIClass::config(SPISettings settings)
{
_p_sercom->disableSPI();
_p_sercom->initSPI(SPI_PAD_0_SCK_1, SERCOM_RX_PAD_2, SPI_CHAR_SIZE_8_BITS, settings.bitOrder);
_p_sercom->initSPIClock(settings.dataMode, settings.clockFreq);
_p_sercom->enableSPI();
}
void SPIClass::end()
{
_p_sercom->resetSPI();
initialized = false;
}
#ifndef interruptsStatus
#define interruptsStatus() __interruptsStatus()
static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused));
static inline unsigned char __interruptsStatus(void)
{
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIBGJ.html
return (__get_PRIMASK() ? 0 : 1);
}
#endif
void SPIClass::usingInterrupt(int interruptNumber)
{
if ((interruptNumber == NOT_AN_INTERRUPT) || (interruptNumber == EXTERNAL_INT_NMI))
return;
uint8_t irestore = interruptsStatus();
noInterrupts();
if (interruptNumber >= EXTERNAL_NUM_INTERRUPTS)
interruptMode = SPI_IMODE_GLOBAL;
else
{
interruptMode |= SPI_IMODE_EXTINT;
interruptMask |= (1 << interruptNumber);
}
if (irestore)
interrupts();
}
void SPIClass::beginTransaction(SPISettings settings)
{
if (interruptMode != SPI_IMODE_NONE)
{
if (interruptMode & SPI_IMODE_GLOBAL)
{
interruptSave = interruptsStatus();
noInterrupts();
}
else if (interruptMode & SPI_IMODE_EXTINT)
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(interruptMask);
}
config(settings);
}
void SPIClass::endTransaction(void)
{
if (interruptMode != SPI_IMODE_NONE)
{
if (interruptMode & SPI_IMODE_GLOBAL)
{
if (interruptSave)
interrupts();
}
else if (interruptMode & SPI_IMODE_EXTINT)
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(interruptMask);
}
}
void SPIClass::setBitOrder(BitOrder order)
{
if (order == LSBFIRST) {
_p_sercom->setDataOrderSPI(LSB_FIRST);
} else {
_p_sercom->setDataOrderSPI(MSB_FIRST);
}
}
void SPIClass::setDataMode(uint8_t mode)
{
switch (mode)
{
case SPI_MODE0:
_p_sercom->setClockModeSPI(SERCOM_SPI_MODE_0);
break;
case SPI_MODE1:
_p_sercom->setClockModeSPI(SERCOM_SPI_MODE_1);
break;
case SPI_MODE2:
_p_sercom->setClockModeSPI(SERCOM_SPI_MODE_2);
break;
case SPI_MODE3:
_p_sercom->setClockModeSPI(SERCOM_SPI_MODE_3);
break;
default:
break;
}
}
void SPIClass::setClockDivider(uint8_t div)
{
if (div < SPI_MIN_CLOCK_DIVIDER) {
_p_sercom->setBaudrateSPI(SPI_MIN_CLOCK_DIVIDER);
} else {
_p_sercom->setBaudrateSPI(div);
}
}
byte SPIClass::transfer(uint8_t data)
{
// Writing the data
_p_sercom->writeDataSPI(data);
// Read data
return _p_sercom->readDataSPI() & 0xFF;
}
void SPIClass::attachInterrupt() {
// Should be enableInterrupt()
}
void SPIClass::detachInterrupt() {
// Should be disableInterrupt()
}
SPIClass SPI( &sercom1, RADIO_SPI_MISO, RADIO_SPI_SCK, RADIO_SPI_MOSI );
SPIClass SPI_ETH (&sercom4, NET_SPI_MISO, NET_SPI_SCK, NET_SPI_MOSI);
SPIClass SPI_USER(&sercom5, USR_SPI_MISO, USR_SPI_SCK, USR_SPI_MOSI);