Fork of the espurna firmware for `mhsw` switches
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.

187 lines
3.9 KiB

  1. /*
  2. MCP23S08 MODULE
  3. Copyright (C) 2020 by Eddi De Pieri <eddi at depieri dot com>
  4. Adapted from https://github.com/kmpelectronics/Arduino
  5. Copyright (C) 2016 Plamen Kovandjiev <p.kovandiev@kmpelectronics.eu> & Dimitar Antonov <d.antonov@kmpelectronics.eu>
  6. (ref. https://github.com/kmpelectronics/Arduino/blob/master/ProDinoWiFiEsp/src/PRODINoESP8266/src/KMPDinoWiFiESP.cpp)
  7. */
  8. #include "mcp23s08.h"
  9. #if MCP23S08_SUPPORT
  10. #include <SPI.h>
  11. #include <bitset>
  12. // TODO: check if this needed for SPI operation
  13. #define MCP23S08_CS_PIN 15
  14. // Known commands
  15. #define READ_CMD 0x41
  16. #define WRITE_CMD 0x40
  17. // Registers
  18. #define IODIR 0x00
  19. #define IPOL 0x01
  20. #define GPINTEN 0x02
  21. #define DEFVAL 0x03
  22. #define INTCON 0x04
  23. #define IOCON 0x05
  24. #define GPPU 0x06
  25. #define INTF 0x07
  26. #define INTCAP 0x08
  27. #define GPIO 0x09
  28. #define OLAT 0x0A
  29. static uint8_t _mcp23s08TxData[16] __attribute__((aligned(4)));
  30. static uint8_t _mcp23s08RxData[16] __attribute__((aligned(4)));
  31. McpGpioPin::McpGpioPin(unsigned char pin) :
  32. BasePin(pin)
  33. {}
  34. inline void McpGpioPin::pinMode(int8_t mode) {
  35. ::MCP23S08SetDirection(this->pin, mode);
  36. }
  37. inline void McpGpioPin::digitalWrite(int8_t val) {
  38. ::MCP23S08SetPin(this->pin, val);
  39. }
  40. inline int McpGpioPin::digitalRead() {
  41. return ::MCP23S08GetPin(this->pin);
  42. }
  43. void MCP23S08Setup()
  44. {
  45. DEBUG_MSG_P(PSTR("[MCP23S08] Initialize SPI bus\n"));
  46. // Expander SPI settings
  47. SPI.begin();
  48. SPI.setHwCs(true);
  49. SPI.setFrequency(1000000);
  50. SPI.setDataMode(SPI_MODE0);
  51. pinMode(MCP23S08_CS_PIN, OUTPUT);
  52. digitalWrite(MCP23S08_CS_PIN, HIGH);
  53. }
  54. /**
  55. * @brief Set a expander MCP23S08 the pin direction.
  56. *
  57. * @param pinNumber Pin number for set.
  58. * @param mode direction mode. 0 - INPUT, 1 - OUTPUT.
  59. *
  60. * @return void
  61. */
  62. void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode)
  63. {
  64. uint8_t registerData = MCP23S08ReadRegister(IODIR);
  65. if (INPUT == mode)
  66. {
  67. registerData |= (1 << pinNumber);
  68. }
  69. else
  70. {
  71. registerData &= ~(1 << pinNumber);
  72. }
  73. MCP23S08WriteRegister(IODIR, registerData);
  74. }
  75. /**
  76. * @brief Read an expander MCP23S08 a register.
  77. *
  78. * @param address A register address.
  79. *
  80. * @return The data from the register.
  81. */
  82. uint8_t MCP23S08ReadRegister(uint8_t address)
  83. {
  84. _mcp23s08TxData[0] = READ_CMD;
  85. _mcp23s08TxData[1] = address;
  86. digitalWrite(MCP23S08_CS_PIN, LOW);
  87. SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3);
  88. digitalWrite(MCP23S08_CS_PIN, HIGH);
  89. return _mcp23s08RxData[2];
  90. }
  91. /**
  92. * @brief Write data in expander MCP23S08 register.
  93. *
  94. * @param address A register address.
  95. * @param data A byte for write.
  96. *
  97. * @return void.
  98. */
  99. void MCP23S08WriteRegister(uint8_t address, uint8_t data)
  100. {
  101. _mcp23s08TxData[0] = WRITE_CMD;
  102. _mcp23s08TxData[1] = address;
  103. _mcp23s08TxData[2] = data;
  104. digitalWrite(MCP23S08_CS_PIN, LOW);
  105. SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3);
  106. digitalWrite(MCP23S08_CS_PIN, HIGH);
  107. }
  108. /**
  109. * @brief Set expander MCP23S08 pin state.
  110. *
  111. * @param pinNumber The number of pin to be set.
  112. * @param state The pin state, true - 1, false - 0.
  113. *
  114. * @return void
  115. */
  116. void MCP23S08SetPin(uint8_t pinNumber, bool state)
  117. {
  118. uint8_t registerData = MCP23S08ReadRegister(OLAT);
  119. if (state)
  120. {
  121. registerData |= (1 << pinNumber);
  122. }
  123. else
  124. {
  125. registerData &= ~(1 << pinNumber);
  126. }
  127. MCP23S08WriteRegister(OLAT, registerData);
  128. }
  129. /**
  130. * @brief Get MCP23S08 pin state.
  131. *
  132. * @param pinNumber The number of pin to get.
  133. *
  134. * @return State true - 1, false - 0.
  135. */
  136. bool MCP23S08GetPin(uint8_t pinNumber)
  137. {
  138. uint8_t registerData = MCP23S08ReadRegister(GPIO);
  139. return registerData & (1 << pinNumber);
  140. }
  141. /**
  142. * @brief Ensure pin number is valid.
  143. *
  144. * @param pinNumber The number of pin to be get.
  145. *
  146. * @return State true - 1, false - 0.
  147. */
  148. bool mcpGpioValid(unsigned char gpio)
  149. {
  150. return gpio < McpGpioPins;
  151. }
  152. #endif // MCP23S08_SUPPORT