diff options
author | Alex Ong <the.onga@gmail.com> | 2019-04-04 08:45:55 +1100 |
---|---|---|
committer | Drashna Jaelre <drashna@live.com> | 2019-04-03 14:45:55 -0700 |
commit | 17e7762de7e3fdfc61c20aa61022f47370630c6a (patch) | |
tree | acad10cdb64e24d78154c7c04de3585dece32cc3 | |
parent | e1e08a494bf9ea46e1385559df76d5f49b8e9087 (diff) | |
download | qmk_firmware-17e7762de7e3fdfc61c20aa61022f47370630c6a.tar.gz qmk_firmware-17e7762de7e3fdfc61c20aa61022f47370630c6a.zip |
Eager Per Row Debouncing added (added to Ergodox) (#5498)
* Implemented Eager Per Row debouncing algorithm.
Good for when fingers can only press one row at a time (e.g. when keyboard is wired so that "rows" are vertical)
* Added documentation for eager_pr
* Ported ergodox_ez to eager_pr debouncing.
* Removed check for changes in matrix_scan.
* Added further clarification in docs.
* Accidental merge with ergodox_ez
* Small cleanup in eager_pr
* Forgot to debounce_init - this would probably cause seg-faults.
-rw-r--r-- | docs/feature_debounce_type.md | 5 | ||||
-rw-r--r-- | keyboards/ergodox_ez/matrix.c | 458 | ||||
-rw-r--r-- | keyboards/ergodox_ez/rules.mk | 1 | ||||
-rw-r--r-- | quantum/debounce/eager_pr.c | 100 | ||||
-rw-r--r-- | quantum/debounce/readme.md | 2 |
5 files changed, 302 insertions, 264 deletions
diff --git a/docs/feature_debounce_type.md b/docs/feature_debounce_type.md index 5d4343f08..38eca3f37 100644 --- a/docs/feature_debounce_type.md +++ b/docs/feature_debounce_type.md | |||
@@ -33,7 +33,10 @@ The debounce code is compatible with split keyboards. | |||
33 | # Changing between included debouncing methods | 33 | # Changing between included debouncing methods |
34 | You can either use your own code, by including your own debounce.c, or switch to another included one. | 34 | You can either use your own code, by including your own debounce.c, or switch to another included one. |
35 | Included debounce methods are: | 35 | Included debounce methods are: |
36 | * eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` millseconds of no further input for that key | 36 | * eager_pr - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE_DELAY``` milliseconds of no further input for that row. |
37 | For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be | ||
38 | appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use. | ||
39 | * eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` milliseconds of no further input for that key | ||
37 | * sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed. | 40 | * sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed. |
38 | 41 | ||
39 | 42 | ||
diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c index 860cf7b22..97f764113 100644 --- a/keyboards/ergodox_ez/matrix.c +++ b/keyboards/ergodox_ez/matrix.c | |||
@@ -33,14 +33,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
33 | #include "debug.h" | 33 | #include "debug.h" |
34 | #include "util.h" | 34 | #include "util.h" |
35 | #include "matrix.h" | 35 | #include "matrix.h" |
36 | #include "debounce.h" | ||
36 | #include QMK_KEYBOARD_H | 37 | #include QMK_KEYBOARD_H |
37 | #ifdef DEBUG_MATRIX_SCAN_RATE | 38 | #ifdef DEBUG_MATRIX_SCAN_RATE |
38 | #include "timer.h" | 39 | # include "timer.h" |
39 | #endif | 40 | #endif |
40 | 41 | ||
41 | /* | 42 | /* |
42 | * This constant define not debouncing time in msecs, but amount of matrix | 43 | * This constant define not debouncing time in msecs, assuming eager_pr. |
43 | * scan loops which should be made to get stable debounced results. | ||
44 | * | 44 | * |
45 | * On Ergodox matrix scan rate is relatively low, because of slow I2C. | 45 | * On Ergodox matrix scan rate is relatively low, because of slow I2C. |
46 | * Now it's only 317 scans/second, or about 3.15 msec/scan. | 46 | * Now it's only 317 scans/second, or about 3.15 msec/scan. |
@@ -52,26 +52,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
52 | */ | 52 | */ |
53 | 53 | ||
54 | #ifndef DEBOUNCE | 54 | #ifndef DEBOUNCE |
55 | # define DEBOUNCE 5 | 55 | # define DEBOUNCE 5 |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | /* matrix state(1:on, 0:off) */ | 58 | /* matrix state(1:on, 0:off) */ |
59 | static matrix_row_t matrix[MATRIX_ROWS]; | 59 | static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values |
60 | /* | 60 | static matrix_row_t matrix[MATRIX_ROWS]; // debounced values |
61 | * matrix state(1:on, 0:off) | ||
62 | * contains the raw values without debounce filtering of the last read cycle. | ||
63 | */ | ||
64 | static matrix_row_t raw_matrix[MATRIX_ROWS]; | ||
65 | |||
66 | // Debouncing: store for each key the number of scans until it's eligible to | ||
67 | // change. When scanning the matrix, ignore any changes in keys that have | ||
68 | // already changed in the last DEBOUNCE scans. | ||
69 | static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS]; | ||
70 | 61 | ||
71 | static matrix_row_t read_cols(uint8_t row); | 62 | static matrix_row_t read_cols(uint8_t row); |
72 | static void init_cols(void); | 63 | static void init_cols(void); |
73 | static void unselect_rows(void); | 64 | static void unselect_rows(void); |
74 | static void select_row(uint8_t row); | 65 | static void select_row(uint8_t row); |
75 | 66 | ||
76 | static uint8_t mcp23018_reset_loop; | 67 | static uint8_t mcp23018_reset_loop; |
77 | // static uint16_t mcp23018_reset_loop; | 68 | // static uint16_t mcp23018_reset_loop; |
@@ -81,197 +72,137 @@ uint32_t matrix_timer; | |||
81 | uint32_t matrix_scan_count; | 72 | uint32_t matrix_scan_count; |
82 | #endif | 73 | #endif |
83 | 74 | ||
75 | __attribute__((weak)) void matrix_init_user(void) {} | ||
84 | 76 | ||
85 | __attribute__ ((weak)) | 77 | __attribute__((weak)) void matrix_scan_user(void) {} |
86 | void matrix_init_user(void) {} | ||
87 | 78 | ||
88 | __attribute__ ((weak)) | 79 | __attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); } |
89 | void matrix_scan_user(void) {} | ||
90 | 80 | ||
91 | __attribute__ ((weak)) | 81 | __attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); } |
92 | void matrix_init_kb(void) { | ||
93 | matrix_init_user(); | ||
94 | } | ||
95 | 82 | ||
96 | __attribute__ ((weak)) | 83 | inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } |
97 | void matrix_scan_kb(void) { | ||
98 | matrix_scan_user(); | ||
99 | } | ||
100 | |||
101 | inline | ||
102 | uint8_t matrix_rows(void) | ||
103 | { | ||
104 | return MATRIX_ROWS; | ||
105 | } | ||
106 | 84 | ||
107 | inline | 85 | inline uint8_t matrix_cols(void) { return MATRIX_COLS; } |
108 | uint8_t matrix_cols(void) | ||
109 | { | ||
110 | return MATRIX_COLS; | ||
111 | } | ||
112 | 86 | ||
113 | void matrix_init(void) | 87 | void matrix_init(void) { |
114 | { | 88 | // initialize row and col |
115 | // initialize row and col | ||
116 | 89 | ||
117 | mcp23018_status = init_mcp23018(); | 90 | mcp23018_status = init_mcp23018(); |
118 | 91 | ||
92 | unselect_rows(); | ||
93 | init_cols(); | ||
119 | 94 | ||
120 | unselect_rows(); | 95 | // initialize matrix state: all keys off |
121 | init_cols(); | 96 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
122 | 97 | matrix[i] = 0; | |
123 | // initialize matrix state: all keys off | 98 | raw_matrix[i] = 0; |
124 | for (uint8_t i=0; i < MATRIX_ROWS; i++) { | 99 | } |
125 | matrix[i] = 0; | ||
126 | raw_matrix[i] = 0; | ||
127 | for (uint8_t j=0; j < MATRIX_COLS; ++j) { | ||
128 | debounce_matrix[i * MATRIX_COLS + j] = 0; | ||
129 | } | ||
130 | } | ||
131 | 100 | ||
132 | #ifdef DEBUG_MATRIX_SCAN_RATE | 101 | #ifdef DEBUG_MATRIX_SCAN_RATE |
133 | matrix_timer = timer_read32(); | 102 | matrix_timer = timer_read32(); |
134 | matrix_scan_count = 0; | 103 | matrix_scan_count = 0; |
135 | #endif | 104 | #endif |
136 | 105 | debounce_init(MATRIX_ROWS); | |
137 | matrix_init_quantum(); | 106 | matrix_init_quantum(); |
138 | |||
139 | } | 107 | } |
140 | 108 | ||
141 | void matrix_power_up(void) { | 109 | void matrix_power_up(void) { |
142 | mcp23018_status = init_mcp23018(); | 110 | mcp23018_status = init_mcp23018(); |
143 | 111 | ||
144 | unselect_rows(); | 112 | unselect_rows(); |
145 | init_cols(); | 113 | init_cols(); |
146 | 114 | ||
147 | // initialize matrix state: all keys off | 115 | // initialize matrix state: all keys off |
148 | for (uint8_t i=0; i < MATRIX_ROWS; i++) { | 116 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
149 | matrix[i] = 0; | 117 | matrix[i] = 0; |
150 | } | 118 | } |
151 | 119 | ||
152 | #ifdef DEBUG_MATRIX_SCAN_RATE | 120 | #ifdef DEBUG_MATRIX_SCAN_RATE |
153 | matrix_timer = timer_read32(); | 121 | matrix_timer = timer_read32(); |
154 | matrix_scan_count = 0; | 122 | matrix_scan_count = 0; |
155 | #endif | 123 | #endif |
156 | } | 124 | } |
157 | 125 | ||
158 | // Returns a matrix_row_t whose bits are set if the corresponding key should be | 126 | uint8_t matrix_scan(void) { |
159 | // eligible to change in this scan. | 127 | if (mcp23018_status) { // if there was an error |
160 | matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) { | 128 | if (++mcp23018_reset_loop == 0) { |
161 | matrix_row_t result = 0; | 129 | // if (++mcp23018_reset_loop >= 1300) { |
162 | matrix_row_t change = rawcols ^ raw_matrix[row]; | 130 | // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans |
163 | raw_matrix[row] = rawcols; | 131 | // this will be approx bit more frequent than once per second |
164 | for (uint8_t i = 0; i < MATRIX_COLS; ++i) { | 132 | print("trying to reset mcp23018\n"); |
165 | if (debounce_matrix[row * MATRIX_COLS + i]) { | 133 | mcp23018_status = init_mcp23018(); |
166 | --debounce_matrix[row * MATRIX_COLS + i]; | 134 | if (mcp23018_status) { |
167 | } else { | 135 | print("left side not responding\n"); |
168 | result |= (1 << i); | 136 | } else { |
169 | } | 137 | print("left side attached\n"); |
170 | if (change & (1 << i)) { | 138 | ergodox_blink_all_leds(); |
171 | debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE; | 139 | } |
172 | } | 140 | } |
173 | } | 141 | } |
174 | return result; | ||
175 | } | ||
176 | |||
177 | matrix_row_t debounce_read_cols(uint8_t row) { | ||
178 | // Read the row without debouncing filtering and store it for later usage. | ||
179 | matrix_row_t cols = read_cols(row); | ||
180 | // Get the Debounce mask. | ||
181 | matrix_row_t mask = debounce_mask(cols, row); | ||
182 | // debounce the row and return the result. | ||
183 | return (cols & mask) | (matrix[row] & ~mask);; | ||
184 | } | ||
185 | |||
186 | uint8_t matrix_scan(void) | ||
187 | { | ||
188 | if (mcp23018_status) { // if there was an error | ||
189 | if (++mcp23018_reset_loop == 0) { | ||
190 | // if (++mcp23018_reset_loop >= 1300) { | ||
191 | // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans | ||
192 | // this will be approx bit more frequent than once per second | ||
193 | print("trying to reset mcp23018\n"); | ||
194 | mcp23018_status = init_mcp23018(); | ||
195 | if (mcp23018_status) { | ||
196 | print("left side not responding\n"); | ||
197 | } else { | ||
198 | print("left side attached\n"); | ||
199 | ergodox_blink_all_leds(); | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | 142 | ||
204 | #ifdef DEBUG_MATRIX_SCAN_RATE | 143 | #ifdef DEBUG_MATRIX_SCAN_RATE |
205 | matrix_scan_count++; | 144 | matrix_scan_count++; |
206 | 145 | ||
207 | uint32_t timer_now = timer_read32(); | 146 | uint32_t timer_now = timer_read32(); |
208 | if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) { | 147 | if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) { |
209 | print("matrix scan frequency: "); | 148 | print("matrix scan frequency: "); |
210 | pdec(matrix_scan_count); | 149 | pdec(matrix_scan_count); |
211 | print("\n"); | 150 | print("\n"); |
212 | 151 | ||
213 | matrix_timer = timer_now; | 152 | matrix_timer = timer_now; |
214 | matrix_scan_count = 0; | 153 | matrix_scan_count = 0; |
215 | } | 154 | } |
216 | #endif | 155 | #endif |
217 | 156 | ||
218 | #ifdef LEFT_LEDS | 157 | #ifdef LEFT_LEDS |
219 | mcp23018_status = ergodox_left_leds_update(); | 158 | mcp23018_status = ergodox_left_leds_update(); |
220 | #endif // LEFT_LEDS | 159 | #endif // LEFT_LEDS |
221 | for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { | 160 | for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { |
222 | select_row(i); | 161 | // select rows from left and right hands |
223 | // and select on left hand | 162 | select_row(i); |
224 | select_row(i + MATRIX_ROWS_PER_SIDE); | 163 | select_row(i + MATRIX_ROWS_PER_SIDE); |
225 | // we don't need a 30us delay anymore, because selecting a | 164 | |
226 | // left-hand row requires more than 30us for i2c. | 165 | // we don't need a 30us delay anymore, because selecting a |
227 | 166 | // left-hand row requires more than 30us for i2c. | |
228 | // grab cols from left hand | 167 | |
229 | matrix[i] = debounce_read_cols(i); | 168 | // grab left + right cols. |
230 | // grab cols from right hand | 169 | raw_matrix[i] = read_cols(i); |
231 | matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE); | 170 | raw_matrix[i+MATRIX_ROWS_PER_SIDE] = read_cols(i+MATRIX_ROWS_PER_SIDE); |
232 | 171 | ||
233 | unselect_rows(); | 172 | unselect_rows(); |
234 | } | 173 | } |
235 | 174 | ||
236 | matrix_scan_quantum(); | 175 | debounce(raw_matrix, matrix, MATRIX_ROWS, true); |
176 | matrix_scan_quantum(); | ||
237 | 177 | ||
238 | return 1; | 178 | return 1; |
239 | } | 179 | } |
240 | 180 | ||
241 | bool matrix_is_modified(void) // deprecated and evidently not called. | 181 | bool matrix_is_modified(void) // deprecated and evidently not called. |
242 | { | 182 | { |
243 | return true; | 183 | return true; |
244 | } | 184 | } |
245 | 185 | ||
246 | inline | 186 | inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); } |
247 | bool matrix_is_on(uint8_t row, uint8_t col) | ||
248 | { | ||
249 | return (matrix[row] & ((matrix_row_t)1<<col)); | ||
250 | } | ||
251 | 187 | ||
252 | inline | 188 | inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; } |
253 | matrix_row_t matrix_get_row(uint8_t row) | ||
254 | { | ||
255 | return matrix[row]; | ||
256 | } | ||
257 | 189 | ||
258 | void matrix_print(void) | 190 | void matrix_print(void) { |
259 | { | 191 | print("\nr/c 0123456789ABCDEF\n"); |
260 | print("\nr/c 0123456789ABCDEF\n"); | 192 | for (uint8_t row = 0; row < MATRIX_ROWS; row++) { |
261 | for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | 193 | phex(row); |
262 | phex(row); print(": "); | 194 | print(": "); |
263 | pbin_reverse16(matrix_get_row(row)); | 195 | pbin_reverse16(matrix_get_row(row)); |
264 | print("\n"); | 196 | print("\n"); |
265 | } | 197 | } |
266 | } | 198 | } |
267 | 199 | ||
268 | uint8_t matrix_key_count(void) | 200 | uint8_t matrix_key_count(void) { |
269 | { | 201 | uint8_t count = 0; |
270 | uint8_t count = 0; | 202 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
271 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | 203 | count += bitpop16(matrix[i]); |
272 | count += bitpop16(matrix[i]); | 204 | } |
273 | } | 205 | return count; |
274 | return count; | ||
275 | } | 206 | } |
276 | 207 | ||
277 | /* Column pin configuration | 208 | /* Column pin configuration |
@@ -284,43 +215,45 @@ uint8_t matrix_key_count(void) | |||
284 | * col: 0 1 2 3 4 5 | 215 | * col: 0 1 2 3 4 5 |
285 | * pin: B5 B4 B3 B2 B1 B0 | 216 | * pin: B5 B4 B3 B2 B1 B0 |
286 | */ | 217 | */ |
287 | static void init_cols(void) | 218 | static void init_cols(void) { |
288 | { | 219 | // init on mcp23018 |
289 | // init on mcp23018 | 220 | // not needed, already done as part of init_mcp23018() |
290 | // not needed, already done as part of init_mcp23018() | 221 | |
291 | 222 | // init on teensy | |
292 | // init on teensy | 223 | // Input with pull-up(DDR:0, PORT:1) |
293 | // Input with pull-up(DDR:0, PORT:1) | 224 | DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0); |
294 | DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); | 225 | PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0); |
295 | PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); | ||
296 | } | 226 | } |
297 | 227 | ||
298 | static matrix_row_t read_cols(uint8_t row) | 228 | static matrix_row_t read_cols(uint8_t row) { |
299 | { | 229 | if (row < 7) { |
300 | if (row < 7) { | 230 | if (mcp23018_status) { // if there was an error |
301 | if (mcp23018_status) { // if there was an error | 231 | return 0; |
302 | return 0; | ||
303 | } else { | ||
304 | uint8_t data = 0; | ||
305 | mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
306 | mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
307 | mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
308 | mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status < 0) goto out; | ||
309 | data = ~((uint8_t)mcp23018_status); | ||
310 | mcp23018_status = I2C_STATUS_SUCCESS; | ||
311 | out: | ||
312 | i2c_stop(); | ||
313 | return data; | ||
314 | } | ||
315 | } else { | 232 | } else { |
316 | /* read from teensy | 233 | uint8_t data = 0; |
317 | * bitmask is 0b11110011, but we want those all | 234 | mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); |
318 | * in the lower six bits. | 235 | if (mcp23018_status) goto out; |
319 | * we'll return 1s for the top two, but that's harmless. | 236 | mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); |
320 | */ | 237 | if (mcp23018_status) goto out; |
321 | 238 | mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); | |
322 | return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); | 239 | if (mcp23018_status) goto out; |
240 | mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); | ||
241 | if (mcp23018_status < 0) goto out; | ||
242 | data = ~((uint8_t)mcp23018_status); | ||
243 | mcp23018_status = I2C_STATUS_SUCCESS; | ||
244 | out: | ||
245 | i2c_stop(); | ||
246 | return data; | ||
323 | } | 247 | } |
248 | } else { | ||
249 | /* read from teensy | ||
250 | * bitmask is 0b11110011, but we want those all | ||
251 | * in the lower six bits. | ||
252 | * we'll return 1s for the top two, but that's harmless. | ||
253 | */ | ||
254 | |||
255 | return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); | ||
256 | } | ||
324 | } | 257 | } |
325 | 258 | ||
326 | /* Row pin configuration | 259 | /* Row pin configuration |
@@ -333,69 +266,70 @@ static matrix_row_t read_cols(uint8_t row) | |||
333 | * row: 0 1 2 3 4 5 6 | 266 | * row: 0 1 2 3 4 5 6 |
334 | * pin: A0 A1 A2 A3 A4 A5 A6 | 267 | * pin: A0 A1 A2 A3 A4 A5 A6 |
335 | */ | 268 | */ |
336 | static void unselect_rows(void) | 269 | static void unselect_rows(void) { |
337 | { | 270 | // no need to unselect on mcp23018, because the select step sets all |
338 | // no need to unselect on mcp23018, because the select step sets all | 271 | // the other row bits high, and it's not changing to a different |
339 | // the other row bits high, and it's not changing to a different | 272 | // direction |
340 | // direction | 273 | |
341 | 274 | // unselect on teensy | |
342 | // unselect on teensy | 275 | // Hi-Z(DDR:0, PORT:0) to unselect |
343 | // Hi-Z(DDR:0, PORT:0) to unselect | 276 | DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3); |
344 | DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); | 277 | PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3); |
345 | PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); | 278 | DDRD &= ~(1 << 2 | 1 << 3); |
346 | DDRD &= ~(1<<2 | 1<<3); | 279 | PORTD &= ~(1 << 2 | 1 << 3); |
347 | PORTD &= ~(1<<2 | 1<<3); | 280 | DDRC &= ~(1 << 6); |
348 | DDRC &= ~(1<<6); | 281 | PORTC &= ~(1 << 6); |
349 | PORTC &= ~(1<<6); | ||
350 | } | 282 | } |
351 | 283 | ||
352 | static void select_row(uint8_t row) | 284 | static void select_row(uint8_t row) { |
353 | { | 285 | if (row < 7) { |
354 | if (row < 7) { | 286 | // select on mcp23018 |
355 | // select on mcp23018 | 287 | if (mcp23018_status) { // if there was an error |
356 | if (mcp23018_status) { // if there was an error | 288 | // do nothing |
357 | // do nothing | ||
358 | } else { | ||
359 | // set active row low : 0 | ||
360 | // set other rows hi-Z : 1 | ||
361 | mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
362 | mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
363 | mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; | ||
364 | out: | ||
365 | i2c_stop(); | ||
366 | } | ||
367 | } else { | 289 | } else { |
368 | // select on teensy | 290 | // set active row low : 0 |
369 | // Output low(DDR:1, PORT:0) to select | 291 | // set other rows hi-Z : 1 |
370 | switch (row) { | 292 | mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); |
371 | case 7: | 293 | if (mcp23018_status) goto out; |
372 | DDRB |= (1<<0); | 294 | mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); |
373 | PORTB &= ~(1<<0); | 295 | if (mcp23018_status) goto out; |
374 | break; | 296 | mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT); |
375 | case 8: | 297 | if (mcp23018_status) goto out; |
376 | DDRB |= (1<<1); | 298 | out: |
377 | PORTB &= ~(1<<1); | 299 | i2c_stop(); |
378 | break; | 300 | } |
379 | case 9: | 301 | } else { |
380 | DDRB |= (1<<2); | 302 | // select on teensy |
381 | PORTB &= ~(1<<2); | 303 | // Output low(DDR:1, PORT:0) to select |
382 | break; | 304 | switch (row) { |
383 | case 10: | 305 | case 7: |
384 | DDRB |= (1<<3); | 306 | DDRB |= (1 << 0); |
385 | PORTB &= ~(1<<3); | 307 | PORTB &= ~(1 << 0); |
386 | break; | 308 | break; |
387 | case 11: | 309 | case 8: |
388 | DDRD |= (1<<2); | 310 | DDRB |= (1 << 1); |
389 | PORTD &= ~(1<<2); | 311 | PORTB &= ~(1 << 1); |
390 | break; | 312 | break; |
391 | case 12: | 313 | case 9: |
392 | DDRD |= (1<<3); | 314 | DDRB |= (1 << 2); |
393 | PORTD &= ~(1<<3); | 315 | PORTB &= ~(1 << 2); |
394 | break; | 316 | break; |
395 | case 13: | 317 | case 10: |
396 | DDRC |= (1<<6); | 318 | DDRB |= (1 << 3); |
397 | PORTC &= ~(1<<6); | 319 | PORTB &= ~(1 << 3); |
398 | break; | 320 | break; |
399 | } | 321 | case 11: |
322 | DDRD |= (1 << 2); | ||
323 | PORTD &= ~(1 << 2); | ||
324 | break; | ||
325 | case 12: | ||
326 | DDRD |= (1 << 3); | ||
327 | PORTD &= ~(1 << 3); | ||
328 | break; | ||
329 | case 13: | ||
330 | DDRC |= (1 << 6); | ||
331 | PORTC &= ~(1 << 6); | ||
332 | break; | ||
400 | } | 333 | } |
334 | } | ||
401 | } | 335 | } |
diff --git a/keyboards/ergodox_ez/rules.mk b/keyboards/ergodox_ez/rules.mk index 446ba3e21..e96cd2082 100644 --- a/keyboards/ergodox_ez/rules.mk +++ b/keyboards/ergodox_ez/rules.mk | |||
@@ -83,6 +83,7 @@ SLEEP_LED_ENABLE = no | |||
83 | API_SYSEX_ENABLE = no | 83 | API_SYSEX_ENABLE = no |
84 | RGBLIGHT_ENABLE = yes | 84 | RGBLIGHT_ENABLE = yes |
85 | RGB_MATRIX_ENABLE = no # enable later | 85 | RGB_MATRIX_ENABLE = no # enable later |
86 | DEBOUNCE_TYPE = eager_pr | ||
86 | 87 | ||
87 | ifeq ($(strip $(RGB_MATRIX_ENABLE)), no) | 88 | ifeq ($(strip $(RGB_MATRIX_ENABLE)), no) |
88 | SRC += i2c_master.c | 89 | SRC += i2c_master.c |
diff --git a/quantum/debounce/eager_pr.c b/quantum/debounce/eager_pr.c new file mode 100644 index 000000000..9eb9480a7 --- /dev/null +++ b/quantum/debounce/eager_pr.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | Copyright 2019 Alex Ong<the.onga@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 | |||
15 | /* | ||
16 | Basic per-row algorithm. Uses an 8-bit counter per row. | ||
17 | After pressing a key, it immediately changes state, and sets a counter. | ||
18 | No further inputs are accepted until DEBOUNCE milliseconds have occurred. | ||
19 | */ | ||
20 | |||
21 | #include "matrix.h" | ||
22 | #include "timer.h" | ||
23 | #include "quantum.h" | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #ifndef DEBOUNCE | ||
27 | #define DEBOUNCE 5 | ||
28 | #endif | ||
29 | |||
30 | |||
31 | #define debounce_counter_t uint8_t | ||
32 | |||
33 | static debounce_counter_t *debounce_counters; | ||
34 | |||
35 | #define DEBOUNCE_ELAPSED 251 | ||
36 | #define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1) | ||
37 | |||
38 | void update_debounce_counters(uint8_t num_rows, uint8_t current_time); | ||
39 | void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time); | ||
40 | |||
41 | //we use num_rows rather than MATRIX_ROWS to support split keyboards | ||
42 | void debounce_init(uint8_t num_rows) | ||
43 | { | ||
44 | debounce_counters = (debounce_counter_t*)malloc(num_rows*sizeof(debounce_counter_t)); | ||
45 | for (uint8_t r = 0; r < num_rows; r++) | ||
46 | { | ||
47 | debounce_counters[r] = DEBOUNCE_ELAPSED; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) | ||
52 | { | ||
53 | uint8_t current_time = timer_read() % MAX_DEBOUNCE; | ||
54 | update_debounce_counters(num_rows, current_time); | ||
55 | transfer_matrix_values(raw, cooked, num_rows, current_time); | ||
56 | } | ||
57 | |||
58 | //If the current time is > debounce counter, set the counter to enable input. | ||
59 | void update_debounce_counters(uint8_t num_rows, uint8_t current_time) | ||
60 | { | ||
61 | debounce_counter_t *debounce_pointer = debounce_counters; | ||
62 | for (uint8_t row = 0; row < num_rows; row++) | ||
63 | { | ||
64 | if (*debounce_pointer != DEBOUNCE_ELAPSED) | ||
65 | { | ||
66 | if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) { | ||
67 | *debounce_pointer = DEBOUNCE_ELAPSED; | ||
68 | } | ||
69 | } | ||
70 | debounce_pointer++; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | // upload from raw_matrix to final matrix; | ||
75 | void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) | ||
76 | { | ||
77 | debounce_counter_t *debounce_pointer = debounce_counters; | ||
78 | for (uint8_t row = 0; row < num_rows; row++) | ||
79 | { | ||
80 | matrix_row_t existing_row = cooked[row]; | ||
81 | matrix_row_t raw_row = raw[row]; | ||
82 | |||
83 | //determine new value basd on debounce pointer + raw value | ||
84 | if (*debounce_pointer == DEBOUNCE_ELAPSED && | ||
85 | (existing_row != raw_row)) | ||
86 | { | ||
87 | *debounce_pointer = current_time; | ||
88 | existing_row = raw_row; | ||
89 | } | ||
90 | cooked[row] = existing_row; | ||
91 | |||
92 | debounce_pointer++; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | bool debounce_active(void) | ||
97 | { | ||
98 | return true; | ||
99 | } | ||
100 | |||
diff --git a/quantum/debounce/readme.md b/quantum/debounce/readme.md index 5b318d845..f77f78c76 100644 --- a/quantum/debounce/readme.md +++ b/quantum/debounce/readme.md | |||
@@ -22,7 +22,7 @@ Here are a few that could be implemented: | |||
22 | sym_g.c | 22 | sym_g.c |
23 | sym_pk.c | 23 | sym_pk.c |
24 | sym_pr.c | 24 | sym_pr.c |
25 | sym_pr_cycles.c //currently used in ergo-dox | 25 | sym_pr_cycles.c |
26 | eager_g.c | 26 | eager_g.c |
27 | eager_pk.c | 27 | eager_pk.c |
28 | eager_pr.c //could be used in ergo-dox! | 28 | eager_pr.c //could be used in ergo-dox! |