Skip to content

Commit

Permalink
Merge pull request #7 from cyril-L/dev/keybi
Browse files Browse the repository at this point in the history
Started the keyboard matrix driver and a keymap, tested on prototype PCB
  • Loading branch information
cyril-L authored Jul 15, 2020
2 parents 11c6363 + 54369d9 commit e20066d
Show file tree
Hide file tree
Showing 22 changed files with 1,500 additions and 112 deletions.
6 changes: 4 additions & 2 deletions build/gcc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,10 @@ SRC = ../../src/main.c \
SRC += ../../src/keybi/keybi.c \
../../src/keybi/hid_keyboard.c \
../../src/keybi/hid_mouse.c \
../../src/keybi/tests.c \
../../src/keybi/drivers/pmw3360.c
../../src/keybi/keymap.c \
../../src/keybi/drivers/delay.c \
../../src/keybi/drivers/pmw3360.c \
../../src/keybi/drivers/matrix.c


# List C source files here which must be compiled in ARM-Mode.
Expand Down
2 changes: 1 addition & 1 deletion build/gcc/stm32.ld
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ INCLUDE "./STM32_COMMON.ld"
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* also change _estack below */
FLASH (rx) : ORIGIN = 0x8002000, LENGTH = 110K-8K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 110K
USER (rx) : ORIGIN = 0x8000000 + 110K, LENGTH = 128K-110K
FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
Expand Down
8 changes: 5 additions & 3 deletions src/inc/platform_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@
/* Define the STM32F10x hardware depending on the used evaluation board */
#ifdef USE_STM3210B_EVAL

#define USB_DISCONNECT GPIOA
#define USB_DISCONNECT_PIN GPIO_Pin_15 // Use GPIO_Pin_10
// FIXME changed for patched keybi board, revert to PA15 like on nkpro
// (routed without USB_EN / DISCONNECT, but had trouble enumerating without it
#define USB_DISCONNECT GPIOC
#define USB_DISCONNECT_PIN GPIO_Pin_8 // Use GPIO_Pin_10
// for older PCB
#define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOA
#define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOC


// smartcard power supply
Expand Down
22 changes: 22 additions & 0 deletions src/keybi/drivers/delay.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "keybi/drivers/delay.h"
#include "stm32f10x_systick.h"

void Keybi_DelayUs(uint32_t duration_us) {
uint32_t remaining_ticks = duration_us * 72;
uint32_t prev = SysTick_GetCounter();

while (1) {
uint32_t curr = SysTick_GetCounter();
uint32_t elapsed;
if (curr > prev) {
elapsed = 719999 + prev - curr;
} else {
elapsed = prev - curr;
}
if (elapsed >= remaining_ticks) {
break;
}
remaining_ticks -= elapsed;
prev = curr;
}
}
5 changes: 5 additions & 0 deletions src/keybi/drivers/delay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "stm32f10x.h"

void Keybi_DelayUs(uint32_t duration_us);
80 changes: 80 additions & 0 deletions src/keybi/drivers/matrix.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "keybi/drivers/matrix.h"
#include "keybi/drivers/delay.h"

typedef struct gpio_t {
GPIO_TypeDef * port;
uint16_t pin;
} gpio_t;

static gpio_t rows[KEYBI_MATRIX_ROWS] = {
{GPIOC, GPIO_Pin_3}, // R01
{GPIOA, GPIO_Pin_0}, // R02
{GPIOA, GPIO_Pin_1}, // R03
{GPIOC, GPIO_Pin_4}, // R04
{GPIOC, GPIO_Pin_5}}; // R05

static gpio_t cols[KEYBI_MATRIX_COLS] = {
{GPIOB, GPIO_Pin_7}, // C01
{GPIOB, GPIO_Pin_8}, // C02
{GPIOB, GPIO_Pin_9}, // C03
{GPIOC, GPIO_Pin_0}, // C04
{GPIOC, GPIO_Pin_1}, // C05
{GPIOC, GPIO_Pin_2}, // C06
{GPIOA, GPIO_Pin_15}, // C07
{GPIOC, GPIO_Pin_10}, // C08
{GPIOC, GPIO_Pin_11}, // C09
{GPIOC, GPIO_Pin_12}, // C10
{GPIOA, GPIO_Pin_10}, // C11
{GPIOA, GPIO_Pin_9}, // C12
{GPIOC, GPIO_Pin_9}, // C13
{GPIOB, GPIO_Pin_1}}; // C14

static uint8_t key_states[KEYBI_MATRIX_COLS][KEYBI_MATRIX_ROWS] = {0};

void Keybi_Matrix_Init(void) {

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

for (int r = 0; r < KEYBI_MATRIX_ROWS; ++r) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = rows[r].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(rows[r].port, &GPIO_InitStructure);
}

for (int c = 0; c < KEYBI_MATRIX_COLS; ++c) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = cols[c].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(cols[c].port, &GPIO_InitStructure);
}
}

void Keybi_Matrix_Scan(int (*callback)(keybi_keyboard_matrix_event_t)) {
for (uint8_t c = 0; c < KEYBI_MATRIX_COLS; ++c) {
GPIO_SetBits(cols[c].port, cols[c].pin);
for (uint8_t r = 0; r < KEYBI_MATRIX_ROWS; ++r) {
uint8_t state = GPIO_ReadInputDataBit(rows[r].port, rows[r].pin);
if (state != key_states[c][r]) {
keybi_keyboard_matrix_event_t event = {
.col = c,
.row = r,
.pressed = state,
.time = 0
};
if (callback(event) == 0) {
// Save state if callback has been able to handle it
key_states[c][r] = state;
}
}
}
GPIO_ResetBits(cols[c].port, cols[c].pin);
// Adjacent columns of the first rows registered on a single key press
// TODO investigate why and find the appropriate delay
Keybi_DelayUs(100);
}
}
16 changes: 16 additions & 0 deletions src/keybi/drivers/matrix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "stm32f10x.h"

#define KEYBI_MATRIX_ROWS (5)
#define KEYBI_MATRIX_COLS (14)

typedef struct {
uint8_t col;
uint8_t row;
uint8_t pressed;
uint16_t time;
} keybi_keyboard_matrix_event_t;

void Keybi_Matrix_Init(void);
void Keybi_Matrix_Scan(int (*callback)(keybi_keyboard_matrix_event_t));
48 changes: 12 additions & 36 deletions src/keybi/drivers/pmw3360.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "keybi/drivers/pmw3360.h"

#include "stm32f10x_spi.h"
#include "stm32f10x_systick.h"
#include "keybi/drivers/delay.h"

// Registers
#define Product_ID 0x00
Expand Down Expand Up @@ -68,7 +68,6 @@ int init_complete = 0;
static const unsigned char firmware_data[4094];

static void performStartup(void);
static void delayMicroseconds(uint32_t delay_us);
static byte adns_read_reg(byte reg_addr);
static void adns_write_reg(byte reg_addr, byte data);

Expand Down Expand Up @@ -111,7 +110,7 @@ int Keybi_Pmw3360_Init() {

performStartup();

delayMicroseconds(1000 * 1000); // 1s (TODO was 5s but 1s is still too long I guess)
Keybi_DelayUs(1000 * 1000); // 1s (TODO was 5s but 1s is still too long I guess)

uint8_t product_id = adns_read_reg(Product_ID);
uint8_t inverse_product_id = adns_read_reg(Inverse_Product_ID);
Expand All @@ -136,29 +135,6 @@ void Keybi_Pmw3360_Read(keybi_pmw3360_motion_t * motion) {
}
}

static void delayMicroseconds(uint32_t delay_us)
{
uint32_t remaining_ticks = delay_us * 72;

uint32_t prev = SysTick_GetCounter();

while (1)
{
uint32_t curr = SysTick_GetCounter();
uint32_t elapsed;
if (curr > prev) {
elapsed = prev; // FIXME don’t know initial value
} else {
elapsed = prev - curr;
}
if (elapsed > remaining_ticks) {
break;
}
remaining_ticks -= elapsed;
prev = curr;
}
}

static uint8_t Keybi_Pmw3360_SpiTransfer(uint8_t data);

static uint8_t Keybi_Pmw3360_SpiTransfer(uint8_t data) {
Expand Down Expand Up @@ -186,13 +162,13 @@ static byte adns_read_reg(byte reg_addr){

// send adress of the register, with MSBit = 0 to indicate it's a read
Keybi_Pmw3360_SpiTransfer(reg_addr & 0x7f );
delayMicroseconds(100); // tSRAD
Keybi_DelayUs(100); // tSRAD
// read data
byte data = Keybi_Pmw3360_SpiTransfer(0);

delayMicroseconds(1); // tSCLK-NCS for read operation is 120ns
Keybi_DelayUs(1); // tSCLK-NCS for read operation is 120ns
adns_com_end();
delayMicroseconds(19); // tSRW/tSRR (=20us) minus tSCLK-NCS
Keybi_DelayUs(19); // tSRW/tSRR (=20us) minus tSCLK-NCS

return data;
}
Expand All @@ -205,9 +181,9 @@ static void adns_write_reg(byte reg_addr, byte data){
//sent data
Keybi_Pmw3360_SpiTransfer(data);

delayMicroseconds(20); // tSCLK-NCS for write operation
Keybi_DelayUs(20); // tSCLK-NCS for write operation
adns_com_end();
delayMicroseconds(100); // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
Keybi_DelayUs(100); // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
}

static void adns_upload_firmware(void);
Expand All @@ -222,20 +198,20 @@ static void adns_upload_firmware(){
adns_write_reg(SROM_Enable, 0x1d);

// wait for more than one frame period
delayMicroseconds(10 * 1000); // assume that the frame rate is as low as 100fps... even if it should never be that low
Keybi_DelayUs(10 * 1000); // assume that the frame rate is as low as 100fps... even if it should never be that low

// write 0x18 to SROM_enable to start SROM download
adns_write_reg(SROM_Enable, 0x18);

// write the SROM file (=firmware data)
adns_com_begin();
Keybi_Pmw3360_SpiTransfer(SROM_Load_Burst | 0x80); // write burst destination adress
delayMicroseconds(15);
Keybi_DelayUs(15);

// send all bytes of the firmware
for(int i = 0; i < sizeof(firmware_data); i++){
Keybi_Pmw3360_SpiTransfer(firmware_data[i]);
delayMicroseconds(15);
Keybi_DelayUs(15);
}

//Read the SROM_ID register to verify the ID before any other register reads or writes.
Expand All @@ -256,7 +232,7 @@ static void performStartup(void){
adns_com_begin(); // ensure that the serial port is reset
adns_com_end(); // ensure that the serial port is reset
adns_write_reg(Power_Up_Reset, 0x5a); // force reset
delayMicroseconds(50 * 1000); // wait for it to reboot
Keybi_DelayUs(50 * 1000); // wait for it to reboot
// read registers 0x02 to 0x06 (and discard the data)
adns_read_reg(Motion);
adns_read_reg(Delta_X_L);
Expand All @@ -265,7 +241,7 @@ static void performStartup(void){
adns_read_reg(Delta_Y_H);
// upload the firmware
adns_upload_firmware();
delayMicroseconds(10 * 1000);
Keybi_DelayUs(10 * 1000);
}

static const unsigned char firmware_data[] = {
Expand Down
57 changes: 57 additions & 0 deletions src/keybi/hid_keyboard.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "keybi/hid_keyboard.h"
#include "keybi/qmk/keycode.h"

#include "CCIDHID_usb_conf.h"
#include "CCIDHID_usb_desc.h"
Expand Down Expand Up @@ -100,3 +101,59 @@ uint8_t* Keybi_Keyboard_GetHIDDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Keybi_Keyboard_Hid_Descriptor);
}

int Keybi_Keyboard_QueueEvents(keybi_keyboard_event_queue_t * queue, keybi_keyboard_event_t * events, uint8_t count) {
if (queue->size + count > queue->capacity) {
return -1;
}
for (int i = 0; i < count; ++i) {
unsigned tail = (queue->head + queue->size) % queue->capacity;
queue->events[tail] = events[i];
queue->size++;
}
return 0;
}

int Keybi_Keyboard_QueueEvent(keybi_keyboard_event_queue_t * queue, keybi_keyboard_event_t event) {
return Keybi_Keyboard_QueueEvents(queue, &event, 1);
}

int Keybi_Keyboard_QueueToReport(keybi_keyboard_event_queue_t * queue, uint8_t * report) {
if (queue->size == 0) {
return 0;
}
keybi_keyboard_event_t * event = &queue->events[queue->head];
queue->head = (queue->head + 1) % queue->capacity;
queue->size--;
if (IS_KEY(event->keycode)) {
if (event->pressed) {
// Do not add a pressed event if already pressed
for (int i = 2; i < 8; ++i) {
if (report[i] == event->keycode) {
return 1;
}
}
// Add the pressed event to the first available report byte
for (int i = 2; i < 8; ++i) {
if (report[i] == 0) {
report[i] = event->keycode;
return 1;
}
}
} else {
for (int i = 2; i < 8; ++i) {
if (report[i] == event->keycode) {
report[i] = 0;
return 1;
}
}
}
} else if (IS_MOD(event->keycode)) {
if (event->pressed) {
report[0] |= MOD_BIT(event->keycode);
} else {
report[0] &= ~MOD_BIT(event->keycode);
}
}
return 1;
}
17 changes: 17 additions & 0 deletions src/keybi/hid_keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,20 @@ uint8_t* Keybi_Keyboard_GetReportDescriptor(uint16_t Length);
uint8_t* Keybi_Keyboard_GetHIDDescriptor(uint16_t Length);

void Keybi_Keyboard_SendReportCompleted(void);

typedef struct {
uint8_t keycode;
uint8_t pressed;
} keybi_keyboard_event_t;

typedef struct {
keybi_keyboard_event_t* events;
uint32_t head;
uint32_t size;
uint32_t capacity;
} keybi_keyboard_event_queue_t;

int Keybi_Keyboard_QueueEvents(keybi_keyboard_event_queue_t * queue, keybi_keyboard_event_t * event, uint8_t count);
int Keybi_Keyboard_QueueEvent(keybi_keyboard_event_queue_t * queue, keybi_keyboard_event_t event);

int Keybi_Keyboard_QueueToReport(keybi_keyboard_event_queue_t * queue, uint8_t * report);
Loading

0 comments on commit e20066d

Please sign in to comment.