|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719 |
- /*
- * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
- * 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.
- */
-
- #include "SPI.h"
- #include "pins_arduino.h"
-
- //#define DEBUG_DMA_TRANSFERS
-
- /**********************************************************/
- /* 8 bit AVR-based boards */
- /**********************************************************/
-
- #if defined(__AVR__)
-
- SPIClass SPI;
-
- uint8_t SPIClass::interruptMode = 0;
- uint8_t SPIClass::interruptMask = 0;
- uint8_t SPIClass::interruptSave = 0;
- #ifdef SPI_TRANSACTION_MISMATCH_LED
- uint8_t SPIClass::inTransactionFlag = 0;
- #endif
- uint8_t SPIClass::_transferWriteFill = 0;
-
-
- void SPIClass::begin()
- {
- // Set SS to high so a connected chip will be "deselected" by default
- digitalWrite(SS, HIGH);
-
- // When the SS pin is set as OUTPUT, it can be used as
- // a general purpose output port (it doesn't influence
- // SPI operations).
- pinMode(SS, OUTPUT);
-
- // Warning: if the SS pin ever becomes a LOW INPUT then SPI
- // automatically switches to Slave, so the data direction of
- // the SS pin MUST be kept as OUTPUT.
- SPCR |= _BV(MSTR);
- SPCR |= _BV(SPE);
-
- // Set direction register for SCK and MOSI pin.
- // MISO pin automatically overrides to INPUT.
- // By doing this AFTER enabling SPI, we avoid accidentally
- // clocking in a single bit since the lines go directly
- // from "input" to SPI control.
- // http://code.google.com/p/arduino/issues/detail?id=888
- pinMode(SCK, OUTPUT);
- pinMode(MOSI, OUTPUT);
- }
-
- void SPIClass::end() {
- SPCR &= ~_BV(SPE);
- }
-
- // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
- #if defined(__AVR_ATmega32U4__)
- #define SPI_INT0_MASK (1<<INT0)
- #define SPI_INT1_MASK (1<<INT1)
- #define SPI_INT2_MASK (1<<INT2)
- #define SPI_INT3_MASK (1<<INT3)
- #define SPI_INT4_MASK (1<<INT6)
- #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
- #define SPI_INT0_MASK (1<<INT0)
- #define SPI_INT1_MASK (1<<INT1)
- #define SPI_INT2_MASK (1<<INT2)
- #define SPI_INT3_MASK (1<<INT3)
- #define SPI_INT4_MASK (1<<INT4)
- #define SPI_INT5_MASK (1<<INT5)
- #define SPI_INT6_MASK (1<<INT6)
- #define SPI_INT7_MASK (1<<INT7)
- #elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
- #define SPI_INT0_MASK (1<<INT4)
- #define SPI_INT1_MASK (1<<INT5)
- #define SPI_INT2_MASK (1<<INT0)
- #define SPI_INT3_MASK (1<<INT1)
- #define SPI_INT4_MASK (1<<INT2)
- #define SPI_INT5_MASK (1<<INT3)
- #define SPI_INT6_MASK (1<<INT6)
- #define SPI_INT7_MASK (1<<INT7)
- #else
- #ifdef INT0
- #define SPI_INT0_MASK (1<<INT0)
- #endif
- #ifdef INT1
- #define SPI_INT1_MASK (1<<INT1)
- #endif
- #ifdef INT2
- #define SPI_INT2_MASK (1<<INT2)
- #endif
- #endif
-
- void SPIClass::usingInterrupt(uint8_t interruptNumber)
- {
- uint8_t stmp, mask;
-
- if (interruptMode > 1) return;
-
- stmp = SREG;
- noInterrupts();
- switch (interruptNumber) {
- #ifdef SPI_INT0_MASK
- case 0: mask = SPI_INT0_MASK; break;
- #endif
- #ifdef SPI_INT1_MASK
- case 1: mask = SPI_INT1_MASK; break;
- #endif
- #ifdef SPI_INT2_MASK
- case 2: mask = SPI_INT2_MASK; break;
- #endif
- #ifdef SPI_INT3_MASK
- case 3: mask = SPI_INT3_MASK; break;
- #endif
- #ifdef SPI_INT4_MASK
- case 4: mask = SPI_INT4_MASK; break;
- #endif
- #ifdef SPI_INT5_MASK
- case 5: mask = SPI_INT5_MASK; break;
- #endif
- #ifdef SPI_INT6_MASK
- case 6: mask = SPI_INT6_MASK; break;
- #endif
- #ifdef SPI_INT7_MASK
- case 7: mask = SPI_INT7_MASK; break;
- #endif
- default:
- interruptMode = 2;
- SREG = stmp;
- return;
- }
- interruptMode = 1;
- interruptMask |= mask;
- SREG = stmp;
- }
-
- void SPIClass::transfer(const void * buf, void * retbuf, uint32_t count) {
- if (count == 0) return;
-
- const uint8_t *p = (const uint8_t *)buf;
- uint8_t *pret = (uint8_t *)retbuf;
- uint8_t in;
-
- uint8_t out = p ? *p++ : _transferWriteFill;
- SPDR = out;
- while (--count > 0) {
- if (p) {
- out = *p++;
- }
- while (!(SPSR & _BV(SPIF))) ;
- in = SPDR;
- SPDR = out;
- if (pret)*pret++ = in;
- }
- while (!(SPSR & _BV(SPIF))) ;
- in = SPDR;
- if (pret)*pret = in;
- }
-
-
- /**********************************************************/
- /* 32 bit Teensy 3.x */
- /**********************************************************/
-
- #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
- #if defined(KINETISK) && defined( SPI_HAS_TRANSFER_ASYNC)
-
- #ifndef TRANSFER_COUNT_FIXED
- inline void DMAChanneltransferCount(DMAChannel * dmac, unsigned int len) {
- // note does no validation of length...
- DMABaseClass::TCD_t *tcd = dmac->TCD;
- if (!(tcd->BITER & DMA_TCD_BITER_ELINK)) {
- tcd->BITER = len & 0x7fff;
- } else {
- tcd->BITER = (tcd->BITER & 0xFE00) | (len & 0x1ff);
- }
- tcd->CITER = tcd->BITER;
- }
- #else
- inline void DMAChanneltransferCount(DMAChannel * dmac, unsigned int len) {
- dmac->transferCount(len);
- }
- #endif
- #endif
-
-
- #if defined(__MK20DX128__) || defined(__MK20DX256__)
- #ifdef SPI_HAS_TRANSFER_ASYNC
- void _spi_dma_rxISR0(void) {SPI.dma_rxisr();}
- #else
- void _spi_dma_rxISR0(void) {;}
- #endif
-
- const SPIClass::SPI_Hardware_t SPIClass::spi0_hardware = {
- SIM_SCGC6, SIM_SCGC6_SPI0, 4, IRQ_SPI0,
- 32767, DMAMUX_SOURCE_SPI0_TX, DMAMUX_SOURCE_SPI0_RX,
- _spi_dma_rxISR0,
- 12, 8,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 11, 7,
- PORT_PCR_DSE | PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 13, 14,
- PORT_PCR_DSE | PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 10, 2, 9, 6, 20, 23, 21, 22, 15,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 0x1, 0x1, 0x2, 0x2, 0x4, 0x4, 0x8, 0x8, 0x10
- };
- SPIClass SPI((uintptr_t)&KINETISK_SPI0, (uintptr_t)&SPIClass::spi0_hardware);
-
- #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
- #ifdef SPI_HAS_TRANSFER_ASYNC
- void _spi_dma_rxISR0(void) {SPI.dma_rxisr();}
- void _spi_dma_rxISR1(void) {SPI1.dma_rxisr();}
- void _spi_dma_rxISR2(void) {SPI2.dma_rxisr();}
- #else
- void _spi_dma_rxISR0(void) {;}
- void _spi_dma_rxISR1(void) {;}
- void _spi_dma_rxISR2(void) {;}
- #endif
- const SPIClass::SPI_Hardware_t SPIClass::spi0_hardware = {
- SIM_SCGC6, SIM_SCGC6_SPI0, 4, IRQ_SPI0,
- 32767, DMAMUX_SOURCE_SPI0_TX, DMAMUX_SOURCE_SPI0_RX,
- _spi_dma_rxISR0,
- 12, 8, 39, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0,
- 11, 7, 28, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0,
- 13, 14, 27,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 10, 2, 9, 6, 20, 23, 21, 22, 15, 26, 45,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(3),
- 0x1, 0x1, 0x2, 0x2, 0x4, 0x4, 0x8, 0x8, 0x10, 0x1, 0x20
- };
- const SPIClass::SPI_Hardware_t SPIClass::spi1_hardware = {
- SIM_SCGC6, SIM_SCGC6_SPI1, 1, IRQ_SPI1,
- #if defined(__MK66FX1M0__)
- 32767, DMAMUX_SOURCE_SPI1_TX, DMAMUX_SOURCE_SPI1_RX,
- #else
- // T3.5 does not have good DMA support on 1 and 2
- 511, 0, DMAMUX_SOURCE_SPI1,
- #endif
- _spi_dma_rxISR1,
- 1, 5, 61, 59,
- PORT_PCR_MUX(2), PORT_PCR_MUX(7), PORT_PCR_MUX(2), PORT_PCR_MUX(7),
- 0, 21, 61, 59,
- PORT_PCR_MUX(2), PORT_PCR_MUX(7), PORT_PCR_MUX(7), PORT_PCR_MUX(2),
- 32, 20, 60,
- PORT_PCR_MUX(2), PORT_PCR_MUX(7), PORT_PCR_MUX(2),
- 6, 31, 58, 62, 63, 255, 255, 255, 255, 255, 255,
- PORT_PCR_MUX(7), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0, 0, 0, 0, 0, 0,
- 0x1, 0x1, 0x2, 0x1, 0x4, 0, 0, 0, 0, 0, 0
- };
- const SPIClass::SPI_Hardware_t SPIClass::spi2_hardware = {
- SIM_SCGC3, SIM_SCGC3_SPI2, 1, IRQ_SPI2,
- #if defined(__MK66FX1M0__)
- 32767, DMAMUX_SOURCE_SPI2_TX, DMAMUX_SOURCE_SPI2_RX,
- #else
- // T3.5 does not have good DMA support on 1 and 2
- 511, 0, DMAMUX_SOURCE_SPI2,
- #endif
- _spi_dma_rxISR2,
- 45, 51, 255, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0, 0,
- 44, 52, 255, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0, 0,
- 46, 53, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0,
- 43, 54, 55, 255, 255, 255, 255, 255, 255, 255, 255,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2), PORT_PCR_MUX(2), 0, 0, 0, 0, 0, 0, 0, 0,
- 0x1, 0x2, 0x1, 0, 0, 0, 0, 0, 0, 0, 0
- };
- SPIClass SPI((uintptr_t)&KINETISK_SPI0, (uintptr_t)&SPIClass::spi0_hardware);
- SPIClass SPI1((uintptr_t)&KINETISK_SPI1, (uintptr_t)&SPIClass::spi1_hardware);
- SPIClass SPI2((uintptr_t)&KINETISK_SPI2, (uintptr_t)&SPIClass::spi2_hardware);
- #endif
-
-
- void SPIClass::begin()
- {
- volatile uint32_t *reg;
-
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- port().MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- port().CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
- port().CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
- port().MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = hardware().mosi_mux[mosi_pin_index];
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg= hardware().miso_mux[miso_pin_index];
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = hardware().sck_mux[sck_pin_index];
- }
-
- void SPIClass::end()
- {
- volatile uint32_t *reg;
-
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = 0;
- port().MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- }
-
- void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
- {
- uint32_t n = (uint32_t)interruptName;
-
- if (n >= NVIC_NUM_INTERRUPTS) return;
-
- //Serial.print("usingInterrupt ");
- //Serial.println(n);
- interruptMasksUsed |= (1 << (n >> 5));
- interruptMask[n >> 5] |= (1 << (n & 0x1F));
- //Serial.printf("interruptMasksUsed = %d\n", interruptMasksUsed);
- //Serial.printf("interruptMask[0] = %08X\n", interruptMask[0]);
- //Serial.printf("interruptMask[1] = %08X\n", interruptMask[1]);
- //Serial.printf("interruptMask[2] = %08X\n", interruptMask[2]);
- }
-
- void SPIClass::notUsingInterrupt(IRQ_NUMBER_t interruptName)
- {
- uint32_t n = (uint32_t)interruptName;
- if (n >= NVIC_NUM_INTERRUPTS) return;
- interruptMask[n >> 5] &= ~(1 << (n & 0x1F));
- if (interruptMask[n >> 5] == 0) {
- interruptMasksUsed &= ~(1 << (n >> 5));
- }
- }
-
- const uint16_t SPISettings::ctar_div_table[23] = {
- 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40,
- 56, 64, 96, 128, 192, 256, 384, 512, 640, 768
- };
- const uint32_t SPISettings::ctar_clock_table[23] = {
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7)
- };
-
- void SPIClass::updateCTAR(uint32_t ctar)
- {
- if (port().CTAR0 != ctar) {
- uint32_t mcr = port().MCR;
- if (mcr & SPI_MCR_MDIS) {
- port().CTAR0 = ctar;
- port().CTAR1 = ctar | SPI_CTAR_FMSZ(8);
- } else {
- port().MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- port().CTAR0 = ctar;
- port().CTAR1 = ctar | SPI_CTAR_FMSZ(8);
- port().MCR = mcr;
- }
- }
- }
-
- void SPIClass::setBitOrder(uint8_t bitOrder)
- {
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- uint32_t ctar = port().CTAR0;
- if (bitOrder == LSBFIRST) {
- ctar |= SPI_CTAR_LSBFE;
- } else {
- ctar &= ~SPI_CTAR_LSBFE;
- }
- updateCTAR(ctar);
- }
-
- void SPIClass::setDataMode(uint8_t dataMode)
- {
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- //uint32_t ctar = port().CTAR0;
-
- // TODO: implement with native code
- //SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
- }
-
- void SPIClass::setClockDivider_noInline(uint32_t clk)
- {
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- uint32_t ctar = port().CTAR0;
- ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
- if (ctar & SPI_CTAR_CPHA) {
- clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
- }
- ctar |= clk;
- updateCTAR(ctar);
- }
-
- uint8_t SPIClass::pinIsChipSelect(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) return hardware().cs_mask[i];
- }
- return 0;
- }
-
- bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
- {
- uint8_t pin1_mask, pin2_mask;
- if ((pin1_mask = (uint8_t)pinIsChipSelect(pin1)) == 0) return false;
- if ((pin2_mask = (uint8_t)pinIsChipSelect(pin2)) == 0) return false;
- //Serial.printf("pinIsChipSelect %d %d %x %x\n\r", pin1, pin2, pin1_mask, pin2_mask);
- if ((pin1_mask & pin2_mask) != 0) return false;
- return true;
- }
-
- bool SPIClass::pinIsMOSI(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().mosi_pin); i++) {
- if (pin == hardware().mosi_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsMISO(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().miso_pin); i++) {
- if (pin == hardware().miso_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsSCK(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().sck_pin); i++) {
- if (pin == hardware().sck_pin[i]) return true;
- }
- return false;
- }
-
- // setCS() is not intended for use from normal Arduino programs/sketches.
- uint8_t SPIClass::setCS(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) {
- volatile uint32_t *reg = portConfigRegister(pin);
- *reg = hardware().cs_mux[i];
- return hardware().cs_mask[i];
- }
- }
- return 0;
- }
-
- void SPIClass::setMOSI(uint8_t pin)
- {
- if (hardware_addr == (uintptr_t)&spi0_hardware) {
- SPCR.setMOSI_soft(pin);
- }
- if (pin != hardware().mosi_pin[mosi_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().mosi_pin); i++) {
- if (pin == hardware().mosi_pin[i]) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().mosi_pin[i]);
- *reg = hardware().mosi_mux[i];
- }
- mosi_pin_index = i;
- return;
- }
- }
- }
- }
-
- void SPIClass::setMISO(uint8_t pin)
- {
- if (hardware_addr == (uintptr_t)&spi0_hardware) {
- SPCR.setMISO_soft(pin);
- }
- if (pin != hardware().miso_pin[miso_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().miso_pin); i++) {
- if (pin == hardware().miso_pin[i]) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().miso_pin[i]);
- *reg = hardware().miso_mux[i];
- }
- miso_pin_index = i;
- return;
- }
- }
- }
- }
-
- void SPIClass::setSCK(uint8_t pin)
- {
- if (hardware_addr == (uintptr_t)&spi0_hardware) {
- SPCR.setSCK_soft(pin);
- }
- if (pin != hardware().sck_pin[sck_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().sck_pin); i++) {
- if (pin == hardware().sck_pin[i]) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().sck_pin[i]);
- *reg = hardware().sck_mux[i];
- }
- sck_pin_index = i;
- return;
- }
- }
- }
- }
-
- void SPIClass::transfer(const void * buf, void * retbuf, size_t count)
- {
-
- if (count == 0) return;
- if (!(port().CTAR0 & SPI_CTAR_LSBFE)) {
- // We are doing the standard MSB order
- const uint8_t *p_write = (const uint8_t *)buf;
- uint8_t *p_read = (uint8_t *)retbuf;
- size_t count_read = count;
-
- // Lets clear the reader queue
- port().MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
-
- uint32_t sr;
-
- // Now lets loop while we still have data to output
- if (count & 1) {
- if (p_write) {
- if (count > 1)
- port().PUSHR = *p_write++ | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0);
- else
- port().PUSHR = *p_write++ | SPI_PUSHR_CTAS(0);
- } else {
- if (count > 1)
- port().PUSHR = _transferWriteFill | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0);
- else
- port().PUSHR = _transferWriteFill | SPI_PUSHR_CTAS(0);
- }
- count--;
- }
-
- uint16_t w = (uint16_t)(_transferWriteFill << 8) | _transferWriteFill;
-
- while (count > 0) {
- // Push out the next byte;
- if (p_write) {
- w = (*p_write++) << 8;
- w |= *p_write++;
- }
- uint16_t queue_full_status_mask = (hardware().queue_size-1) << 12;
- if (count == 2)
- port().PUSHR = w | SPI_PUSHR_CTAS(1);
- else
- port().PUSHR = w | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1);
- count -= 2; // how many bytes to output.
- // Make sure queue is not full before pushing next byte out
- do {
- sr = port().SR;
- if (sr & 0xF0) {
- uint16_t w = port().POPR; // Read any pending RX bytes in
- if (count_read & 1) {
- if (p_read) {
- *p_read++ = w; // Read any pending RX bytes in
- }
- count_read--;
- } else {
- if (p_read) {
- *p_read++ = w >> 8;
- *p_read++ = (w & 0xff);
- }
- count_read -= 2;
- }
- }
- } while ((sr & (15 << 12)) > queue_full_status_mask);
-
- }
-
- // now lets wait for all of the read bytes to be returned...
- while (count_read) {
- sr = port().SR;
- if (sr & 0xF0) {
- uint16_t w = port().POPR; // Read any pending RX bytes in
- if (count_read & 1) {
- if (p_read)
- *p_read++ = w; // Read any pending RX bytes in
- count_read--;
- } else {
- if (p_read) {
- *p_read++ = w >> 8;
- *p_read++ = (w & 0xff);
- }
- count_read -= 2;
- }
- }
- }
- } else {
- // We are doing the less ofen LSB mode
- const uint8_t *p_write = (const uint8_t *)buf;
- uint8_t *p_read = (uint8_t *)retbuf;
- size_t count_read = count;
-
- // Lets clear the reader queue
- port().MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
-
- uint32_t sr;
-
- // Now lets loop while we still have data to output
- if (count & 1) {
- if (p_write) {
- if (count > 1)
- port().PUSHR = *p_write++ | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0);
- else
- port().PUSHR = *p_write++ | SPI_PUSHR_CTAS(0);
- } else {
- if (count > 1)
- port().PUSHR = _transferWriteFill | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0);
- else
- port().PUSHR = _transferWriteFill | SPI_PUSHR_CTAS(0);
- }
- count--;
- }
-
- uint16_t w = _transferWriteFill;
-
- while (count > 0) {
- // Push out the next byte;
- if (p_write) {
- w = *p_write++;
- w |= ((*p_write++) << 8);
- }
- uint16_t queue_full_status_mask = (hardware().queue_size-1) << 12;
- if (count == 2)
- port().PUSHR = w | SPI_PUSHR_CTAS(1);
- else
- port().PUSHR = w | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1);
- count -= 2; // how many bytes to output.
- // Make sure queue is not full before pushing next byte out
- do {
- sr = port().SR;
- if (sr & 0xF0) {
- uint16_t w = port().POPR; // Read any pending RX bytes in
- if (count_read & 1) {
- if (p_read) {
- *p_read++ = w; // Read any pending RX bytes in
- }
- count_read--;
- } else {
- if (p_read) {
- *p_read++ = (w & 0xff);
- *p_read++ = w >> 8;
- }
- count_read -= 2;
- }
- }
- } while ((sr & (15 << 12)) > queue_full_status_mask);
-
- }
-
- // now lets wait for all of the read bytes to be returned...
- while (count_read) {
- sr = port().SR;
- if (sr & 0xF0) {
- uint16_t w = port().POPR; // Read any pending RX bytes in
- if (count_read & 1) {
- if (p_read)
- *p_read++ = w; // Read any pending RX bytes in
- count_read--;
- } else {
- if (p_read) {
- *p_read++ = (w & 0xff);
- *p_read++ = w >> 8;
- }
- count_read -= 2;
- }
- }
- }
- }
- }
- //=============================================================================
- // ASYNCH Support
- //=============================================================================
- //=========================================================================
- // Try Transfer using DMA.
- //=========================================================================
- #ifdef SPI_HAS_TRANSFER_ASYNC
- static uint8_t bit_bucket;
- #define dontInterruptAtCompletion(dmac) (dmac)->TCD->CSR &= ~DMA_TCD_CSR_INTMAJOR
-
- //=========================================================================
- // Init the DMA channels
- //=========================================================================
- bool SPIClass::initDMAChannels() {
- // Allocate our channels.
- _dmaTX = new DMAChannel();
- if (_dmaTX == nullptr) {
- return false;
- }
-
- _dmaRX = new DMAChannel();
- if (_dmaRX == nullptr) {
- delete _dmaTX; // release it
- _dmaTX = nullptr;
- return false;
- }
-
- // Let's setup the RX chain
- _dmaRX->disable();
- _dmaRX->source((volatile uint8_t&)port().POPR);
- _dmaRX->disableOnCompletion();
- _dmaRX->triggerAtHardwareEvent(hardware().rx_dma_channel);
- _dmaRX->attachInterrupt(hardware().dma_rxisr);
- _dmaRX->interruptAtCompletion();
-
- // We may be using settings chain here so lets set it up.
- // Now lets setup TX chain. Note if trigger TX is not set
- // we need to have the RX do it for us.
- _dmaTX->disable();
- _dmaTX->destination((volatile uint8_t&)port().PUSHR);
- _dmaTX->disableOnCompletion();
-
- if (hardware().tx_dma_channel) {
- _dmaTX->triggerAtHardwareEvent(hardware().tx_dma_channel);
- } else {
- // Serial.printf("SPI InitDMA tx triger by RX: %x\n", (uint32_t)_dmaRX);
- _dmaTX->triggerAtTransfersOf(*_dmaRX);
- }
-
-
- _dma_state = DMAState::idle; // Should be first thing set!
- return true;
- }
-
- //=========================================================================
- // Main Async Transfer function
- //=========================================================================
-
- bool SPIClass::transfer(const void *buf, void *retbuf, size_t count, EventResponderRef event_responder) {
- uint8_t dma_first_byte;
- if (_dma_state == DMAState::notAllocated) {
- if (!initDMAChannels())
- return false;
- }
-
- if (_dma_state == DMAState::active)
- return false; // already active
-
- event_responder.clearEvent(); // Make sure it is not set yet
- if (count < 2) {
- // Use non-async version to simplify cases...
- transfer(buf, retbuf, count);
- event_responder.triggerEvent();
- return true;
- }
-
- // Now handle the cases where the count > then how many we can output in one DMA request
- if (count > hardware().max_dma_count) {
- _dma_count_remaining = count - hardware().max_dma_count;
- count = hardware().max_dma_count;
- } else {
- _dma_count_remaining = 0;
- }
-
- // Now See if caller passed in a source buffer.
- _dmaTX->TCD->ATTR_DST = 0; // Make sure set for 8 bit mode
- uint8_t *write_data = (uint8_t*) buf;
- if (buf) {
- dma_first_byte = *write_data;
- _dmaTX->sourceBuffer((uint8_t*)write_data+1, count-1);
- _dmaTX->TCD->SLAST = 0; // Finish with it pointing to next location
- } else {
- dma_first_byte = _transferWriteFill;
- _dmaTX->source((uint8_t&)_transferWriteFill); // maybe have setable value
- DMAChanneltransferCount(_dmaTX, count-1);
- }
- if (retbuf) {
- // On T3.5 must handle SPI1/2 differently as only one DMA channel
- _dmaRX->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
- _dmaRX->destinationBuffer((uint8_t*)retbuf, count);
- _dmaRX->TCD->DLASTSGA = 0; // At end point after our bufffer
- } else {
- // Write only mode
- _dmaRX->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
- _dmaRX->destination((uint8_t&)bit_bucket);
- DMAChanneltransferCount(_dmaRX, count);
- }
-
- _dma_event_responder = &event_responder;
- // Now try to start it?
- // Setup DMA main object
- yield();
- port().MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_CLR_TXF | SPI_MCR_PCSIS(0x1F);
-
- port().SR = 0xFF0F0000;
-
- // Lets try to output the first byte to make sure that we are in 8 bit mode...
- port().PUSHR = dma_first_byte | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
-
- if (hardware().tx_dma_channel) {
- port().RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
- _dmaRX->enable();
- // Get the initial settings.
- _dmaTX->enable();
- } else {
- //T3.5 SP1 and SPI2 - TX is not triggered by SPI but by RX...
- port().RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS ;
- _dmaTX->triggerAtTransfersOf(*_dmaRX);
- _dmaTX->enable();
- _dmaRX->enable();
- }
-
- _dma_state = DMAState::active;
- return true;
- }
-
-
- //-------------------------------------------------------------------------
- // DMA RX ISR
- //-------------------------------------------------------------------------
- void SPIClass::dma_rxisr(void) {
- _dmaRX->clearInterrupt();
- _dmaTX->clearComplete();
- _dmaRX->clearComplete();
-
- uint8_t should_reenable_tx = true; // should we re-enable TX maybe not if count will be 0...
- if (_dma_count_remaining) {
- // What do I need to do to start it back up again...
- // We will use the BITR/CITR from RX as TX may have prefed some stuff
- if (_dma_count_remaining > hardware().max_dma_count) {
- _dma_count_remaining -= hardware().max_dma_count;
- } else {
- DMAChanneltransferCount(_dmaTX, _dma_count_remaining-1);
- DMAChanneltransferCount(_dmaRX, _dma_count_remaining);
- if (_dma_count_remaining == 1) should_reenable_tx = false;
-
- _dma_count_remaining = 0;
- }
- // In some cases we need to again start the TX manually to get it to work...
- if (_dmaTX->TCD->SADDR == &_transferWriteFill) {
- if (port().CTAR0 & SPI_CTAR_FMSZ(8)) {
- port().PUSHR = (_transferWriteFill | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT);
- } else {
- port().PUSHR = (_transferWriteFill | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT);
- }
- } else {
- if (port().CTAR0 & SPI_CTAR_FMSZ(8)) {
- // 16 bit mode
- uint16_t w = *((uint16_t*)_dmaTX->TCD->SADDR);
- _dmaTX->TCD->SADDR = (volatile uint8_t*)(_dmaTX->TCD->SADDR) + 2;
- port().PUSHR = (w | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT);
- } else {
- uint8_t w = *((uint8_t*)_dmaTX->TCD->SADDR);
- _dmaTX->TCD->SADDR = (volatile uint8_t*)(_dmaTX->TCD->SADDR) + 1;
- port().PUSHR = (w | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT);
- }
- }
- _dmaRX->enable();
- if (should_reenable_tx)
- _dmaTX->enable();
- } else {
-
- port().RSER = 0;
- //port().MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F); // clear out the queue
- port().SR = 0xFF0F0000;
- port().CTAR0 &= ~(SPI_CTAR_FMSZ(8)); // Hack restore back to 8 bits
-
- _dma_state = DMAState::completed; // set back to 1 in case our call wants to start up dma again
- _dma_event_responder->triggerEvent();
-
- }
- }
- #endif // SPI_HAS_TRANSFER_ASYNC
-
-
- /**********************************************************/
- /* 32 bit Teensy-LC */
- /**********************************************************/
-
- #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
-
- #ifdef SPI_HAS_TRANSFER_ASYNC
- void _spi_dma_rxISR0(void) {SPI.dma_isr();}
- void _spi_dma_rxISR1(void) {SPI1.dma_isr();}
- #else
- void _spi_dma_rxISR0(void) {;}
- void _spi_dma_rxISR1(void) {;}
- #endif
-
- const SPIClass::SPI_Hardware_t SPIClass::spi0_hardware = {
- SIM_SCGC4, SIM_SCGC4_SPI0,
- 0, // BR index 0
- DMAMUX_SOURCE_SPI0_TX, DMAMUX_SOURCE_SPI0_RX, _spi_dma_rxISR0,
- 12, 8,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 11, 7,
- PORT_PCR_DSE | PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 13, 14,
- PORT_PCR_DSE | PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 10, 2,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 0x1, 0x1
- };
- SPIClass SPI((uintptr_t)&KINETISL_SPI0, (uintptr_t)&SPIClass::spi0_hardware);
-
- const SPIClass::SPI_Hardware_t SPIClass::spi1_hardware = {
- SIM_SCGC4, SIM_SCGC4_SPI1,
- 1, // BR index 1 in SPI Settings
- DMAMUX_SOURCE_SPI1_TX, DMAMUX_SOURCE_SPI1_RX, _spi_dma_rxISR1,
- 1, 5,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 0, 21,
- PORT_PCR_MUX(2), PORT_PCR_MUX(2),
- 20, 255,
- PORT_PCR_MUX(2), 0,
- 6, 255,
- PORT_PCR_MUX(2), 0,
- 0x1, 0
- };
- SPIClass SPI1((uintptr_t)&KINETISL_SPI1, (uintptr_t)&SPIClass::spi1_hardware);
-
-
- void SPIClass::begin()
- {
- volatile uint32_t *reg;
-
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- port().C1 = SPI_C1_SPE | SPI_C1_MSTR;
- port().C2 = 0;
- uint8_t tmp __attribute__((unused)) = port().S;
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = hardware().mosi_mux[mosi_pin_index];
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg = hardware().miso_mux[miso_pin_index];
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = hardware().sck_mux[sck_pin_index];
- }
-
- void SPIClass::end() {
- volatile uint32_t *reg;
-
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = 0;
- port().C1 = 0;
- }
-
- const uint16_t SPISettings::br_div_table[30] = {
- 2, 4, 6, 8, 10, 12, 14, 16, 20, 24,
- 28, 32, 40, 48, 56, 64, 80, 96, 112, 128,
- 160, 192, 224, 256, 320, 384, 448, 512, 640, 768,
- };
-
- const uint8_t SPISettings::br_clock_table[30] = {
- SPI_BR_SPPR(0) | SPI_BR_SPR(0),
- SPI_BR_SPPR(1) | SPI_BR_SPR(0),
- SPI_BR_SPPR(2) | SPI_BR_SPR(0),
- SPI_BR_SPPR(3) | SPI_BR_SPR(0),
- SPI_BR_SPPR(4) | SPI_BR_SPR(0),
- SPI_BR_SPPR(5) | SPI_BR_SPR(0),
- SPI_BR_SPPR(6) | SPI_BR_SPR(0),
- SPI_BR_SPPR(7) | SPI_BR_SPR(0),
- SPI_BR_SPPR(4) | SPI_BR_SPR(1),
- SPI_BR_SPPR(5) | SPI_BR_SPR(1),
- SPI_BR_SPPR(6) | SPI_BR_SPR(1),
- SPI_BR_SPPR(7) | SPI_BR_SPR(1),
- SPI_BR_SPPR(4) | SPI_BR_SPR(2),
- SPI_BR_SPPR(5) | SPI_BR_SPR(2),
- SPI_BR_SPPR(6) | SPI_BR_SPR(2),
- SPI_BR_SPPR(7) | SPI_BR_SPR(2),
- SPI_BR_SPPR(4) | SPI_BR_SPR(3),
- SPI_BR_SPPR(5) | SPI_BR_SPR(3),
- SPI_BR_SPPR(6) | SPI_BR_SPR(3),
- SPI_BR_SPPR(7) | SPI_BR_SPR(3),
- SPI_BR_SPPR(4) | SPI_BR_SPR(4),
- SPI_BR_SPPR(5) | SPI_BR_SPR(4),
- SPI_BR_SPPR(6) | SPI_BR_SPR(4),
- SPI_BR_SPPR(7) | SPI_BR_SPR(4),
- SPI_BR_SPPR(4) | SPI_BR_SPR(5),
- SPI_BR_SPPR(5) | SPI_BR_SPR(5),
- SPI_BR_SPPR(6) | SPI_BR_SPR(5),
- SPI_BR_SPPR(7) | SPI_BR_SPR(5),
- SPI_BR_SPPR(4) | SPI_BR_SPR(6),
- SPI_BR_SPPR(5) | SPI_BR_SPR(6)
- };
-
- void SPIClass::setMOSI(uint8_t pin)
- {
- if (pin != hardware().mosi_pin[mosi_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().mosi_pin); i++) {
- if (pin == hardware().mosi_pin[i] ) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().mosi_pin[i]);
- *reg = hardware().mosi_mux[i];
- }
- mosi_pin_index = i;
- return;
- }
- }
- }
- }
-
- void SPIClass::setMISO(uint8_t pin)
- {
- if (pin != hardware().miso_pin[miso_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().miso_pin); i++) {
- if (pin == hardware().miso_pin[i] ) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().miso_pin[i]);
- *reg = hardware().miso_mux[i];
- }
- miso_pin_index = i;
- return;
- }
- }
- }
- }
-
- void SPIClass::setSCK(uint8_t pin)
- {
- if (pin != hardware().sck_pin[sck_pin_index]) {
- for (unsigned int i = 0; i < sizeof(hardware().sck_pin); i++) {
- if (pin == hardware().sck_pin[i] ) {
- if (hardware().clock_gate_register & hardware().clock_gate_mask) {
- volatile uint32_t *reg;
- reg = portConfigRegister(hardware().sck_pin[sck_pin_index]);
- *reg = 0;
- reg = portConfigRegister(hardware().sck_pin[i]);
- *reg = hardware().sck_mux[i];
- }
- sck_pin_index = i;
- return;
- }
- }
- }
- }
-
- bool SPIClass::pinIsChipSelect(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) return hardware().cs_mask[i];
- }
- return 0;
- }
-
- bool SPIClass::pinIsMOSI(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().mosi_pin); i++) {
- if (pin == hardware().mosi_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsMISO(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().miso_pin); i++) {
- if (pin == hardware().miso_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsSCK(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().sck_pin); i++) {
- if (pin == hardware().sck_pin[i]) return true;
- }
- return false;
- }
-
- // setCS() is not intended for use from normal Arduino programs/sketches.
- uint8_t SPIClass::setCS(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) {
- volatile uint32_t *reg = portConfigRegister(pin);
- *reg = hardware().cs_mux[i];
- return hardware().cs_mask[i];
- }
- }
- return 0;
- }
-
- void SPIClass::transfer(const void * buf, void * retbuf, size_t count) {
- if (count == 0) return;
- const uint8_t *p = (const uint8_t *)buf;
- uint8_t *pret = (uint8_t *)retbuf;
- uint8_t in;
-
- while (!(port().S & SPI_S_SPTEF)) ; // wait
- uint8_t out = p ? *p++ : _transferWriteFill;
- port().DL = out;
- while (--count > 0) {
- if (p) {
- out = *p++;
- }
- while (!(port().S & SPI_S_SPTEF)) ; // wait
- __disable_irq();
- port().DL = out;
- while (!(port().S & SPI_S_SPRF)) ; // wait
- in = port().DL;
- __enable_irq();
- if (pret)*pret++ = in;
- }
- while (!(port().S & SPI_S_SPRF)) ; // wait
- in = port().DL;
- if (pret)*pret = in;
- }
- //=============================================================================
- // ASYNCH Support
- //=============================================================================
- //=========================================================================
- // Try Transfer using DMA.
- //=========================================================================
- #ifdef SPI_HAS_TRANSFER_ASYNC
- static uint8_t _dma_dummy_rx;
-
- void SPIClass::dma_isr(void) {
- // Serial.println("_spi_dma_rxISR");
- _dmaRX->clearInterrupt();
- port().C2 = 0;
- uint8_t tmp __attribute__((unused)) = port().S;
- _dmaTX->clearComplete();
- _dmaRX->clearComplete();
-
- _dma_state = DMAState::completed; // set back to 1 in case our call wants to start up dma again
- _dma_event_responder->triggerEvent();
- }
-
- bool SPIClass::initDMAChannels() {
- //Serial.println("First dma call"); Serial.flush();
- _dmaTX = new DMAChannel();
- if (_dmaTX == nullptr) {
- return false;
- }
-
- _dmaTX->disable();
- _dmaTX->destination((volatile uint8_t&)port().DL);
- _dmaTX->disableOnCompletion();
- _dmaTX->triggerAtHardwareEvent(hardware().tx_dma_channel);
-
-
- _dmaRX = new DMAChannel();
- if (_dmaRX == NULL) {
- delete _dmaTX;
- _dmaRX = nullptr;
- return false;
- }
- _dmaRX->disable();
- _dmaRX->source((volatile uint8_t&)port().DL);
- _dmaRX->disableOnCompletion();
- _dmaRX->triggerAtHardwareEvent(hardware().rx_dma_channel);
- _dmaRX->attachInterrupt(hardware().dma_isr);
- _dmaRX->interruptAtCompletion();
-
- _dma_state = DMAState::idle; // Should be first thing set!
- //Serial.println("end First dma call");
- return true;
- }
-
- //=========================================================================
- // Main Async Transfer function
- //=========================================================================
- bool SPIClass::transfer(const void *buf, void *retbuf, size_t count, EventResponderRef event_responder) {
- if (_dma_state == DMAState::notAllocated) {
- if (!initDMAChannels()) {
- return false;
- }
- }
-
- if (_dma_state == DMAState::active)
- return false; // already active
-
- event_responder.clearEvent(); // Make sure it is not set yet
-
- if (count < 2) {
- // Use non-async version to simplify cases...
- transfer(buf, retbuf, count);
- event_responder.triggerEvent();
- return true;
- }
- //_dmaTX->destination((volatile uint8_t&)port().DL);
- //_dmaRX->source((volatile uint8_t&)port().DL);
- _dmaTX->CFG->DCR = (_dmaTX->CFG->DCR & ~DMA_DCR_DSIZE(3)) | DMA_DCR_DSIZE(1);
- _dmaRX->CFG->DCR = (_dmaRX->CFG->DCR & ~DMA_DCR_SSIZE(3)) | DMA_DCR_SSIZE(1); // 8 bit transfer
-
- // Now see if the user passed in TX buffer to send.
- uint8_t first_char;
- if (buf) {
- uint8_t *data_out = (uint8_t*)buf;
- first_char = *data_out++;
- _dmaTX->sourceBuffer(data_out, count-1);
- } else {
- first_char = (_transferWriteFill & 0xff);
- _dmaTX->source((uint8_t&)_transferWriteFill); // maybe have setable value
- _dmaTX->transferCount(count-1);
- }
-
- if (retbuf) {
- _dmaRX->destinationBuffer((uint8_t*)retbuf, count);
- } else {
- _dmaRX->destination(_dma_dummy_rx); // NULL ?
- _dmaRX->transferCount(count);
- }
-
- _dma_event_responder = &event_responder;
-
- //Serial.println("Before DMA C2");
- // Try pushing the first character
- while (!(port().S & SPI_S_SPTEF));
- port().DL = first_char;
-
- port().C2 |= SPI_C2_TXDMAE | SPI_C2_RXDMAE;
-
- // Now make sure SPI is enabled.
- port().C1 |= SPI_C1_SPE;
-
- _dmaRX->enable();
- _dmaTX->enable();
- _dma_state = DMAState::active;
- return true;
- }
- #endif //SPI_HAS_TRANSFER_ASYNC
-
-
-
-
- /**********************************************************/
- /* 32 bit Teensy 4.x */
- /**********************************************************/
-
- #elif defined(__arm__) && defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__))
-
- //#include "debug/printf.h"
-
- void SPIClass::begin()
- {
-
- // CBCMR[LPSPI_CLK_SEL] - PLL2 = 528 MHz
- // CBCMR[LPSPI_PODF] - div4 = 132 MHz
-
-
- hardware().clock_gate_register &= ~hardware().clock_gate_mask;
-
- CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
- CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2); // pg 714
-
- uint32_t fastio = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3);
- //uint32_t fastio = IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3);
- //Serial.printf("SPI MISO: %d MOSI: %d, SCK: %d\n", hardware().miso_pin[miso_pin_index], hardware().mosi_pin[mosi_pin_index], hardware().sck_pin[sck_pin_index]);
- *(portControlRegister(hardware().miso_pin[miso_pin_index])) = fastio;
- *(portControlRegister(hardware().mosi_pin[mosi_pin_index])) = fastio;
- *(portControlRegister(hardware().sck_pin[sck_pin_index])) = fastio;
-
- //printf("CBCMR = %08lX\n", CCM_CBCMR);
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- *(portConfigRegister(hardware().miso_pin[miso_pin_index])) = hardware().miso_mux[miso_pin_index];
- *(portConfigRegister(hardware().mosi_pin [mosi_pin_index])) = hardware().mosi_mux[mosi_pin_index];
- *(portConfigRegister(hardware().sck_pin [sck_pin_index])) = hardware().sck_mux[sck_pin_index];
-
- // Set the Mux pins
- //Serial.println("SPI: Set Input select registers");
- hardware().sck_select_input_register = hardware().sck_select_val;
- hardware().sdi_select_input_register = hardware().sdi_select_val;
- hardware().sdo_select_input_register = hardware().sdo_select_val;
-
- //digitalWriteFast(10, HIGH);
- //pinMode(10, OUTPUT);
- //digitalWriteFast(10, HIGH);
- port().CR = LPSPI_CR_RST;
-
- // Lets initialize the Transmit FIFO watermark to FIFO size - 1...
- // BUGBUG:: I assume queue of 16 for now...
- port().FCR = LPSPI_FCR_TXWATER(15);
- }
-
- uint8_t SPIClass::pinIsChipSelect(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) return 1;
- }
- return 0;
- }
-
- bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
- {
- return false; // only one CS defined
- }
-
- bool SPIClass::pinIsMOSI(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().mosi_pin); i++) {
- if (pin == hardware().mosi_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsMISO(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().miso_pin); i++) {
- if (pin == hardware().miso_pin[i]) return true;
- }
- return false;
- }
-
- bool SPIClass::pinIsSCK(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().sck_pin); i++) {
- if (pin == hardware().sck_pin[i]) return true;
- }
- return false;
- }
-
- // setCS() is not intended for use from normal Arduino programs/sketches.
- uint8_t SPIClass::setCS(uint8_t pin)
- {
- for (unsigned int i = 0; i < sizeof(hardware().cs_pin); i++) {
- if (pin == hardware().cs_pin[i]) {
- *(portConfigRegister(pin)) = hardware().sck_mux[i];
- return 1;
- }
- }
- return 0;
- }
-
- void SPIClass::setMOSI(uint8_t pin)
- {
- // Currently only one defined so just return...
- }
-
- void SPIClass::setMISO(uint8_t pin)
- {
- // Currently only one defined so just return...
- }
-
- void SPIClass::setSCK(uint8_t pin)
- {
- // Currently only one defined so just return...
- }
-
-
- void SPIClass::setBitOrder(uint8_t bitOrder)
- {
- hardware().clock_gate_register |= hardware().clock_gate_mask;
-
- if (bitOrder == LSBFIRST) {
- port().TCR |= LPSPI_TCR_LSBF;
- } else {
- port().TCR &= ~LPSPI_TCR_LSBF;
- }
- }
-
- void SPIClass::setDataMode(uint8_t dataMode)
- {
- hardware().clock_gate_register |= hardware().clock_gate_mask;
- //SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
- }
-
- void _spi_dma_rxISR0(void) {SPI.dma_rxisr();}
-
- const SPIClass::SPI_Hardware_t SPIClass::spiclass_lpspi4_hardware = {
- CCM_CCGR1, CCM_CCGR1_LPSPI4(CCM_CCGR_ON),
- DMAMUX_SOURCE_LPSPI4_TX, DMAMUX_SOURCE_LPSPI4_RX, _spi_dma_rxISR0,
- 12,
- 3 | 0x10,
- 11,
- 3 | 0x10,
- 13,
- 3 | 0x10,
- 10,
- 3 | 0x10,
- IOMUXC_LPSPI4_SCK_SELECT_INPUT, IOMUXC_LPSPI4_SDI_SELECT_INPUT, IOMUXC_LPSPI4_SDO_SELECT_INPUT, IOMUXC_LPSPI4_PCS0_SELECT_INPUT,
- 0, 0, 0, 0
- };
-
-
- SPIClass SPI((uintptr_t)&IMXRT_LPSPI4_S, (uintptr_t)&SPIClass::spiclass_lpspi4_hardware);
-
- #if defined(__IMXRT1062__)
- // T4 has two other possible SPI objects...
- void _spi_dma_rxISR1(void) {SPI1.dma_rxisr();}
-
- const SPIClass::SPI_Hardware_t SPIClass::spiclass_lpspi3_hardware = {
- CCM_CCGR1, CCM_CCGR1_LPSPI3(CCM_CCGR_ON),
- DMAMUX_SOURCE_LPSPI3_TX, DMAMUX_SOURCE_LPSPI3_RX, _spi_dma_rxISR1,
- 1,
- 7 | 0x10,
- 26,
- 7 | 0x10,
- 27,
- 7 | 0x10,
- 0,
- 7 | 0x10,
- IOMUXC_LPSPI3_SCK_SELECT_INPUT, IOMUXC_LPSPI3_SDI_SELECT_INPUT, IOMUXC_LPSPI3_SDO_SELECT_INPUT, IOMUXC_LPSPI3_PCS0_SELECT_INPUT,
- 1, 1, 0, 0
- };
- SPIClass SPI1((uintptr_t)&IMXRT_LPSPI3_S, (uintptr_t)&SPIClass::spiclass_lpspi3_hardware);
-
- void _spi_dma_rxISR2(void) {SPI2.dma_rxisr();}
-
- const SPIClass::SPI_Hardware_t SPIClass::spiclass_lpspi1_hardware = {
- CCM_CCGR1, CCM_CCGR1_LPSPI1(CCM_CCGR_ON),
- DMAMUX_SOURCE_LPSPI1_TX, DMAMUX_SOURCE_LPSPI1_RX, _spi_dma_rxISR1,
- 34,
- 4 | 0x10,
- 35,
- 4 | 0x10,
- 37,
- 4 | 0x10,
- 36,
- 4 | 0x10,
- IOMUXC_LPSPI1_SCK_SELECT_INPUT, IOMUXC_LPSPI1_SDI_SELECT_INPUT, IOMUXC_LPSPI1_SDO_SELECT_INPUT, IOMUXC_LPSPI1_PCS0_SELECT_INPUT,
- 1, 1, 1, 0
- };
- SPIClass SPI2((uintptr_t)&IMXRT_LPSPI1_S, (uintptr_t)&SPIClass::spiclass_lpspi1_hardware);
- #endif
-
- //SPIClass SPI(&IMXRT_LPSPI4_S, &spiclass_lpspi4_hardware);
-
- void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
- {
- uint32_t n = (uint32_t)interruptName;
-
- if (n >= NVIC_NUM_INTERRUPTS) return;
-
- //Serial.print("usingInterrupt ");
- //Serial.println(n);
- interruptMasksUsed |= (1 << (n >> 5));
- interruptMask[n >> 5] |= (1 << (n & 0x1F));
- //Serial.printf("interruptMasksUsed = %d\n", interruptMasksUsed);
- //Serial.printf("interruptMask[0] = %08X\n", interruptMask[0]);
- //Serial.printf("interruptMask[1] = %08X\n", interruptMask[1]);
- //Serial.printf("interruptMask[2] = %08X\n", interruptMask[2]);
- }
-
- void SPIClass::notUsingInterrupt(IRQ_NUMBER_t interruptName)
- {
- uint32_t n = (uint32_t)interruptName;
- if (n >= NVIC_NUM_INTERRUPTS) return;
- interruptMask[n >> 5] &= ~(1 << (n & 0x1F));
- if (interruptMask[n >> 5] == 0) {
- interruptMasksUsed &= ~(1 << (n >> 5));
- }
- }
-
- void SPIClass::transfer(const void * buf, void * retbuf, size_t count)
- {
-
- if (count == 0) return;
- uint8_t *p_write = (uint8_t*)buf;
- uint8_t *p_read = (uint8_t*)retbuf;
- size_t count_read = count;
-
- // Pass 1 keep it simple and don't try packing 8 bits into 16 yet..
- // Lets clear the reader queue
- port().CR = LPSPI_CR_RRF | LPSPI_CR_MEN; // clear the queue and make sure still enabled.
-
- while (count > 0) {
- // Push out the next byte;
- port().TDR = p_write? *p_write++ : _transferWriteFill;
- count--; // how many bytes left to output.
- // Make sure queue is not full before pushing next byte out
- do {
- if ((port().RSR & LPSPI_RSR_RXEMPTY) == 0) {
- uint8_t b = port().RDR; // Read any pending RX bytes in
- if (p_read) *p_read++ = b;
- count_read--;
- }
- } while ((port().SR & LPSPI_SR_TDF) == 0) ;
-
- }
-
- // now lets wait for all of the read bytes to be returned...
- while (count_read) {
- if ((port().RSR & LPSPI_RSR_RXEMPTY) == 0) {
- uint8_t b = port().RDR; // Read any pending RX bytes in
- if (p_read) *p_read++ = b;
- count_read--;
- }
- }
- }
-
-
- void SPIClass::end(){}
-
- //=============================================================================
- // ASYNCH Support
- //=============================================================================
- //=========================================================================
- // Try Transfer using DMA.
- //=========================================================================
- #ifdef SPI_HAS_TRANSFER_ASYNC
- static uint8_t bit_bucket;
- #define dontInterruptAtCompletion(dmac) (dmac)->TCD->CSR &= ~DMA_TCD_CSR_INTMAJOR
-
- //=========================================================================
- // Init the DMA channels
- //=========================================================================
- bool SPIClass::initDMAChannels() {
- // Allocate our channels.
- _dmaTX = new DMAChannel();
- if (_dmaTX == nullptr) {
- return false;
- }
-
- _dmaRX = new DMAChannel();
- if (_dmaRX == nullptr) {
- delete _dmaTX; // release it
- _dmaTX = nullptr;
- return false;
- }
-
- // Let's setup the RX chain
- _dmaRX->disable();
- _dmaRX->source((volatile uint8_t&)port().RDR);
- _dmaRX->disableOnCompletion();
- _dmaRX->triggerAtHardwareEvent(hardware().rx_dma_channel);
- _dmaRX->attachInterrupt(hardware().dma_rxisr);
- _dmaRX->interruptAtCompletion();
-
- // We may be using settings chain here so lets set it up.
- // Now lets setup TX chain. Note if trigger TX is not set
- // we need to have the RX do it for us.
- _dmaTX->disable();
- _dmaTX->destination((volatile uint8_t&)port().TDR);
- _dmaTX->disableOnCompletion();
-
- if (hardware().tx_dma_channel) {
- _dmaTX->triggerAtHardwareEvent(hardware().tx_dma_channel);
- } else {
- // Serial.printf("SPI InitDMA tx triger by RX: %x\n", (uint32_t)_dmaRX);
- _dmaTX->triggerAtTransfersOf(*_dmaRX);
- }
-
-
- _dma_state = DMAState::idle; // Should be first thing set!
- return true;
- }
-
- //=========================================================================
- // Main Async Transfer function
- //=========================================================================
- #ifndef TRANSFER_COUNT_FIXED
- inline void DMAChanneltransferCount(DMAChannel * dmac, unsigned int len) {
- // note does no validation of length...
- DMABaseClass::TCD_t *tcd = dmac->TCD;
- if (!(tcd->BITER & DMA_TCD_BITER_ELINK)) {
- tcd->BITER = len & 0x7fff;
- } else {
- tcd->BITER = (tcd->BITER & 0xFE00) | (len & 0x1ff);
- }
- tcd->CITER = tcd->BITER;
- }
- #else
- inline void DMAChanneltransferCount(DMAChannel * dmac, unsigned int len) {
- dmac->transferCount(len);
- }
- #endif
- #ifdef DEBUG_DMA_TRANSFERS
- void dumpDMA_TCD(DMABaseClass *dmabc)
- {
- Serial4.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);
-
- Serial4.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
- dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR,
- dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
- }
- #endif
-
- bool SPIClass::transfer(const void *buf, void *retbuf, size_t count, EventResponderRef event_responder) {
- if (_dma_state == DMAState::notAllocated) {
- if (!initDMAChannels())
- return false;
- }
-
- if (_dma_state == DMAState::active)
- return false; // already active
-
- event_responder.clearEvent(); // Make sure it is not set yet
- if (count < 2) {
- // Use non-async version to simplify cases...
- transfer(buf, retbuf, count);
- event_responder.triggerEvent();
- return true;
- }
-
- // Now handle the cases where the count > then how many we can output in one DMA request
- if (count > MAX_DMA_COUNT) {
- _dma_count_remaining = count - MAX_DMA_COUNT;
- count = MAX_DMA_COUNT;
- } else {
- _dma_count_remaining = 0;
- }
-
- // Now See if caller passed in a source buffer.
- _dmaTX->TCD->ATTR_DST = 0; // Make sure set for 8 bit mode
- uint8_t *write_data = (uint8_t*) buf;
- if (buf) {
- _dmaTX->sourceBuffer((uint8_t*)write_data, count);
- _dmaTX->TCD->SLAST = 0; // Finish with it pointing to next location
- if ((uint32_t)write_data >= 0x20200000u) arm_dcache_flush(write_data, count);
- } else {
- _dmaTX->source((uint8_t&)_transferWriteFill); // maybe have setable value
- DMAChanneltransferCount(_dmaTX, count);
- }
- if (retbuf) {
- // On T3.5 must handle SPI1/2 differently as only one DMA channel
- _dmaRX->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
- _dmaRX->destinationBuffer((uint8_t*)retbuf, count);
- _dmaRX->TCD->DLASTSGA = 0; // At end point after our bufffer
- if ((uint32_t)retbuf >= 0x20200000u) arm_dcache_delete(retbuf, count);
- } else {
- // Write only mode
- _dmaRX->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
- _dmaRX->destination((uint8_t&)bit_bucket);
- DMAChanneltransferCount(_dmaRX, count);
- }
-
- _dma_event_responder = &event_responder;
- // Now try to start it?
- // Setup DMA main object
- yield();
-
- #ifdef DEBUG_DMA_TRANSFERS
- // Lets dump TX, RX
- dumpDMA_TCD(_dmaTX);
- dumpDMA_TCD(_dmaRX);
- #endif
-
- // Make sure port is in 8 bit mode and clear watermark
- port().TCR = (port().TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7);
- port().FCR = 0;
-
- // Lets try to output the first byte to make sure that we are in 8 bit mode...
- port().DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX
- port().SR = 0x3f00; // clear out all of the other status...
-
- _dmaRX->enable();
- _dmaTX->enable();
-
- _dma_state = DMAState::active;
- return true;
- }
-
-
- //-------------------------------------------------------------------------
- // DMA RX ISR
- //-------------------------------------------------------------------------
- void SPIClass::dma_rxisr(void) {
- _dmaRX->clearInterrupt();
- _dmaTX->clearComplete();
- _dmaRX->clearComplete();
-
- if (_dma_count_remaining) {
- // What do I need to do to start it back up again...
- // We will use the BITR/CITR from RX as TX may have prefed some stuff
- if (_dma_count_remaining > MAX_DMA_COUNT) {
- _dma_count_remaining -= MAX_DMA_COUNT;
- } else {
- DMAChanneltransferCount(_dmaTX, _dma_count_remaining);
- DMAChanneltransferCount(_dmaRX, _dma_count_remaining);
-
- _dma_count_remaining = 0;
- }
- _dmaRX->enable();
- _dmaTX->enable();
- } else {
-
- port().FCR = LPSPI_FCR_TXWATER(15); // _spi_fcr_save; // restore the FSR status...
- port().DER = 0; // DMA no longer doing TX (or RX)
-
- port().CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
- port().SR = 0x3f00; // clear out all of the other status...
-
- _dma_state = DMAState::completed; // set back to 1 in case our call wants to start up dma again
- _dma_event_responder->triggerEvent();
-
- }
- }
- #endif // SPI_HAS_TRANSFER_ASYNC
-
-
-
- #endif
|