This is a part of the Kinetiszer project.
Diff: keyboard.c
- Revision:
- 0:cb80470434eb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/keyboard.c Tue Oct 28 12:19:42 2014 +0000 @@ -0,0 +1,468 @@ +#include "atmegatron.h" + + +keyboard_key_t g_encoder[] = +{ + // Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN), + // meaning that it has to be set in all cases. + // No pull-ups or -downs on rotary encoder pins. All inputs are inverted to read as 1 on contact closed. + // Rotary encoders are handled as two non-matrix keys. + + #if defined BOARD_KEYBOARD_RE0 /* S1 */ + { BOARD_KEYBOARD_RE0_A_PORT, BOARD_KEYBOARD_RE0_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE0_B_PORT, BOARD_KEYBOARD_RE0_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE1 /* S2 */ + { BOARD_KEYBOARD_RE1_A_PORT, BOARD_KEYBOARD_RE1_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE1_B_PORT, BOARD_KEYBOARD_RE1_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE2 /* S3 */ + { BOARD_KEYBOARD_RE2_A_PORT, BOARD_KEYBOARD_RE2_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE2_B_PORT, BOARD_KEYBOARD_RE2_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE3 /* S4 */ + { BOARD_KEYBOARD_RE3_A_PORT, BOARD_KEYBOARD_RE3_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE3_B_PORT, BOARD_KEYBOARD_RE3_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE4 /* S5 */ + { BOARD_KEYBOARD_RE4_A_PORT, BOARD_KEYBOARD_RE4_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE4_B_PORT, BOARD_KEYBOARD_RE4_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE5 /* S6 */ + { BOARD_KEYBOARD_RE5_A_PORT, BOARD_KEYBOARD_RE5_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE5_B_PORT, BOARD_KEYBOARD_RE5_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE6 /* S7 */ + { BOARD_KEYBOARD_RE6_A_PORT, BOARD_KEYBOARD_RE6_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE6_B_PORT, BOARD_KEYBOARD_RE6_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif + + #if defined BOARD_KEYBOARD_RE7 /* S8 */ + { BOARD_KEYBOARD_RE7_A_PORT, BOARD_KEYBOARD_RE7_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + { BOARD_KEYBOARD_RE7_B_PORT, BOARD_KEYBOARD_RE7_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif +}; + + +keyboard_key_t g_key[] = +{ + // Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN), + // meaning that it has to be set in all cases. + // Pull-ups needed. All inputs are inverted to read as 1 on contact closed. + + // S9 (ISP) + { BOARD_KEYBOARD_ISP_PORT, BOARD_KEYBOARD_ISP_PIN, IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN }, + + #if defined RESET_IS_GPIO + // S10 (reset) could go here... + { BOARD_KEYBOARD_RESET_PORT, BOARD_KEYBOARD_RESET_PIN, IOCON_FUNC1|IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN }, + #endif +}; + + +keyboard_matrix_key_t g_matrix_key[] = +{ +#ifdef BOARD_KEYBOARD_S00 /* S1 */ + { BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S01 /* S2 */ + { BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S02 /* S3 */ + { BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S10 /* S4 */ + { BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S11 /* S5 */ + { BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S12 /* S6 */ + { BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S20 /* S7 */ + { BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }}, +#endif + +#ifdef BOARD_KEYBOARD_S21 /* S8 */ + { BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }}, +#endif + + // FYI: S9 is ISP, S10 is reset button. + +#ifdef BOARD_KEYBOARD_S22 /* S11 */ + { BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }}, +#endif +}; + + +// Since all data is zero, a memset would have been quicker to type. +keyboard_rotary_encoder_data_t g_encoder_data[] = +{ +#ifdef BOARD_KEYBOARD_RE0 /* S1 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE1 /* S2 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE2 /* S3 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE3 /* S4 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE4 /* S5 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE5 /* S6 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE6 /* S7 */ + { + 0, 0, 0, 0, 0 + }, +#endif + +#ifdef BOARD_KEYBOARD_RE7 /* S8 */ + { + 0, 0, 0, 0, 0 + }, +#endif +}; + + +#define MATRIX_KEY_COUNT (sizeof(g_matrix_key)/sizeof(g_matrix_key[0])) +#define ENCODER_PIN_COUNT (sizeof(g_encoder)/sizeof(g_encoder[0])) +#define ENCODER_COUNT (sizeof(g_encoder_data)/sizeof(g_encoder_data[0])) +#define KEYS_OTHER_COUNT (sizeof(g_key)/sizeof(g_key[0])) + +/* +DigitalIn encoder1_a(PTA0); // phase A +DigitalIn encoder1_b(PTE27); // phase B +DigitalIn encoder1_k(PTD2); // integrated pushbutton + +DigitalIn encoder2_a(PTC4); // phase A +DigitalIn encoder2_b(PTE25); // phase B +DigitalIn encoder2_k(PTD0); // integrated pushbutton + +AnalogIn pot2(A5); +AnalogIn pot3(A4); +AnalogIn pot4(A3); +AnalogIn pot5(A2); +AnalogIn pot6(A1); +AnalogIn pot7(A0); +*/ +void keyboard_init(void) +{ + int i; + + //encoder1_a.mode(PullUp); + //encoder1_b.mode(PullUp); + //encoder1_k.mode(PullUp); + //encoder2_a.mode(PullUp); + //encoder2_b.mode(PullUp); + //encoder2_k.mode(PullUp); + + keyboard_matrix_key_t *p_matrix_key; + keyboard_key_t *p_encoder; + keyboard_key_t *p_keys_other; + + // Initialize key matrix. + p_matrix_key = g_matrix_key; + for (i=0; i<MATRIX_KEY_COUNT; i++) + { + // Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN), + // meaning that it has to be set in all cases. + // Pull-ups needed on row pins. All inputs are inverted to read as 1 on contact closed. + //Chip_IOCON_PinMuxSet(LPC_IOCON,p_matrix_key->row_port,p_matrix_key->row_pin,IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN); + //Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_matrix_key->col_port,p_matrix_key->col_pin,OUTPUT); + //Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_matrix_key->row_port,p_matrix_key->row_pin,INPUT); + p_matrix_key->data.debounce = 0; + p_matrix_key->data.value = key_released; + p_matrix_key->data.changed = false; + p_matrix_key++; + } + + // Initialize rotary encoders. + p_encoder = g_encoder; + // A rotary encoder has two pins which is why we use ENCODER_PIN_COUNT. + for (i=0; i<ENCODER_PIN_COUNT; i++) + { + //Chip_IOCON_PinMuxSet(LPC_IOCON,p_encoder->port,p_encoder->pin,p_encoder->function); + //Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_encoder->port,p_encoder->pin,INPUT); + p_encoder->data.debounce = 0; + p_encoder->data.value = key_released; + p_encoder++; + } + + // Initialize remaining keys like S9 & S10. + p_keys_other = g_key; + for (i=0; i<KEYS_OTHER_COUNT; i++) + { + //Chip_IOCON_PinMuxSet(LPC_IOCON,p_keys_other->port,p_keys_other->pin,p_keys_other->function); + //Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_keys_other->port,p_keys_other->pin,INPUT); + p_keys_other->data.debounce = 0; + p_keys_other->data.value = key_released; + p_keys_other++; + } +} + + +int8_t keyboard_key_is_debounced(int8_t debounce) +{ + int8_t result = 0; + if (debounce>=KEY_DEBOUNCE_MAX) + { + // Key debounced high. + result = 1; + } + else if (debounce<=KEY_DEBOUNCE_MIN) + { + // Key debounced low. + result = -1; + } + return result; +} + + +uint8_t keyboard_matrix_key_read(keyboard_matrix_key_t *p_key) +{ + uint8_t value = 0; + + // Scan a key. Pressed keys read as high (inverted input). +// Chip_GPIO_WritePortBit(LPC_GPIO_PORT,p_key->col_port,p_key->col_pin,0); +// value = Chip_GPIO_ReadPortBit(LPC_GPIO_PORT,p_key->row_port,p_key->row_pin); +// Chip_GPIO_WritePortBit(LPC_GPIO_PORT,p_key->col_port,p_key->col_pin,1); + return value; +} + + +inline uint8_t keyboard_key_read(keyboard_key_t *p_key) +{ + // Pressed keys read as high (inverted input). + //return Chip_GPIO_ReadPortBit(LPC_GPIO_PORT,p_key->port,p_key->pin); + return 0; +} + + +uint8_t keyboard_key_debounce(int8_t *p_debounce, uint8_t state) +{ + uint8_t result = 0; + + // Debounce. + if (state!=0) + { + if ((*p_debounce)<KEY_DEBOUNCE_MAX) (*p_debounce)++; + if ((*p_debounce)>=KEY_DEBOUNCE_MAX) result = 1; + } + else + { + if ((*p_debounce)>KEY_DEBOUNCE_MIN) (*p_debounce)--; + if ((*p_debounce)<=KEY_DEBOUNCE_MIN) result = 1; + } + + return result; +} + + +uint32_t keyboard_scan_matrix(void) +{ + int i; + uint8_t state; + + // Scan key matrix. + for (i=0; i<MATRIX_KEY_COUNT; i++) + { + state = keyboard_matrix_key_read(&g_matrix_key[i]); + if (keyboard_key_debounce(&g_matrix_key[i].data.debounce,state)!=0) + { + // Update pushbutton value. + if (g_matrix_key[i].data.debounce>=KEY_DEBOUNCE_MAX) + { + if (g_matrix_key[i].data.value!=key_pressed) + { + g_matrix_key[i].data.changed = true; + } + g_matrix_key[i].data.value = key_pressed; + } + else + { + if (g_matrix_key[i].data.value!=key_released) + { + g_matrix_key[i].data.changed = true; + } + g_matrix_key[i].data.value = key_released; + } + } + } + + // Scan other keys (S9, S10) too. + for (i=0; i<KEYS_OTHER_COUNT; i++) + { + state = keyboard_key_read(&g_key[i]); + if (keyboard_key_debounce(&g_key[i].data.debounce,state)!=0) + { + // Update pushbutton value. + if (g_key[i].data.debounce>=KEY_DEBOUNCE_MAX) + { + if (g_key[i].data.value!=key_pressed) + { + g_key[i].data.changed = true; + } + g_key[i].data.value = key_pressed; + } + else + { + if (g_key[i].data.value!=key_released) + { + g_key[i].data.changed = true; + } + g_key[i].data.value = key_released; + } + } + } + + return 0; +} + + +uint32_t keyboard_scan_encoders(void) +{ + int i, j, inc; + int8_t state_new; + uint8_t a, b; + + j = 0; + for (i=0; i<ENCODER_COUNT; i++) + { + a = keyboard_key_read(&g_encoder[j]); + j += 1; + b = keyboard_key_read(&g_encoder[j]); + j += 1; + state_new = (a<<1) | b; + if (state_new!=g_encoder_data[i].state) + { + inc = a ^ (g_encoder_data[i].state&0x01); + if (inc==0) inc = -1; + g_encoder_data[i].state = state_new; + + g_encoder_data[i].state_sub += inc; + if ((g_encoder_data[i].state_sub<=-4) || (g_encoder_data[i].state_sub>=4)) + { + g_encoder_data[i].state_sub = 0; + g_encoder_data[i].value -= inc; + keyboard_encoder_speed(&g_encoder_data[i]); + } + } + } + + return 0; +} + + +void keyboard_encoder_speed(keyboard_rotary_encoder_data_t *p_encoder_data) +{ + uint32_t timestamp = systick_counter; + uint32_t delta = timestamp - p_encoder_data->timestamp; + //delta = 0x1ffff >> delta; + if (delta<KEY_PERIOD_MIN) delta = KEY_PERIOD_MIN; + else if (delta>KEY_PERIOD_MAX) delta = KEY_PERIOD_MAX; + p_encoder_data->accelerator = (uint8_t)(KEY_PERIOD_MAX/delta); + if (p_encoder_data->accelerator==0) p_encoder_data->accelerator = 1; + p_encoder_data->timestamp = timestamp; +} + + +bool keyboard_get_pushbutton_changed(uint8_t key_nr) +{ + if (key_nr>=BOARD_KEYBOARD_ISP) + { + // "Other" pushbuttons start at S9. + return g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed; + } + else + { + return g_matrix_key[key_nr].data.changed; + } +} + + +keyboard_key_press_t keyboard_get_pushbutton(uint8_t key_nr, bool use) +{ + if (key_nr>=BOARD_KEYBOARD_ISP) + { + // "Other" pushbuttons start at S9. + if (use==true) g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed = false; + return g_key[key_nr-BOARD_KEYBOARD_ISP].data.value; + } + else + { + if (use==true) g_matrix_key[key_nr].data.changed = false; + return g_matrix_key[key_nr].data.value; + } +} + + +void keyboard_set_pushbutton(uint8_t key_nr, keyboard_key_press_t value) +{ + if (key_nr>=BOARD_KEYBOARD_ISP) + { + // "Other" pushbuttons start at S9. + g_key[key_nr-BOARD_KEYBOARD_ISP].data.value = value; + g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed = false; + } + else + { + g_matrix_key[key_nr].data.value = value; + g_matrix_key[key_nr].data.changed = false; + } +} + + +int8_t keyboard_get_rotary_encoder_value(uint8_t encoder_nr) +{ + return g_encoder_data[encoder_nr].value; +} + + +void keyboard_set_rotary_encoder_value(uint8_t encoder_nr, int8_t value) +{ + g_encoder_data[encoder_nr].value = value; +} + + +uint8_t keyboard_get_rotary_encoder_accelerator(uint8_t encoder_nr) +{ + return g_encoder_data[encoder_nr].accelerator; +} +