acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Arduino_SWSPI.cpp (16027B)

      1 /*
      2  * start rewrite from:
      3  * https://github.com/adafruit/Adafruit-GFX-Library.git
      4  */
      5 #include "Arduino_SWSPI.h"
      6 
      7 Arduino_SWSPI::Arduino_SWSPI(int8_t dc, int8_t cs, int8_t sck, int8_t mosi, int8_t miso /* = GFX_NOT_DEFINED */)
      8     : _dc(dc), _cs(cs), _sck(sck), _mosi(mosi), _miso(miso)
      9 {
     10 }
     11 
     12 bool Arduino_SWSPI::begin(int32_t speed, int8_t dataMode)
     13 {
     14   UNUSED(speed);
     15   UNUSED(dataMode);
     16 
     17   if (_dc != GFX_NOT_DEFINED)
     18   {
     19     pinMode(_dc, OUTPUT);
     20     digitalWrite(_dc, HIGH); // Data mode
     21   }
     22   if (_cs != GFX_NOT_DEFINED)
     23   {
     24     pinMode(_cs, OUTPUT);
     25     digitalWrite(_cs, HIGH); // Deselect
     26   }
     27   pinMode(_sck, OUTPUT);
     28   digitalWrite(_sck, LOW);
     29   pinMode(_mosi, OUTPUT);
     30   digitalWrite(_mosi, LOW);
     31   if (_miso != GFX_NOT_DEFINED)
     32   {
     33     pinMode(_miso, INPUT);
     34   }
     35 
     36 #if defined(USE_FAST_PINIO)
     37 #if defined(HAS_PORT_SET_CLR)
     38 #if defined(ARDUINO_ARCH_NRF52840)
     39   uint32_t pin;
     40   NRF_GPIO_Type *reg;
     41   if (_dc != GFX_NOT_DEFINED)
     42   {
     43     pin = digitalPinToPinName((pin_size_t)_dc);
     44     reg = nrf_gpio_pin_port_decode(&pin);
     45     _dcPinMask = 1UL << pin;
     46     _dcPortSet = &reg->OUTSET;
     47     _dcPortClr = &reg->OUTCLR;
     48   }
     49   if (_cs != GFX_NOT_DEFINED)
     50   {
     51     pin = digitalPinToPinName((pin_size_t)_cs);
     52     NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin);
     53     _csPinMask = 1UL << pin;
     54     _csPortSet = &reg->OUTSET;
     55     _csPortClr = &reg->OUTCLR;
     56   }
     57   pin = digitalPinToPinName((pin_size_t)_sck);
     58   reg = nrf_gpio_pin_port_decode(&pin);
     59   _sckPinMask = 1UL << pin;
     60   _sckPortSet = &reg->OUTSET;
     61   _sckPortClr = &reg->OUTCLR;
     62   pin = digitalPinToPinName((pin_size_t)_mosi);
     63   reg = nrf_gpio_pin_port_decode(&pin);
     64   _mosiPinMask = 1UL << pin;
     65   _mosiPortSet = &reg->OUTSET;
     66   _mosiPortClr = &reg->OUTCLR;
     67   if (_miso != GFX_NOT_DEFINED)
     68   {
     69     pin = digitalPinToPinName((pin_size_t)_miso);
     70     reg = nrf_gpio_pin_port_decode(&pin);
     71     _misoPinMask = 1UL << pin;
     72     _misoPort = &reg->IN;
     73   }
     74 #elif defined(TARGET_RP2040)
     75   if (_dc != GFX_NOT_DEFINED)
     76   {
     77     _dcPinMask = digitalPinToBitMask(_dc);
     78     _dcPortSet = (PORTreg_t)&sio_hw->gpio_set;
     79     _dcPortClr = (PORTreg_t)&sio_hw->gpio_clr;
     80   }
     81   if (_cs != GFX_NOT_DEFINED)
     82   {
     83     _csPinMask = digitalPinToBitMask(_cs);
     84     _csPortSet = (PORTreg_t)&sio_hw->gpio_set;
     85     _csPortClr = (PORTreg_t)&sio_hw->gpio_clr;
     86   }
     87   _sckPinMask = digitalPinToBitMask(_sck);
     88   _sckPortSet = (PORTreg_t)&sio_hw->gpio_set;
     89   _sckPortClr = (PORTreg_t)&sio_hw->gpio_clr;
     90   _mosiPinMask = digitalPinToBitMask(_mosi);
     91   _mosiPortSet = (PORTreg_t)&sio_hw->gpio_set;
     92   _mosiPortClr = (PORTreg_t)&sio_hw->gpio_clr;
     93   if (_miso != GFX_NOT_DEFINED)
     94   {
     95     _misoPinMask = digitalPinToBitMask(_miso);
     96     _misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
     97   }
     98 #elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32C3)
     99   _dcPinMask = digitalPinToBitMask(_dc);
    100   _dcPortSet = (PORTreg_t)&GPIO.out_w1ts;
    101   _dcPortClr = (PORTreg_t)&GPIO.out_w1tc;
    102   if (_cs != GFX_NOT_DEFINED)
    103   {
    104     _csPinMask = digitalPinToBitMask(_cs);
    105     _csPortSet = (PORTreg_t)&GPIO.out_w1ts;
    106     _csPortClr = (PORTreg_t)&GPIO.out_w1tc;
    107   }
    108   _sckPinMask = digitalPinToBitMask(_sck);
    109   _sckPortSet = (PORTreg_t)&GPIO.out_w1ts;
    110   _sckPortClr = (PORTreg_t)&GPIO.out_w1tc;
    111   _mosiPinMask = digitalPinToBitMask(_mosi);
    112   _mosiPortSet = (PORTreg_t)&GPIO.out_w1ts;
    113   _mosiPortClr = (PORTreg_t)&GPIO.out_w1tc;
    114   if (_miso != GFX_NOT_DEFINED)
    115   {
    116     _misoPinMask = digitalPinToBitMask(_miso);
    117     _misoPort = (PORTreg_t)GPIO_IN_REG;
    118   }
    119 #elif defined(ESP32)
    120   _dcPinMask = digitalPinToBitMask(_dc);
    121   if (_dc >= 32)
    122   {
    123     _dcPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
    124     _dcPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
    125   }
    126   else if (_dc != GFX_NOT_DEFINED)
    127   {
    128     _dcPortSet = (PORTreg_t)&GPIO.out_w1ts;
    129     _dcPortClr = (PORTreg_t)&GPIO.out_w1tc;
    130   }
    131   if (_cs >= 32)
    132   {
    133     _csPinMask = digitalPinToBitMask(_cs);
    134     _csPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
    135     _csPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
    136   }
    137   else if (_cs != GFX_NOT_DEFINED)
    138   {
    139     _csPinMask = digitalPinToBitMask(_cs);
    140     _csPortSet = (PORTreg_t)&GPIO.out_w1ts;
    141     _csPortClr = (PORTreg_t)&GPIO.out_w1tc;
    142   }
    143   _sckPinMask = digitalPinToBitMask(_sck);
    144   _mosiPinMask = digitalPinToBitMask(_mosi);
    145   if (_sck >= 32)
    146   {
    147     _sckPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
    148     _sckPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
    149   }
    150   else
    151   {
    152     _sckPortSet = (PORTreg_t)&GPIO.out_w1ts;
    153     _sckPortClr = (PORTreg_t)&GPIO.out_w1tc;
    154   }
    155   if (_mosi >= 32)
    156   {
    157     _mosiPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
    158     _mosiPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
    159   }
    160   else
    161   {
    162     _mosiPortSet = (PORTreg_t)&GPIO.out_w1ts;
    163     _mosiPortClr = (PORTreg_t)&GPIO.out_w1tc;
    164   }
    165   if (_miso != GFX_NOT_DEFINED)
    166   {
    167     _misoPinMask = digitalPinToBitMask(_miso);
    168     _misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
    169   }
    170 #elif defined(CORE_TEENSY)
    171   if (_dc != GFX_NOT_DEFINED)
    172   {
    173 #if !defined(KINETISK)
    174     _dcPinMask = digitalPinToBitMask(_dc);
    175 #endif
    176     _dcPortSet = portSetRegister(_dc);
    177     _dcPortClr = portClearRegister(_dc);
    178   }
    179   if (_cs != GFX_NOT_DEFINED)
    180   {
    181 #if !defined(KINETISK)
    182     _csPinMask = digitalPinToBitMask(_cs);
    183 #endif
    184     _csPortSet = portSetRegister(_cs);
    185     _csPortClr = portClearRegister(_cs);
    186   }
    187 #if !defined(KINETISK)
    188   _sckPinMask = digitalPinToBitMask(_sck);
    189 #endif
    190   _sckPortSet = portSetRegister(_sck);
    191   _sckPortClr = portClearRegister(_sck);
    192 #if !defined(KINETISK)
    193   _mosiPinMask = digitalPinToBitMask(_mosi);
    194 #endif
    195   _mosiPortSet = portSetRegister(_mosi);
    196   _mosiPortClr = portClearRegister(_mosi);
    197   if (_miso != GFX_NOT_DEFINED)
    198   {
    199 #if !defined(KINETISK)
    200     _misoPinMask = digitalPinToBitMask(_miso);
    201 #endif
    202     _misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
    203   }
    204 #else  // !CORE_TEENSY
    205   if (_dc != GFX_NOT_DEFINED)
    206   {
    207     _dcPinMask = digitalPinToBitMask(_dc);
    208     _dcPortSet = &(PORT->Group[g_APinDescription[_dc].ulPort].OUTSET.reg);
    209     _dcPortClr = &(PORT->Group[g_APinDescription[_dc].ulPort].OUTCLR.reg);
    210   }
    211   if (_cs != GFX_NOT_DEFINED)
    212   {
    213     _csPinMask = digitalPinToBitMask(_cs);
    214     _csPortSet = &(PORT->Group[g_APinDescription[_cs].ulPort].OUTSET.reg);
    215     _csPortClr = &(PORT->Group[g_APinDescription[_cs].ulPort].OUTCLR.reg);
    216   }
    217   _sckPinMask = digitalPinToBitMask(_sck);
    218   _sckPortSet = &(PORT->Group[g_APinDescription[_sck].ulPort].OUTSET.reg);
    219   _sckPortClr = &(PORT->Group[g_APinDescription[_sck].ulPort].OUTCLR.reg);
    220   _mosiPinMask = digitalPinToBitMask(_mosi);
    221   _mosiPortSet = &(PORT->Group[g_APinDescription[_mosi].ulPort].OUTSET.reg);
    222   _mosiPortClr = &(PORT->Group[g_APinDescription[_mosi].ulPort].OUTCLR.reg);
    223   if (_miso != GFX_NOT_DEFINED)
    224   {
    225     _misoPinMask = digitalPinToBitMask(_miso);
    226     _misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
    227   }
    228 #endif // end !CORE_TEENSY
    229 #else  // !HAS_PORT_SET_CLR
    230   if (_dc != GFX_NOT_DEFINED)
    231   {
    232     _dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_dc));
    233     _dcPinMaskSet = digitalPinToBitMask(_dc);
    234     _dcPinMaskClr = ~_dcPinMaskSet;
    235   }
    236   if (_cs != GFX_NOT_DEFINED)
    237   {
    238     _csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_cs));
    239     _csPinMaskSet = digitalPinToBitMask(_cs);
    240     _csPinMaskClr = ~_csPinMaskSet;
    241   }
    242   _sckPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_sck));
    243   _sckPinMaskSet = digitalPinToBitMask(_sck);
    244   _sckPinMaskClr = ~_sckPinMaskSet;
    245   _mosiPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_mosi));
    246   _mosiPinMaskSet = digitalPinToBitMask(_mosi);
    247   _mosiPinMaskClr = ~_mosiPinMaskSet;
    248   if (_miso != GFX_NOT_DEFINED)
    249   {
    250     _misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
    251     _misoPinMask = digitalPinToBitMask(_miso);
    252   }
    253 #endif // !HAS_PORT_SET_CLR
    254 #endif // USE_FAST_PINIO
    255 
    256   return true;
    257 }
    258 
    259 void Arduino_SWSPI::beginWrite()
    260 {
    261   if (_dc != GFX_NOT_DEFINED)
    262   {
    263     DC_HIGH();
    264   }
    265   CS_LOW();
    266 }
    267 
    268 void Arduino_SWSPI::endWrite()
    269 {
    270   CS_HIGH();
    271 }
    272 
    273 void Arduino_SWSPI::writeCommand(uint8_t c)
    274 {
    275   if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
    276   {
    277     WRITE9BITCOMMAND(c);
    278   }
    279   else
    280   {
    281     DC_LOW();
    282     WRITE(c);
    283     DC_HIGH();
    284   }
    285 }
    286 
    287 void Arduino_SWSPI::writeCommand16(uint16_t c)
    288 {
    289   if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
    290   {
    291     _data16.value = c;
    292     WRITE9BITCOMMAND(_data16.msb);
    293     WRITE9BITCOMMAND(_data16.lsb);
    294   }
    295   else
    296   {
    297     DC_LOW();
    298     WRITE16(c);
    299     DC_HIGH();
    300   }
    301 }
    302 
    303 void Arduino_SWSPI::write(uint8_t d)
    304 {
    305   if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
    306   {
    307     WRITE9BITDATA(d);
    308   }
    309   else
    310   {
    311     WRITE(d);
    312   }
    313 }
    314 
    315 void Arduino_SWSPI::write16(uint16_t d)
    316 {
    317   if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
    318   {
    319     _data16.value = d;
    320     WRITE9BITDATA(_data16.msb);
    321     WRITE9BITDATA(_data16.lsb);
    322   }
    323   else
    324   {
    325     WRITE16(d);
    326   }
    327 }
    328 
    329 void Arduino_SWSPI::writeRepeat(uint16_t p, uint32_t len)
    330 {
    331   if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
    332   {
    333 // ESP8266 avoid trigger watchdog
    334 #if defined(ESP8266)
    335     while (len > (ESP8266SAFEBATCHBITSIZE / 9))
    336     {
    337       WRITE9BITREPEAT(p, ESP8266SAFEBATCHBITSIZE / 9);
    338       len -= ESP8266SAFEBATCHBITSIZE / 9;
    339       yield();
    340     }
    341     WRITE9BITREPEAT(p, len);
    342 #else
    343     WRITE9BITREPEAT(p, len);
    344 #endif
    345   }
    346   else
    347   {
    348 #if defined(ESP8266)
    349     while (len > (ESP8266SAFEBATCHBITSIZE / 8))
    350     {
    351       WRITEREPEAT(p, ESP8266SAFEBATCHBITSIZE / 8);
    352       len -= ESP8266SAFEBATCHBITSIZE / 8;
    353       yield();
    354     }
    355     WRITEREPEAT(p, len);
    356 #else
    357     WRITEREPEAT(p, len);
    358 #endif
    359   }
    360 }
    361 
    362 void Arduino_SWSPI::writePixels(uint16_t *data, uint32_t len)
    363 {
    364   while (len--)
    365   {
    366     WRITE16(*data++);
    367   }
    368 }
    369 
    370 #if !defined(LITTLE_FOOT_PRINT)
    371 void Arduino_SWSPI::writeBytes(uint8_t *data, uint32_t len)
    372 {
    373   while (len--)
    374   {
    375     WRITE(*data++);
    376   }
    377 }
    378 
    379 void Arduino_SWSPI::writePattern(uint8_t *data, uint8_t len, uint32_t repeat)
    380 {
    381   while (repeat--)
    382   {
    383     for (uint8_t i = 0; i < len; i++)
    384     {
    385       WRITE(data[i]);
    386     }
    387   }
    388 }
    389 #endif // !defined(LITTLE_FOOT_PRINT)
    390 
    391 INLINE void Arduino_SWSPI::WRITE9BITCOMMAND(uint8_t c)
    392 {
    393   // D/C bit, command
    394   SPI_MOSI_LOW();
    395   SPI_SCK_HIGH();
    396   SPI_SCK_LOW();
    397 
    398   uint8_t bit = 0x80;
    399   while (bit)
    400   {
    401     if (c & bit)
    402     {
    403       SPI_MOSI_HIGH();
    404     }
    405     else
    406     {
    407       SPI_MOSI_LOW();
    408     }
    409     SPI_SCK_HIGH();
    410     bit >>= 1;
    411     SPI_SCK_LOW();
    412   }
    413 }
    414 
    415 INLINE void Arduino_SWSPI::WRITE9BITDATA(uint8_t d)
    416 {
    417   // D/C bit, data
    418   SPI_MOSI_HIGH();
    419   SPI_SCK_HIGH();
    420   SPI_SCK_LOW();
    421 
    422   uint8_t bit = 0x80;
    423   while (bit)
    424   {
    425     if (d & bit)
    426     {
    427       SPI_MOSI_HIGH();
    428     }
    429     else
    430     {
    431       SPI_MOSI_LOW();
    432     }
    433     SPI_SCK_HIGH();
    434     bit >>= 1;
    435     SPI_SCK_LOW();
    436   }
    437 }
    438 
    439 INLINE void Arduino_SWSPI::WRITE(uint8_t d)
    440 {
    441   uint8_t bit = 0x80;
    442   while (bit)
    443   {
    444     if (d & bit)
    445     {
    446       SPI_MOSI_HIGH();
    447     }
    448     else
    449     {
    450       SPI_MOSI_LOW();
    451     }
    452     SPI_SCK_HIGH();
    453     bit >>= 1;
    454     SPI_SCK_LOW();
    455   }
    456 }
    457 
    458 INLINE void Arduino_SWSPI::WRITE16(uint16_t d)
    459 {
    460   uint16_t bit = 0x8000;
    461   while (bit)
    462   {
    463     if (d & bit)
    464     {
    465       SPI_MOSI_HIGH();
    466     }
    467     else
    468     {
    469       SPI_MOSI_LOW();
    470     }
    471     SPI_SCK_HIGH();
    472     bit >>= 1;
    473     SPI_SCK_LOW();
    474   }
    475 }
    476 
    477 INLINE void Arduino_SWSPI::WRITE9BITREPEAT(uint16_t p, uint32_t len)
    478 {
    479   if (p == 0xffff) // no need to set MOSI level while filling white
    480   {
    481     SPI_MOSI_HIGH();
    482     len *= 18; // 9-bit * 2
    483     while (len--)
    484     {
    485       SPI_SCK_HIGH();
    486       SPI_SCK_LOW();
    487     }
    488   }
    489   else
    490   {
    491     _data16.value = p;
    492     while (len--)
    493     {
    494       WRITE9BITDATA(_data16.msb);
    495       WRITE9BITDATA(_data16.lsb);
    496     }
    497   }
    498 }
    499 
    500 INLINE void Arduino_SWSPI::WRITEREPEAT(uint16_t p, uint32_t len)
    501 {
    502   if ((p == 0x0000) || (p == 0xffff)) // no need to set MOSI level while filling black or white
    503   {
    504     if (p)
    505     {
    506       SPI_MOSI_HIGH();
    507     }
    508     else
    509     {
    510       SPI_MOSI_LOW();
    511     }
    512     len *= 16;
    513     while (len--)
    514     {
    515       SPI_SCK_HIGH();
    516       SPI_SCK_LOW();
    517     }
    518   }
    519   else
    520   {
    521     while (len--)
    522     {
    523       WRITE16(p);
    524     }
    525   }
    526 }
    527 
    528 /******** low level bit twiddling **********/
    529 
    530 INLINE void Arduino_SWSPI::DC_HIGH(void)
    531 {
    532 #if defined(USE_FAST_PINIO)
    533 #if defined(HAS_PORT_SET_CLR)
    534 #if defined(KINETISK)
    535   *_dcPortSet = 1;
    536 #else  // !KINETISK
    537   *_dcPortSet = _dcPinMask;
    538 #endif // end !KINETISK
    539 #else  // !HAS_PORT_SET_CLR
    540   *_dcPort |= _dcPinMaskSet;
    541 #endif // end !HAS_PORT_SET_CLR
    542 #else  // !USE_FAST_PINIO
    543   digitalWrite(_dc, HIGH);
    544 #endif // end !USE_FAST_PINIO
    545 }
    546 
    547 INLINE void Arduino_SWSPI::DC_LOW(void)
    548 {
    549 #if defined(USE_FAST_PINIO)
    550 #if defined(HAS_PORT_SET_CLR)
    551 #if defined(KINETISK)
    552   *_dcPortClr = 1;
    553 #else  // !KINETISK
    554   *_dcPortClr = _dcPinMask;
    555 #endif // end !KINETISK
    556 #else  // !HAS_PORT_SET_CLR
    557   *_dcPort &= _dcPinMaskClr;
    558 #endif // end !HAS_PORT_SET_CLR
    559 #else  // !USE_FAST_PINIO
    560   digitalWrite(_dc, LOW);
    561 #endif // end !USE_FAST_PINIO
    562 }
    563 
    564 INLINE void Arduino_SWSPI::CS_HIGH(void)
    565 {
    566   if (_cs != GFX_NOT_DEFINED)
    567   {
    568 #if defined(USE_FAST_PINIO)
    569 #if defined(HAS_PORT_SET_CLR)
    570 #if defined(KINETISK)
    571     *_csPortSet = 1;
    572 #else  // !KINETISK
    573     *_csPortSet = _csPinMask;
    574 #endif // end !KINETISK
    575 #else  // !HAS_PORT_SET_CLR
    576     *_csPort |= _csPinMaskSet;
    577 #endif // end !HAS_PORT_SET_CLR
    578 #else  // !USE_FAST_PINIO
    579     digitalWrite(_cs, HIGH);
    580 #endif // end !USE_FAST_PINIO
    581   }
    582 }
    583 
    584 INLINE void Arduino_SWSPI::CS_LOW(void)
    585 {
    586   if (_cs != GFX_NOT_DEFINED)
    587   {
    588 #if defined(USE_FAST_PINIO)
    589 #if defined(HAS_PORT_SET_CLR)
    590 #if defined(KINETISK)
    591     *_csPortClr = 1;
    592 #else  // !KINETISK
    593     *_csPortClr = _csPinMask;
    594 #endif // end !KINETISK
    595 #else  // !HAS_PORT_SET_CLR
    596     *_csPort &= _csPinMaskClr;
    597 #endif // end !HAS_PORT_SET_CLR
    598 #else  // !USE_FAST_PINIO
    599     digitalWrite(_cs, LOW);
    600 #endif // end !USE_FAST_PINIO
    601   }
    602 }
    603 
    604 /*!
    605     @brief  Set the software (bitbang) SPI MOSI line HIGH.
    606 */
    607 INLINE void Arduino_SWSPI::SPI_MOSI_HIGH(void)
    608 {
    609 #if defined(USE_FAST_PINIO)
    610 #if defined(HAS_PORT_SET_CLR)
    611 #if defined(KINETISK)
    612   *_mosiPortSet = 1;
    613 #else // !KINETISK
    614   *_mosiPortSet = _mosiPinMask;
    615 #endif
    616 #else  // !HAS_PORT_SET_CLR
    617   *_mosiPort |= _mosiPinMaskSet;
    618 #endif // end !HAS_PORT_SET_CLR
    619 #else  // !USE_FAST_PINIO
    620   digitalWrite(_mosi, HIGH);
    621 #endif // end !USE_FAST_PINIO
    622 }
    623 
    624 /*!
    625     @brief  Set the software (bitbang) SPI MOSI line LOW.
    626 */
    627 INLINE void Arduino_SWSPI::SPI_MOSI_LOW(void)
    628 {
    629 #if defined(USE_FAST_PINIO)
    630 #if defined(HAS_PORT_SET_CLR)
    631 #if defined(KINETISK)
    632   *_mosiPortClr = 1;
    633 #else // !KINETISK
    634   *_mosiPortClr = _mosiPinMask;
    635 #endif
    636 #else  // !HAS_PORT_SET_CLR
    637   *_mosiPort &= _mosiPinMaskClr;
    638 #endif // end !HAS_PORT_SET_CLR
    639 #else  // !USE_FAST_PINIO
    640   digitalWrite(_mosi, LOW);
    641 #endif // end !USE_FAST_PINIO
    642 }
    643 
    644 /*!
    645     @brief  Set the software (bitbang) SPI SCK line HIGH.
    646 */
    647 INLINE void Arduino_SWSPI::SPI_SCK_HIGH(void)
    648 {
    649 #if defined(USE_FAST_PINIO)
    650 #if defined(HAS_PORT_SET_CLR)
    651 #if defined(KINETISK)
    652   *_sckPortSet = 1;
    653 #else                                                // !KINETISK
    654   *_sckPortSet = _sckPinMask;
    655 #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
    656   for (volatile uint8_t i = 0; i < 1; i++)
    657     ;
    658 #endif
    659 #endif
    660 #else  // !HAS_PORT_SET_CLR
    661   *_sckPort |= _sckPinMaskSet;
    662 #endif // end !HAS_PORT_SET_CLR
    663 #else  // !USE_FAST_PINIO
    664   digitalWrite(_sck, HIGH);
    665 #endif // end !USE_FAST_PINIO
    666 }
    667 
    668 /*!
    669     @brief  Set the software (bitbang) SPI SCK line LOW.
    670 */
    671 INLINE void Arduino_SWSPI::SPI_SCK_LOW(void)
    672 {
    673 #if defined(USE_FAST_PINIO)
    674 #if defined(HAS_PORT_SET_CLR)
    675 #if defined(KINETISK)
    676   *_sckPortClr = 1;
    677 #else                                                // !KINETISK
    678   *_sckPortClr = _sckPinMask;
    679 #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
    680   for (volatile uint8_t i = 0; i < 1; i++)
    681     ;
    682 #endif
    683 #endif
    684 #else  // !HAS_PORT_SET_CLR
    685   *_sckPort &= _sckPinMaskClr;
    686 #endif // end !HAS_PORT_SET_CLR
    687 #else  // !USE_FAST_PINIO
    688   digitalWrite(_sck, LOW);
    689 #endif // end !USE_FAST_PINIO
    690 }
    691 
    692 /*!
    693     @brief   Read the state of the software (bitbang) SPI MISO line.
    694     @return  true if HIGH, false if LOW.
    695 */
    696 INLINE bool Arduino_SWSPI::SPI_MISO_READ(void)
    697 {
    698 #if defined(USE_FAST_PINIO)
    699 #if defined(KINETISK)
    700   return *_misoPort;
    701 #else  // !KINETISK
    702   return *_misoPort & _misoPinMask;
    703 #endif // end !KINETISK
    704 #else  // !USE_FAST_PINIO
    705   return digitalRead(_miso);
    706 #endif // end !USE_FAST_PINIO
    707 }