From 6be6cee2acce6c4012b7731d40fb016784401b7d Mon Sep 17 00:00:00 2001 From: true Date: Wed, 30 Oct 2024 13:57:32 -0700 Subject: [PATCH] some boilerplate and notes about i2c slave --- nametag8_CH592/README.md | 18 +++++++++++++++ nametag8_CH592/user/comm/soft_i2c_slave.c | 14 ++++++++---- .../user/comm/soft_i2c_slave_handler.c | 22 +++++++++++++++++++ .../user/comm/soft_i2c_slave_handler.h | 17 ++++++++++++++ nametag8_CH592/user/main.c | 6 ++++- nametag8_CH592/user/port_intr.c | 18 +++++++++++++-- 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 nametag8_CH592/user/comm/soft_i2c_slave_handler.c create mode 100644 nametag8_CH592/user/comm/soft_i2c_slave_handler.h diff --git a/nametag8_CH592/README.md b/nametag8_CH592/README.md index 8beadc1..13a8189 100644 --- a/nametag8_CH592/README.md +++ b/nametag8_CH592/README.md @@ -8,6 +8,22 @@ main mcu firmware for the GAT Nametag originally shown at Supercon 8. This is a MounRiver Studio project. Build in MRS. +## loading firmware over USB + +Easiest way is to use WCHISPStudio. This comes bundled with MRS. `Tools > WCH In-System Programmer` + + +## enabling debug + +By default, the debug interface is locked. To unlock the debug interface, do the following within a roughly 5 second window: + +- Hold down BOOT, then plug in to USB +- Device should be dected in WCHISPStudio +- Within WCHISPStudio, click the `Enable Simulat` button at the bottom + +At this point flash will be cleared and the debug interface will be re-enabled. + + ## bugs, quirks, omissions - this micro has VERY SLOW flash. therefore, most user code is executed from RAM. additionally, the flash is protected and not really documented. will take time to reverse engineer it from the provided .a file to possibly determine if wait states can be adjusted. @@ -15,6 +31,8 @@ This is a MounRiver Studio project. Build in MRS. - i2c master is bitbanged and may still have bugs. - i2c slave is bitbanged and hasn't been tested at all. + +- i2c master and i2c slave are both BLOCKING. this means that while data is being manipulated on OLED or other I2C slaves on the addon, the addon will not respond as I2C slave. to address this device as a slave, ack poll until you get an ack, then send your payload. make sure to wait at least 4 bit times before trying each ack poll. - "idle mode" isn't really a power saving mode. no time to implement. need to do the following to implement this properly: - implement a low power mode in the sub MCU as well, tell it to go to sleep diff --git a/nametag8_CH592/user/comm/soft_i2c_slave.c b/nametag8_CH592/user/comm/soft_i2c_slave.c index fe2e878..d063670 100644 --- a/nametag8_CH592/user/comm/soft_i2c_slave.c +++ b/nametag8_CH592/user/comm/soft_i2c_slave.c @@ -16,8 +16,8 @@ -#define I2CSS_ERR_TIMEOUT 6 // timeout in bit-times before i2c slave releases control -#define I2CSS_IDLE_TIMEOUT 3 // idle timeout required in bit-times before i2c slave can be addressed again +#define I2CSS_ERR_TIMEOUT 3 // timeout in bit-times before i2c slave releases control +#define I2CSS_IDLE_TIMEOUT 4 // idle timeout required in bit-times before i2c slave can be addressed again // todo: use with struct instead of hard-coding to allow for multiple slaves, but make it fast too @@ -54,7 +54,7 @@ static uint16_t idle_timeout = 0; -static int8_t i2css_wait_for_scl_hi() +static inline int8_t i2css_wait_for_scl_hi() { int16_t timeout = I2CSS_ERR_TIMEOUT * bit_time; @@ -62,7 +62,7 @@ static int8_t i2css_wait_for_scl_hi() return I2CSS_OK; } -static int8_t i2css_wait_for_scl_lo() +static inline int8_t i2css_wait_for_scl_lo() { uint8_t old_data = SDA_GET(); int16_t timeout = I2CSS_ERR_TIMEOUT * bit_time; @@ -103,6 +103,7 @@ int8_t i2css_idle_init(struct I2CSoftSlave *slave) // returns 0 if idle, or -1 if not idle. // if not idle, restarts the idle timer. +__HIGH_CODE int8_t i2css_idle_check(struct I2CSoftSlave *slave) { // requires a hardware timer or something to manage bus idle time @@ -117,6 +118,7 @@ int8_t i2css_idle_check(struct I2CSoftSlave *slave) return -1; } +__HIGH_CODE int8_t i2css_read(struct I2CSoftSlave *slave) { int8_t i; @@ -164,6 +166,7 @@ int8_t i2css_read(struct I2CSoftSlave *slave) return ack ? I2CSS_NACK : I2CSS_OK; } +__HIGH_CODE int8_t i2css_write(struct I2CSoftSlave *slave) { int8_t i; @@ -219,6 +222,7 @@ int8_t i2css_write(struct I2CSoftSlave *slave) // blocking implementation of i2c slave, with 8-bit address register. // basically, simulates a 24C02 EEPROM. // externally kicked off by a low transition on SCL. +__HIGH_CODE static inline int8_t i2css_process(struct I2CSoftSlave *slave) { int32_t i; @@ -281,6 +285,7 @@ static inline int8_t i2css_process(struct I2CSoftSlave *slave) return ret; } +__HIGH_CODE int8_t i2css_blocking(struct I2CSoftSlave *slave) { int8_t ret; @@ -300,6 +305,7 @@ int8_t i2css_blocking(struct I2CSoftSlave *slave) } // call this function with SDA falling low interrupt. +__HIGH_CODE int8_t i2css_start(struct I2CSoftSlave *slave) { uint8_t scl; diff --git a/nametag8_CH592/user/comm/soft_i2c_slave_handler.c b/nametag8_CH592/user/comm/soft_i2c_slave_handler.c new file mode 100644 index 0000000..9bcaa50 --- /dev/null +++ b/nametag8_CH592/user/comm/soft_i2c_slave_handler.c @@ -0,0 +1,22 @@ +/* + * i2c_slave_handler.c + * + * Created on: Oct 30, 2024 + * Author: true + */ + +#include "soft_i2c_slave_handler.h" +#include "soft_i2c_slave.h" + +#include + + + +struct I2CSoftSlave addon_i2c; + + + +void i2css_addon_init() +{ + +} diff --git a/nametag8_CH592/user/comm/soft_i2c_slave_handler.h b/nametag8_CH592/user/comm/soft_i2c_slave_handler.h new file mode 100644 index 0000000..68389e8 --- /dev/null +++ b/nametag8_CH592/user/comm/soft_i2c_slave_handler.h @@ -0,0 +1,17 @@ +/* + * soft_i2c_slave_handler.h + * + * Created on: Oct 30, 2024 + * Author: true + */ + +#ifndef USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_ +#define USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_ + + + +extern struct I2CSoftSlave addon_i2c; + + + +#endif /* USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_ */ diff --git a/nametag8_CH592/user/main.c b/nametag8_CH592/user/main.c index 6453744..161adbc 100644 --- a/nametag8_CH592/user/main.c +++ b/nametag8_CH592/user/main.c @@ -133,7 +133,7 @@ void rtcisr_init() rtc_reset_trig(); - PFIC_SetPriority(RTC_IRQn, 0x00); // rtc is highest priority interrupt + PFIC_SetPriority(RTC_IRQn, 0x10); // rtc is second highest priority interrupt PFIC_EnableIRQ(RTC_IRQn); } @@ -427,6 +427,10 @@ __INTERRUPT __HIGH_CODE void RTC_IRQHandler(void) { + // todo: + // - get real elapsed time + // - calculate interrupts/second actually executed + // clear interrupt flag and reset RTC rtc_reset_trig(); diff --git a/nametag8_CH592/user/port_intr.c b/nametag8_CH592/user/port_intr.c index 5e821d6..26ed606 100644 --- a/nametag8_CH592/user/port_intr.c +++ b/nametag8_CH592/user/port_intr.c @@ -14,8 +14,12 @@ #include "CH59x_common.h" #include "port_intr.h" +#include "comm/soft_i2c_slave.h" +#include "comm/soft_i2c_slave_handler.h" + #include "hw/ch32sub.h" + #include @@ -46,8 +50,11 @@ void port_intr_init() // clear state R16_PB_INT_IF = 0xff; - // then enable interrupt as low priority - PFIC_SetPriority(RTC_IRQn, 0x30); + PFIC_SetPriority(GPIO_A_IRQn, 0x00); // high priority + PFIC_EnableIRQ(GPIO_A_IRQn); + + // then enable interrupt + PFIC_SetPriority(GPIO_B_IRQn, 0x30); // low priority PFIC_EnableIRQ(GPIO_B_IRQn); } @@ -62,6 +69,13 @@ void GPIOA_IRQHandler(void) // clear flags R16_PA_INT_IF = flag; + + // addon header i2c data pin + if (flag & (1 << 13)) { + SetSysClock(SYSCLK_FREQ_USEI2C); + i2css_start(&addon_i2c); + SetSysClock(SYSCLK_FREQ_IDLE); + } } __INTERRUPT