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.

184 lines
3.8 KiB

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