Parent directory

matrix.c

6982 bytes
  1/*
  2Copyright 2012 Jun Wako <wakojun@gmail.com>
  3Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
  4Copyright 2015 ZSA Technology Labs Inc (@zsa)
  5Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
  6Copyright 2021 Gary Kong <kongkm88@gmail.com> (@garykong)
  7
  8This program is free software: you can redistribute it and/or modify
  9it under the terms of the GNU General Public License as published by
 10the Free Software Foundation, either version 2 of the License, or
 11(at your option) any later version.
 12
 13This program is distributed in the hope that it will be useful,
 14but WITHOUT ANY WARRANTY; without even the implied warranty of
 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16GNU General Public License for more details.
 17
 18You should have received a copy of the GNU General Public License
 19along with this program.  If not, see <http://www.gnu.org/licenses/>.
 20*/
 21
 22
 23/*
 24 * scan matrix
 25 */
 26#include <stdint.h>
 27#include <stdbool.h>
 28#include <avr/io.h>
 29#include "wait.h"
 30#include "action_layer.h"
 31#include "print.h"
 32#include "debug.h"
 33#include "util.h"
 34#include "matrix.h"
 35#include "debounce.h"
 36#include "bajjak.h"
 37
 38
 39/*
 40 * This constant define not debouncing time in msecs, assuming eager_pr.
 41 *
 42 * On BAJJAK matrix scan rate is relatively low, because of slow I2C.
 43 * Now it's only 317 scans/second, or about 3.15 msec/scan.
 44 * According to Cherry specs, debouncing time is 5 msec.
 45 *
 46 * However, some switches seem to have higher debouncing requirements, or
 47 * something else might be wrong. (Also, the scan speed has improved since
 48 * that comment was written.)
 49 */
 50
 51/* matrix state(1:on, 0:off) */
 52extern matrix_row_t matrix[MATRIX_ROWS];      // debounced values
 53extern matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
 54
 55static matrix_row_t read_cols(uint8_t row);
 56static void         init_cols(void);
 57static void         unselect_rows(void);
 58static void         select_row(uint8_t row);
 59
 60static uint8_t mcp23018_reset_loop;
 61
 62void matrix_init_custom(void) {
 63    // initialize row and col
 64
 65    mcp23018_status = init_mcp23018();
 66
 67    unselect_rows();
 68    init_cols();
 69}
 70
 71// Reads and stores a row, returning
 72// whether a change occurred.
 73static inline bool store_raw_matrix_row(uint8_t index) {
 74    matrix_row_t temp = read_cols(index);
 75    if (raw_matrix[index] != temp) {
 76        raw_matrix[index] = temp;
 77        return true;
 78    }
 79    return false;
 80}
 81
 82bool matrix_scan_custom(matrix_row_t current_matrix[]) {
 83    if (mcp23018_status) {  // if there was an error
 84        if (++mcp23018_reset_loop == 0) {
 85            print("trying to reset mcp23018\n");
 86            mcp23018_status = init_mcp23018();
 87            if (mcp23018_status) {
 88                print("left side not responding\n");
 89            } else {
 90                print("left side attached\n");
 91                bajjak_blink_all_leds();
 92            }
 93        }
 94    }
 95
 96#ifdef LEFT_LEDS
 97    mcp23018_status = bajjak_left_leds_update();
 98#endif  // LEFT_LEDS
 99    bool changed = false;
100    for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
101        // select rows from left and right hands
102        uint8_t left_index  = i;
103        uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
104        select_row(left_index);
105        select_row(right_index);
106
107        changed |= store_raw_matrix_row(left_index);
108        changed |= store_raw_matrix_row(right_index);
109
110        unselect_rows();
111    }
112
113    return changed;
114}
115
116/* Column pin configuration
117 *
118 * Teensy
119 * col: 0   1   2   3   4   5
120 * pin: F0  F1  F4  F5  F6  F7
121 *
122 * MCP23018
123 * col: 0   1   2   3   4   5
124 * pin: B5  B4  B3  B2  B1  B0
125 */
126static void init_cols(void) {
127    // init on mcp23018
128    // not needed, already done as part of init_mcp23018()
129
130    // init on teensy
131    gpio_set_pin_input_high(F0);
132    gpio_set_pin_input_high(F1);
133    gpio_set_pin_input_high(F4);
134    gpio_set_pin_input_high(F5);
135    gpio_set_pin_input_high(F6);
136    gpio_set_pin_input_high(F7);
137    gpio_set_pin_input_high(D7);
138}
139
140static matrix_row_t read_cols(uint8_t row) {
141    if (row < 7) {
142        if (mcp23018_status) {  // if there was an error
143            return 0;
144        } else {
145            uint8_t data = 0;
146            // reading GPIOB (column port) since in mcp23018's sequential mode
147            // it is addressed directly after writing to GPIOA in select_row()
148            mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
149            return ~data;
150        }
151    } else {
152        /* read from teensy
153         * bitmask is 0b11110011, but we want those all
154         * in the lower six bits.
155         * we'll return 1s for the top two, but that's harmless.
156         */
157
158        return ~( (PINF & 0x03) | ((PINF & 0xF0) >> 2) | ((PIND & 0x80) >> 1) );
159    }
160}
161
162/* Row pin configuration
163 *
164 * Teensy
165 * row: 7   8   9   10  11  12  13
166 * pin: B0  B1  B2  B3  D2  D3  C6
167 *
168 * MCP23018
169 * row: 0   1   2   3   4   5   6
170 * pin: A0  A1  A2  A3  A4  A5  A6
171 */
172static void unselect_rows(void) {
173    // no need to unselect on mcp23018, because the select step sets all
174    // the other row bits high, and it's not changing to a different
175    // direction
176
177    // unselect on teensy
178    gpio_set_pin_input(B0);
179    gpio_set_pin_input(B1);
180    gpio_set_pin_input(B2);
181    gpio_set_pin_input(B3);
182    gpio_set_pin_input(D2);
183    gpio_set_pin_input(D3);
184    gpio_set_pin_input(C6);
185}
186
187static void select_row(uint8_t row) {
188    if (row < 7) {
189        // select on mcp23018
190        if (!mcp23018_status) {
191            // set active row low  : 0
192            // set other rows hi-Z : 1
193            uint8_t data;
194            data = 0xFF & ~(1 << row);
195            mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
196
197        }
198    } else {
199        // select on teensy
200        // Output low(DDR:1, PORT:0) to select
201        switch (row) {
202            case 7:
203                gpio_set_pin_output(B0);
204                gpio_write_pin_low(B0);
205                break;
206            case 8:
207                gpio_set_pin_output(B1);
208                gpio_write_pin_low(B1);
209                break;
210            case 9:
211                gpio_set_pin_output(B2);
212                gpio_write_pin_low(B2);
213                break;
214            case 10:
215                gpio_set_pin_output(B3);
216                gpio_write_pin_low(B3);
217                break;
218            case 11:
219                gpio_set_pin_output(D2);
220                gpio_write_pin_low(D2);
221                break;
222            case 12:
223                gpio_set_pin_output(D3);
224                gpio_write_pin_low(D3);
225                break;
226            case 13:
227                gpio_set_pin_output(C6);
228                gpio_write_pin_low(C6);
229                break;
230        }
231    }
232}
233
234// DO NOT REMOVE
235// Needed for proper wake/sleep
236void matrix_power_up(void) {
237    mcp23018_status = init_mcp23018();
238
239    unselect_rows();
240    init_cols();
241
242    // initialize matrix state: all keys off
243    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
244        matrix[i] = 0;
245    }
246
247}