Compare commits

...

4 commits

Author SHA1 Message Date
dean
ae3d233b56 DM: in progress SPI DMA 2018-08-28 17:09:02 -04:00
dean
a278034831 DM: add spi DMA to other boards and reserved channels macro 2018-07-25 17:44:53 -04:00
dean
703c6dd497 DM: fix for samd21 2018-07-25 17:38:04 -04:00
dean
16567c4af4 DM: add SPI DMA stuff 2018-07-25 16:44:53 -04:00
14 changed files with 503 additions and 24 deletions

View file

@ -337,23 +337,115 @@ bool SERCOM::isDataRegisterEmptySPI()
return sercom->SPI.INTFLAG.bit.DRE;
}
//bool SERCOM::isTransmitCompleteSPI()
//{
// //TXC : Transmit complete
// return sercom->SPI.INTFLAG.bit.TXC;
//}
//
//bool SERCOM::isReceiveCompleteSPI()
//{
// //RXC : Receive complete
// return sercom->SPI.INTFLAG.bit.RXC;
//}
bool SERCOM::isTransmitCompleteSPI()
{
//TXC : Transmit complete
return sercom->SPI.INTFLAG.bit.TXC;
}
bool SERCOM::isReceiveCompleteSPI()
{
//RXC : Receive complete
return sercom->SPI.INTFLAG.bit.RXC;
}
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
{
return SERCOM_FREQ_REF / (2 * baudrate) - 1;
}
void SERCOM::initSPIDMA( uint8_t channelRx, uint8_t channelTx, DmacDescriptor *descrx, DmacDescriptor *desctx )
{
descrx->SRCADDR.reg = (uint32_t)(&sercom->SPI.DATA.reg);
desctx->DSTADDR.reg = (uint32_t)(&sercom->SPI.DATA.reg);
#ifdef __SAMD51__
if(sercom == SERCOM0)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM0_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM0_DMAC_ID_TX;
}
else if(sercom == SERCOM1)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM1_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM1_DMAC_ID_TX;
}
else if(sercom == SERCOM2)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM2_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM2_DMAC_ID_TX;
}
else if(sercom == SERCOM3)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM3_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM3_DMAC_ID_TX;
}
else if(sercom == SERCOM4)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM4_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM4_DMAC_ID_TX;
}
else if(sercom == SERCOM5)
{
DMAC->Channel[channelRx].CHCTRLA.bit.TRIGSRC = SERCOM5_DMAC_ID_RX;
DMAC->Channel[channelTx].CHCTRLA.bit.TRIGSRC = SERCOM5_DMAC_ID_TX;
}
#else
if(sercom == SERCOM0)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM0_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM0_DMAC_ID_TX;
}
else if(sercom == SERCOM1)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM1_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM1_DMAC_ID_TX;
}
else if(sercom == SERCOM2)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM2_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM2_DMAC_ID_TX;
}
else if(sercom == SERCOM3)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM3_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM3_DMAC_ID_TX;
}
#if defined(SERCOM4)
else if(sercom == SERCOM4)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM4_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM4_DMAC_ID_TX;
}
#endif
#if defined(SERCOM5)
else if(sercom == SERCOM5)
{
DMAC->CHID.bit.ID = channelRx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM5_DMAC_ID_RX;
DMAC->CHID.bit.ID = channelTx;
DMAC->CHCTRLB.bit.TRIGSRC = SERCOM5_DMAC_ID_TX;
}
#endif
#endif
}
/* =========================
* ===== Sercom WIRE
@ -374,7 +466,7 @@ void SERCOM::enableWIRE()
{
// I2C Master and Slave modes share the ENABLE bit function.
// Enable the I²C master mode
// Enable the I<EFBFBD>C master mode
sercom->I2CM.CTRLA.bit.ENABLE = 1 ;
while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 )
@ -395,7 +487,7 @@ void SERCOM::disableWIRE()
{
// I2C Master and Slave modes share the ENABLE bit function.
// Enable the I²C master mode
// Enable the I<EFBFBD>C master mode
sercom->I2CM.CTRLA.bit.ENABLE = 0 ;
while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 )

View file

@ -20,6 +20,7 @@
#define _SERCOM_CLASS_
#include "sam.h"
#include "dma.h"
#define SERCOM_FREQ_REF 48000000ul
@ -180,6 +181,7 @@ class SERCOM
bool isDataRegisterEmptySPI( void ) ;
bool isTransmitCompleteSPI( void ) ;
bool isReceiveCompleteSPI( void ) ;
void initSPIDMA( uint8_t channelRx, uint8_t channelTx, DmacDescriptor *descrx, DmacDescriptor *desctx ) ;
/* ========== WIRE ========== */
void initSlaveWIRE(uint8_t address) ;

141
cores/arduino/dma.h Normal file
View file

@ -0,0 +1,141 @@
/**
* \file
*
* \brief SAM Direct Memory Access Controller Driver
*
* Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef DMA_H_INCLUDED
#define DMA_H_INCLUDED
// THIS IS A PARED-DOWN VERSION OF DMA.H FROM ATMEL ASFCORE 3.
// Please keep original copyright and license intact!
#ifdef __cplusplus
extern "C" {
#endif
extern DmacDescriptor // 128 bit alignment
_descriptor[DMAC_CH_NUM],
_writeback[DMAC_CH_NUM];
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || defined(__DOXYGEN__) || defined(__SAMD51__)
#define FEATURE_DMA_CHANNEL_STANDBY
#endif
enum dma_transfer_trigger_action{
#ifdef __SAMD51__
// SAMD51 has a 'burst' transfer which can be set to one
// beat to accomplish same idea as SAMD21's 'beat' transfer.
// Trigger name is ACTON_BEAT for backward compatibility.
DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLA_TRIGACT_BLOCK_Val,
DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLA_TRIGACT_BURST_Val,
DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLA_TRIGACT_TRANSACTION_Val,
#else
DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
#endif
};
enum dma_callback_type {
// First item here is for any transfer errors. A transfer error is
// flagged if a bus error is detected during an AHB access or when
// the DMAC fetches an invalid descriptor
DMA_CALLBACK_TRANSFER_ERROR,
DMA_CALLBACK_TRANSFER_DONE,
DMA_CALLBACK_CHANNEL_SUSPEND,
DMA_CALLBACK_N, // Number of available callbacks
};
enum dma_beat_size {
DMA_BEAT_SIZE_BYTE = 0, // 8-bit
DMA_BEAT_SIZE_HWORD, // 16-bit
DMA_BEAT_SIZE_WORD, // 32-bit
};
enum dma_event_output_selection {
DMA_EVENT_OUTPUT_DISABLE = 0, // Disable event generation
DMA_EVENT_OUTPUT_BLOCK, // Event strobe when block xfer complete
DMA_EVENT_OUTPUT_RESERVED,
DMA_EVENT_OUTPUT_BEAT, // Event strobe when beat xfer complete
};
enum dma_block_action {
DMA_BLOCK_ACTION_NOACT = 0,
// Channel in normal operation and sets transfer complete interrupt
// flag after block transfer
DMA_BLOCK_ACTION_INT,
// Trigger channel suspend after block transfer and sets channel
// suspend interrupt flag once the channel is suspended
DMA_BLOCK_ACTION_SUSPEND,
// Sets transfer complete interrupt flag after a block transfer and
// trigger channel suspend. The channel suspend interrupt flag will
// be set once the channel is suspended.
DMA_BLOCK_ACTION_BOTH,
};
// DMA step selection. This bit determines whether the step size setting
// is applied to source or destination address.
enum dma_step_selection {
DMA_STEPSEL_DST = 0,
DMA_STEPSEL_SRC,
};
// Address increment step size. These bits select the address increment step
// size. The setting apply to source or destination address, depending on
// STEPSEL setting.
enum dma_address_increment_stepsize {
DMA_ADDRESS_INCREMENT_STEP_SIZE_1 = 0, // beat size * 1
DMA_ADDRESS_INCREMENT_STEP_SIZE_2, // beat size * 2
DMA_ADDRESS_INCREMENT_STEP_SIZE_4, // beat size * 4
DMA_ADDRESS_INCREMENT_STEP_SIZE_8, // etc...
DMA_ADDRESS_INCREMENT_STEP_SIZE_16,
DMA_ADDRESS_INCREMENT_STEP_SIZE_32,
DMA_ADDRESS_INCREMENT_STEP_SIZE_64,
DMA_ADDRESS_INCREMENT_STEP_SIZE_128,
};
#ifdef __cplusplus
}
#endif
#endif // DMA_H_INCLUDED

View file

@ -62,6 +62,12 @@ void calibrateADC()
* - Watchdog is disabled by default, unless someone plays with NVM User page
* - During reset, all PORT lines are configured as inputs with input buffers, output buffers and pull disabled.
*/
// DMA descriptor list entry point (and writeback buffer) per channel
__attribute__((__aligned__(16))) DmacDescriptor // 128 bit alignment
_descriptor[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR,
_writeback[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
void init( void )
{
// Set Systick to 1ms interval, common to all Cortex-M variants
@ -185,6 +191,26 @@ void init( void )
#endif //SAMD51
//init DMAC
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21)
PM->AHBMASK.bit.DMAC_ = 1;
#elif defined(__SAMD51__)
MCLK->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks
#else
PM->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks
PM->APBBMASK.bit.DMAC_ = 1;
#endif
DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA controller
DMAC->CTRL.bit.SWRST = 1; // Perform software reset
// Initialize descriptor list addresses
DMAC->BASEADDR.bit.BASEADDR = (uint32_t)_descriptor;
DMAC->WRBADDR.bit.WRBADDR = (uint32_t)_writeback;
memset(_descriptor, 0, sizeof(_descriptor));
memset(_writeback , 0, sizeof(_writeback));
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xF);
}
#ifdef __cplusplus

View file

@ -28,7 +28,8 @@
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad PadTx, SercomRXPad PadRx)
SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI,
SercomSpiTXPad PadTx, SercomRXPad PadRx, int8_t dmaChannelRx, int8_t dmaChannelTx)
{
initialized = false;
assert(p_sercom != NULL);
@ -39,6 +40,9 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
_uc_pinSCK = uc_pinSCK;
_uc_pinMosi = uc_pinMOSI;
_dmaChannelRx = dmaChannelRx;
_dmaChannelTx = dmaChannelTx;
// SERCOM pads
_padTx=PadTx;
_padRx=PadRx;
@ -53,6 +57,64 @@ void SPIClass::begin()
pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
if(_dmaChannelRx > -1 && _dmaChannelTx > -1){
descrx = &_descriptor[_dmaChannelRx];
desctx = &_descriptor[_dmaChannelTx];
descrx->BTCTRL.bit.VALID = true;
descrx->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE;
descrx->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT;
descrx->BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE;
descrx->BTCTRL.bit.SRCINC = false;
descrx->BTCTRL.bit.DSTINC = true;
descrx->BTCTRL.bit.STEPSEL = DMA_STEPSEL_DST;
descrx->BTCTRL.bit.STEPSIZE = DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
descrx->BTCNT.reg = 0;
descrx->SRCADDR.reg = (uint32_t)0;
desctx->BTCTRL.bit.VALID = true;
desctx->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE;
desctx->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT;
desctx->BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE;
desctx->BTCTRL.bit.SRCINC = true;
desctx->BTCTRL.bit.DSTINC = false;
desctx->BTCTRL.bit.STEPSEL = DMA_STEPSEL_DST;
desctx->BTCTRL.bit.STEPSIZE = DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
desctx->BTCNT.reg = 0;
desctx->SRCADDR.reg = (uint32_t)0;
#ifdef __SAMD51__
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.ENABLE = 0;
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.SWRST = 1;
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.ENABLE = 0;
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.SWRST = 1;
DMAC->Channel[_dmaChannelRx].CHPRILVL.bit.PRILVL = 0;
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.TRIGACT = DMA_TRIGGER_ACTON_BEAT;
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.BURSTLEN = DMAC_CHCTRLA_BURSTLEN_SINGLE_Val; // Single-beat burst length
DMAC->Channel[_dmaChannelTx].CHPRILVL.bit.PRILVL = 0;
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.TRIGACT = DMA_TRIGGER_ACTON_BEAT;
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.BURSTLEN = DMAC_CHCTRLA_BURSTLEN_SINGLE_Val; // Single-beat burst length
DMAC->SWTRIGCTRL.reg &= ~(1UL << _dmaChannelTx);
DMAC->SWTRIGCTRL.reg &= ~(1UL << _dmaChannelRx);
#else
DMAC->CHID.bit.ID = _dmaChannelRx;
DMAC->CHCTRLA.bit.ENABLE = 0;
DMAC->CHCTRLA.bit.SWRST = 1;
DMAC->CHCTRLB.bit.LVL = 0;
DMAC->CHCTRLB.bit.TRIGACT = DMA_TRIGGER_ACTON_BEAT;
DMAC->CHID.bit.ID = _dmaChannelTx;
DMAC->CHCTRLA.bit.ENABLE = 0;
DMAC->CHCTRLA.bit.SWRST = 1;
DMAC->CHCTRLB.bit.LVL = 0;
DMAC->CHCTRLB.bit.TRIGACT = DMA_TRIGGER_ACTON_BEAT;
#endif
_p_sercom->initSPIDMA(_dmaChannelRx, _dmaChannelTx, descrx, desctx);
}
config(DEFAULT_SPI_SETTINGS);
}
@ -206,13 +268,82 @@ uint16_t SPIClass::transfer16(uint16_t data) {
return t.val;
}
void SPIClass::transfer(void *buf, size_t count)
void SPIClass::transfer(void *rx, void *tx, size_t count)
{
uint8_t *buffer = reinterpret_cast<uint8_t *>(buf);
for (size_t i=0; i<count; i++) {
*buffer = transfer(*buffer);
buffer++;
}
if(count > 2 && count < 65536 && _dmaChannelRx > -1 && _dmaChannelTx > -1){
//use a synchronous DMA transfer
descrx->BTCTRL.bit.VALID = true;
descrx->DSTADDR.reg = (uint32_t)rx + count;
descrx->BTCNT.reg = count;
desctx->BTCTRL.bit.VALID = true;
desctx->SRCADDR.reg = (uint32_t)tx + count;
desctx->BTCNT.reg = count;
#ifdef __SAMD51__
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.ENABLE = 1;
if(rx != NULL)
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.ENABLE = 1;
#else
DMAC->CHID.bit.ID = _dmaChannelTx;
DMAC->CHCTRLA.bit.ENABLE = 1;
DMAC->CHID.bit.ID = _dmaChannelRx;
DMAC->CHCTRLA.bit.ENABLE = 1;
#endif
//wait for the transfer to finish
while(_writeback[_dmaChannelTx].BTCTRL.bit.VALID || !_p_sercom->isDataRegisterEmptySPI());
while(!_p_sercom->isTransmitCompleteSPI());
}
else{
//use a normal transfer
uint8_t *rxBuffer = reinterpret_cast<uint8_t *>(rx);
uint8_t *txBuffer = reinterpret_cast<uint8_t *>(tx);
for (size_t i=0; i<count; i++) {
*rxBuffer++ = transfer(*txBuffer++);
}
}
}
//returns true if the transfer could be started, false otherwise
bool SPIClass::transferNonBlocking(void *rx, void *tx, size_t count)
{
if(count < 65536 && _dmaChannelRx > -1 && _dmaChannelTx > -1){
//previous transfer has not finished
if(_writeback[_dmaChannelTx].BTCTRL.bit.VALID || !_p_sercom->isDataRegisterEmptySPI() ||
!_p_sercom->isTransmitCompleteSPI()){
return false;
}
//use a synchronous DMA transfer
descrx->BTCTRL.bit.VALID = true;
descrx->DSTADDR.reg = (uint32_t)rx + count;
descrx->BTCNT.reg = count;
desctx->BTCTRL.bit.VALID = true;
desctx->SRCADDR.reg = (uint32_t)tx + count;
desctx->BTCNT.reg = count;
#ifdef __SAMD51__
DMAC->Channel[_dmaChannelTx].CHCTRLA.bit.ENABLE = 1;
if(rx != NULL)
DMAC->Channel[_dmaChannelRx].CHCTRLA.bit.ENABLE = 1;
#else
DMAC->CHID.bit.ID = _dmaChannelTx;
DMAC->CHCTRLA.bit.ENABLE = 1;
DMAC->CHID.bit.ID = _dmaChannelRx;
DMAC->CHCTRLA.bit.ENABLE = 1;
#endif
return true;
}
else{
return false;
}
}
void SPIClass::transfer(void *buf, size_t count){
transfer(buf, buf, count);
}
void SPIClass::attachInterrupt() {
@ -233,26 +364,51 @@ void SPIClass::detachInterrupt() {
* - SercomSpiTXPad
* - SercomRXPad
*/
#ifndef PERIPH_SPI
#ifndef PERIPH_SPI
#define PERIPH_SPI sercom4
#define PAD_SPI_TX SPI_PAD_2_SCK_3
#define PAD_SPI_RX SERCOM_RX_PAD_0
#endif // PERIPH_SPI
#endif // PERIPH_SPI
#ifdef SPI_HAS_DMA
SPIClass SPI (&PERIPH_SPI, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PAD_SPI_TX, PAD_SPI_RX, SPI_DMA_CHANNEL_RX, SPI_DMA_CHANNEL_TX);
#else
SPIClass SPI (&PERIPH_SPI, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PAD_SPI_TX, PAD_SPI_RX);
#endif
#endif
#if SPI_INTERFACES_COUNT > 1
#ifdef SPI1_HAS_DMA
SPIClass SPI1(&PERIPH_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI, PAD_SPI1_TX, PAD_SPI1_RX, SPI1_DMA_CHANNEL_RX, SPI1_DMA_CHANNEL_TX);
#else
SPIClass SPI1(&PERIPH_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI, PAD_SPI1_TX, PAD_SPI1_RX);
#endif
#endif
#if SPI_INTERFACES_COUNT > 2
SPIClass SPI2(&PERIPH_SPI2, PIN_SPI2_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, PAD_SPI2_TX, PAD_SPI2_RX);
#ifdef SPI2_HAS_DMA
SPIClass SPI2(&PERIPH_SPI2, PIN_SPI2_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, PAD_SPI2_TX, PAD_SPI2_RX, SPI2_DMA_CHANNEL_RX, SPI2_DMA_CHANNEL_TX);
#else
SPIClass SPI2(&PERIPH_SPI2, PIN_SPI1_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, PAD_SPI2_TX, PAD_SPI2_RX);
#endif
#endif
#if SPI_INTERFACES_COUNT > 3
#ifdef SPI3_HAS_DMA
SPIClass SPI3(&PERIPH_SPI3, PIN_SPI3_MISO, PIN_SPI3_SCK, PIN_SPI3_MOSI, PAD_SPI3_TX, PAD_SPI3_RX, SPI3_DMA_CHANNEL_RX, SPI3_DMA_CHANNEL_TX);
#else
SPIClass SPI3(&PERIPH_SPI3, PIN_SPI3_MISO, PIN_SPI3_SCK, PIN_SPI3_MOSI, PAD_SPI3_TX, PAD_SPI3_RX);
#endif
#endif
#if SPI_INTERFACES_COUNT > 4
#ifdef SPI4_HAS_DMA
SPIClass SPI4(&PERIPH_SPI4, PIN_SPI4_MISO, PIN_SPI4_SCK, PIN_SPI4_MOSI, PAD_SPI4_TX, PAD_SPI4_RX, SPI4_DMA_CHANNEL_RX, SPI4_DMA_CHANNEL_TX);
#else
SPIClass SPI4(&PERIPH_SPI4, PIN_SPI4_MISO, PIN_SPI4_SCK, PIN_SPI4_MOSI, PAD_SPI4_TX, PAD_SPI4_RX);
#endif
#endif
#if SPI_INTERFACES_COUNT > 5
#ifdef SPI5_HAS_DMA
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX, SPI5_DMA_CHANNEL_RX, SPI5_DMA_CHANNEL_TX);
#else
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
#endif
#endif

View file

@ -21,6 +21,7 @@
#define _SPI_H_INCLUDED
#include <Arduino.h>
#include "dma.h"
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
@ -91,12 +92,14 @@ class SPISettings {
class SPIClass {
public:
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad);
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad PadTx, SercomRXPad PadRx, int8_t dmaChannelRx=-1, int8_t dmaChannelTx=-1);
byte transfer(uint8_t data);
uint16_t transfer16(uint16_t data);
void transfer(void *buf, size_t count);
void transfer(void *rx, void *tx, size_t count);
bool transferNonBlocking(void *rx, void *tx, size_t count);
// Transaction Functions
void usingInterrupt(int interruptNumber);
@ -122,6 +125,10 @@ class SPIClass {
uint8_t _uc_pinMiso;
uint8_t _uc_pinMosi;
uint8_t _uc_pinSCK;
DmacDescriptor *descrx;
DmacDescriptor *desctx;
int8_t _dmaChannelRx;
int8_t _dmaChannelTx;
SercomSpiTXPad _padTx;
SercomRXPad _padRx;

View file

@ -146,6 +146,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
/*
* Wire Interfaces
*/

View file

@ -151,6 +151,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
#define PIN_SPI1_MISO (36u)
#define PIN_SPI1_MOSI (37u)

View file

@ -143,6 +143,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
/*
* Wire Interfaces
*/

View file

@ -130,6 +130,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
/*
* Wire Interfaces

View file

@ -145,6 +145,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
#define PIN_SPI1_MISO (36u)
#define PIN_SPI1_MOSI (37u)

View file

@ -142,6 +142,13 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
/*
* Wire Interfaces
*/

View file

@ -151,6 +151,12 @@ static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
#define PIN_SPI1_MISO (36u)
#define PIN_SPI1_MOSI (37u)

View file

@ -143,6 +143,13 @@ static const uint8_t ATN = PIN_ATN;
#define PAD_SPI_TX SPI_PAD_0_SCK_1
#define PAD_SPI_RX SERCOM_RX_PAD_2
#define SPI_HAS_DMA
#define SPI_DMA_CHANNEL_RX (DMAC_CH_NUM-2)
#define SPI_DMA_CHANNEL_TX (DMAC_CH_NUM-1)
#define DMAC_RESERVED_CHANNELS ((1UL << SPI_DMA_CHANNEL_RX) | \
(1UL << SPI_DMA_CHANNEL_TX))
static const uint8_t SS = PIN_A2 ;
static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;