some button fixes
buttons are now somewhat working properly, but register 0x12 (button debounce value) keeps getting overwritten / corrupted. once this is fixed then buttons will likley work properly.
This commit is contained in:
parent
d6026c38ff
commit
0a940b692d
|
@ -9,20 +9,25 @@
|
|||
* even in interrupt mode would result in higher speeds and less
|
||||
* power consumption, living without debug is worse.
|
||||
*
|
||||
* quirks and features:
|
||||
* quirks, features and limitations:
|
||||
* - this implementation is blocking.
|
||||
* - clock stretching is supported, and somewhat tested
|
||||
* - any slave stuck clock stretching will lock everything until released;
|
||||
* there is no timeout or cancel operation implemented
|
||||
*
|
||||
* known good settings:
|
||||
* known good settings at 32MHz:
|
||||
* CYCLES_TO_HI = 5, CYCLES_TO_LOW = 2: ~400-500kHz
|
||||
* CYCLES_TO_HI = 2, CYCLES_TO_LOW = 0: ~650KHz
|
||||
* CYCLES_TO_HI = 1, bit_delay_lo = __nop: ~900KHz, but sub MCU fails to respond
|
||||
*
|
||||
*/
|
||||
|
||||
#include <CH59x_common.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#define CYCLES_TO_HI 2
|
||||
|
||||
#define CYCLES_TO_HI 3
|
||||
#define CYCLES_TO_LO 0
|
||||
|
||||
//#define CYCLES_RD 2 // cycles spent in read routine
|
||||
|
@ -66,8 +71,6 @@
|
|||
|
||||
|
||||
static uint16_t delay_hi, delay_lo;
|
||||
|
||||
|
||||
static volatile uint16_t spin;
|
||||
|
||||
|
||||
|
@ -108,6 +111,8 @@ void i2cm_restart()
|
|||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
bit_delay_hi(); // wait a little bit
|
||||
bit_delay_hi(); // sub MCU can corrupt data if we don't wait
|
||||
i2cm_start();
|
||||
}
|
||||
|
||||
|
@ -122,6 +127,8 @@ void i2cm_stop()
|
|||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
}
|
||||
|
||||
// returns: data byte
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "led/rgbled.h"
|
||||
|
||||
#include "misc/accel.h"
|
||||
#include "misc/tinymt.h"
|
||||
|
||||
#include "ui/menu.h"
|
||||
#include "ui/oled.h"
|
||||
|
@ -43,18 +44,17 @@
|
|||
|
||||
|
||||
// global settings
|
||||
#define OLED_UPDATE_RATE 13 // framerate of OLED; { (256*(8/8)) / OLED_UPDATE_RATE }; 13 = 19FPS
|
||||
#define OLED_UPDATE_RATE 13 // framerate of OLED; { (256*(8/8)) / OLED_UPDATE_RATE }; 13 = 19FPS, 15 = 17FPS
|
||||
|
||||
// flags
|
||||
#define FLAG_OLED_UPDATE (1 << 0)
|
||||
#define FLAG_RGBLED_RUN_PROG (1 << 1)
|
||||
#define FLAG_PROG_TICK_INTR (1 << 7)
|
||||
|
||||
#define FLAG_RESET_SYSTICK (1 << 6)
|
||||
|
||||
#define PROG_TICK_RATE ((32768 / 256) - 1)
|
||||
|
||||
#define FLAG_RGBLED_RUN (1 << 1)
|
||||
#define FLAG_ACCEL_POLL (1 << 2)
|
||||
#define FLAG_RGBLED_SEND (1 << 5)
|
||||
|
||||
#define PROG_TICK_RATE ((32768-8192-4096) / 256) // not sure why this value can't be 32768/256
|
||||
// this was checked with a stopwatch and is close enough
|
||||
// this value IS FRAMERATE DEPENDENT for some reason... figure it out later
|
||||
|
||||
const uint8_t vers[] = "241015a";
|
||||
|
||||
|
@ -73,7 +73,7 @@ uint32_t idle_time_still;
|
|||
uint8_t idle_go_sleep;
|
||||
|
||||
static volatile uint8_t flags_lo = 0;
|
||||
static uint8_t flags_hi = FLAG_RESET_SYSTICK;
|
||||
//static uint8_t flags_hi = FLAG_RESET_SYSTICK;
|
||||
|
||||
static uint8_t st_tick = 0; // program tick counter
|
||||
static uint8_t oled_tick = 0; // oled framerate counter
|
||||
|
@ -83,7 +83,7 @@ static uint8_t oled_tick = 0; // oled framerate counter
|
|||
void ch59x_xtal_conf()
|
||||
{
|
||||
HSECFG_Current(HSE_RCur_125);
|
||||
HSECFG_Capacitance(HSECap_14p);
|
||||
HSECFG_Capacitance(HSECap_12p);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,6 +117,8 @@ void rtcisr_init()
|
|||
Calibration_LSI(Level_128); // calibrate LSI fromm HSE
|
||||
|
||||
rtc_reset_trig();
|
||||
|
||||
PFIC_SetPriority(RTC_IRQn, 0x00); // rtc is highest priority interrupt
|
||||
PFIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
|
@ -183,7 +185,7 @@ void oled_update_done()
|
|||
menu_tick();
|
||||
|
||||
// calculate CPU usage
|
||||
cpu_pct = (cpu_use * 100) / cpu_max;
|
||||
cpu_pct = ((cpu_use * 100) / OLED_UPDATE_RATE) / cpu_max;
|
||||
if (cpu_pct > cpu_pct_max) cpu_pct_max = cpu_pct;
|
||||
}
|
||||
|
||||
|
@ -202,11 +204,23 @@ void lowprio_task() {
|
|||
// can corrupt transactions
|
||||
SYS_DisableAllIrq(&interrupt_flags);
|
||||
|
||||
// temporary: enable sub interrupts
|
||||
// temporary: re-send sub interrupts, sub button holds, enable rgb_hwen
|
||||
ch32sub_intr_defaults();
|
||||
btn_commit_hold();
|
||||
ch32sub_rgb_hwen(1);
|
||||
// process sub MCU interrupt, if pending
|
||||
ch32sub_process();
|
||||
|
||||
if (flags_lo & FLAG_RGBLED_SEND) {
|
||||
flags_lo &= ~FLAG_RGBLED_SEND;
|
||||
// rgbled_send();
|
||||
}
|
||||
|
||||
if (flags_lo & FLAG_ACCEL_POLL) {
|
||||
flags_lo &= ~FLAG_ACCEL_POLL;
|
||||
// accel_poll();
|
||||
}
|
||||
|
||||
// send the last oled frame data
|
||||
if (flags_lo & FLAG_OLED_UPDATE) {
|
||||
flags_lo &= ~FLAG_OLED_UPDATE;
|
||||
|
@ -227,15 +241,7 @@ void lowprio_task() {
|
|||
}
|
||||
ssd1306_update();
|
||||
}
|
||||
}
|
||||
|
||||
// send the RGBLED data
|
||||
// todo
|
||||
|
||||
// capture CPU use
|
||||
if (flags_lo & FLAG_PROG_TICK_INTR) {
|
||||
flags_lo &= ~FLAG_PROG_TICK_INTR;
|
||||
flags_hi |= FLAG_RESET_SYSTICK;
|
||||
cpu_use = SysTick->CNT;
|
||||
}
|
||||
|
||||
|
@ -243,8 +249,9 @@ void lowprio_task() {
|
|||
SYS_RecoverIrq(interrupt_flags);
|
||||
|
||||
// render new rgbled frame
|
||||
if (flags_lo & FLAG_RGBLED_RUN_PROG) {
|
||||
flags_lo &= ~FLAG_RGBLED_RUN_PROG;
|
||||
// this is not included in cpu calcs :/
|
||||
if (flags_lo & FLAG_RGBLED_RUN) {
|
||||
flags_lo &= ~FLAG_RGBLED_RUN;
|
||||
rgbled_runprog(st_tick);
|
||||
}
|
||||
|
||||
|
@ -261,36 +268,36 @@ int main()
|
|||
SetSysClock(SYSCLK_FREQ_USEI2C);
|
||||
// note that system clock speed is decreased after every use of I2C.
|
||||
|
||||
PWR_DCDCCfg(ENABLE); // enable DC-DC converter; brings significant power saving
|
||||
PWR_DCDCCfg(ENABLE); // enable DC-DC converter; brings significant power saving
|
||||
|
||||
i2c_init(); // get i2c initialized since most stuff will need it
|
||||
i2c_init(); // get i2c initialized since most stuff will need it
|
||||
|
||||
uconf_load(); // read the user config
|
||||
uconf_load(); // read the user config
|
||||
|
||||
ch32sub_init(); // initialize aux MCU
|
||||
ch32sub_rgb_hwen(1); // and enable RGBLED controller hardware pin so the controller can wake up
|
||||
ch32sub_init(); // initialize aux MCU
|
||||
ch32sub_rgb_hwen(1); // and enable RGBLED controller hardware pin so the controller can wake up
|
||||
|
||||
accel_init(); // initialize accelerometer
|
||||
rgbled_init(); // initialize RGBLED controller
|
||||
tinymt32_init(&tinymt32_s, 1337); // let's get random
|
||||
|
||||
gat_gpio_init(); // configure GAT aux GPIOs, get gat ID
|
||||
// todo: implement // configure GAT i2c slave
|
||||
accel_init(); // initialize accelerometer
|
||||
rgbled_init(); // initialize RGBLED controller
|
||||
|
||||
ssd1306fb_set_target(&oled); // start up the OLED and menu system
|
||||
ssd1306_init(1); // we'll try to init later too, since sometimes OLED fails to init
|
||||
menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode
|
||||
gat_gpio_init(); // configure GAT aux GPIOs, get gat ID
|
||||
// todo: implement // configure GAT i2c slave
|
||||
|
||||
systick_init(); // start up the system tick, used for CPU percentage calculation
|
||||
ssd1306fb_set_target(&oled); // start up the OLED and menu system
|
||||
ssd1306_init(1); // we'll try to init later too, since sometimes OLED fails to init
|
||||
menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode
|
||||
|
||||
systick_init(); // start up the system tick, used for CPU percentage calculation
|
||||
cpu_max = GetSysClock() / PROG_TICK_RATE;
|
||||
|
||||
port_intr_init(); // configure port-based interrupts (used for ch32sub interrupt)
|
||||
ch32sub_intr_defaults(); // configure interrupt sources on sub MCU - buttons, etc
|
||||
port_intr_init(); // configure port-based interrupts (used for ch32sub interrupt)
|
||||
ch32sub_intr_defaults(); // configure interrupt sources on sub MCU - buttons, etc
|
||||
|
||||
// configure main program tick interrupt
|
||||
rtcisr_init();
|
||||
rtcisr_init(); // configure main program tick interrupt
|
||||
|
||||
// start the low priority task loop
|
||||
lowprio_task();
|
||||
lowprio_task(); // start the low priority task loop
|
||||
}
|
||||
|
||||
|
||||
|
@ -298,19 +305,12 @@ __INTERRUPT
|
|||
__HIGH_CODE
|
||||
void RTC_IRQHandler(void)
|
||||
{
|
||||
// clear systick for CPU usage counting
|
||||
if (flags_hi & FLAG_RESET_SYSTICK) {
|
||||
SysTick->CNT = 0;
|
||||
flags_hi &= ~FLAG_RESET_SYSTICK;
|
||||
flags_lo |= FLAG_PROG_TICK_INTR;
|
||||
}
|
||||
// clear interrupt flag and reset RTC
|
||||
rtc_reset_trig();
|
||||
|
||||
// speed up
|
||||
SetSysClock(SYSCLK_FREQ_NORMAL);
|
||||
|
||||
// clear interrupt flag and reset RTC
|
||||
rtc_reset_trig();
|
||||
|
||||
// manual uptime counter
|
||||
st_tick++;
|
||||
if (!st_tick) {
|
||||
|
@ -320,6 +320,13 @@ void RTC_IRQHandler(void)
|
|||
uptime_sec = (uint8_t)((uptime ) % 60);
|
||||
}
|
||||
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
SysTick->CNT = 0;
|
||||
flags_lo |= FLAG_OLED_UPDATE;
|
||||
}
|
||||
|
||||
// operations
|
||||
switch (st_tick & 0x7) {
|
||||
case 0:
|
||||
|
@ -329,22 +336,14 @@ void RTC_IRQHandler(void)
|
|||
uconf.ledprog_rgb_idx = 0;
|
||||
}
|
||||
|
||||
// send any rendered data now
|
||||
rgbled_send();
|
||||
|
||||
// defer rendering
|
||||
flags_lo |= FLAG_RGBLED_RUN_PROG;
|
||||
// send RGBLEDs, render new program
|
||||
flags_lo |= FLAG_RGBLED_SEND;
|
||||
flags_lo |= FLAG_RGBLED_RUN;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
accel_poll();
|
||||
flags_lo |= FLAG_ACCEL_POLL;
|
||||
// no break
|
||||
}
|
||||
}
|
||||
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
flags_lo |= FLAG_OLED_UPDATE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,8 +43,11 @@ void port_intr_cb_register(uint8_t port, uint8_t idx, void (*fn)(void))
|
|||
|
||||
void port_intr_init()
|
||||
{
|
||||
// clear state then enable port interrupt
|
||||
// clear state
|
||||
R16_PB_INT_IF = 0xff;
|
||||
|
||||
// then enable interrupt as low priority
|
||||
PFIC_SetPriority(RTC_IRQn, 0x30);
|
||||
PFIC_EnableIRQ(GPIO_B_IRQn);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,17 @@ uint8_t btn_held;
|
|||
|
||||
|
||||
|
||||
static uint8_t btn_map[BTN_COUNT] = {2, 1, 3, 0, 4}; // bot left, top left, bot right, top right
|
||||
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_push_cb(uint8_t idx)
|
||||
{
|
||||
btn_pushed |= (1 << idx);
|
||||
if (btn[idx].cb_push) btn[idx].cb_push(idx);
|
||||
if (!(btn_pushed & (1 << idx))) {
|
||||
btn_pushed |= (1 << idx);
|
||||
if (btn[idx].cb_push) btn[idx].cb_push(idx);
|
||||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
|
@ -52,8 +58,8 @@ void btn_commit_hold()
|
|||
|
||||
x = 0;
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
val[x + 0x00] = btn[i].hold >> 8;
|
||||
val[x + 0x01] = btn[i].hold & 0xff;
|
||||
val[x + 0x00] = btn[btn_map[i]].hold >> 8;
|
||||
val[x + 0x01] = btn[btn_map[i]].hold & 0xff;
|
||||
x += 2;
|
||||
}
|
||||
|
||||
|
@ -61,8 +67,8 @@ void btn_commit_hold()
|
|||
|
||||
x = 0;
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
val[x + 0x00] = btn[i].repeat >> 8;
|
||||
val[x + 0x01] = btn[i].repeat & 0xff;
|
||||
val[x + 0x00] = btn[btn_map[i]].repeat >> 8;
|
||||
val[x + 0x01] = btn[btn_map[i]].repeat & 0xff;
|
||||
x += 2;
|
||||
}
|
||||
|
||||
|
@ -87,13 +93,13 @@ void btn_intr()
|
|||
// process callbacks for new events
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
if (btn_state[1] & (1 << i)) {
|
||||
btn_push_cb(i);
|
||||
btn_push_cb(btn_map[i]);
|
||||
}
|
||||
if (btn_state[2] & (1 << i)) {
|
||||
btn_hold_cb(i);
|
||||
btn_hold_cb(btn_map[i]);
|
||||
}
|
||||
if (btn_state[3] & (1 << i)) {
|
||||
btn_release_cb(i);
|
||||
btn_release_cb(btn_map[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
|
||||
|
||||
|
||||
#define BTN_COUNT 5
|
||||
#define BTN_COUNT 5 // total buttons in system
|
||||
#define MENU_BTN_COUNT 4 // buttons used for menu, must be the first buttons
|
||||
#define HOLD_PERIOD 5 // period in milliseconds for each "hold" tick internally
|
||||
|
||||
|
||||
|
|
|
@ -15,19 +15,24 @@
|
|||
|
||||
|
||||
|
||||
|
||||
void NMI_Handler(void); //__attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void HardFault_Handler(void); //__attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
#define SYSTICK_COOLDOWN 3
|
||||
uint8_t systick_timeout;
|
||||
|
||||
|
||||
|
||||
__attribute__((interrupt()))
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
__attribute__((interrupt()))
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
// hopefully we're running well enough to isolate the i2c bus
|
||||
|
||||
// then reboot, because we shouldn't really be here
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
@ -36,31 +41,31 @@ void SysTick_Handler(void)
|
|||
{
|
||||
// ---- PROCESS UI AND COMMS
|
||||
|
||||
// button handler
|
||||
btn_poll();
|
||||
btn_poll(); // button handler
|
||||
irda_process(); // irda timeout and retry
|
||||
|
||||
// irda timeout and retry
|
||||
irda_process();
|
||||
|
||||
// clear comparison flag
|
||||
SysTick->SR = 0;
|
||||
SysTick->SR = 0; // clear comparison flag
|
||||
|
||||
|
||||
// ---- DISABLE INTERRUPT
|
||||
|
||||
// see if any buttons are currently pushed
|
||||
if ((BTN_PORT->INDR & BTN_PIN_MASK) != BTN_PIN_MASK) {
|
||||
// yup, something is pushed, so keep the interrupt on
|
||||
// something is pushed, so keep the tick interrupt enabled
|
||||
systick_timeout = SYSTICK_COOLDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
// see if irda is active
|
||||
|
||||
// nothing is active, so shut down this interrupt
|
||||
NVIC_DisableIRQ(SysTicK_IRQn);
|
||||
// nothing is active, so shut down this interrupt source
|
||||
systick_timeout--;
|
||||
if (!systick_timeout) {
|
||||
NVIC_DisableIRQ(SysTicK_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((interrupt("WCH-Interrupt-fast")))
|
||||
__attribute__((interrupt()))
|
||||
void EXTI7_0_IRQHandler(void)
|
||||
{
|
||||
if (EXTI_GetITStatus(EXTI_Line3)) {
|
||||
|
@ -75,6 +80,7 @@ void EXTI7_0_IRQHandler(void)
|
|||
// enable main tick handler on button push.
|
||||
// tick handler will sense when it isn't needed and shut itself off.
|
||||
SysTick->SR = 0;
|
||||
systick_timeout = SYSTICK_COOLDOWN;
|
||||
NVIC_EnableIRQ(SysTicK_IRQn);
|
||||
EXTI_ClearITPendingBit(EXTI_Line0 | EXTI_Line4 | EXTI_Line5 | EXTI_Line6 | EXTI_Line7);
|
||||
}
|
||||
|
|
|
@ -140,6 +140,8 @@ void btn_poll()
|
|||
|
||||
uint8_t pushed;
|
||||
|
||||
set_interrupt = 0;
|
||||
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
pushed = 0;
|
||||
|
||||
|
@ -161,20 +163,21 @@ void btn_poll()
|
|||
// first push?
|
||||
if (!(btn[i]._mask & BTN_PUSH)) {
|
||||
btn[i]._mask = BTN_PUSH | ignore;
|
||||
if (btn[i].cb_push && !ignore) {
|
||||
btn[i].cb_push(i);
|
||||
if (!ignore) {
|
||||
if (btn[i].cb_push) btn[i].cb_push(i);
|
||||
btn[i]._mask |= (BTN_PUSH << 4);
|
||||
}
|
||||
} else if (btn[i]._count >= btn[i].hold) {
|
||||
// held to count limit
|
||||
} else
|
||||
|
||||
// held to count limit
|
||||
if (btn[i].hold && (btn[i]._count >= btn[i].hold)) {
|
||||
// if button is not repeatable, do not retrigger
|
||||
if ((btn[i]._mask & BTN_HOLD) && !btn[i].repeat) continue;
|
||||
|
||||
btn[i]._mask |= BTN_HOLD;
|
||||
// call callback only if not in ignore state
|
||||
if (btn[i].cb_hold && !ignore) {
|
||||
btn[i].cb_hold(i);
|
||||
if (!ignore) {
|
||||
if (btn[i].cb_hold) btn[i].cb_hold(i);
|
||||
btn[i]._mask |= (BTN_HOLD << 4);
|
||||
}
|
||||
|
||||
|
@ -188,19 +191,18 @@ void btn_poll()
|
|||
if (!(btn[i]._mask & BTN_RELEASE)) {
|
||||
// note: release will remove ignore status
|
||||
btn[i]._mask = BTN_RELEASE;
|
||||
btn[i]._count = 0;
|
||||
// call callback only if not in ignore state
|
||||
if (btn[i].cb_release && !ignore) {
|
||||
btn[i].cb_release(i);
|
||||
btn[i]._mask |= (BTN_RELEASE << 4);
|
||||
}
|
||||
}
|
||||
btn[i]._count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// any button event with enabled interrupt flags will set button interrupt flag
|
||||
if (set_interrupt) {
|
||||
i2cs_append_flag(INT_BTN);
|
||||
set_interrupt = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ static void i2cs_int_check()
|
|||
void i2cs_write_cb(uint16_t initial_reg, uint16_t last_reg)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t trig = 0;
|
||||
uint8_t trig;
|
||||
uint16_t w;
|
||||
|
||||
// nothing written?
|
||||
|
@ -73,7 +73,7 @@ void i2cs_write_cb(uint16_t initial_reg, uint16_t last_reg)
|
|||
for (i = 0; i < sizeof(write_cb_trig); i++) {
|
||||
if ((initial_reg <= write_cb_trig[i]) && (last_reg >= write_cb_trig[i])) {
|
||||
trig = write_cb_trig[i];
|
||||
}
|
||||
} else continue;
|
||||
|
||||
switch (trig) {
|
||||
case REG_INTR_FLAGS_CLEAR: {
|
||||
|
@ -151,9 +151,6 @@ void i2cs_init(uint8_t address, uint8_t read_only_mode)
|
|||
{
|
||||
I2C_InitTypeDef i2c = {0};
|
||||
|
||||
i2cs_state.first_write = 1;
|
||||
i2cs_state.offset = 0;
|
||||
i2cs_state.position = 0;
|
||||
i2cs_state.reg_file = i2cs_reg;
|
||||
i2cs_state.reg_len = sizeof(i2cs_reg);
|
||||
i2cs_state.write_callback = i2cs_write_cb;
|
||||
|
@ -161,7 +158,7 @@ void i2cs_init(uint8_t address, uint8_t read_only_mode)
|
|||
i2cs_state.read_callback = i2cs_read_cb;
|
||||
i2cs_state.read_only = read_only_mode;
|
||||
|
||||
i2c.I2C_ClockSpeed = 500000;
|
||||
i2c.I2C_ClockSpeed = 600000;
|
||||
i2c.I2C_Mode = I2C_Mode_I2C;
|
||||
i2c.I2C_DutyCycle = I2C_DutyCycle_2;
|
||||
i2c.I2C_OwnAddress1 = address;
|
||||
|
@ -195,6 +192,7 @@ void i2cs_poll()
|
|||
|
||||
}
|
||||
|
||||
//__attribute__((section(".ramfunc")))
|
||||
__attribute__((interrupt("WCH-Interrupt-fast")))
|
||||
void I2C1_EV_IRQHandler(void)
|
||||
{
|
||||
|
@ -205,21 +203,23 @@ void I2C1_EV_IRQHandler(void)
|
|||
STAR2 = I2C1->STAR2;
|
||||
|
||||
if (STAR1 & I2C_STAR1_ADDR) { // Start event
|
||||
i2cs_state.first_write = 1; // Next write will be the offset
|
||||
i2cs_state.position = i2cs_state.offset; // Reset position
|
||||
i2cs_state.addr_write = 1; // Next write will be the 16-bit register address
|
||||
i2cs_state.addr_req = 0; // reset this address
|
||||
i2cs_state.writing = 0; // not yet writing data from master
|
||||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_RXNE) { // Write from master event
|
||||
if (i2cs_state.first_write == 2) { // low address byte written; set the offset
|
||||
i2cs_state.offset = i2cs_state.offset | I2C1->DATAR;
|
||||
i2cs_state.position = i2cs_state.offset;
|
||||
i2cs_state.first_write = 0;
|
||||
i2cs_state.writing = 0;
|
||||
} else if (i2cs_state.first_write == 1) { // high address byte written
|
||||
i2cs_state.offset = I2C1->DATAR << 8;
|
||||
i2cs_state.first_write++;
|
||||
if (i2cs_state.addr_write == 2) { // low address byte written
|
||||
i2cs_state.addr_req |= I2C1->DATAR;
|
||||
|
||||
i2cs_state.position = i2cs_state.addr_req; // position set to requested index
|
||||
i2cs_state.addr_write = 0; // not writing the address anymore
|
||||
} else
|
||||
{ // Normal register write
|
||||
if (i2cs_state.addr_write == 1) { // high address byte written
|
||||
i2cs_state.addr_req = I2C1->DATAR << 8;
|
||||
i2cs_state.addr_write++;
|
||||
} else
|
||||
{ // Normal register write
|
||||
i2cs_state.writing = 1;
|
||||
|
||||
if (i2cs_state.position < i2cs_state.reg_len && !i2cs_state.read_only) {
|
||||
|
@ -242,7 +242,6 @@ void I2C1_EV_IRQHandler(void)
|
|||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_TXE) { // Read to master event
|
||||
i2cs_state.writing = 0;
|
||||
if (i2cs_state.position < i2cs_state.reg_len) {
|
||||
I2C1->DATAR = i2cs_state.reg_file[i2cs_state.position];
|
||||
if (i2cs_state.read_callback != 0) {
|
||||
|
@ -258,25 +257,33 @@ void I2C1_EV_IRQHandler(void)
|
|||
I2C1->CTLR1 &= ~(I2C_CTLR1_STOP); // Clear stop
|
||||
|
||||
if (i2cs_state.write_callback != 0 && i2cs_state.writing) {
|
||||
i2cs_state.write_callback(i2cs_state.offset, i2cs_state.position - 1);
|
||||
i2cs_state.write_callback(i2cs_state.addr_req, i2cs_state.position - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((interrupt("WCH-Interrupt-fast")))
|
||||
__attribute__((interrupt()))
|
||||
void I2C1_ER_IRQHandler(void)
|
||||
{
|
||||
uint8_t err = 0;
|
||||
uint16_t STAR1 = I2C1->STAR1;
|
||||
|
||||
if (STAR1 & I2C_STAR1_BERR) { // Bus error
|
||||
err++;
|
||||
I2C1->STAR1 &= ~(I2C_STAR1_BERR); // Clear error
|
||||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_ARLO) { // Arbitration lost error
|
||||
err++;
|
||||
I2C1->STAR1 &= ~(I2C_STAR1_ARLO); // Clear error
|
||||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_AF) { // Acknowledge failure
|
||||
err++;
|
||||
I2C1->STAR1 &= ~(I2C_STAR1_AF); // Clear error
|
||||
}
|
||||
|
||||
if (err) {
|
||||
I2C1->CTLR1 &= ~(I2C_CTLR1_STOP); // Clear stop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,9 +87,9 @@ typedef void (*i2c_werr_callback_t)(uint16_t reg, uint8_t data, uint8_t error);
|
|||
typedef void (*i2c_read_callback_t)(uint16_t reg);
|
||||
|
||||
typedef struct i2c_slave_state {
|
||||
uint8_t first_write; // first 2 bytes address the register file
|
||||
uint16_t offset; // offset within the register file as sent by the master
|
||||
uint16_t position; // current read/write position within the register file
|
||||
uint8_t addr_write; // first 2 bytes address the register file
|
||||
uint16_t addr_req; // requested read/write index as sent by the master
|
||||
uint16_t position; // current read/write index within the register file
|
||||
volatile uint8_t* volatile reg_file; // register file pointer
|
||||
uint16_t reg_len; // register file max length
|
||||
i2c_write_callback_t write_callback;
|
||||
|
|
|
@ -96,9 +96,9 @@ static inline void exti_nvic_init()
|
|||
|
||||
void systick_init(void)
|
||||
{
|
||||
SysTick->CMP = (SystemCoreClock / 200 / 8) - 1; // we want a 200Hz interrupt
|
||||
SysTick->CMP = (SystemCoreClock / 200) - 1; // we want a 200Hz interrupt
|
||||
SysTick->CNT = 0; // clear counter
|
||||
SysTick->CTLR = 0xB; // start counter in /8 mode, enable interrupts, auto-reset counter
|
||||
SysTick->CTLR = 0xF; // start counter in /1 mode, enable interrupts, auto-reset counter
|
||||
SysTick->SR = 0; // clear count comparison flag
|
||||
|
||||
NVIC_EnableIRQ(SysTicK_IRQn); // enable interrupt
|
||||
|
@ -121,9 +121,10 @@ int main(void)
|
|||
|
||||
// enable peripheral clocks used in this program
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_I2C1, ENABLE);
|
||||
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA |
|
||||
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
|
||||
RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_I2C1, ENABLE);
|
||||
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO |
|
||||
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC |
|
||||
RCC_APB2Periph_GPIOD, ENABLE);
|
||||
|
||||
|
||||
// configure gpio
|
||||
|
@ -143,6 +144,8 @@ int main(void)
|
|||
systick_init();
|
||||
|
||||
while (1) {
|
||||
__WFI();
|
||||
// todo: determine why we HardFault with user button interrupts
|
||||
// randomly but only with __WFI being used
|
||||
// __WFI();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue