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 lines
4.4 KiB

  1. /*
  2. Copyright 2017 Luiz Ribeiro <luizribeiro@gmail.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include "quantum.h"
  17. #include "i2c_master.h"
  18. #include "split78.h"
  19. #define RIGHT_HALF
  20. void matrix_set_row_status(uint8_t row);
  21. #if defined(RIGHT_HALF)
  22. #define I2C_TIMEOUT 10
  23. #define MCP23018_TWI_ADDRESS 0b0100000
  24. #define TW_READ 1
  25. #define TW_WRITE 0
  26. #define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
  27. #define TWI_ADDR_READ ( (MCP23018_TWI_ADDRESS<<1) | TW_READ )
  28. #define IODIRA 0x00 // i/o direction register
  29. #define IODIRB 0x01
  30. #define IODIRA 0x00 // i/o direction register
  31. #define IODIRB 0x01
  32. #define GPPUA 0x0C // GPIO pull-up resistor register
  33. #define GPPUB 0x0D
  34. #define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
  35. #define GPIOB 0x13
  36. #define OLATA 0x14 // output latch register
  37. #define OLATB 0x15
  38. #define MCP_ROWS_START 8
  39. static uint8_t mcp23018_init(void) {
  40. uint8_t ret;
  41. uint8_t data[3];
  42. // set pin direction
  43. // - unused : input : 1
  44. // - input : input : 1
  45. // - driving : output : 0
  46. data[0] = IODIRA;
  47. data[1] = 0b00000000; // IODIRA
  48. data[2] = (0b11111111); // IODIRB
  49. ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
  50. if (ret) goto out; // make sure we got an ACK
  51. // set pull-up
  52. // - unused : on : 1
  53. // - input : on : 1
  54. // - driving : off : 0
  55. data[0] = GPPUA;
  56. data[1] = 0b00000000; // IODIRA
  57. data[2] = (0b11111111); // IODIRB
  58. ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
  59. if (ret) goto out; // make sure we got an ACK
  60. // set logical value (doesn't matter on inputs)
  61. // - unused : hi-Z : 1
  62. // - input : hi-Z : 1
  63. // - driving : hi-Z : 1
  64. data[0] = OLATA;
  65. data[1] = 0b11111111; // IODIRA
  66. data[2] = (0b11111111); // IODIRB
  67. ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
  68. out:
  69. return ret;
  70. }
  71. #endif
  72. void matrix_init_custom(void) {
  73. // Set rows as output starting high
  74. DDRB = 0xFF;
  75. PORTB = 0xFF;
  76. // Set columns as inputs with pull-up enabled
  77. DDRA = 0x00;
  78. PORTA = 0xFF;
  79. // Initialize i2c communication
  80. i2c_init();
  81. #if defined(RIGHT_HALF)
  82. // Initialize the chip on the other half
  83. mcp23018_init();
  84. #endif
  85. }
  86. static i2c_status_t mcp23018_status = I2C_STATUS_SUCCESS;
  87. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  88. bool matrix_has_changed = false;
  89. #if defined(RIGHT_HALF)
  90. if (mcp23018_status != I2C_STATUS_SUCCESS) {
  91. mcp23018_status = mcp23018_init();
  92. }
  93. #endif
  94. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  95. // Store last value of row prior to reading
  96. matrix_row_t last_row_value = current_matrix[row];
  97. matrix_row_t cols = 0;
  98. // Select the row to scan
  99. matrix_set_row_status(row);
  100. matrix_io_delay();
  101. //Set the local row
  102. #if defined(RIGHT_HALF)
  103. // Initialize to 0x7F in case I2C read fails,
  104. // as 0x75 would be no keys pressed
  105. uint8_t data = 0x7F;
  106. // Receive the columns from right half
  107. if (mcp23018_status == I2C_STATUS_SUCCESS) {
  108. mcp23018_status = i2c_receive(TWI_ADDR_WRITE, &data, 1, I2C_TIMEOUT);
  109. }
  110. #endif
  111. cols |= ((~(PINA | 0x80)) & 0x7F);
  112. #if defined(RIGHT_HALF)
  113. cols |= (((~(data | 0x80)) & 0x7F) << 7);
  114. #endif
  115. current_matrix[row] = cols;
  116. matrix_has_changed |= (last_row_value != current_matrix[row]);
  117. }
  118. return matrix_has_changed;
  119. }
  120. void matrix_set_row_status(uint8_t row) {
  121. #if defined(RIGHT_HALF)
  122. uint8_t txdata[3];
  123. //Set the remote row on port A
  124. txdata[0] = (GPIOA);
  125. txdata[1] = ( 0xFF & ~(1<<row) );
  126. if (mcp23018_status == I2C_STATUS_SUCCESS) {
  127. mcp23018_status = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)txdata, 2, I2C_TIMEOUT);
  128. }
  129. #endif
  130. //Set the local row on port B
  131. DDRB = (1 << row);
  132. PORTB = ~(1 << row);
  133. }