PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 satır
3.3KB

  1. // SoftwareSPI.cpp
  2. // Author: Chris Lapa (chris@lapa.com.au)
  3. // Copyright (C) 2014 Chris Lapa
  4. // Contributed by Chris Lapa
  5. #include <RHSoftwareSPI.h>
  6. RHSoftwareSPI::RHSoftwareSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode)
  7. :
  8. RHGenericSPI(frequency, bitOrder, dataMode)
  9. {
  10. setPins(12, 11, 13);
  11. }
  12. // Caution: on Arduino Uno and many other CPUs, digitalWrite is quite slow, taking about 4us
  13. // digitalWrite is also slow, taking about 3.5us
  14. // resulting in very slow SPI bus speeds using this technique, up to about 120us per octet of transfer
  15. uint8_t RHSoftwareSPI::transfer(uint8_t data)
  16. {
  17. uint8_t readData;
  18. uint8_t writeData;
  19. uint8_t builtReturn;
  20. uint8_t mask;
  21. if (_bitOrder == BitOrderMSBFirst)
  22. {
  23. mask = 0x80;
  24. }
  25. else
  26. {
  27. mask = 0x01;
  28. }
  29. builtReturn = 0;
  30. readData = 0;
  31. for (uint8_t count=0; count<8; count++)
  32. {
  33. if (data & mask)
  34. {
  35. writeData = HIGH;
  36. }
  37. else
  38. {
  39. writeData = LOW;
  40. }
  41. if (_clockPhase == 1)
  42. {
  43. // CPHA=1, miso/mosi changing state now
  44. digitalWrite(_mosi, writeData);
  45. digitalWrite(_sck, ~_clockPolarity);
  46. delayPeriod();
  47. // CPHA=1, miso/mosi stable now
  48. readData = digitalRead(_miso);
  49. digitalWrite(_sck, _clockPolarity);
  50. delayPeriod();
  51. }
  52. else
  53. {
  54. // CPHA=0, miso/mosi changing state now
  55. digitalWrite(_mosi, writeData);
  56. digitalWrite(_sck, _clockPolarity);
  57. delayPeriod();
  58. // CPHA=0, miso/mosi stable now
  59. readData = digitalRead(_miso);
  60. digitalWrite(_sck, ~_clockPolarity);
  61. delayPeriod();
  62. }
  63. if (_bitOrder == BitOrderMSBFirst)
  64. {
  65. mask >>= 1;
  66. builtReturn |= (readData << (7 - count));
  67. }
  68. else
  69. {
  70. mask <<= 1;
  71. builtReturn |= (readData << count);
  72. }
  73. }
  74. digitalWrite(_sck, _clockPolarity);
  75. return builtReturn;
  76. }
  77. /// Initialise the SPI library
  78. void RHSoftwareSPI::begin()
  79. {
  80. if (_dataMode == DataMode0 ||
  81. _dataMode == DataMode1)
  82. {
  83. _clockPolarity = LOW;
  84. }
  85. else
  86. {
  87. _clockPolarity = HIGH;
  88. }
  89. if (_dataMode == DataMode0 ||
  90. _dataMode == DataMode2)
  91. {
  92. _clockPhase = 0;
  93. }
  94. else
  95. {
  96. _clockPhase = 1;
  97. }
  98. digitalWrite(_sck, _clockPolarity);
  99. // Caution: these counts assume that digitalWrite is very fast, which is usually not true
  100. switch (_frequency)
  101. {
  102. case Frequency1MHz:
  103. _delayCounts = 8;
  104. break;
  105. case Frequency2MHz:
  106. _delayCounts = 4;
  107. break;
  108. case Frequency4MHz:
  109. _delayCounts = 2;
  110. break;
  111. case Frequency8MHz:
  112. _delayCounts = 1;
  113. break;
  114. case Frequency16MHz:
  115. _delayCounts = 0;
  116. break;
  117. }
  118. }
  119. /// Disables the SPI bus usually, in this case
  120. /// there is no hardware controller to disable.
  121. void RHSoftwareSPI::end() { }
  122. /// Sets the pins used by this SoftwareSPIClass instance.
  123. /// \param[in] miso master in slave out pin used
  124. /// \param[in] mosi master out slave in pin used
  125. /// \param[in] sck clock pin used
  126. void RHSoftwareSPI::setPins(uint8_t miso, uint8_t mosi, uint8_t sck)
  127. {
  128. _miso = miso;
  129. _mosi = mosi;
  130. _sck = sck;
  131. pinMode(_miso, INPUT);
  132. pinMode(_mosi, OUTPUT);
  133. pinMode(_sck, OUTPUT);
  134. digitalWrite(_sck, _clockPolarity);
  135. }
  136. void RHSoftwareSPI::delayPeriod()
  137. {
  138. for (uint8_t count = 0; count < _delayCounts; count++)
  139. {
  140. __asm__ __volatile__ ("nop");
  141. }
  142. }