diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..1d953f4bd7 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore index ca9f00a733..38791a7412 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,4 @@ compile_commands.json # VIA(L) files that don't belong in QMK repo via*.json /keyboards/**/keymaps/vial/* +.direnv diff --git a/keyboards/rkb1/config.h b/keyboards/rkb1/config.h index c3c99a357b..f3a6d47385 100644 --- a/keyboards/rkb1/config.h +++ b/keyboards/rkb1/config.h @@ -3,6 +3,10 @@ #pragma once +#define SPLIT_HAND_PIN GP21 +#define SPLIT_HAND_PIN_LOW_IS_LEFT +#define SPLIT_USB_DETECT + /* * Feature disable options * These options are also useful to firmware size reduction. diff --git a/keyboards/rkb1/i2c_master.c b/keyboards/rkb1/i2c_master.c new file mode 100644 index 0000000000..8a6aebf98e --- /dev/null +++ b/keyboards/rkb1/i2c_master.c @@ -0,0 +1,74 @@ +// rp2040 implementation of i2c_master.c +#include "i2c_master.h" +#include "hardware/i2c.h" +#include "hardware/gpio.h" +#include + +void cos_i2c_init(void) { + static bool is_initialized = false; + if (!is_initialized) { + is_initialized = true; + + gpio_set_function(24, GPIO_FUNC_I2C); + gpio_set_function(25, GPIO_FUNC_I2C); + gpio_pull_up(24); + gpio_pull_up(25); + } +} + +static bool enabled = false; +static void init_i2c(void) { + if(!enabled) { + i2c_init(i2c0, 100 * 1000); // 100kb/s + enabled = true; + } +} + +static uint8_t i2c_address; + +static i2c_status_t pico_to_qmk(int result) { + if(result == PICO_ERROR_TIMEOUT) + return I2C_STATUS_TIMEOUT; + if(result < 0) + return I2C_STATUS_ERROR; + return I2C_STATUS_SUCCESS; +} + +i2c_status_t cos_i2c_start(uint8_t address) { + i2c_address = address; + init_i2c(); + return I2C_STATUS_SUCCESS; +} + +i2c_status_t cos_i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) { + cos_i2c_start(address); + return pico_to_qmk(i2c_write_timeout_us(i2c0, address, data, (size_t)length, false, (uint32_t)timeout * 1000)); +} + +i2c_status_t cos_i2c_receive(uint8_t address, uint8_t * data, uint16_t length, uint16_t timeout) { + cos_i2c_start(address); + return pico_to_qmk(i2c_read_timeout_us(i2c0, address, data, (size_t)length, false, (uint32_t)timeout * 1000)); +} + +i2c_status_t cos_i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { + cos_i2c_start(devaddr); + uint8_t complete_packet[length + 1]; + memcpy(complete_packet + 1, data, (size_t)length); + complete_packet[0] = regaddr; + + return cos_i2c_transmit(devaddr, complete_packet, length + 1, timeout); +} + +i2c_status_t cos_i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout){ + cos_i2c_start(devaddr); + // TODO: uses 2x timeout + i2c_status_t reg_result = cos_i2c_transmit(devaddr, ®addr, 1, timeout); + if(reg_result != I2C_STATUS_SUCCESS) + return reg_result; + return cos_i2c_receive(devaddr, data, length, timeout); +} + +void cos_i2c_stop(void) { + enabled = false; + i2c_deinit(i2c0); +} diff --git a/keyboards/rkb1/i2c_slave.c b/keyboards/rkb1/i2c_slave.c new file mode 100644 index 0000000000..63a6f69a9c --- /dev/null +++ b/keyboards/rkb1/i2c_slave.c @@ -0,0 +1,119 @@ +#include "i2c_slave.h" +#include "hardware/i2c.h" +#include "hardware/gpio.h" +#include "hardware/irq.h" +#include +#include "transactions.h" + +// Code taken from here: https://github.com/harsha-vk/weeder_bot/blob/0bb2ac3f627dc2b3867480d210c0536ae0f684a5/assets/raspberry_pi_pico_code/src/i2c_slave.cpp + +static volatile bool is_callback_executor = false; +volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT]; +static volatile uint8_t buffer_address; +static volatile bool sub_has_register_set = false; + +static volatile bool transfer_in_progress = false; +enum i2c_event_t { + I2C_SUB_RECEIVE, + I2C_SUB_REQUEST, + I2C_SUB_FINISH +}; + +static void i2c_sub_handler(enum i2c_event_t event) { + //uint8_t ack = 1; + switch(event) { + case I2C_SUB_RECEIVE: { + while(i2c_get_read_available(i2c0)) { + if(!sub_has_register_set) { + i2c_read_raw_blocking(i2c0, (uint8_t *)&buffer_address, 1); + if (buffer_address >= I2C_SLAVE_REG_COUNT) { + //ack = 0; + buffer_address = 0; + } + sub_has_register_set = true; + is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset; + } else { + // find out how many bytes we can safely read + uint32_t bytes_left = I2C_SLAVE_REG_COUNT - buffer_address; + uint32_t bytes_to_read = i2c_get_read_available(i2c0); + uint32_t num_bytes = (bytes_left < bytes_to_read) ? bytes_left : bytes_to_read; + i2c_read_raw_blocking(i2c0, (uint8_t *)i2c_slave_reg + buffer_address, num_bytes); + buffer_address += num_bytes; + if(buffer_address >= I2C_SLAVE_REG_COUNT) + buffer_address = 0; + // If we're intending to execute a transaction callback, do so, as we've just received the transaction ID + if (is_callback_executor) { + split_transaction_desc_t *trans = &split_transaction_table[split_shmem->transaction_id]; + if (trans->slave_callback) { + trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans)); + } + } + } + } + } + break; + case I2C_SUB_REQUEST: { + i2c_write_raw_blocking(i2c0, (uint8_t*)i2c_slave_reg + buffer_address, 1); + buffer_address++; + break; + } + case I2C_SUB_FINISH: + sub_has_register_set = false; + is_callback_executor = false; + break; + } + // TODO: ack?? +} + +static void finish_transfer(void) { + transfer_in_progress = false; + i2c_sub_handler(I2C_SUB_FINISH); +} + +static void i2c_handler(void) { + i2c_hw_t *hw = i2c_get_hw(i2c0); + uint32_t intr_stat = hw->intr_stat; + if(intr_stat == 0) return; // spurious + if(intr_stat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { + hw->clr_tx_abrt; + finish_transfer(); + } + if(intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) { + hw->clr_start_det; + finish_transfer(); + } + if(intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + hw->clr_stop_det; + finish_transfer(); + } + if(intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { + transfer_in_progress = true; + i2c_sub_handler(I2C_SUB_RECEIVE); + } + if(intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { + hw->clr_rd_req; + transfer_in_progress = true; + i2c_sub_handler(I2C_SUB_REQUEST); + } +} + +void cos_i2c_slave_init(uint8_t address) { + i2c_init(i2c0, 100 * 1000); + i2c_set_slave_mode(i2c0, true, address); + gpio_set_function(24, GPIO_FUNC_I2C); + gpio_set_function(25, GPIO_FUNC_I2C); + gpio_pull_up(24); + gpio_pull_up(25); + + i2c_hw_t *hw = i2c_get_hw(i2c0); + hw->intr_mask = I2C_IC_INTR_MASK_M_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS | I2C_IC_INTR_MASK_M_STOP_DET_BITS | I2C_IC_INTR_MASK_M_START_DET_BITS; + irq_set_exclusive_handler(I2C0_IRQ, i2c_handler); + irq_set_enabled(I2C0_IRQ, true); +} + +void cos_i2c_slave_stop(void) { + i2c_set_slave_mode(i2c0, false, 0); + i2c_deinit(i2c0); +} + + diff --git a/keyboards/rkb1/i2c_slave.h b/keyboards/rkb1/i2c_slave.h new file mode 100644 index 0000000000..e1f390eef8 --- /dev/null +++ b/keyboards/rkb1/i2c_slave.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2019 Elia Ritterbusch + + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* Library made by: g4lvanix + * GitHub repository: https://github.com/g4lvanix/I2C-slave-lib + + Info: Inititate the library by giving the required address. + Read or write to the necessary buffer according to the opperation. + */ + +#pragma once + +#ifndef I2C_SLAVE_REG_COUNT + +# if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS) +# include "transport.h" +# define I2C_SLAVE_REG_COUNT sizeof(split_shared_memory_t) +# else // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS) +# define I2C_SLAVE_REG_COUNT 30 +# endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS) + +#endif // I2C_SLAVE_REG_COUNT + +_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte"); + +extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT]; + +void cos_i2c_slave_init(uint8_t address); +void cos_i2c_slave_stop(void); diff --git a/keyboards/rkb1/rules.mk b/keyboards/rkb1/rules.mk index 6e7633bfe0..cf1cb994a5 100644 --- a/keyboards/rkb1/rules.mk +++ b/keyboards/rkb1/rules.mk @@ -1 +1,9 @@ -# This file intentionally left blank +SPLIT_KEYBOARD = yes +SPLIT_TRANSPORT = custom +RP2040_INTRINSICS_ENABLED = yes + +SRC += i2c_slave.c i2c_master.c +QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c $(QUANTUM_DIR)/split_common/transactions.c +OPT_DEFS += -DSPLIT_COMMON_TRANSACTIONS +COMMON_VPATH += $(QUANTUM_PATH)/split_common +EXTRAINCDIRS += $(BOARD_PATH) diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index ad11d850dd..c0f2d6c726 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -207,4 +207,4 @@ __attribute__((weak)) i2c_status_t i2c_ping_address(uint8_t address, uint16_t ti // This approach may produce false negative results for I2C devices that do not respond to a register 0 read request. uint8_t data = 0; return i2c_readReg(address, 0, &data, sizeof(data), timeout); -} \ No newline at end of file +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h index e1e2433601..88dd369b4e 100644 --- a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h @@ -3,6 +3,13 @@ #pragma once #ifndef __ASSEMBLER__ +#define _PICO_ASSERT_H +#include +#include +#define PARAM_ASSERTIONS_ENABLED(x) /* x */ +#define invalid_params_if(x, test) /* x test */ +#define valid_params_if(x, test) /* x test */ +#define hard_assert_if(x, test) /* x test */ # include "hardware/flash.h" #endif @@ -30,3 +37,4 @@ #ifndef WEAR_LEVELING_RP2040_FLASH_BASE # define WEAR_LEVELING_RP2040_FLASH_BASE ((WEAR_LEVELING_RP2040_FLASH_SIZE) - (WEAR_LEVELING_BACKING_SIZE)) #endif + diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk index 94f023d72b..df450704ba 100644 --- a/platforms/chibios/vendors/RP/RP2040.mk +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -31,7 +31,20 @@ PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \ $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \ $(PICOSDKROOT)/src/rp2_common/hardware_xosc/xosc.c \ - $(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c + $(PICOSDKROOT)/src/rp2_common/hardware_i2c/i2c.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_irq/irq.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_irq/irq_handler_chain.S \ + $(PICOSDKROOT)/src/rp2_common/hardware_timer/timer.c \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c \ + $(PICOSDKROOT)/src/common/pico_time/time.c \ + $(PICOSDKROOT)/src/common/pico_time/timeout_helper.c \ + $(PICOSDKROOT)/src/common/pico_util/datetime.c \ + $(PICOSDKROOT)/src/common/pico_util/pheap.c \ + $(PICOSDKROOT)/src/common/pico_util/queue.c \ + $(PICOSDKROOT)/src/common/pico_sync/critical_section.c \ + $(PICOSDKROOT)/src/common/pico_sync/lock_core.c \ + $(PICOSDKROOT)/src/common/pico_sync/mutex.c \ + $(PICOSDKROOT)/src/common/pico_sync/sem.c \ PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ $(PICOSDKROOT)/src/common/pico_base/include \ @@ -49,10 +62,15 @@ PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ $(PICOSDKROOT)/src/rp2_common/hardware_resets/include \ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/include \ $(PICOSDKROOT)/src/rp2_common/hardware_xosc/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_i2c/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_timer/include \ $(PICOSDKROOT)/src/rp2040/hardware_regs/include \ $(PICOSDKROOT)/src/rp2040/hardware_structs/include \ $(PICOSDKROOT)/src/boards/include \ - $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include \ + $(PICOSDKROOT)/src/common/pico_time/include \ + $(PICOSDKROOT)/src/common/pico_util/include \ + $(PICOSDKROOT)/src/common/pico_sync/include PLATFORM_SRC += $(PICOSDKSRC) EXTRAINCDIRS += $(PICOSDKINC) diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c index 83edc34859..6eb981ac94 100644 --- a/quantum/split_common/transport.c +++ b/quantum/split_common/transport.c @@ -128,3 +128,4 @@ bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { transactions_slave(master_matrix, slave_matrix); } +