Advertisement
Guest User

Untitled

a guest
Apr 18th, 2020
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.46 KB | None | 0 0
  1. /*-------------------------------------------------------------------------*
  2.  * Combined SPI library for ATTinyCore - based on official Arduino SPI     *
  3.  * library and tinySPI by Jack Christensen                                 *
  4.  * Combination by Spence Konde 2018                                        *
  5.  *                                                                         *
  6.  * Original version of tinyISP by Jack Christensen 24Oct2013               *
  7.  *                                                                         *
  8.  * Added support for Attiny24/25, and Attiny2313/4313                      *
  9.  * by Leonardo Miliani 28Nov2014                                           *
  10.  *                                                                         *
  11.  * CC BY-SA-NC:                                                            *
  12.  * This work is licensed under the Creative Commons Attribution-           *
  13.  * ShareAlike- Not Commercial 4.0 Unported License. To view a copy of this *
  14.  * license, visit                                                          *
  15.  * http://creativecommons.org/licenses/by-sa/4.0/ or send a                *
  16.  * letter to Creative Commons, 171 Second Street, Suite 300,               *
  17.  * San Francisco, California, 94105, USA.                                  *
  18.  *-------------------------------------------------------------------------*/
  19.  
  20. #include "SPI.h"
  21.  
  22.  
  23. #ifdef SPDR //Then we have hardware SPI, let's use it:
  24.  
  25.  
  26. #include "SPI.h"
  27.  
  28. SPIClass SPI;
  29.  
  30. uint8_t SPIClass::initialized = 0;
  31. uint8_t SPIClass::interruptMode = 0;
  32. uint8_t SPIClass::interruptMask = 0;
  33. uint8_t SPIClass::interruptSave = 0;
  34. #ifdef SPI_TRANSACTION_MISMATCH_LED
  35. uint8_t SPIClass::inTransactionFlag = 0;
  36. #endif
  37.  
  38. void SPIClass::begin()
  39. {
  40.   uint8_t sreg = SREG;
  41.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  42.   if (!initialized) {
  43.  
  44.     #ifdef  REMAP
  45.     uint8_t SS_pin=0;
  46.  
  47.     if (REMAP & 1<<SPIMAP) {
  48.       pinMode(SCK_REMAP, OUTPUT);
  49.       pinMode(MOSI_REMAP, OUTPUT);
  50.       SS_pin=SS_REMAP;
  51.     } else {
  52.       pinMode(SCK, OUTPUT);
  53.       pinMode(MOSI, OUTPUT);
  54.       SS_pin=SS;
  55.     }
  56.     uint8_t port = digitalPinToPort(SS_pin);
  57.     uint8_t bit = digitalPinToBitMask(SS_pin);
  58.     volatile uint8_t *reg = portModeRegister(port);
  59.  
  60.     // if the SS pin is not already configured as an output
  61.     // then set it high (to enable the internal pull-up resistor)
  62.     if(!(*reg & bit)){
  63.       digitalWrite(SS_pin, HIGH);
  64.     }
  65.     pinMode(SS_pin, OUTPUT);
  66.     #else
  67.     uint8_t port = digitalPinToPort(SS);
  68.     uint8_t bit = digitalPinToBitMask(SS);
  69.     volatile uint8_t *reg = portModeRegister(port);
  70.  
  71.     // if the SS pin is not already configured as an output
  72.     // then set it high (to enable the internal pull-up resistor)
  73.     if(!(*reg & bit)){
  74.       digitalWrite(SS, HIGH);
  75.     }
  76.        // Set SS to high so a connected chip will be "deselected" by default
  77.  
  78.  
  79.  
  80.     // When the SS pin is set as OUTPUT, it can be used as
  81.     // a general purpose output port (it doesn't influence
  82.     // SPI operations).
  83.  
  84.     // Warning: if the SS pin ever becomes a LOW INPUT then SPI
  85.     // automatically switches to Slave, so the data direction of
  86.     // the SS pin MUST be kept as OUTPUT.
  87.  
  88.     // Set direction register for SCK and MOSI pin.
  89.     // MISO pin automatically overrides to INPUT.
  90.     // By doing this AFTER enabling SPI, we avoid accidentally
  91.     // clocking in a single bit since the lines go directly
  92.     // from "input" to SPI control.
  93.     // http://code.google.com/p/arduino/issues/detail?id=888
  94.     pinMode(SS, OUTPUT);
  95.     pinMode(SCK, OUTPUT);
  96.     pinMode(MOSI, OUTPUT);
  97.     #endif
  98.     SPCR |= _BV(MSTR);
  99.     SPCR |= _BV(SPE);
  100.   }
  101.   initialized++; // reference count
  102.   SREG = sreg;
  103. }
  104.  
  105. void SPIClass::end() {
  106.   uint8_t sreg = SREG;
  107.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  108.   // Decrease the reference counter
  109.   if (initialized)
  110.     initialized--;
  111.   // If there are no more references disable SPI
  112.   if (!initialized) {
  113.     SPCR &= ~_BV(SPE);
  114.     interruptMode = 0;
  115.     #ifdef SPI_TRANSACTION_MISMATCH_LED
  116.     inTransactionFlag = 0;
  117.     #endif
  118.   }
  119.   SREG = sreg;
  120. }
  121.  
  122. // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
  123. #if defined(__AVR_ATmega32U4__)
  124.   #define SPI_INT0_MASK  (1<<INT0)
  125.   #define SPI_INT1_MASK  (1<<INT1)
  126.   #define SPI_INT2_MASK  (1<<INT2)
  127.   #define SPI_INT3_MASK  (1<<INT3)
  128.   #define SPI_INT4_MASK  (1<<INT6)
  129. #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  130.   #define SPI_INT0_MASK  (1<<INT0)
  131.   #define SPI_INT1_MASK  (1<<INT1)
  132.   #define SPI_INT2_MASK  (1<<INT2)
  133.   #define SPI_INT3_MASK  (1<<INT3)
  134.   #define SPI_INT4_MASK  (1<<INT4)
  135.   #define SPI_INT5_MASK  (1<<INT5)
  136.   #define SPI_INT6_MASK  (1<<INT6)
  137.   #define SPI_INT7_MASK  (1<<INT7)
  138. #elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
  139.   #define SPI_INT0_MASK  (1<<INT4)
  140.   #define SPI_INT1_MASK  (1<<INT5)
  141.   #define SPI_INT2_MASK  (1<<INT0)
  142.   #define SPI_INT3_MASK  (1<<INT1)
  143.   #define SPI_INT4_MASK  (1<<INT2)
  144.   #define SPI_INT5_MASK  (1<<INT3)
  145.   #define SPI_INT6_MASK  (1<<INT6)
  146.   #define SPI_INT7_MASK  (1<<INT7)
  147. #else
  148.   #ifdef INT0
  149.   #define SPI_INT0_MASK  (1<<INT0)
  150.   #endif
  151.   #ifdef INT1
  152.   #define SPI_INT1_MASK  (1<<INT1)
  153.   #endif
  154.   #ifdef INT2
  155.   #define SPI_INT2_MASK  (1<<INT2)
  156.   #endif
  157. #endif
  158.  
  159. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  160. {
  161.   uint8_t mask = 0;
  162.   uint8_t sreg = SREG;
  163.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  164.   switch (interruptNumber) {
  165.   #ifdef SPI_INT0_MASK
  166.   case 0: mask = SPI_INT0_MASK; break;
  167.   #endif
  168.   #ifdef SPI_INT1_MASK
  169.   case 1: mask = SPI_INT1_MASK; break;
  170.   #endif
  171.   #ifdef SPI_INT2_MASK
  172.   case 2: mask = SPI_INT2_MASK; break;
  173.   #endif
  174.   #ifdef SPI_INT3_MASK
  175.   case 3: mask = SPI_INT3_MASK; break;
  176.   #endif
  177.   #ifdef SPI_INT4_MASK
  178.   case 4: mask = SPI_INT4_MASK; break;
  179.   #endif
  180.   #ifdef SPI_INT5_MASK
  181.   case 5: mask = SPI_INT5_MASK; break;
  182.   #endif
  183.   #ifdef SPI_INT6_MASK
  184.   case 6: mask = SPI_INT6_MASK; break;
  185.   #endif
  186.   #ifdef SPI_INT7_MASK
  187.   case 7: mask = SPI_INT7_MASK; break;
  188.   #endif
  189.   default:
  190.     interruptMode = 2;
  191.     break;
  192.   }
  193.   interruptMask |= mask;
  194.   if (!interruptMode)
  195.     interruptMode = 1;
  196.   SREG = sreg;
  197. }
  198.  
  199. void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
  200. {
  201.   // Once in mode 2 we can't go back to 0 without a proper reference count
  202.   if (interruptMode == 2)
  203.     return;
  204.   uint8_t mask = 0;
  205.   uint8_t sreg = SREG;
  206.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  207.   switch (interruptNumber) {
  208.   #ifdef SPI_INT0_MASK
  209.   case 0: mask = SPI_INT0_MASK; break;
  210.   #endif
  211.   #ifdef SPI_INT1_MASK
  212.   case 1: mask = SPI_INT1_MASK; break;
  213.   #endif
  214.   #ifdef SPI_INT2_MASK
  215.   case 2: mask = SPI_INT2_MASK; break;
  216.   #endif
  217.   #ifdef SPI_INT3_MASK
  218.   case 3: mask = SPI_INT3_MASK; break;
  219.   #endif
  220.   #ifdef SPI_INT4_MASK
  221.   case 4: mask = SPI_INT4_MASK; break;
  222.   #endif
  223.   #ifdef SPI_INT5_MASK
  224.   case 5: mask = SPI_INT5_MASK; break;
  225.   #endif
  226.   #ifdef SPI_INT6_MASK
  227.   case 6: mask = SPI_INT6_MASK; break;
  228.   #endif
  229.   #ifdef SPI_INT7_MASK
  230.   case 7: mask = SPI_INT7_MASK; break;
  231.   #endif
  232.   default:
  233.     break;
  234.     // this case can't be reached
  235.   }
  236.   interruptMask &= ~mask;
  237.   if (!interruptMask)
  238.     interruptMode = 0;
  239.   SREG = sreg;
  240. }
  241.  
  242.  
  243. #else
  244. #ifdef USICR
  245.  
  246. #include <util/delay_basic.h>
  247.  
  248. SPIClass::SPIClass()
  249. {
  250. }
  251.  
  252. USI_impl::ClockOut SPIClass::clockoutfn = 0;
  253. uint8_t SPIClass::delay = 0;
  254. uint8_t SPIClass::msb1st = MSBFIRST;
  255.  
  256. uint8_t SPIClass::interruptMode = 0;
  257. uint8_t SPIClass::interruptMask = 0;
  258. uint8_t SPIClass::interruptSave = 0;
  259.  
  260. void SPIClass::begin(void)
  261. {
  262.     USICR &= ~(_BV(USISIE) | _BV(USIOIE) | _BV(USIWM1));
  263.     USICR |= _BV(USIWM0) | _BV(USICS1) | _BV(USICLK);
  264.     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output
  265.     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output
  266.     USI_DDR_PORT &= ~_BV(DI_DD_PIN);    //set the DI pin as input
  267.     applySettings(SPISettings());
  268. }
  269.  
  270. void SPIClass::setDataMode(uint8_t spiDataMode)
  271. {
  272.     if (spiDataMode == SPI_MODE1) {
  273.         USICR |= _BV(USICS0);
  274.     } else {
  275.         USICR &= ~_BV(USICS0);
  276.     }
  277.     if (spiDataMode == SPI_MODE2 || spiDataMode == SPI_MODE3) {
  278.         digitalWrite(SCK, HIGH);
  279.     } else {
  280.         digitalWrite(SCK, LOW);
  281.     }
  282. }
  283.  
  284. USI_impl::ClockOut USI_impl::dispatchClockout_slow(uint8_t div, uint8_t* delay)
  285. {
  286.     return dispatchClockout(div, delay);
  287. }
  288.  
  289. static byte reverse (byte x){
  290.  byte result;
  291.  asm("mov __tmp_reg__, %[in] \n\t"
  292.   "lsl __tmp_reg__  \n\t"   /* shift out high bit to carry */
  293.   "ror %[out] \n\t"  /* rotate carry __tmp_reg__to low bit (eventually) */
  294.   "lsl __tmp_reg__  \n\t"   /* 2 */
  295.   "ror %[out] \n\t"
  296.   "lsl __tmp_reg__  \n\t"   /* 3 */
  297.   "ror %[out] \n\t"
  298.   "lsl __tmp_reg__  \n\t"   /* 4 */
  299.   "ror %[out] \n\t"
  300.   "lsl __tmp_reg__  \n\t"   /* 5 */
  301.   "ror %[out] \n\t"
  302.   "lsl __tmp_reg__  \n\t"   /* 6 */
  303.   "ror %[out] \n\t"
  304.   "lsl __tmp_reg__  \n\t"   /* 7 */
  305.   "ror %[out] \n\t"
  306.   "lsl __tmp_reg__  \n\t"   /* 8 */
  307.   "ror %[out] \n\t"
  308.   : [out] "=r" (result) : [in] "r" (x));
  309.   return(result);
  310. }
  311.  
  312. uint8_t USI_impl::clockoutUSI2(uint8_t data, uint8_t)
  313. {
  314.     // Unlike other clockout methods, this one cannot rely on the
  315.     // "external" clock source (USICS1) because it is too slow and
  316.     // glitches. Instead, it uses software strobe explicitly.
  317.     uint8_t strobe1 = _BV(USIWM0) | _BV(USITC);
  318.     uint8_t strobe2 = _BV(USIWM0) | _BV(USITC) | _BV(USICLK);
  319.     uint8_t usicr = USICR;
  320.     bool mode1 = usicr & _BV(USICS0);
  321.     USISR = _BV(USIOIF);  //clear counter and counter overflow interrupt flag
  322.     USIDR = data;
  323.     // Use asm to prevent instruction reordering.
  324.     if (!mode1) {
  325.         asm volatile("out %[usicr], %[strobe1] \n\t"
  326.                      "out %[usicr], %[strobe2] \n\t"
  327.                      "out %[usicr], %[strobe1] \n\t"
  328.                      "out %[usicr], %[strobe2] \n\t"
  329.                      "out %[usicr], %[strobe1] \n\t"
  330.                      "out %[usicr], %[strobe2] \n\t"
  331.                      "out %[usicr], %[strobe1] \n\t"
  332.                      "out %[usicr], %[strobe2] \n\t"
  333.                      "out %[usicr], %[strobe1] \n\t"
  334.                      "out %[usicr], %[strobe2] \n\t"
  335.                      "out %[usicr], %[strobe1] \n\t"
  336.                      "out %[usicr], %[strobe2] \n\t"
  337.                      "out %[usicr], %[strobe1] \n\t"
  338.                      "out %[usicr], %[strobe2] \n\t"
  339.                      "out %[usicr], %[strobe1] \n\t"
  340.                      "out %[usicr], %[strobe2] \n\t"
  341.                      :: [usicr] "I" (_SFR_IO_ADDR(USICR)),
  342.                         [strobe1] "r" (strobe1),
  343.                         [strobe2] "r" (strobe2));
  344.     } else {
  345.         asm volatile("out %[usicr], %[strobe1] \n\t"
  346.                      "out %[usicr], %[strobe1] \n\t"
  347.                      "out %[usicr], %[strobe1] \n\t"
  348.                      "out %[usicr], %[strobe2] \n\t"
  349.                      "out %[usicr], %[strobe1] \n\t"
  350.                      "out %[usicr], %[strobe2] \n\t"
  351.                      "out %[usicr], %[strobe1] \n\t"
  352.                      "out %[usicr], %[strobe2] \n\t"
  353.                      "out %[usicr], %[strobe1] \n\t"
  354.                      "out %[usicr], %[strobe2] \n\t"
  355.                      "out %[usicr], %[strobe1] \n\t"
  356.                      "out %[usicr], %[strobe2] \n\t"
  357.                      "out %[usicr], %[strobe1] \n\t"
  358.                      "out %[usicr], %[strobe2] \n\t"
  359.                      "out %[usicr], %[strobe1] \n\t"
  360.                      "out %[usicr], %[strobe2] \n\t"
  361.                      :: [usicr] "I" (_SFR_IO_ADDR(USICR)),
  362.                         [strobe1] "r" (strobe1),
  363.                         [strobe2] "r" (strobe2));
  364.     }
  365.     uint8_t retval = USIDR;
  366.     USICR = usicr;
  367.     return retval;
  368. }
  369.  
  370. __attribute__((optimize (3, "unroll-all-loops")))
  371. uint8_t USI_impl::clockoutUSI4(uint8_t data, uint8_t)
  372. {
  373.     USISR = _BV(USIOIF);
  374.     USIDR = data;
  375.     for (byte i = 0; i < 16; ++i) {
  376.         USICR |= _BV(USITC); // compiles to sbi, two cycles
  377.     }
  378.     return USIDR;
  379. }
  380.  
  381. __attribute__((optimize (3, "unroll-all-loops")))
  382. uint8_t USI_impl::clockoutUSI8(uint8_t data, uint8_t)
  383. {
  384.     USISR = _BV(USIOIF);
  385.     USIDR = data;
  386.     for (byte i = 0; i < 16; ++i) {
  387.         USICR |= _BV(USITC); // compiles to sbi, two cycles
  388.         USICR &= ~_BV(USITC); // compiles to cbi, two cycles, effectively nop
  389.     }
  390.     return USIDR;
  391. }
  392.  
  393. __attribute__((optimize ("Os")))
  394. uint8_t USI_impl::clockoutUSI(uint8_t data, uint8_t delay)
  395. {
  396.     uint8_t tmp = USICR | _BV(USITC);
  397.     USISR = _BV(USIOIF);
  398.     USIDR = data;
  399.     for (byte i = 0; i < 16; ++i) {
  400.         USICR = tmp; // compiles to out, one cycle
  401.         _delay_loop_1(delay); // delay calculated by SPISettings.
  402.     }
  403.     return USIDR;
  404. }
  405.  
  406. uint8_t SPIClass::transfer(uint8_t spiData)
  407. {
  408.     if (msb1st) {
  409.         return clockoutfn(spiData, delay);
  410.     } else {
  411.         return reverse(clockoutfn(reverse(spiData), delay));
  412.     }
  413. }
  414.  
  415. uint16_t SPIClass::transfer16(uint16_t data)
  416. {
  417.     union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } tmp;
  418.     tmp.val = data;
  419.     if (msb1st) {
  420.         tmp.msb = clockoutfn(tmp.msb, delay);
  421.         tmp.lsb = clockoutfn(tmp.lsb, delay);
  422.     } else {
  423.         tmp.lsb = reverse(clockoutfn(reverse(tmp.lsb), delay));
  424.         tmp.msb = reverse(clockoutfn(reverse(tmp.msb), delay));
  425.     }
  426.     return tmp.val;
  427. }
  428.  
  429. void SPIClass::transfer(void* _buf, size_t count) {
  430.     uint8_t* buf = (uint8_t*)_buf;
  431.     if (!msb1st) {
  432.         for (uint8_t i = 0; i < count; ++i) {
  433.             buf[i] = reverse(buf[i]);
  434.         }
  435.     }
  436.     for (uint8_t i = 0; i < count; ++i) {
  437.         buf[i] = clockoutfn(buf[i], delay);
  438.     }
  439.     if (!msb1st) {
  440.         for (uint8_t i = 0; i < count; ++i) {
  441.             buf[i] = reverse(buf[i]);
  442.         }
  443.     }
  444. }
  445.  
  446. void SPIClass::applySettings(SPISettings settings) {
  447.     USICR = settings.usicr;
  448.     msb1st = settings.msb1st ;
  449.     delay = settings.delay;
  450.     clockoutfn = settings.clockoutfn;
  451.     if (settings.cpol) {
  452.         digitalWrite(SCK, HIGH);
  453.     } else {
  454.         digitalWrite(SCK, LOW);
  455.     }
  456. }
  457.  
  458. void SPIClass::beginTransaction(SPISettings settings) {
  459.     if (interruptMode > 0) {
  460.       uint8_t sreg = SREG;
  461.       noInterrupts();
  462.  
  463.       #ifdef SPI_AVR_EIMSK
  464.       if (interruptMode == 1) {
  465.         interruptSave = SPI_AVR_EIMSK;
  466.         SPI_AVR_EIMSK &= ~interruptMask;
  467.         SREG = sreg;
  468.       } else
  469.       #endif
  470.       {
  471.         interruptSave = sreg;
  472.       }
  473.     }
  474.     applySettings(settings);
  475.   }
  476.  
  477. void SPIClass::endTransaction(void) {
  478.   if (interruptMode > 0) {
  479.     #ifdef SPI_AVR_EIMSK
  480.     uint8_t sreg = SREG;
  481.     #endif
  482.     noInterrupts();
  483.     #ifdef SPI_AVR_EIMSK
  484.     if (interruptMode == 1) {
  485.       SPI_AVR_EIMSK = interruptSave;
  486.       SREG = sreg;
  487.     } else
  488.     #endif
  489.     {
  490.       SREG = interruptSave;
  491.     }
  492.   }
  493. }
  494. #ifdef INT0
  495. #define SPI_INT0_MASK  (1<<INT0)
  496. #endif
  497. #ifdef INT1
  498. #define SPI_INT1_MASK  (1<<INT1)
  499. #endif
  500. #ifdef INT2
  501. #define SPI_INT2_MASK  (1<<INT2)
  502. #endif
  503.  
  504. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  505. {
  506.   uint8_t mask = 0;
  507.   uint8_t sreg = SREG;
  508.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  509.   switch (interruptNumber) {
  510.   #ifdef SPI_INT0_MASK
  511.   case 0: mask = SPI_INT0_MASK; break;
  512.   #endif
  513.   #ifdef SPI_INT1_MASK
  514.   case 1: mask = SPI_INT1_MASK; break;
  515.   #endif
  516.   #ifdef SPI_INT2_MASK
  517.   case 2: mask = SPI_INT2_MASK; break;
  518.   #endif
  519.   default:
  520.     interruptMode = 2;
  521.     break;
  522.   }
  523.   interruptMask |= mask;
  524.   if (!interruptMode)
  525.     interruptMode = 1;
  526.   SREG = sreg;
  527. }
  528.  
  529. void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
  530. {
  531.   // Once in mode 2 we can't go back to 0 without a proper reference count
  532.   if (interruptMode == 2)
  533.     return;
  534.   uint8_t mask = 0;
  535.   uint8_t sreg = SREG;
  536.   noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  537.   switch (interruptNumber) {
  538.   #ifdef SPI_INT0_MASK
  539.   case 0: mask = SPI_INT0_MASK; break;
  540.   #endif
  541.   #ifdef SPI_INT1_MASK
  542.   case 1: mask = SPI_INT1_MASK; break;
  543.   #endif
  544.   #ifdef SPI_INT2_MASK
  545.   case 2: mask = SPI_INT2_MASK; break;
  546.   #endif
  547.   default:
  548.     break;
  549.     // this case can't be reached
  550.   }
  551.   interruptMask &= ~mask;
  552.   if (!interruptMask)
  553.     interruptMode = 0;
  554.   SREG = sreg;
  555. }
  556. void SPIClass::end(void)
  557. {
  558.     USICR &= ~(_BV(USIWM1) | _BV(USIWM0));
  559. }
  560.  
  561. SPIClass SPI = SPIClass();                //instantiate a tinySPI object
  562.  
  563.  
  564. #endif
  565. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement