1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-12-10 21:24:12 +01:00
Arduino/hardware/arduino/sam/libraries/SPI/SPI.cpp

229 lines
6.2 KiB
C++
Raw Normal View History

2011-06-21 00:03:22 +02:00
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
2014-08-01 14:57:13 +02:00
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
2011-06-21 00:03:22 +02:00
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
2013-11-21 12:35:31 +01:00
#include "SPI.h"
2011-06-21 00:03:22 +02:00
2012-05-18 01:30:54 +02:00
SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) :
spi(_spi), id(_id), initCb(_initCb), initialized(false)
{
// Empty
}
void SPIClass::begin() {
init();
2012-06-09 15:02:51 +02:00
// NPCS control is left to the user
// Default speed set to 4Mhz
setClockDivider(BOARD_SPI_DEFAULT_SS, 21);
2012-06-09 15:02:51 +02:00
setDataMode(BOARD_SPI_DEFAULT_SS, SPI_MODE0);
setBitOrder(BOARD_SPI_DEFAULT_SS, MSBFIRST);
2012-06-09 15:02:51 +02:00
}
2012-05-18 01:30:54 +02:00
void SPIClass::begin(uint8_t _pin) {
init();
uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
PIO_Configure(
g_APinDescription[spiPin].pPort,
g_APinDescription[spiPin].ulPinType,
g_APinDescription[spiPin].ulPin,
g_APinDescription[spiPin].ulPinConfiguration);
2012-09-17 15:47:17 +02:00
// Default speed set to 4Mhz
setClockDivider(_pin, 21);
setDataMode(_pin, SPI_MODE0);
setBitOrder(_pin, MSBFIRST);
}
void SPIClass::init() {
if (initialized)
return;
2014-08-01 14:57:13 +02:00
interruptMode = 0;
interruptSave = 0;
2014-08-02 01:44:47 +02:00
interruptMask[0] = 0;
interruptMask[1] = 0;
interruptMask[2] = 0;
interruptMask[3] = 0;
initCb();
SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS);
SPI_Enable(spi);
initialized = true;
}
2014-08-01 14:57:13 +02:00
#ifndef interruptsStatus
#define interruptsStatus() __interruptsStatus()
static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused));
static inline unsigned char __interruptsStatus(void) {
2014-09-10 15:21:18 +02:00
unsigned int primask, faultmask;
asm volatile ("mrs %0, primask" : "=r" (primask));
if (primask) return 0;
asm volatile ("mrs %0, faultmask" : "=r" (faultmask));
if (faultmask) return 0;
return 1;
2014-08-01 14:57:13 +02:00
}
#endif
void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
uint8_t irestore;
irestore = interruptsStatus();
noInterrupts();
2014-08-02 01:44:47 +02:00
if (interruptMode < 16) {
2014-08-01 14:57:13 +02:00
if (interruptNumber > NUM_DIGITAL_PINS) {
2014-08-02 01:44:47 +02:00
interruptMode = 16;
2014-08-01 14:57:13 +02:00
} else {
Pio *pio = g_APinDescription[interruptNumber].pPort;
2014-08-02 01:44:47 +02:00
uint32_t mask = g_APinDescription[interruptNumber].ulPin;
2014-08-01 14:57:13 +02:00
if (pio == PIOA) {
2014-08-02 01:44:47 +02:00
interruptMode |= 1;
interruptMask[0] |= mask;
2014-08-01 14:57:13 +02:00
} else if (pio == PIOB) {
2014-08-02 01:44:47 +02:00
interruptMode |= 2;
interruptMask[1] |= mask;
2014-08-01 14:57:13 +02:00
} else if (pio == PIOC) {
2014-08-02 01:44:47 +02:00
interruptMode |= 4;
interruptMask[2] |= mask;
2014-08-01 14:57:13 +02:00
} else if (pio == PIOD) {
2014-08-02 01:44:47 +02:00
interruptMode |= 8;
interruptMask[3] |= mask;
} else {
interruptMode = 16;
2014-08-01 14:57:13 +02:00
}
}
}
if (irestore) interrupts();
}
void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
{
2014-08-02 01:44:47 +02:00
uint8_t mode = interruptMode;
if (mode > 0) {
if (mode < 16) {
if (mode & 1) PIOA->PIO_IDR = interruptMask[0];
if (mode & 2) PIOB->PIO_IDR = interruptMask[1];
if (mode & 4) PIOC->PIO_IDR = interruptMask[2];
if (mode & 8) PIOD->PIO_IDR = interruptMask[3];
2014-08-01 14:57:13 +02:00
} else {
interruptSave = interruptsStatus();
noInterrupts();
}
}
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin);
bitOrder[ch] = settings.border;
SPI_ConfigureNPCS(spi, ch, settings.config);
2014-08-02 01:44:47 +02:00
//setBitOrder(pin, settings.border);
//setDataMode(pin, settings.datamode);
//setClockDivider(pin, settings.clockdiv);
2014-08-01 14:57:13 +02:00
}
void SPIClass::endTransaction(void)
{
2014-08-02 01:44:47 +02:00
uint8_t mode = interruptMode;
if (mode > 0) {
if (mode < 16) {
if (mode & 1) PIOA->PIO_IER = interruptMask[0];
if (mode & 2) PIOB->PIO_IER = interruptMask[1];
if (mode & 4) PIOC->PIO_IER = interruptMask[2];
if (mode & 8) PIOD->PIO_IER = interruptMask[3];
2014-08-01 14:57:13 +02:00
} else {
if (interruptSave) interrupts();
}
}
}
void SPIClass::end(uint8_t _pin) {
uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
// Setting the pin as INPUT will disconnect it from SPI peripheral
pinMode(spiPin, INPUT);
2011-06-21 00:03:22 +02:00
}
2011-12-02 16:29:50 +01:00
void SPIClass::end() {
SPI_Disable(spi);
initialized = false;
2011-06-21 00:03:22 +02:00
}
void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
bitOrder[ch] = _bitOrder;
}
2011-06-21 00:03:22 +02:00
2012-05-18 01:30:54 +02:00
void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
mode[ch] = _mode | SPI_CSR_CSAAT;
// SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
// transfer. Some device needs that for working properly.
SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
2011-06-21 00:03:22 +02:00
}
2012-05-18 01:30:54 +02:00
void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
divider[ch] = _divider;
// SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
// transfer. Some device needs that for working properly.
SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
}
2012-05-18 01:30:54 +02:00
byte SPIClass::transfer(byte _pin, uint8_t _data, SPITransferMode _mode) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
// Reverse bit order
if (bitOrder[ch] == LSBFIRST)
_data = __REV(__RBIT(_data));
uint32_t d = _data | SPI_PCS(ch);
2012-05-18 01:30:54 +02:00
if (_mode == SPI_LAST)
d |= SPI_TDR_LASTXFER;
// SPI_Write(spi, _channel, _data);
2014-09-10 15:21:18 +02:00
while ((spi->SPI_SR & SPI_SR_TDRE) == 0)
;
spi->SPI_TDR = d;
// return SPI_Read(spi);
while ((spi->SPI_SR & SPI_SR_RDRF) == 0)
;
d = spi->SPI_RDR;
// Reverse bit order
if (bitOrder[ch] == LSBFIRST)
d = __REV(__RBIT(d));
2014-09-10 15:21:18 +02:00
return d & 0xFF;
}
2011-12-02 16:29:50 +01:00
void SPIClass::attachInterrupt(void) {
// Should be enableInterrupt()
}
2011-12-02 16:29:50 +01:00
void SPIClass::detachInterrupt(void) {
// Should be disableInterrupt()
}
2011-12-02 16:29:50 +01:00
#if SPI_INTERFACES_COUNT > 0
static void SPI_0_Init(void) {
PIO_Configure(
g_APinDescription[PIN_SPI_MOSI].pPort,
g_APinDescription[PIN_SPI_MOSI].ulPinType,
g_APinDescription[PIN_SPI_MOSI].ulPin,
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_MISO].pPort,
g_APinDescription[PIN_SPI_MISO].ulPinType,
g_APinDescription[PIN_SPI_MISO].ulPin,
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_SCK].pPort,
g_APinDescription[PIN_SPI_SCK].ulPinType,
g_APinDescription[PIN_SPI_SCK].ulPin,
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
}
2012-05-18 01:30:54 +02:00
SPIClass SPI(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init);
2011-12-02 16:29:50 +01:00
#endif
2014-08-01 14:57:13 +02:00