Skip to content
Snippets Groups Projects
Commit cb722cfd authored by Claudio Indellicati's avatar Claudio Indellicati Committed by Claudio Indellicati
Browse files

Implemented SPI Transaction API.

parent 730ff493
No related branches found
No related tags found
No related merge requests found
/*
* SPI Master library for arduino.
* Copyright (c) 2014 Arduino.
* SPI Master library for Arduino.
* Copyright (c) 2015 Arduino LLC
*
* 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
......@@ -13,8 +13,15 @@
#include "assert.h"
#include "variant.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;
......@@ -25,14 +32,32 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
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);
// Default speed set to 4Mhz, SPI mode set to MODE 0 and Bit order set to MSB first.
_p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, MSB_FIRST);
_p_sercom->initSPIClock(SERCOM_SPI_MODE_0, 4000000);
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_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, settings.bitOrder);
_p_sercom->initSPIClock(settings.dataMode, settings.clockFreq);
_p_sercom->enableSPI();
}
......@@ -40,25 +65,67 @@ void SPIClass::begin()
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(uint8_t interruptNumber)
void SPIClass::usingInterrupt(int interruptNumber)
{
// XXX: TODO
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)
{
// XXX: TODO
setBitOrder(settings.bitOrder);
setClockDivider(settings.clockDiv);
setDataMode(settings.dataMode);
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)
{
// XXX: TODO
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)
......@@ -110,7 +177,7 @@ byte SPIClass::transfer(uint8_t data)
_p_sercom->writeDataSPI(data);
// Read data
return _p_sercom->readDataSPI();
return _p_sercom->readDataSPI() & 0xFF;
}
void SPIClass::attachInterrupt() {
......
/*
* SPI Master library for Arduino.
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* SPI Master library for arduino.
* Copyright (c) 2015 Arduino LLC
*
* 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
......@@ -13,6 +14,13 @@
#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
......@@ -38,6 +46,7 @@ class SPISettings {
}
}
// 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:
......@@ -46,21 +55,32 @@ class SPISettings {
}
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
uint8_t div;
if (clock < (F_CPU / 255)) {
div = 255;
} else if (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER)) {
div = SPI_MIN_CLOCK_DIVIDER;
} else {
div = (F_CPU / (clock + 1)) + 1;
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;
case SPI_MODE1:
this->dataMode = SERCOM_SPI_MODE_1;
case SPI_MODE2:
this->dataMode = SERCOM_SPI_MODE_2;
case SPI_MODE3:
this->dataMode = SERCOM_SPI_MODE_3;
default:
this->dataMode = SERCOM_SPI_MODE_0;
}
this->clockDiv = div;
this->dataMode = dataMode;
this->bitOrder = bitOrder;
}
uint8_t clockDiv, dataMode;
BitOrder bitOrder;
uint32_t clockFreq;
SercomSpiClockMode dataMode;
SercomDataOrder bitOrder;
friend class SPIClass;
};
......@@ -73,7 +93,7 @@ class SPIClass {
inline void transfer(void *buf, size_t count);
// Transaction Functions
void usingInterrupt(uint8_t interruptNumber);
void usingInterrupt(int interruptNumber);
void beginTransaction(SPISettings settings);
void endTransaction(void);
......@@ -89,10 +109,17 @@ class SPIClass {
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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment