2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <util/delay.h>
25 #include "action_layer.h"
31 #include "i2cmaster.h"
36 static uint8_t debouncing = DEBOUNCE;
38 /* matrix state(1:on, 0:off) */
39 static matrix_row_t matrix[MATRIX_ROWS];
40 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
42 static matrix_row_t read_cols(uint8_t mcp23018_status, uint8_t row);
43 static void init_cols(void);
44 static void unselect_rows(uint8_t mcp23018_status);
45 static void select_row(uint8_t mcp23018_status, uint8_t row);
49 uint8_t matrix_rows(void)
55 uint8_t matrix_cols(void)
60 void matrix_init(void)
62 // initialize row and col
64 uint8_t mcp23018_status;
65 mcp23018_status = init_mcp23018();
66 unselect_rows(mcp23018_status);
69 // initialize matrix state: all keys off
70 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
72 matrix_debouncing[i] = 0;
76 uint8_t matrix_scan(void)
79 uint8_t layer = biton32(layer_state);
82 ergodox_left_led_1_on();
83 ergodox_left_led_2_off();
84 ergodox_left_led_3_off();
85 } else if (layer == 2) {
86 ergodox_left_led_1_off();
87 ergodox_left_led_2_on();
88 ergodox_left_led_3_off();
89 } else if (layer == 3) {
90 ergodox_left_led_1_off();
91 ergodox_left_led_2_off();
92 ergodox_left_led_3_on();
93 } else if (layer == 4) {
94 ergodox_left_led_1_on();
95 ergodox_left_led_2_off();
96 ergodox_left_led_3_on();
97 } else if (layer == 5) {
98 ergodox_left_led_1_on();
99 ergodox_left_led_2_on();
100 ergodox_left_led_3_off();
101 } else if (layer == 6) {
102 ergodox_left_led_1_off();
103 ergodox_left_led_2_on();
104 ergodox_left_led_3_on();
105 } else if (layer == 7) {
106 ergodox_left_led_1_on();
107 ergodox_left_led_2_on();
108 ergodox_left_led_3_on();
110 ergodox_left_led_1_off();
111 ergodox_left_led_2_off();
112 ergodox_left_led_3_off();
115 // not actually needed because we already calling init_mcp23018() in next line
116 // ergodox_left_leds_update();
120 uint8_t mcp23018_status = init_mcp23018();
122 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
123 select_row(mcp23018_status, i);
124 _delay_us(30); // without this wait read unstable value.
125 matrix_row_t cols = read_cols(mcp23018_status, i);
126 if (matrix_debouncing[i] != cols) {
127 matrix_debouncing[i] = cols;
129 debug("bounce!: "); debug_hex(debouncing); debug("\n");
131 debouncing = DEBOUNCE;
133 unselect_rows(mcp23018_status);
140 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
141 matrix[i] = matrix_debouncing[i];
149 bool matrix_is_modified(void)
151 if (debouncing) return false;
156 bool matrix_is_on(uint8_t row, uint8_t col)
158 return (matrix[row] & ((matrix_row_t)1<<col));
162 matrix_row_t matrix_get_row(uint8_t row)
167 void matrix_print(void)
169 print("\nr/c 0123456789ABCDEF\n");
170 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
171 phex(row); print(": ");
172 pbin_reverse16(matrix_get_row(row));
177 uint8_t matrix_key_count(void)
180 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
181 count += bitpop16(matrix[i]);
186 /* Column pin configuration
190 * pin: F0 F1 F4 F5 F6 F7
194 * pin: B5 B4 B3 B2 B1 B0
196 static void init_cols(void)
199 // not needed, already done as part of init_mcp23018()
202 // Input with pull-up(DDR:0, PORT:1)
203 DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
204 PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
207 static matrix_row_t read_cols(uint8_t mcp23018_status, uint8_t row)
210 if (mcp23018_status) { // if there was an error
215 err = i2c_start(I2C_ADDR_WRITE); if (err) goto out;
216 err = i2c_write(GPIOB); if (err) goto out;
217 err = i2c_start(I2C_ADDR_READ); if (err) goto out;
218 data = i2c_readNak();
227 (PINF&(1<<0) ? 0 : (1<<0)) |
228 (PINF&(1<<1) ? 0 : (1<<1)) |
229 (PINF&(1<<4) ? 0 : (1<<2)) |
230 (PINF&(1<<5) ? 0 : (1<<3)) |
231 (PINF&(1<<6) ? 0 : (1<<4)) |
232 (PINF&(1<<7) ? 0 : (1<<5)) ;
236 /* Row pin configuration
239 * row: 7 8 9 10 11 12 13
240 * pin: B0 B1 B2 B3 D2 D3 C6
244 * pin: A0 A1 A2 A3 A4 A5 A6
246 static void unselect_rows(uint8_t mcp23018_status)
248 // unselect on mcp23018
249 if (mcp23018_status) { // if there was an error
252 // set all rows hi-Z : 1
254 err = i2c_start(I2C_ADDR_WRITE); if (err) goto out;
255 err = i2c_write(GPIOA); if (err) goto out;
256 err = i2c_write( 0xFF
257 & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
258 ); if (err) goto out;
263 // unselect on teensy
264 // Hi-Z(DDR:0, PORT:0) to unselect
265 DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
266 PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
267 DDRD &= ~(1<<2 | 1<<3);
268 PORTD &= ~(1<<2 | 1<<3);
273 static void select_row(uint8_t mcp23018_status, uint8_t row)
276 // select on mcp23018
277 if (mcp23018_status) { // if there was an error
280 // set active row low : 0
281 // set other rows hi-Z : 1
283 err = i2c_start(I2C_ADDR_WRITE); if (err) goto out;
284 err = i2c_write(GPIOA); if (err) goto out;
285 err = i2c_write( 0xFF & ~(1<<row)
286 & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
287 ); if (err) goto out;
293 // Output low(DDR:1, PORT:0) to select