Compare commits

..

2 Commits

Author SHA1 Message Date
true 6be6cee2ac some boilerplate and notes about i2c slave 2024-10-30 13:57:32 -07:00
true 33a42edc7f configure unused GPIO, flash lightsense LED during boot for testing 2024-10-28 08:05:03 -07:00
6 changed files with 108 additions and 7 deletions

View File

@ -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

View File

@ -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;

View File

@ -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 <stdint.h>
struct I2CSoftSlave addon_i2c;
void i2css_addon_init()
{
}

View File

@ -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_ */

View File

@ -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);
}
@ -146,6 +146,21 @@ void systick_init(void)
SysTick->CTLR = SysTick_CTLR_STCLK | SysTick_CTLR_STE; // enable counter in /1 mode
}
void gpio_init()
{
// by default pins are floating inputs
// lightsense pins anode (PA5), cathode (PA14) low outputs
R32_PA_DIR = (1 << 5) | (1 << 14);
// configure unused as pullup
R8_PA_PU_1 = 0x8f; // unused PA8-11, PA15
R8_PB_PU_2 = 0x80; // unused PB23
// disable input buffer on unused pins
R32_PIN_CONFIG2 = 0x0200cf00; // also PA14, only ever an input
}
static void idle_clear()
{
@ -372,6 +387,9 @@ int main()
PWR_DCDCCfg(ENABLE); // enable DC-DC converter; brings significant power saving
gpio_init(); // configure default states for GPIO pins
R32_PA_OUT |= (1 << 14); // enable lightsense LED during boot for testing
i2c_init(); // get i2c initialized since most stuff will need it
uconf_load(); // read the user config
@ -399,6 +417,8 @@ int main()
rtcisr_init(); // configure main program tick interrupt
R32_PA_CLR = (1 << 14); // turn off lightsense LED now
lowprio_task(); // start the low priority task loop
}
@ -407,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();

View File

@ -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 <stdint.h>
@ -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