From acb403bcbcbc05256500083d1caea7e22ce4db11 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Thu, 25 May 2017 21:56:08 +0100 Subject: Basic keyboard implementation --- Makefile | 2 +- pit.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- pit.h | 1 + setup.c | 4 +- usb/descriptors.h | 42 +++++++----------- usb/endpt1.c | 71 +++++++++++++++++++++--------- usb/endpt1.h | 7 +++ vectors.s | 2 +- 8 files changed, 202 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index c9f111c..f270a6d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CFLAGS = -std=c11 $(WARNINGS) -O2 -flto -MMD -MP -ffreestanding -nostdlib LDFLAGS = -T layout.ld -O2 -flto -ffreestanding -nostdlib ASFLAGS = $(TARGET_ARCH) -OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/le.o usb/usb.o \ +OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/le.o pit.o usb/usb.o \ usb/endpt0.o usb/endpt1.o usb/txhandler.o uart.o include $(MK20DX256)/mk20dx256.mk diff --git a/pit.c b/pit.c index d52292e..1241766 100644 --- a/pit.c +++ b/pit.c @@ -16,13 +16,133 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include +#include +#include #include +#include +#include +#include +#include +#include #include "pit.h" +#include "usb/endpt1.h" +#include "usb/keycodes.h" + +enum { + T0_CYCLES = 5000, +}; + +struct gpio { + uint32_t port; + uint32_t gpio; + uint32_t bit; + unsigned char pin; +}; +#define GPIO_PIN(port, pin) { \ + PORT##port##_BASE, \ + GPIO##port##_BASE, \ + BV((pin)), \ + (pin), \ +} + +static const struct gpio cols[] = { + GPIO_PIN(B, 2), + GPIO_PIN(B, 3), + GPIO_PIN(B, 18), + GPIO_PIN(B, 19), + GPIO_PIN(C, 0), + GPIO_PIN(C, 8), + GPIO_PIN(C, 9), + GPIO_PIN(C, 10), + GPIO_PIN(C, 11), +}; + +static const struct gpio rows[] = { + GPIO_PIN(D, 0), + GPIO_PIN(D, 1), + GPIO_PIN(D, 4), + GPIO_PIN(D, 5), + GPIO_PIN(D, 6), + GPIO_PIN(D, 7), + GPIO_PIN(C, 1), + GPIO_PIN(C, 2), +}; + +/* COL AND ROW SWAPPED!!! */ +static enum keycode keymap[ARRLEN(rows)][ARRLEN(cols)] = { + { /* S01 */ KEY_ESCAPE, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, }, + { /* S10 */ KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_NONE, KEY_BACKSPACE, KEY_GRAVE, KEY_TAB, KEY_Q, }, + { /* S19 */ KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, }, + { /* S28 */ KEY_LSQUARE, KEY_RSQUARE, KEY_NONE, KEY_DELETE, KEY_CAPSLK, KEY_A, KEY_S, KEY_D, KEY_F, }, + { /* S37 */ KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_QUOTE, KEY_BACKSLASH, KEY_ENTER, }, + { /* S46 */ KEY_PGUP, KEY_LSHIFT, KEY_NU_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, }, + { /* S55 */ KEY_M, KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_RSHIFT, KEY_UP, KEY_PGDN, KEY_LCTRL, KEY_LGUI, }, + { /* S64 */ KEY_LALT, KEY_SPACE, KEY_RALT, KEY_NONE, KEY_RCTRL, KEY_LEFT, KEY_DOWN, KEY_RIGHT, KEY_NONE, }, +}; void pit_setup(void) { - /* TODO */ - while (1) - ; + /* Set up ports (could be done with GPC registers */ + for (size_t i = 0; i < ARRLEN(cols); i++) { + SET_BIT(GPIO_PDDR(cols[i].gpio), cols[i].pin); + GPIO_PCOR(cols[i].gpio) = cols[i].bit; + PORT_PCR(cols[i].port, cols[i].pin) = BV(PCR_SRE) | BV(PCR_DSE) + | 1 << PCR_MUX; + } + for (size_t i = 0; i < ARRLEN(rows); i++) { + UNSET_BIT(GPIO_PDDR(rows[i].gpio), rows[i].pin); + PORT_PCR(rows[i].port, rows[i].pin) = BV(PCR_PFE) | BV(PCR_PE) + | 1 << PCR_MUX; + } + + /* Enable clock */ + SET_BIT(SIM_SCGC6, SCGC6_PIT); + + /* NVIC Enable interrupt */ + ISR_CLRPEND(68); + ISR_SETENA(68); + INTPRI(68) = 0x10; + + /* First column strobe */ + GPIO_PSOR(cols[0].gpio) = cols[0].bit; + + /* Set up PIT0 */ + PIT_MCR = 0; + + PIT_LDVAL(0) = T0_CYCLES - 1; + PIT_TFLG(0) = BV(TFLG_TIF); + PIT_TCTRL(0) = BV(TCTRL_TIE) | BV(TCTRL_TEN); +} + +static uint8_t kstates[ARRLEN(cols)][ARRLEN(rows)] = { 0 }; + +static void key_state(int col, int row, bool state) +{ + uint8_t kstate; + + kstate = kstates[col][row] = kstates[col][row] << 1 | state; + + if (kstate == 0x7f) + usb_endpt1_setkey(keymap[row][col], true); + else if (kstate == 0x80) + usb_endpt1_setkey(keymap[row][col], false); +} + +void pit0_isr(void) +{ + static unsigned char col = 0; + + for (size_t row = 0; row < ARRLEN(rows); row++) + key_state(col, row, !!(GPIO_PDIR(rows[row].gpio) & rows[row].bit)); + + GPIO_PCOR(cols[col].gpio) = cols[col].bit; + col = (col + 1) % ARRLEN(cols); + GPIO_PSOR(cols[col].gpio) = cols[col].bit; + + if (col == 0) + usb_endpt1_send(); + + PIT_TFLG(0) = BV(TFLG_TIF); } diff --git a/pit.h b/pit.h index d82587a..811f024 100644 --- a/pit.h +++ b/pit.h @@ -20,5 +20,6 @@ #define FMK_PIT_H void pit_setup(void); +void pit0_isr(void); #endif /* FMK_PIT_H */ diff --git a/setup.c b/setup.c index 568caaf..89a7762 100644 --- a/setup.c +++ b/setup.c @@ -20,8 +20,9 @@ #include #include -#include "usb/usb.h" +#include "pit.h" #include "uart.h" +#include "usb/usb.h" extern unsigned char _ldata[], _sdata[], _edata[]; extern unsigned char _sbss[], _ebss[]; @@ -108,6 +109,7 @@ void setup(void) uart_setup(); usb_setup(); + pit_setup(); /* Enable interrupts for setup */ STI(); diff --git a/usb/descriptors.h b/usb/descriptors.h index df603a5..a81a0f7 100644 --- a/usb/descriptors.h +++ b/usb/descriptors.h @@ -67,17 +67,17 @@ unsigned char ds_conf[] = { 1, // Number of endpoints 3, // Interface class 1, // Interface sub class - 2, // Interface protocol + 1, // Interface protocol 0, // Interface string /* HID */ 9, // Length 33, // Descriptor type U16LE(0x0111), // HID Class spec version - 0, // Country code + 32, // Country code 1, // Number of descriptors 34, // Descriptor type -#define DS_HIDREP_SIZE 52 +#define DS_HIDREP_SIZE 29 U16LE(DS_HIDREP_SIZE), // Descriptor length /* Endpoint */ @@ -93,31 +93,19 @@ _Static_assert(sizeof ds_conf == DS_CONF_SIZE, "sizeof ds_conf != DS_CONF_SIZE") /* HID Report descriptor */ unsigned char ds_hidrep[] = { HR_USAGE_PAGE(1), HR_PAGE_GENERIC_DESKTOP, - HR_USAGE(1), HR_GD_MOUSE, + HR_USAGE(1), HR_GD_KEYBOARD, HR_COLLECTION(1), HR_APPLICATION, - HR_USAGE(1), HR_GD_POINTER, - HR_COLLECTION(1), HR_PHYSICAL, - HR_USAGE_PAGE(1), HR_PAGE_BUTTON, - HR_USAGE_MINIMUM(1), 1, - HR_USAGE_MAXIMUM(1), 5, - HR_LOGICAL_MINIMUM(1), 0, - HR_LOGICAL_MAXIMUM(1), 1, - HR_REPORT_COUNT(1), 5, - HR_REPORT_SIZE(1), 1, - HR_INPUT(1), HR_DATA | HR_VARIABLE | HR_ABSOLUTE | HR_BIT_FIELD, - HR_REPORT_COUNT(1), 1, - HR_REPORT_SIZE(1), 3, - HR_INPUT(1), HR_CONSTANT | HR_ARRAY | HR_ABSOLUTE | HR_BIT_FIELD, - HR_USAGE_PAGE(1), HR_PAGE_GENERIC_DESKTOP, - HR_USAGE(1), HR_GD_X, - HR_USAGE(1), HR_GD_Y, - HR_USAGE(1), HR_GD_WHEEL, - HR_LOGICAL_MINIMUM(1), -127, - HR_LOGICAL_MAXIMUM(1), 127, - HR_REPORT_SIZE(1), 8, - HR_REPORT_COUNT(1), 3, - HR_INPUT(1), HR_DATA | HR_VARIABLE | HR_RELATIVE | HR_BIT_FIELD, - HR_END_COLLECTION(0), + HR_USAGE_PAGE(1), HR_PAGE_KEYBOARD, + HR_USAGE_MINIMUM(1), 4, + HR_USAGE_MAXIMUM(1), 231, + HR_LOGICAL_MINIMUM(1), 0, + HR_LOGICAL_MAXIMUM(1), 1, + HR_REPORT_SIZE(1), 1, + HR_REPORT_COUNT(1), 228, + HR_INPUT(1), HR_DATA | HR_VARIABLE | HR_ABSOLUTE | HR_BIT_FIELD, + HR_REPORT_SIZE(1), 4, + HR_REPORT_COUNT(1), 1, + HR_INPUT(1), HR_CONSTANT | HR_ARRAY | HR_ABSOLUTE | HR_BIT_FIELD, HR_END_COLLECTION(0), }; _Static_assert(sizeof ds_hidrep == DS_HIDREP_SIZE, "sizeof ds_hidrep != DS_HIDREP_SIZE"); diff --git a/usb/endpt1.c b/usb/endpt1.c index 0580349..dcfc61b 100644 --- a/usb/endpt1.c +++ b/usb/endpt1.c @@ -19,40 +19,73 @@ #include #include #include +#include + +#include #include "../uart.h" #include "bdt.h" #include "endpt1.h" +#include "keycodes.h" +#include "txhandler.h" #define MAX_PACKET 64 -static unsigned char report[4][4] = { - { 0x00, 5, 0, 0x00, }, - { 0x00, 0, 5, 0x00, }, - { 0x00, -5, 0, 0x00, }, - { 0x00, 0, -5, 0x00, }, -}; -static int nextrep; +static struct tx_ctx tx; +#define THIS_EP 1 +static volatile struct usb0_bd (* const this_bdt)[2] = usb_bdt[THIS_EP]; -void usb_endpt1_enable(void) +unsigned char report[29]; +volatile bool sendrep; + +void usb_endpt1_setkey(enum keycode keycode, bool state) { - nextrep = 0; + unsigned char byte, bit; + + if (keycode == KEY_NONE) + return; + + keycode -= 4; + byte = keycode / 8; + bit = keycode % 8; + + if (state) + SET_BIT(report[byte], bit); + else + UNSET_BIT(report[byte], bit); + + sendrep = true; +} - usb_bdt[1][BDT_TX][BDT_EVEN].addr = &report[0]; - usb_bdt[1][BDT_TX][BDT_EVEN].desc = USB0_BD_INIT(4, nextrep % 2); - nextrep++; +void usb_endpt1_send(void) +{ + if (!sendrep) + return; + if (!tx_isempty(&tx)) { + return; + } + + tx_que(&tx, report, sizeof report); + sendrep = false; +} + +void usb_endpt1_enable(void) +{ + this_bdt[BDT_TX][BDT_EVEN].addr = NULL; + this_bdt[BDT_TX][BDT_EVEN].desc = 0; - usb_bdt[1][BDT_TX][BDT_ODD].addr = &report[1]; - usb_bdt[1][BDT_TX][BDT_ODD].desc = USB0_BD_INIT(4, nextrep % 2); - nextrep++; + this_bdt[BDT_TX][BDT_ODD].addr = NULL; + this_bdt[BDT_TX][BDT_ODD].desc = 0; - USB0_ENDPT(1) = BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK); + USB0_ENDPT(THIS_EP) = BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK); + tx = TX_CTX(this_bdt[BDT_TX], MAX_PACKET); + tx_que(&tx, report, sizeof report); } void usb_endpt1_disable(void) { - USB0_ENDPT(1) = 0; + USB0_ENDPT(THIS_EP) = 0; } void usb_endpt1_token(uint8_t state) @@ -63,9 +96,7 @@ void usb_endpt1_token(uint8_t state) switch (GET_BITS(bd->desc, BD_TOK_PID)) { case BD_TOK_PID_IN: - bd->addr = &report[nextrep]; - bd->desc = USB0_BD_INIT(4, nextrep % 2); - nextrep = (nextrep + 1) % 4; + tx_push(&tx); break; } } diff --git a/usb/endpt1.h b/usb/endpt1.h index fa26bd9..35e1a2c 100644 --- a/usb/endpt1.h +++ b/usb/endpt1.h @@ -19,6 +19,13 @@ #ifndef FMK_USB_ENDPT1_H #define FMK_USB_ENDPT1_H +#include +#include + +#include "keycodes.h" + +void usb_endpt1_setkey(enum keycode keycode, bool state); +void usb_endpt1_send(void); void usb_endpt1_enable(void); void usb_endpt1_disable(void); void usb_endpt1_token(uint8_t state); diff --git a/vectors.s b/vectors.s index 794d194..c0d382c 100644 --- a/vectors.s +++ b/vectors.s @@ -92,7 +92,7 @@ .long 0 // 81 CMT: - .long 0 // 82 RTC: Alarm interrupt .long 0 // 83 RTC: Seconds interrupt -.long 0 // 84 PIT: Channel 0 +.long pit0_isr// 84 PIT: Channel 0 .long 0 // 85 PIT: Channel 1 .long 0 // 86 PIT: Channel 2 .long 0 // 87 PIT: Channel 3 -- cgit v1.2.3-54-g00ecf