aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalz Guenat <balz.guenat@gmail.com>2017-12-12 03:05:12 +0100
committerJack Humbert <jack.humb@gmail.com>2017-12-11 21:05:12 -0500
commiteeb64437673c0f5c16f0ddf1e2a8362be81b615a (patch)
tree0c1c65a087f8b427cdf5e85ec9082ce0ba9a0dd0
parentc1a6ca46a77d88da40647a54bf1e712da69bc143 (diff)
downloadqmk_firmware-eeb64437673c0f5c16f0ddf1e2a8362be81b615a.tar.gz
qmk_firmware-eeb64437673c0f5c16f0ddf1e2a8362be81b615a.zip
actuation point adjustment for fc980c and fc660c (#2134)
* add i2c lib submodule * add actuation point adjustment to fc980c * add actuation point adjustment to fc660c also. * use https for i2c submodule * move to existing i2c lib * properly remove old submodule * oops, forgot some files for the fc660c
-rw-r--r--keyboards/fc660c/README.md11
-rw-r--r--keyboards/fc660c/actuation_point.c87
-rw-r--r--keyboards/fc660c/actuation_point.h32
-rw-r--r--keyboards/fc660c/config.h9
-rw-r--r--keyboards/fc660c/fc660c.c8
-rw-r--r--keyboards/fc660c/i2c.c162
-rw-r--r--keyboards/fc660c/i2c.h49
-rw-r--r--keyboards/fc660c/matrix.c2
-rw-r--r--keyboards/fc660c/rules.mk4
-rw-r--r--keyboards/fc980c/README.md10
-rw-r--r--keyboards/fc980c/actuation_point.c87
-rw-r--r--keyboards/fc980c/actuation_point.h32
-rw-r--r--keyboards/fc980c/config.h9
-rw-r--r--keyboards/fc980c/fc980c.c9
-rw-r--r--keyboards/fc980c/i2c.c162
-rw-r--r--keyboards/fc980c/i2c.h49
-rw-r--r--keyboards/fc980c/keymaps/actuation-point-example/README.md9
-rw-r--r--keyboards/fc980c/keymaps/actuation-point-example/config.h32
-rw-r--r--keyboards/fc980c/keymaps/actuation-point-example/keymap.c77
-rw-r--r--keyboards/fc980c/keymaps/coloneljesus/config.h8
-rw-r--r--keyboards/fc980c/matrix.c2
-rw-r--r--keyboards/fc980c/rules.mk4
22 files changed, 850 insertions, 4 deletions
diff --git a/keyboards/fc660c/README.md b/keyboards/fc660c/README.md
index ce84abad8..5cb9bcea4 100644
--- a/keyboards/fc660c/README.md
+++ b/keyboards/fc660c/README.md
@@ -25,6 +25,17 @@ Thread on Geekhack: https://geekhack.org/index.php?topic=88439.0
25 25
26Also: https://geekhack.org/index.php?topic=88720.0 26Also: https://geekhack.org/index.php?topic=88720.0
27 27
28
29Actuation Point adjustment
30--------------------------
31You can adjust the actuation point of the keys by setting `ACTUATION_DEPTH_ADJUSTMENT` in `config.h`.
32A value above 0 will result in a deeper, less sensitive actuation whereas a value above 1 will result in a more shallow, more sensitive actuation.
33Be careful with this setting and use small values (+/-5).
34See the `actuation-point-example` keymap of the `fc980c` keyboard for an example.
35For more information, inspect the `fc660c_i2c` branch of TMK [here](https://github.com/tmk/tmk_keyboard/tree/fc660c_i2c).
36Functionality for writing to the EEPROM has deliberately not been included to reduce the chance of people messing up their boards.
37
38
28Pinouts 39Pinouts
29------- 40-------
30 41
diff --git a/keyboards/fc660c/actuation_point.c b/keyboards/fc660c/actuation_point.c
new file mode 100644
index 000000000..5f4cb16f4
--- /dev/null
+++ b/keyboards/fc660c/actuation_point.c
@@ -0,0 +1,87 @@
1/*
2Copyright 2017 Balz Guenat
3based on work by Jun Wako <wakojun@gmail.com>
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "actuation_point.h"
20#include "i2c.h"
21
22///////////////////////////////////////////////////////////////////////////////
23//
24// AD5258 I2C digital potentiometer
25// http://www.analog.com/media/en/technical-documentation/data-sheets/AD5258.pdf
26//
27#define AD5258_ADDR 0b0011000
28#define AD5258_INST_RDAC 0x00
29#define AD5258_INST_EEPROM 0x20
30
31uint8_t read_rdac(void) {
32 // read RDAC register
33 i2c_start_write(AD5258_ADDR);
34 i2c_master_write(AD5258_INST_RDAC);
35 i2c_start_read(AD5258_ADDR);
36 uint8_t ret = i2c_master_read(I2C_NACK);
37 i2c_master_stop();
38 return ret;
39};
40
41uint8_t read_eeprom(void) {
42 i2c_start_write(AD5258_ADDR);
43 i2c_master_write(AD5258_INST_EEPROM);
44 i2c_start_read(AD5258_ADDR);
45 uint8_t ret = i2c_master_read(I2C_NACK);
46 i2c_master_stop();
47 return ret;
48};
49
50void write_rdac(uint8_t rdac) {
51 // write RDAC register:
52 i2c_start_write(AD5258_ADDR);
53 i2c_master_write(AD5258_INST_RDAC);
54 i2c_master_write(rdac & 0x3F);
55 i2c_master_stop();
56};
57
58void actuation_point_up(void) {
59 // write RDAC register: lower value makes actuation point shallow
60 uint8_t rdac = read_rdac();
61 if (rdac == 0)
62 write_rdac(0);
63 else
64 write_rdac(rdac-1);
65};
66
67void actuation_point_down(void) {
68 // write RDAC register: higher value makes actuation point deep
69 uint8_t rdac = read_rdac();
70 if (rdac == 63)
71 write_rdac(63);
72 else
73 write_rdac(rdac+1);
74};
75
76void adjust_actuation_point(int offset) {
77 i2c_master_init();
78 uint8_t rdac = read_eeprom() + offset;
79 if (rdac > 63) { // protects from under and overflows
80 if (offset > 0)
81 write_rdac(63);
82 else
83 write_rdac(0);
84 } else {
85 write_rdac(rdac);
86 }
87}
diff --git a/keyboards/fc660c/actuation_point.h b/keyboards/fc660c/actuation_point.h
new file mode 100644
index 000000000..f7066d92c
--- /dev/null
+++ b/keyboards/fc660c/actuation_point.h
@@ -0,0 +1,32 @@
1/*
2Copyright 2017 Balz Guenat
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef ACTUATION_POINT_H
19#define ACTUATION_POINT_H
20
21#include <stdint.h>
22
23// see keymaps/actuation-point-example to see how these functions can be used.
24uint8_t read_rdac(void);
25uint8_t read_eeprom(void);
26void actuation_point_up(void);
27void actuation_point_down(void);
28
29// be careful with this.
30void adjust_actuation_point(int offset);
31
32#endif
diff --git a/keyboards/fc660c/config.h b/keyboards/fc660c/config.h
index 0afd374a0..9771c8c03 100644
--- a/keyboards/fc660c/config.h
+++ b/keyboards/fc660c/config.h
@@ -64,6 +64,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
64 * These options are also useful to firmware size reduction. 64 * These options are also useful to firmware size reduction.
65 */ 65 */
66 66
67#define USE_I2C
68
67/* disable debug print */ 69/* disable debug print */
68//#define NO_DEBUG 70//#define NO_DEBUG
69 71
@@ -77,4 +79,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
77//#define NO_ACTION_MACRO 79//#define NO_ACTION_MACRO
78//#define NO_ACTION_FUNCTION 80//#define NO_ACTION_FUNCTION
79 81
82// higher value means deeper actuation point, less sensitive
83// be careful and only make small adjustments (steps of 1 or 2).
84// too high and keys will fail to actuate. too low and keys will actuate spontaneously.
85// test all keys before further adjustment.
86// this should probably stay in the range +/-5.
87// #define ACTUATION_DEPTH_ADJUSTMENT 0
88
80#endif 89#endif
diff --git a/keyboards/fc660c/fc660c.c b/keyboards/fc660c/fc660c.c
index f2a561767..da6ba9e74 100644
--- a/keyboards/fc660c/fc660c.c
+++ b/keyboards/fc660c/fc660c.c
@@ -16,10 +16,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/ 16*/
17#include "fc660c.h" 17#include "fc660c.h"
18 18
19#ifdef ACTUATION_DEPTH_ADJUSTMENT
20#include "actuation_point.h"
21#endif
22
19void matrix_init_kb(void) { 23void matrix_init_kb(void) {
20 // put your keyboard start-up code here 24 // put your keyboard start-up code here
21 // runs once when the firmware starts up 25 // runs once when the firmware starts up
22 26
27#ifdef ACTUATION_DEPTH_ADJUSTMENT
28 adjust_actuation_point(ACTUATION_DEPTH_ADJUSTMENT);
29#endif
30
23 matrix_init_user(); 31 matrix_init_user();
24} 32}
25 33
diff --git a/keyboards/fc660c/i2c.c b/keyboards/fc660c/i2c.c
new file mode 100644
index 000000000..084c890c4
--- /dev/null
+++ b/keyboards/fc660c/i2c.c
@@ -0,0 +1,162 @@
1#include <util/twi.h>
2#include <avr/io.h>
3#include <stdlib.h>
4#include <avr/interrupt.h>
5#include <util/twi.h>
6#include <stdbool.h>
7#include "i2c.h"
8
9#ifdef USE_I2C
10
11// Limits the amount of we wait for any one i2c transaction.
12// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
13// 9 bits, a single transaction will take around 90μs to complete.
14//
15// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit
16// poll loop takes at least 8 clock cycles to execute
17#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
18
19#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
20
21volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23static volatile uint8_t slave_buffer_pos;
24static volatile bool slave_has_register_set = false;
25
26// Wait for an i2c operation to finish
27inline static
28void i2c_delay(void) {
29 uint16_t lim = 0;
30 while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
31 lim++;
32
33 // easier way, but will wait slightly longer
34 // _delay_us(100);
35}
36
37// Setup twi to run at 100kHz
38void i2c_master_init(void) {
39 // no prescaler
40 TWSR = 0;
41 // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
42 // Check datasheets for more info.
43 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
44}
45
46// Start a transaction with the given i2c slave address. The direction of the
47// transfer is set with I2C_READ and I2C_WRITE.
48// returns: 0 => success
49// 1 => error
50uint8_t i2c_master_start(uint8_t address) {
51 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
52
53 i2c_delay();
54
55 // check that we started successfully
56 if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
57 return 1;
58
59 TWDR = address;
60 TWCR = (1<<TWINT) | (1<<TWEN);
61
62 i2c_delay();
63
64 if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
65 return 1; // slave did not acknowledge
66 else
67 return 0; // success
68}
69
70
71// Finish the i2c transaction.
72void i2c_master_stop(void) {
73 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
74
75 uint16_t lim = 0;
76 while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
77 lim++;
78}
79
80// Write one byte to the i2c slave.
81// returns 0 => slave ACK
82// 1 => slave NACK
83uint8_t i2c_master_write(uint8_t data) {
84 TWDR = data;
85 TWCR = (1<<TWINT) | (1<<TWEN);
86
87 i2c_delay();
88
89 // check if the slave acknowledged us
90 return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
91}
92
93// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
94// if ack=0 the acknowledge bit is not set.
95// returns: byte read from i2c device
96uint8_t i2c_master_read(int ack) {
97 TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
98
99 i2c_delay();
100 return TWDR;
101}
102
103void i2c_reset_state(void) {
104 TWCR = 0;
105}
106
107void i2c_slave_init(uint8_t address) {
108 TWAR = address << 0; // slave i2c address
109 // TWEN - twi enable
110 // TWEA - enable address acknowledgement
111 // TWINT - twi interrupt flag
112 // TWIE - enable the twi interrupt
113 TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
114}
115
116ISR(TWI_vect);
117
118ISR(TWI_vect) {
119 uint8_t ack = 1;
120 switch(TW_STATUS) {
121 case TW_SR_SLA_ACK:
122 // this device has been addressed as a slave receiver
123 slave_has_register_set = false;
124 break;
125
126 case TW_SR_DATA_ACK:
127 // this device has received data as a slave receiver
128 // The first byte that we receive in this transaction sets the location
129 // of the read/write location of the slaves memory that it exposes over
130 // i2c. After that, bytes will be written at slave_buffer_pos, incrementing
131 // slave_buffer_pos after each write.
132 if(!slave_has_register_set) {
133 slave_buffer_pos = TWDR;
134 // don't acknowledge the master if this memory loctaion is out of bounds
135 if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
136 ack = 0;
137 slave_buffer_pos = 0;
138 }
139 slave_has_register_set = true;
140 } else {
141 i2c_slave_buffer[slave_buffer_pos] = TWDR;
142 BUFFER_POS_INC();
143 }
144 break;
145
146 case TW_ST_SLA_ACK:
147 case TW_ST_DATA_ACK:
148 // master has addressed this device as a slave transmitter and is
149 // requesting data.
150 TWDR = i2c_slave_buffer[slave_buffer_pos];
151 BUFFER_POS_INC();
152 break;
153
154 case TW_BUS_ERROR: // something went wrong, reset twi state
155 TWCR = 0;
156 default:
157 break;
158 }
159 // Reset everything, so we are ready for the next TWI interrupt
160 TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
161}
162#endif
diff --git a/keyboards/fc660c/i2c.h b/keyboards/fc660c/i2c.h
new file mode 100644
index 000000000..c15b6bc50
--- /dev/null
+++ b/keyboards/fc660c/i2c.h
@@ -0,0 +1,49 @@
1#ifndef I2C_H
2#define I2C_H
3
4#include <stdint.h>
5
6#ifndef F_CPU
7#define F_CPU 16000000UL
8#endif
9
10#define I2C_READ 1
11#define I2C_WRITE 0
12
13#define I2C_ACK 1
14#define I2C_NACK 0
15
16#define SLAVE_BUFFER_SIZE 0x10
17
18// i2c SCL clock frequency
19#define SCL_CLOCK 400000L
20
21extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23void i2c_master_init(void);
24uint8_t i2c_master_start(uint8_t address);
25void i2c_master_stop(void);
26uint8_t i2c_master_write(uint8_t data);
27uint8_t i2c_master_read(int);
28void i2c_reset_state(void);
29void i2c_slave_init(uint8_t address);
30
31
32static inline unsigned char i2c_start_read(unsigned char addr) {
33 return i2c_master_start((addr << 1) | I2C_READ);
34}
35
36static inline unsigned char i2c_start_write(unsigned char addr) {
37 return i2c_master_start((addr << 1) | I2C_WRITE);
38}
39
40// from SSD1306 scrips
41extern unsigned char i2c_rep_start(unsigned char addr);
42extern void i2c_start_wait(unsigned char addr);
43extern unsigned char i2c_readAck(void);
44extern unsigned char i2c_readNak(void);
45extern unsigned char i2c_read(unsigned char ack);
46
47#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
48
49#endif
diff --git a/keyboards/fc660c/matrix.c b/keyboards/fc660c/matrix.c
index 211506fdf..69a96b979 100644
--- a/keyboards/fc660c/matrix.c
+++ b/keyboards/fc660c/matrix.c
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */ 21 */
22#include <stdint.h> 22#include <stdint.h>
23#include <stdbool.h> 23#include <stdbool.h>
24#include <util/delay.h> 24#include "wait.h"
25#include "print.h" 25#include "print.h"
26#include "debug.h" 26#include "debug.h"
27#include "util.h" 27#include "util.h"
diff --git a/keyboards/fc660c/rules.mk b/keyboards/fc660c/rules.mk
index 883f7e657..c947947f8 100644
--- a/keyboards/fc660c/rules.mk
+++ b/keyboards/fc660c/rules.mk
@@ -61,4 +61,6 @@ NKRO_ENABLE ?= yes # USB Nkey Rollover - not yet supported in LUFA
61#EXTRALDFLAGS = -Wl,--relax 61#EXTRALDFLAGS = -Wl,--relax
62 62
63CUSTOM_MATRIX = yes 63CUSTOM_MATRIX = yes
64SRC += matrix.c 64SRC += matrix.c \
65 actuation_point.c \
66 i2c.c
diff --git a/keyboards/fc980c/README.md b/keyboards/fc980c/README.md
index 7e44436ef..10d84a096 100644
--- a/keyboards/fc980c/README.md
+++ b/keyboards/fc980c/README.md
@@ -32,6 +32,16 @@ The keyboard is very similar electronically to its sibling model FC660C you can
32FC660C Alt Controller: https://geekhack.org/index.php?topic=88439.0 32FC660C Alt Controller: https://geekhack.org/index.php?topic=88439.0
33 33
34 34
35Actuation Point adjustment
36--------------------------
37You can adjust the actuation point of the keys by setting `ACTUATION_DEPTH_ADJUSTMENT` in `config.h`.
38A value above 0 will result in a deeper, less sensitive actuation whereas a value above 1 will result in a more shallow, more sensitive actuation.
39Be careful with this setting and use small values (+/-5).
40See the `actuation-point-example` keymap for an example.
41For more information, inspect the `fc660c_i2c` branch of TMK [here](https://github.com/tmk/tmk_keyboard/tree/fc660c_i2c).
42Functionality for writing to the EEPROM has deliberately not been included to reduce the chance of people messing up their boards.
43
44
35Hardware 45Hardware
36-------- 46--------
37This project uses common and familiar ATmega32u4 but any microcontroller with 5V I/O will work. 47This project uses common and familiar ATmega32u4 but any microcontroller with 5V I/O will work.
diff --git a/keyboards/fc980c/actuation_point.c b/keyboards/fc980c/actuation_point.c
new file mode 100644
index 000000000..5f4cb16f4
--- /dev/null
+++ b/keyboards/fc980c/actuation_point.c
@@ -0,0 +1,87 @@
1/*
2Copyright 2017 Balz Guenat
3based on work by Jun Wako <wakojun@gmail.com>
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "actuation_point.h"
20#include "i2c.h"
21
22///////////////////////////////////////////////////////////////////////////////
23//
24// AD5258 I2C digital potentiometer
25// http://www.analog.com/media/en/technical-documentation/data-sheets/AD5258.pdf
26//
27#define AD5258_ADDR 0b0011000
28#define AD5258_INST_RDAC 0x00
29#define AD5258_INST_EEPROM 0x20
30
31uint8_t read_rdac(void) {
32 // read RDAC register
33 i2c_start_write(AD5258_ADDR);
34 i2c_master_write(AD5258_INST_RDAC);
35 i2c_start_read(AD5258_ADDR);
36 uint8_t ret = i2c_master_read(I2C_NACK);
37 i2c_master_stop();
38 return ret;
39};
40
41uint8_t read_eeprom(void) {
42 i2c_start_write(AD5258_ADDR);
43 i2c_master_write(AD5258_INST_EEPROM);
44 i2c_start_read(AD5258_ADDR);
45 uint8_t ret = i2c_master_read(I2C_NACK);
46 i2c_master_stop();
47 return ret;
48};
49
50void write_rdac(uint8_t rdac) {
51 // write RDAC register:
52 i2c_start_write(AD5258_ADDR);
53 i2c_master_write(AD5258_INST_RDAC);
54 i2c_master_write(rdac & 0x3F);
55 i2c_master_stop();
56};
57
58void actuation_point_up(void) {
59 // write RDAC register: lower value makes actuation point shallow
60 uint8_t rdac = read_rdac();
61 if (rdac == 0)
62 write_rdac(0);
63 else
64 write_rdac(rdac-1);
65};
66
67void actuation_point_down(void) {
68 // write RDAC register: higher value makes actuation point deep
69 uint8_t rdac = read_rdac();
70 if (rdac == 63)
71 write_rdac(63);
72 else
73 write_rdac(rdac+1);
74};
75
76void adjust_actuation_point(int offset) {
77 i2c_master_init();
78 uint8_t rdac = read_eeprom() + offset;
79 if (rdac > 63) { // protects from under and overflows
80 if (offset > 0)
81 write_rdac(63);
82 else
83 write_rdac(0);
84 } else {
85 write_rdac(rdac);
86 }
87}
diff --git a/keyboards/fc980c/actuation_point.h b/keyboards/fc980c/actuation_point.h
new file mode 100644
index 000000000..f7066d92c
--- /dev/null
+++ b/keyboards/fc980c/actuation_point.h
@@ -0,0 +1,32 @@
1/*
2Copyright 2017 Balz Guenat
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef ACTUATION_POINT_H
19#define ACTUATION_POINT_H
20
21#include <stdint.h>
22
23// see keymaps/actuation-point-example to see how these functions can be used.
24uint8_t read_rdac(void);
25uint8_t read_eeprom(void);
26void actuation_point_up(void);
27void actuation_point_down(void);
28
29// be careful with this.
30void adjust_actuation_point(int offset);
31
32#endif
diff --git a/keyboards/fc980c/config.h b/keyboards/fc980c/config.h
index a79f6f57b..1b1f41c90 100644
--- a/keyboards/fc980c/config.h
+++ b/keyboards/fc980c/config.h
@@ -68,6 +68,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
68 * These options are also useful to firmware size reduction. 68 * These options are also useful to firmware size reduction.
69 */ 69 */
70 70
71#define USE_I2C
72
71/* disable debug print */ 73/* disable debug print */
72//#define NO_DEBUG 74//#define NO_DEBUG
73 75
@@ -81,4 +83,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
81//#define NO_ACTION_MACRO 83//#define NO_ACTION_MACRO
82//#define NO_ACTION_FUNCTION 84//#define NO_ACTION_FUNCTION
83 85
86// higher value means deeper actuation point, less sensitive
87// be careful and only make small adjustments (steps of 1 or 2).
88// too high and keys will fail to actuate. too low and keys will actuate spontaneously.
89// test all keys before further adjustment.
90// this should probably stay in the range +/-5.
91// #define ACTUATION_DEPTH_ADJUSTMENT 0
92
84#endif 93#endif
diff --git a/keyboards/fc980c/fc980c.c b/keyboards/fc980c/fc980c.c
index b78243105..c09eacfa3 100644
--- a/keyboards/fc980c/fc980c.c
+++ b/keyboards/fc980c/fc980c.c
@@ -14,12 +14,21 @@ GNU General Public License for more details.
14You should have received a copy of the GNU General Public License 14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>. 15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/ 16*/
17
17#include "fc980c.h" 18#include "fc980c.h"
18 19
20#ifdef ACTUATION_DEPTH_ADJUSTMENT
21#include "actuation_point.h"
22#endif
23
19void matrix_init_kb(void) { 24void matrix_init_kb(void) {
20 // put your keyboard start-up code here 25 // put your keyboard start-up code here
21 // runs once when the firmware starts up 26 // runs once when the firmware starts up
22 27
28#ifdef ACTUATION_DEPTH_ADJUSTMENT
29 adjust_actuation_point(ACTUATION_DEPTH_ADJUSTMENT);
30#endif
31
23 matrix_init_user(); 32 matrix_init_user();
24} 33}
25 34
diff --git a/keyboards/fc980c/i2c.c b/keyboards/fc980c/i2c.c
new file mode 100644
index 000000000..084c890c4
--- /dev/null
+++ b/keyboards/fc980c/i2c.c
@@ -0,0 +1,162 @@
1#include <util/twi.h>
2#include <avr/io.h>
3#include <stdlib.h>
4#include <avr/interrupt.h>
5#include <util/twi.h>
6#include <stdbool.h>
7#include "i2c.h"
8
9#ifdef USE_I2C
10
11// Limits the amount of we wait for any one i2c transaction.
12// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
13// 9 bits, a single transaction will take around 90μs to complete.
14//
15// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit
16// poll loop takes at least 8 clock cycles to execute
17#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
18
19#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
20
21volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23static volatile uint8_t slave_buffer_pos;
24static volatile bool slave_has_register_set = false;
25
26// Wait for an i2c operation to finish
27inline static
28void i2c_delay(void) {
29 uint16_t lim = 0;
30 while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
31 lim++;
32
33 // easier way, but will wait slightly longer
34 // _delay_us(100);
35}
36
37// Setup twi to run at 100kHz
38void i2c_master_init(void) {
39 // no prescaler
40 TWSR = 0;
41 // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
42 // Check datasheets for more info.
43 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
44}
45
46// Start a transaction with the given i2c slave address. The direction of the
47// transfer is set with I2C_READ and I2C_WRITE.
48// returns: 0 => success
49// 1 => error
50uint8_t i2c_master_start(uint8_t address) {
51 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
52
53 i2c_delay();
54
55 // check that we started successfully
56 if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
57 return 1;
58
59 TWDR = address;
60 TWCR = (1<<TWINT) | (1<<TWEN);
61
62 i2c_delay();
63
64 if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
65 return 1; // slave did not acknowledge
66 else
67 return 0; // success
68}
69
70
71// Finish the i2c transaction.
72void i2c_master_stop(void) {
73 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
74
75 uint16_t lim = 0;
76 while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
77 lim++;
78}
79
80// Write one byte to the i2c slave.
81// returns 0 => slave ACK
82// 1 => slave NACK
83uint8_t i2c_master_write(uint8_t data) {
84 TWDR = data;
85 TWCR = (1<<TWINT) | (1<<TWEN);
86
87 i2c_delay();
88
89 // check if the slave acknowledged us
90 return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
91}
92
93// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
94// if ack=0 the acknowledge bit is not set.
95// returns: byte read from i2c device
96uint8_t i2c_master_read(int ack) {
97 TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
98
99 i2c_delay();
100 return TWDR;
101}
102
103void i2c_reset_state(void) {
104 TWCR = 0;
105}
106
107void i2c_slave_init(uint8_t address) {
108 TWAR = address << 0; // slave i2c address
109 // TWEN - twi enable
110 // TWEA - enable address acknowledgement
111 // TWINT - twi interrupt flag
112 // TWIE - enable the twi interrupt
113 TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
114}
115
116ISR(TWI_vect);
117
118ISR(TWI_vect) {
119 uint8_t ack = 1;
120 switch(TW_STATUS) {
121 case TW_SR_SLA_ACK:
122 // this device has been addressed as a slave receiver
123 slave_has_register_set = false;
124 break;
125
126 case TW_SR_DATA_ACK:
127 // this device has received data as a slave receiver
128 // The first byte that we receive in this transaction sets the location
129 // of the read/write location of the slaves memory that it exposes over
130 // i2c. After that, bytes will be written at slave_buffer_pos, incrementing
131 // slave_buffer_pos after each write.
132 if(!slave_has_register_set) {
133 slave_buffer_pos = TWDR;
134 // don't acknowledge the master if this memory loctaion is out of bounds
135 if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
136 ack = 0;
137 slave_buffer_pos = 0;
138 }
139 slave_has_register_set = true;
140 } else {
141 i2c_slave_buffer[slave_buffer_pos] = TWDR;
142 BUFFER_POS_INC();
143 }
144 break;
145
146 case TW_ST_SLA_ACK:
147 case TW_ST_DATA_ACK:
148 // master has addressed this device as a slave transmitter and is
149 // requesting data.
150 TWDR = i2c_slave_buffer[slave_buffer_pos];
151 BUFFER_POS_INC();
152 break;
153
154 case TW_BUS_ERROR: // something went wrong, reset twi state
155 TWCR = 0;
156 default:
157 break;
158 }
159 // Reset everything, so we are ready for the next TWI interrupt
160 TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
161}
162#endif
diff --git a/keyboards/fc980c/i2c.h b/keyboards/fc980c/i2c.h
new file mode 100644
index 000000000..c15b6bc50
--- /dev/null
+++ b/keyboards/fc980c/i2c.h
@@ -0,0 +1,49 @@
1#ifndef I2C_H
2#define I2C_H
3
4#include <stdint.h>
5
6#ifndef F_CPU
7#define F_CPU 16000000UL
8#endif
9
10#define I2C_READ 1
11#define I2C_WRITE 0
12
13#define I2C_ACK 1
14#define I2C_NACK 0
15
16#define SLAVE_BUFFER_SIZE 0x10
17
18// i2c SCL clock frequency
19#define SCL_CLOCK 400000L
20
21extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23void i2c_master_init(void);
24uint8_t i2c_master_start(uint8_t address);
25void i2c_master_stop(void);
26uint8_t i2c_master_write(uint8_t data);
27uint8_t i2c_master_read(int);
28void i2c_reset_state(void);
29void i2c_slave_init(uint8_t address);
30
31
32static inline unsigned char i2c_start_read(unsigned char addr) {
33 return i2c_master_start((addr << 1) | I2C_READ);
34}
35
36static inline unsigned char i2c_start_write(unsigned char addr) {
37 return i2c_master_start((addr << 1) | I2C_WRITE);
38}
39
40// from SSD1306 scrips
41extern unsigned char i2c_rep_start(unsigned char addr);
42extern void i2c_start_wait(unsigned char addr);
43extern unsigned char i2c_readAck(void);
44extern unsigned char i2c_readNak(void);
45extern unsigned char i2c_read(unsigned char ack);
46
47#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
48
49#endif
diff --git a/keyboards/fc980c/keymaps/actuation-point-example/README.md b/keyboards/fc980c/keymaps/actuation-point-example/README.md
new file mode 100644
index 000000000..e4e9ab98c
--- /dev/null
+++ b/keyboards/fc980c/keymaps/actuation-point-example/README.md
@@ -0,0 +1,9 @@
1# Actuation Point adjustment example keymap
2
3This keymap is an example of how the actuation point adjustment functionality could be used. In `config.h`, we set `ACTUATION_DEPTH_ADJUSTMENT` to `+1`, which puts the actuation point slightly deeper, making the keys less sensitive.
4
5If [hid_listen](https://www.pjrc.com/teensy/hid_listen.html) is running, `CAPS_LOCK + F9` prints the current RDAC setting and `CAPS_LOCK + F10` prints the default or base setting. `CAPS_LOCK + F11` and `CAPS_LOCK + F12` can be used to adjust the actuation point dynamically. Make only small adjustments and find your ideal setting. For example, if the base setting of your keyboard is 56 but you prefer a slightly lower actuation point at 58, you should set `ACTUATION_DEPTH_ADJUSTMENT` to `+2`.
6
7If something goes wrong during adjustment, for example keys not actuating anymore or actuating spontaneously, don't panic. Just unplug the keyboard and plug it back in. This will revert all your dynamic changes made with `F11` and `F12`.
8
9If you discover you have set a too high or low value for `ACTUATION_DEPTH_ADJUSTMENT`, you will need to recompile and reflash your keyboard.
diff --git a/keyboards/fc980c/keymaps/actuation-point-example/config.h b/keyboards/fc980c/keymaps/actuation-point-example/config.h
new file mode 100644
index 000000000..6c9893f42
--- /dev/null
+++ b/keyboards/fc980c/keymaps/actuation-point-example/config.h
@@ -0,0 +1,32 @@
1/* Copyright 2017 Balz Guenat
2 *
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 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef CONFIG_USER_H
18#define CONFIG_USER_H
19
20#include "config_common.h"
21
22// place overrides here
23
24// higher value means deeper actuation point, less sensitive
25// be careful and only make small adjustments (steps of 1 or 2).
26// too high and keys will fail to actuate. too low and keys will actuate spontaneously.
27// test all keys before further adjustment.
28// this should probably stay in the range +/-5.
29#undef ACTUATION_DEPTH_ADJUSTMENT
30#define ACTUATION_DEPTH_ADJUSTMENT +1
31
32#endif
diff --git a/keyboards/fc980c/keymaps/actuation-point-example/keymap.c b/keyboards/fc980c/keymaps/actuation-point-example/keymap.c
new file mode 100644
index 000000000..dcecd86b9
--- /dev/null
+++ b/keyboards/fc980c/keymaps/actuation-point-example/keymap.c
@@ -0,0 +1,77 @@
1/*
2Copyright 2017 Balz Guenat
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "fc980c.h"
18#include "actuation_point.h"
19
20enum custom_keycodes {
21 AP_UP = SAFE_RANGE, // Higher actuation point, more sensitive
22 AP_DN, // Lower actuation point, less sensitive
23 AP_READ_RDAC, // Prints current RDAC value to console
24 AP_READ_EEPROM, // Prints base RDAC value to console
25};
26
27const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
28 [0] = KEYMAP(
29 KC_ESC, KC_F1,KC_F2,KC_F3,KC_F4,KC_F5,KC_F6,KC_F7,KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_INS, KC_PGUP,KC_PGDN,
30 KC_GRV, KC_1,KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL, KC_BSPC, KC_NLCK,KC_PSLS,KC_PAST,KC_PMNS,
31 KC_TAB, KC_Q,KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,KC_RBRC,KC_BSLS, KC_P7, KC_P8, KC_P9, KC_PPLS,
32 MO(1) , KC_A,KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT, KC_ENT, KC_P4, KC_P5, KC_P6,
33 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3, KC_PENT,
34 KC_LCTL,KC_LGUI,KC_LALT, KC_SPC, KC_RALT,KC_RCTL,MO(1), KC_LEFT,KC_DOWN,KC_RGHT, KC_P0, KC_PDOT
35 ),
36 [1] = KEYMAP(
37 _______, _______,_______,_______,_______,_______,_______, _______, _______,AP_READ_RDAC,AP_READ_EEPROM,AP_DN,AP_UP, _______,_______,KC_HOME,KC_END,
38 _______,_______,_______,_______,_______,_______,_______,_______, _______, _______,_______,_______,_______,_______, _______,_______,_______,_______,
39 KC_CAPS,KC_MPRV,KC_VOLU,KC_MNXT,KC_PGUP,KC_INS,KC_HOME, LCTL(KC_LEFT),LCTL(KC_RGHT),KC_END, KC_PSCR,KC_SLCK,KC_PAUS,_______, _______,_______,_______,_______,
40 _______,KC_MUTE,KC_VOLD,KC_MPLY,KC_PGDN,KC_DEL,KC_LEFT, KC_DOWN, KC_UP, KC_RGHT,_______,_______, _______, _______,_______,_______,
41 _______, _______,_______,_______,_______,_______,LCTL(KC_BSPC),LCTL(KC_DEL), _______,_______,_______, _______, KC_PGUP, _______,_______,_______,_______,
42 _______,_______,_______, _______, _______,KC_APP, _______, KC_HOME,KC_PGDN,KC_END, _______,_______
43 ),
44};
45
46void matrix_init_user(void) {
47};
48
49bool process_record_user(uint16_t keycode, keyrecord_t *record) {
50 if (record->event.pressed) {
51 switch(keycode) {
52 case AP_UP: {
53 actuation_point_up();
54 return false;
55 }
56 case AP_DN: {
57 actuation_point_down();
58 return false;
59 }
60 case AP_READ_RDAC: {
61 xprintf("RDAC: %d", read_rdac());
62 return false;
63 }
64 case AP_READ_EEPROM: {
65 xprintf("EEPROM: %d", read_eeprom());
66 return false;
67 }
68
69 default: return true;
70 }
71 } else {
72 return true;
73 }
74};
75
76const uint16_t PROGMEM fn_actions[] = {
77};
diff --git a/keyboards/fc980c/keymaps/coloneljesus/config.h b/keyboards/fc980c/keymaps/coloneljesus/config.h
index 596198be1..da86595b3 100644
--- a/keyboards/fc980c/keymaps/coloneljesus/config.h
+++ b/keyboards/fc980c/keymaps/coloneljesus/config.h
@@ -21,4 +21,12 @@
21 21
22// place overrides here 22// place overrides here
23 23
24// higher value means deeper actuation point, less sensitive
25// be careful and only make small adjustments (steps of 1 or 2).
26// too high and keys will fail to actuate. too low and keys will actuate spontaneously.
27// test all keys before further adjustment.
28// this should probably stay in the range +/-5.
29#undef ACTUATION_DEPTH_ADJUSTMENT
30#define ACTUATION_DEPTH_ADJUSTMENT +2
31
24#endif 32#endif
diff --git a/keyboards/fc980c/matrix.c b/keyboards/fc980c/matrix.c
index 906fec29a..3a3a13de5 100644
--- a/keyboards/fc980c/matrix.c
+++ b/keyboards/fc980c/matrix.c
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */ 21 */
22#include <stdint.h> 22#include <stdint.h>
23#include <stdbool.h> 23#include <stdbool.h>
24#include <util/delay.h> 24#include "wait.h"
25#include "print.h" 25#include "print.h"
26#include "debug.h" 26#include "debug.h"
27#include "util.h" 27#include "util.h"
diff --git a/keyboards/fc980c/rules.mk b/keyboards/fc980c/rules.mk
index 79d40dc61..261bb41c8 100644
--- a/keyboards/fc980c/rules.mk
+++ b/keyboards/fc980c/rules.mk
@@ -61,4 +61,6 @@ NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
61#EXTRALDFLAGS = -Wl,--relax 61#EXTRALDFLAGS = -Wl,--relax
62 62
63CUSTOM_MATRIX = yes 63CUSTOM_MATRIX = yes
64SRC += matrix.c 64SRC += matrix.c \
65 actuation_point.c \
66 i2c.c