Compare commits
2 Commits
64ce976b97
...
56cd06876a
Author | SHA1 | Date |
---|---|---|
true | 56cd06876a | |
true | 8d82d83568 |
|
@ -152,6 +152,9 @@ SECTIONS
|
|||
*(.srodata.cst2)
|
||||
*(.srodata .srodata.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramfunc)
|
||||
*(.ramfunc*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _edata = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
|
|
|
@ -1,30 +1,41 @@
|
|||
/*
|
||||
* soft_i2c.c
|
||||
*
|
||||
* looked at random code and fixed it up for CH59x.
|
||||
* looked at random i2c code, used as inspiration, and wrote some
|
||||
* garbage for CH59x.
|
||||
*
|
||||
* i2c hardware peripheral on CH59x is shared with debug pins.
|
||||
* also, i2c on CH59x is not attached to DMA. while using the
|
||||
* peripheral would result in higher speeds and less power usage,
|
||||
* living without debug is worse. maybe I'll use hw i2c later.
|
||||
* i2c hw is also not attached to DMA. while using the peripheral
|
||||
* even in interrupt mode would result in higher speeds and less
|
||||
* power consumption, living without debug is worse.
|
||||
*
|
||||
* quirks and features:
|
||||
* - this implementation is blocking.
|
||||
* - partial clock stretching is supported
|
||||
* (only during start of write, and within read phase).
|
||||
* - timings likely haven't been tested so long as this message exists.
|
||||
* - clock stretching is supported, and somewhat tested
|
||||
*
|
||||
* known good settings:
|
||||
* CYCLES_TO_HI = 5, CYCLES_TO_LOW = 2: ~400-500kHz
|
||||
* CYCLES_TO_HI = 2, CYCLES_TO_LOW = 0: ~650KHz
|
||||
*/
|
||||
|
||||
#include <CH59x_common.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#define CYCLES_TO_HI 5 // these settings will result in ~500KHz (32MHz HCLK)
|
||||
#define CYCLES_TO_LO 2
|
||||
#define CYCLES_TO_HI 2
|
||||
#define CYCLES_TO_LO 0
|
||||
|
||||
#define CYCLES_RD 2 // cycles spent in read routine
|
||||
#define CYCLES_WR_HI 2 // extra cycles spent in write routine
|
||||
#define CYCLES_WR_LO 4
|
||||
//#define CYCLES_RD 2 // cycles spent in read routine
|
||||
//#define CYCLES_WR_HI 2 // extra cycles spent in write routine
|
||||
//#define CYCLES_WR_LO 4
|
||||
|
||||
#define bit_delay_hi() { spin = delay_hi; while(spin--); }
|
||||
#define bit_delay_lo() { spin = delay_lo; while(spin--); }
|
||||
|
||||
#define rd_delay() bit_delay_hi()
|
||||
|
||||
#define wr_delay_hi() bit_delay_hi()
|
||||
#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
|
||||
|
||||
#define SDA_PIN 4
|
||||
|
@ -59,14 +70,6 @@ static uint16_t delay_hi, delay_lo;
|
|||
|
||||
static volatile uint16_t spin;
|
||||
|
||||
#define bit_delay_hi() spin = delay_hi; while(spin--)
|
||||
#define bit_delay_lo() spin = delay_lo; while(spin--)
|
||||
|
||||
#define rd_delay() bit_delay_hi()
|
||||
|
||||
#define wr_delay_hi() bit_delay_hi()
|
||||
#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
|
||||
|
||||
|
||||
// re-run init any time the clock speed changes to recalculate delays.
|
||||
|
@ -104,6 +107,7 @@ void i2cm_restart()
|
|||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
i2cm_start();
|
||||
}
|
||||
|
||||
|
@ -124,7 +128,8 @@ void i2cm_stop()
|
|||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_rd(uint8_t ack)
|
||||
{
|
||||
uint8_t x, in = 0;
|
||||
int8_t x;
|
||||
uint8_t in = 0;
|
||||
|
||||
SDA_IN_HI();
|
||||
|
||||
|
@ -138,15 +143,13 @@ uint8_t i2cm_rd(uint8_t ack)
|
|||
|
||||
if (SDA_GET()) in |= 1;
|
||||
|
||||
SCL_OUTLO();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
if (ack) { SDA_OUTLO(); } // ack
|
||||
else { SDA_IN_HI(); } // nack
|
||||
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
|
||||
SDA_IN_HI();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
|
||||
return in;
|
||||
|
@ -156,7 +159,7 @@ uint8_t i2cm_rd(uint8_t ack)
|
|||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_wr(uint8_t dat)
|
||||
{
|
||||
uint8_t x;
|
||||
int8_t x;
|
||||
uint8_t ack;
|
||||
|
||||
SCL_OUTLO();
|
||||
|
@ -165,8 +168,9 @@ uint8_t i2cm_wr(uint8_t dat)
|
|||
if (dat & 0x80) { SDA_IN_HI(); }
|
||||
else { SDA_OUTLO(); }
|
||||
|
||||
SCL_IN_HI(); wr_delay_hi();
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
wr_delay_hi();
|
||||
|
||||
dat <<= 1;
|
||||
|
||||
|
@ -179,6 +183,7 @@ uint8_t i2cm_wr(uint8_t dat)
|
|||
ack = SDA_GET();
|
||||
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
|
||||
return ack;
|
||||
}
|
||||
|
||||
|
@ -186,7 +191,7 @@ uint8_t i2cm_wr(uint8_t dat)
|
|||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit)
|
||||
{
|
||||
addr &= ~0x1;
|
||||
addr &= 0xfe;
|
||||
addr |= reading_bit ? 1 : 0;
|
||||
return i2cm_wr(addr);
|
||||
}
|
||||
|
|
|
@ -12,15 +12,16 @@
|
|||
|
||||
|
||||
|
||||
#define SYSCLK_FREQ_NORMAL CLK_SOURCE_HSE_16MHz
|
||||
#define SYSCLK_FREQ_NORMAL CLK_SOURCE_PLL_48MHz // CLK_SOURCE_HSE_16MHz
|
||||
#define SYSCLK_FREQ_USEI2C CLK_SOURCE_PLL_32MHz
|
||||
#define SYSCLK_FREQ_IDLE CLK_SOURCE_HSE_8MHz
|
||||
|
||||
|
||||
|
||||
extern const uint8_t vers[];
|
||||
|
||||
extern uint8_t cpu_use;
|
||||
extern uint8_t cpu_max;
|
||||
extern uint16_t cpu_pct;
|
||||
extern uint16_t cpu_pct_max;
|
||||
|
||||
extern uint32_t uptime;
|
||||
extern uint16_t uptime_hour;
|
||||
|
|
|
@ -68,11 +68,7 @@ void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint
|
|||
aw->rows = rows;
|
||||
aw->config = imax & AW20X_CONF_IMAX_MASK;
|
||||
|
||||
// ensure we are on page 0 to start
|
||||
aw20x_page(aw, 0);
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
// wake up
|
||||
// wake up (and set page to config page)
|
||||
aw20x_sleep(aw, 0);
|
||||
|
||||
// enabled columns
|
||||
|
@ -184,9 +180,10 @@ void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit)
|
|||
}
|
||||
/*
|
||||
* enables LEDs based on user LED count, zero-indexed
|
||||
* AW20036 would be 0-35, AW00054 would be 0-53, and so on
|
||||
* for example, LEDs 8-12 on AW20054 would enable C0R8, C1R0, C1R1, C1R2
|
||||
* all other LEDs are disabled
|
||||
* assumes AW20X_MAX_LEDON_BITS per row but will only turn on active defined rows
|
||||
* AW20036 would be 0-35, but AW20054 would be 0-71 and so on
|
||||
* for example, LEDs 8-12 on AW20054 with 9 roww enabled
|
||||
* would enable C0R8, C1R0, C1R1, C1R2. all other LEDs are disabled
|
||||
*
|
||||
* todo:
|
||||
* - read current state, and apply bitfields to the currently active state
|
||||
|
@ -196,7 +193,7 @@ void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit)
|
|||
void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last)
|
||||
{
|
||||
uint8_t c, r;
|
||||
uint8_t offset = 0;
|
||||
uint8_t idx;
|
||||
uint8_t boff;
|
||||
uint8_t *buf;
|
||||
|
||||
|
@ -208,24 +205,25 @@ void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last)
|
|||
// bits are stored 6 bits per byte, 2 bytes per column, one bit for each row
|
||||
// for a maximum of the AW20X_MAX_ROWS of LED on bits
|
||||
// we only want to touch bits that exist on the chip and in the correct order
|
||||
idx = 0;
|
||||
for (c = 0; c < aw->cols; c++) {
|
||||
buf = &aw_buf[c*2];
|
||||
buf[0] = buf[1] = 0;
|
||||
boff = 0;
|
||||
for (r = 0; r < AW20X_MAX_LEDON_BITS*2; r++) {
|
||||
if (r >= aw->rows) break; // max bits to process
|
||||
if (r + idx < first) continue; // only start at the first led
|
||||
if (r + idx > last) break; // and stop at the last
|
||||
|
||||
if (r >= aw->rows) continue; // max bits to process per row
|
||||
|
||||
if (r == AW20X_MAX_LEDON_BITS) { // only this many bits per byte
|
||||
boff += AW20X_MAX_LEDON_BITS;
|
||||
buf++;
|
||||
}
|
||||
|
||||
if (r+offset >= first) {
|
||||
if (r+offset <= last) {
|
||||
*buf |= (1 << r - boff);
|
||||
}
|
||||
}
|
||||
*buf |= (1 << r - boff);
|
||||
}
|
||||
|
||||
offset += aw->rows;
|
||||
idx += AW20X_MAX_LEDON_BITS*2;
|
||||
}
|
||||
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c*2);
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
|
||||
|
||||
volatile uint8_t intr_flag = 0;
|
||||
volatile uint8_t intr_pending = 0;
|
||||
|
||||
static void (*flag_cb[8])() = {
|
||||
static void (*intr_cb[8])() = {
|
||||
btn_intr,
|
||||
0,
|
||||
0,
|
||||
|
@ -34,38 +34,71 @@ static void (*flag_cb[8])() = {
|
|||
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len)
|
||||
{
|
||||
i2c_read_reg16(SUB_I2C_ADDR, reg, dat, len);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len)
|
||||
{
|
||||
i2c_write_reg16(SUB_I2C_ADDR, reg, dat, len);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
uint8_t ch32sub_read_1b(uint16_t reg)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
ch32sub_read(reg, &ret, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ch32sub_write_1b(uint16_t reg, uint8_t dat)
|
||||
{
|
||||
i2c_addr(SUB_I2C_ADDR, 0);
|
||||
i2c_wr(reg >> 8);
|
||||
i2c_wr(reg & 0xff);
|
||||
i2c_wr(dat);
|
||||
i2c_stop();
|
||||
}
|
||||
|
||||
void ch32sub_isr()
|
||||
{
|
||||
// we'll check what the MCU has to say when we're done processing
|
||||
intr_flag = 1;
|
||||
intr_pending = 1;
|
||||
}
|
||||
|
||||
void ch32sub_process()
|
||||
{
|
||||
uint8_t flags;
|
||||
uint8_t clear = 0;
|
||||
uint8_t i;
|
||||
|
||||
if (intr_flag) {
|
||||
intr_flag = 0;
|
||||
flags = 1;
|
||||
if (intr_pending) {
|
||||
intr_pending = 0;
|
||||
|
||||
// get interrupt flags
|
||||
i2c_read_reg16(SUB_I2C_ADDR, REG_INTR_FLAGS, &flags, 1);
|
||||
// get flags
|
||||
flags = ch32sub_read_1b(REG_INTR_FLAGS);
|
||||
|
||||
while (flags) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (intr_flag & (1 << i)) {
|
||||
if (flag_cb[i]) flag_cb[i]();
|
||||
else {
|
||||
// unhandled interrupt; clear it
|
||||
// ch32sub_write_1b(REG_INTR_FLAGS, i << 1);
|
||||
}
|
||||
// process flags
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (flags & (1 << i)) {
|
||||
if (intr_cb[i]) {
|
||||
clear |= (i << 1);
|
||||
intr_cb[i]();
|
||||
}
|
||||
else {
|
||||
// unhandled interrupt; clear it?
|
||||
// ch32sub_write_1b(REG_INTR_FLAGS, i << 1);
|
||||
}
|
||||
}
|
||||
|
||||
// get interrupt flags (again)
|
||||
i2c_read_reg16(SUB_I2C_ADDR, REG_INTR_FLAGS, &flags, 1);
|
||||
}
|
||||
|
||||
// clear flags
|
||||
ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, clear);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,31 +114,29 @@ void ch32sub_init()
|
|||
// note: this is handled as "high priority" within the interrupt handler now.
|
||||
// port_intr_cb_register(PORT_INTR_GPIOB, SUB_INTR_PIN_NR, ch32sub_isr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// things to do
|
||||
void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len)
|
||||
{
|
||||
i2c_read_reg16(SUB_I2C_ADDR, reg, dat, len);
|
||||
}
|
||||
|
||||
void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len)
|
||||
{
|
||||
i2c_write_reg16(SUB_I2C_ADDR, reg, dat, len);
|
||||
}
|
||||
|
||||
void ch32sub_write_1b(uint16_t reg, uint8_t dat)
|
||||
{
|
||||
i2c_start();
|
||||
i2c_addr(SUB_I2C_ADDR, 0);
|
||||
i2c_wr(reg >> 8);
|
||||
i2c_wr(reg & 0xff);
|
||||
i2c_wr(dat);
|
||||
i2c_stop();
|
||||
// clear any interrupts now, to start from clean slate
|
||||
ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, 0xff);
|
||||
}
|
||||
|
||||
void ch32sub_rgb_hwen(uint8_t en)
|
||||
{
|
||||
ch32sub_write_1b(REG_RGB_HWEN, en);
|
||||
}
|
||||
|
||||
void ch32sub_intr_defaults()
|
||||
{
|
||||
int8_t i;
|
||||
uint8_t dat[5];
|
||||
|
||||
// we want interrupted for all button events
|
||||
for (i = 0; i < 5; i++) {
|
||||
dat[i] = BTN_PUSH | BTN_HOLD | BTN_RELEASE;
|
||||
}
|
||||
|
||||
// enable button interrupt sources
|
||||
ch32sub_write(REG_BTN1_INT_ENABLE, dat, 5);
|
||||
|
||||
// enable all interrupt flags we care about
|
||||
dat[0] = INT_BTN | INT_UTX_DONE | INT_UTX_TIMEOUT | INT_UTX_ERROR | INT_URX_RCVD;
|
||||
ch32sub_write_1b(REG_INTR_ENABLE, dat[0]);
|
||||
}
|
||||
|
|
|
@ -97,6 +97,12 @@ enum ch32sub_regmap {
|
|||
};
|
||||
|
||||
|
||||
#define BTN_PUSH (1 << 0)
|
||||
#define BTN_HOLD (1 << 1)
|
||||
#define BTN_RELEASE (1 << 2)
|
||||
#define BTN_IGNORE (1 << 3)
|
||||
|
||||
|
||||
|
||||
void ch32sub_init();
|
||||
void ch32sub_isr();
|
||||
|
@ -106,6 +112,7 @@ void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len);
|
|||
void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len);
|
||||
void ch32sub_write_1b(uint16_t reg, uint8_t dat);
|
||||
|
||||
void ch32sub_intr_defaults();
|
||||
void ch32sub_rgb_hwen(uint8_t en);
|
||||
|
||||
|
||||
|
|
|
@ -19,14 +19,13 @@ void e16_read(uint16_t addr, uint8_t *dat, uint32_t len)
|
|||
{
|
||||
if (len > EEPROM_SIZE) return;
|
||||
|
||||
i2c_start();
|
||||
i2c_addr(EEPROM_I2C_ADDR, 0);
|
||||
i2c_wr(addr >> 8);
|
||||
i2c_wr(addr & 0xff);
|
||||
i2c_restart();
|
||||
i2c_addr(EEPROM_I2C_ADDR, 1);
|
||||
i2c_wr(EEPROM_I2C_ADDR | 1);
|
||||
|
||||
while (len--) *dat++ = i2cm_rd(len > 0);
|
||||
while (len--) *dat++ = i2c_rd(len > 0);
|
||||
|
||||
i2c_stop();
|
||||
}
|
||||
|
@ -42,15 +41,16 @@ void e16_write(uint16_t addr, uint8_t *dat, uint16_t len)
|
|||
// it is your responsibility to correctly address for
|
||||
// page boundaries. most eeprom roll over page boundaries.
|
||||
|
||||
i2c_start();
|
||||
i2c_addr(EEPROM_I2C_ADDR, 0);
|
||||
i2c_wr(addr >> 8);
|
||||
i2c_wr(addr & 0xff);
|
||||
|
||||
while (len--) {
|
||||
nack = i2cm_wr(*dat++);
|
||||
nack = i2c_wr(*dat++);
|
||||
if (nack) break;
|
||||
}
|
||||
|
||||
i2c_stop();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
* - GP1 has UART0 TX and PWM9.
|
||||
* - GP2 has UART0 RX and PWM7.
|
||||
*
|
||||
* errata:
|
||||
* - bottom board marked REV3 has addon header mirrored.
|
||||
* to manufacture this, GAT GPIO is cut and inoperable.
|
||||
* todo: add strapping GPIO check to determine board version.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -61,10 +61,11 @@ void rgbled_init()
|
|||
{
|
||||
volatile uint32_t x;
|
||||
|
||||
ch32sub_rgb_hwen(1);
|
||||
// make sure the hardware pin is on before calling.
|
||||
|
||||
|
||||
// wait a little while to ensure controller is awake
|
||||
x = GetSysClock() / 16384;
|
||||
x = GetSysClock() / 131072;
|
||||
while (x--);
|
||||
|
||||
// clear fade
|
||||
|
@ -76,7 +77,7 @@ void rgbled_init()
|
|||
|
||||
aw20x_set_dim_global(&awled, AW20X_DIM);
|
||||
aw20x_set_fade(&awled);
|
||||
aw20x_led_enable_range(&awled, 0, 23);
|
||||
aw20x_led_enable_range(&awled, 0, 47); // 9x4, but need to send 12x4
|
||||
}
|
||||
|
||||
void rgbled_flag_update()
|
||||
|
@ -104,8 +105,14 @@ void rgbled_send()
|
|||
|
||||
void rgbled_runprog(uint8_t tick_ctr)
|
||||
{
|
||||
uint8_t idx = uconf.ledprog_rgb_idx;
|
||||
|
||||
// run program
|
||||
if (rgb_pgm[uconf.ledprog_rgb_idx].prog) {
|
||||
rgb_pgm[uconf.ledprog_rgb_idx].prog(uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx], tick_ctr);
|
||||
if (rgb_pgm[idx].prog) {
|
||||
// render
|
||||
rgb_pgm[idx].prog(uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx], tick_ctr);
|
||||
|
||||
// and for now, always force an update
|
||||
led_matrix_needs_update = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,20 +43,25 @@
|
|||
|
||||
|
||||
// global settings
|
||||
#define OLED_UPDATE_RATE 8 // framerate of OLED; (256*(6/8)) / OLED_UPDATE_RATE; 8 = 24FPS
|
||||
#define OLED_UPDATE_RATE 13 // framerate of OLED; { (256*(8/8)) / OLED_UPDATE_RATE }; 13 = 19FPS
|
||||
|
||||
// flags
|
||||
#define FLAG_OLED_UPDATE (1 << 0)
|
||||
#define FLAG_RGBLED_RUN_PROG (1 << 1)
|
||||
#define FLAG_PROG_TICK_INTR (1 << 7)
|
||||
|
||||
#define PROG_TICK_RATE (32768 / 256)
|
||||
#define FLAG_RESET_SYSTICK (1 << 6)
|
||||
|
||||
#define PROG_TICK_RATE ((32768 / 256) - 1)
|
||||
|
||||
|
||||
|
||||
const uint8_t vers[] = "241015a";
|
||||
|
||||
uint8_t cpu_use = 0;
|
||||
uint8_t cpu_max = 0;
|
||||
uint32_t cpu_use = 0;
|
||||
uint32_t cpu_max = 0;
|
||||
uint16_t cpu_pct = 0;
|
||||
uint16_t cpu_pct_max = 0;
|
||||
|
||||
uint32_t uptime = 0;
|
||||
uint16_t uptime_hour;
|
||||
|
@ -67,9 +72,10 @@ uint32_t idle_time_menu;
|
|||
uint32_t idle_time_still;
|
||||
uint8_t idle_go_sleep;
|
||||
|
||||
static volatile uint8_t flags = 0;
|
||||
static volatile uint8_t flags_lo = 0;
|
||||
static uint8_t flags_hi = FLAG_RESET_SYSTICK;
|
||||
|
||||
static uint8_t st_tick = 0; // systick loop counter
|
||||
static uint8_t st_tick = 0; // program tick counter
|
||||
static uint8_t oled_tick = 0; // oled framerate counter
|
||||
|
||||
|
||||
|
@ -107,17 +113,22 @@ void rtc_reset_trig()
|
|||
|
||||
void rtcisr_init()
|
||||
{
|
||||
LClk32K_Cfg(Clk32K_LSI, ENABLE); // enable internal oscillator
|
||||
Calibration_LSI(Level_128); // calibrate LSI fromm HSE
|
||||
LClk32K_Cfg(Clk32K_LSI, ENABLE); // enable internal oscillator
|
||||
Calibration_LSI(Level_128); // calibrate LSI fromm HSE
|
||||
|
||||
rtc_reset_trig();
|
||||
PFIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
void systick_init(void)
|
||||
{
|
||||
SysTick->CNT = 0; // clear counter
|
||||
SysTick->CTLR = SysTick_CTLR_STCLK | SysTick_CTLR_STE; // enable counter in /1 mode
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void oled_update_done()
|
||||
{
|
||||
int16_t a;
|
||||
int8_t rot;
|
||||
|
||||
// reset oled callback, clear screen, and set default pixel mode and font size
|
||||
|
@ -153,6 +164,7 @@ void oled_update_done()
|
|||
|
||||
#ifdef MENU_TIMEOUT_TO_NAMETAG
|
||||
// root menu idle counting
|
||||
// note: untested.
|
||||
if (menu == &menu_0) {
|
||||
if (!idle_time_menu) {
|
||||
idle_time_menu = uptime;
|
||||
|
@ -167,87 +179,37 @@ void oled_update_done()
|
|||
}
|
||||
#endif
|
||||
|
||||
// do menu operations
|
||||
// render menu
|
||||
menu_tick();
|
||||
|
||||
// calculate CPU usage
|
||||
// note: we just consider missed ticks a percent.
|
||||
// it's actually more like a tenth. fuck it.
|
||||
// a = missed;
|
||||
// todo: implement this
|
||||
a = 0;
|
||||
|
||||
if (uconf.framemod == UCONF_FRAMERATE_HALF) {
|
||||
// the above calculation is tied to framerate.
|
||||
// so this will compensate for half framerate mode...
|
||||
a >>= 1;
|
||||
}
|
||||
|
||||
if (a > cpu_max) {
|
||||
cpu_max = a;
|
||||
}
|
||||
cpu_use = a;
|
||||
|
||||
|
||||
// reset missed interrupt counter
|
||||
// missed = 0;
|
||||
cpu_pct = (cpu_use * 100) / cpu_max;
|
||||
if (cpu_pct > cpu_pct_max) cpu_pct_max = cpu_pct;
|
||||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void lowprio_task() {
|
||||
uint32_t interrupt_flags;
|
||||
|
||||
int main()
|
||||
{
|
||||
// configure clock
|
||||
ch59x_xtal_conf();
|
||||
SetSysClock(SYSCLK_FREQ_USEI2C);
|
||||
// note that system clock speed is decreased after every use of I2C.
|
||||
|
||||
// enable DC-DC converter; brings significant power saving
|
||||
PWR_DCDCCfg(ENABLE);
|
||||
|
||||
// get i2c initialized since most stuff will need it
|
||||
i2c_init();
|
||||
|
||||
// read the user config
|
||||
uconf_load();
|
||||
|
||||
// initialize aux MCU
|
||||
ch32sub_init();
|
||||
// and enable RGBLED controller hardware pin so the controller can wake up
|
||||
ch32sub_rgb_hwen(1);
|
||||
|
||||
// initialize accelerometer
|
||||
accel_init();
|
||||
|
||||
// initialize RGBLED controller
|
||||
rgbled_init();
|
||||
|
||||
// configure GAT aux GPIOs, get gat ID
|
||||
gat_gpio_init();
|
||||
// configure GAT i2c slave
|
||||
// not yet implemented
|
||||
|
||||
// configure port-based interrupts (used for ch32sub interrupt)
|
||||
port_intr_init();
|
||||
|
||||
// start up the OLED and menu system
|
||||
ssd1306fb_set_target(&oled);
|
||||
ssd1306_init(1); // we'll try to init later too, since sometimes they fail
|
||||
menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode
|
||||
|
||||
// configure main program tick interrupt
|
||||
rtcisr_init();
|
||||
|
||||
while(1) {
|
||||
while (1) {
|
||||
// sleep when we're doing nothing
|
||||
__WFI();
|
||||
if (!flags_lo) {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
// only care about aux MCU when all other processing is done
|
||||
// disable all IRQs when doing any I2C related stuff, as interrupts
|
||||
// can corrupt transactions
|
||||
SYS_DisableAllIrq(&interrupt_flags);
|
||||
|
||||
// temporary: enable sub interrupts
|
||||
ch32sub_intr_defaults();
|
||||
// process sub MCU interrupt, if pending
|
||||
ch32sub_process();
|
||||
|
||||
// send the last oled frame data
|
||||
if (flags & FLAG_OLED_UPDATE) {
|
||||
flags &= ~FLAG_OLED_UPDATE;
|
||||
if (flags_lo & FLAG_OLED_UPDATE) {
|
||||
flags_lo &= ~FLAG_OLED_UPDATE;
|
||||
|
||||
/*** oled ***/
|
||||
if (oled.callback && !(oled.state & SSD1306_STATE_BUSY)) {
|
||||
|
@ -267,24 +229,90 @@ int main()
|
|||
}
|
||||
}
|
||||
|
||||
// render new OLED frame
|
||||
if (flags & FLAG_RGBLED_RUN_PROG) {
|
||||
flags &= ~FLAG_RGBLED_RUN_PROG;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// re-enable IRQs
|
||||
SYS_RecoverIrq(interrupt_flags);
|
||||
|
||||
// render new rgbled frame
|
||||
if (flags_lo & FLAG_RGBLED_RUN_PROG) {
|
||||
flags_lo &= ~FLAG_RGBLED_RUN_PROG;
|
||||
rgbled_runprog(st_tick);
|
||||
}
|
||||
|
||||
// drop into lower clock rate
|
||||
SetSysClock(SYSCLK_FREQ_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// configure clock
|
||||
ch59x_xtal_conf();
|
||||
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
|
||||
|
||||
i2c_init(); // get i2c initialized since most stuff will need it
|
||||
|
||||
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
|
||||
|
||||
accel_init(); // initialize accelerometer
|
||||
rgbled_init(); // initialize RGBLED controller
|
||||
|
||||
gat_gpio_init(); // configure GAT aux GPIOs, get gat ID
|
||||
// todo: implement // configure GAT i2c slave
|
||||
|
||||
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
|
||||
|
||||
// configure main program tick interrupt
|
||||
rtcisr_init();
|
||||
|
||||
// start the low priority task loop
|
||||
lowprio_task();
|
||||
}
|
||||
|
||||
|
||||
__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;
|
||||
}
|
||||
|
||||
// speed up
|
||||
SetSysClock(SYSCLK_FREQ_NORMAL);
|
||||
|
||||
// clear interrupt flag and reset RTC
|
||||
rtc_reset_trig();
|
||||
|
||||
// manual uptime counter
|
||||
st_tick++;
|
||||
|
||||
if (!st_tick) {
|
||||
uptime++;
|
||||
uptime_hour = (uint16_t)(uptime / 3600);
|
||||
|
@ -305,24 +333,18 @@ void RTC_IRQHandler(void)
|
|||
rgbled_send();
|
||||
|
||||
// defer rendering
|
||||
flags |= FLAG_RGBLED_RUN_PROG;
|
||||
flags_lo |= FLAG_RGBLED_RUN_PROG;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
accel_poll();
|
||||
// no break
|
||||
}
|
||||
default: {
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
flags |= FLAG_OLED_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read accelerometer data at 32Hz
|
||||
if ((st_tick & 0x7) == 0x7) {
|
||||
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
flags_lo |= FLAG_OLED_UPDATE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ int32_t accel_i2c_write(void *handle, uint8_t reg, const uint8_t *bufp, uint16_t
|
|||
{
|
||||
(void)(handle);
|
||||
|
||||
i2c_write_reg8(LIS2DW_I2C_ADDR, reg, bufp, len);
|
||||
i2c_write_reg8(LIS2DW_I2C_ADDR_SDO_LOW, reg, bufp, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ int32_t accel_i2c_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
|
|||
{
|
||||
(void)(handle);
|
||||
|
||||
i2c_read_reg8(LIS2DW_I2C_ADDR, reg, bufp, len);
|
||||
i2c_read_reg8(LIS2DW_I2C_ADDR_SDO_LOW, reg, bufp, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ void accel_init()
|
|||
timeout = 0;
|
||||
accel_found = 1;
|
||||
}
|
||||
} while (timeout);
|
||||
} while (timeout--);
|
||||
}
|
||||
|
||||
if (accel_found) {
|
||||
|
@ -98,7 +98,7 @@ void accel_init()
|
|||
void accel_poll()
|
||||
{
|
||||
uint8_t reg = 1;
|
||||
uint16_t xyz[3];
|
||||
int16_t xyz[3];
|
||||
|
||||
if (!accel_found) return;
|
||||
|
||||
|
@ -110,6 +110,9 @@ void accel_poll()
|
|||
// read acceleration data
|
||||
memset(xyz, 0x00, 3 * sizeof(int16_t));
|
||||
lis2dw12_acceleration_raw_get(&dev_ctx, xyz);
|
||||
accel.x = xyz[0] >>= 8;
|
||||
accel.y = xyz[1] >>= 8;
|
||||
accel.z = xyz[2] >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <stdint.h>
|
||||
#include "tinymt.h"
|
||||
|
||||
#include "CH59x_common.h"
|
||||
|
||||
|
||||
|
||||
static void tinymt32_next_state(tinymt32_t *s);
|
||||
|
@ -91,7 +93,8 @@ const uint32_t TINYMT32_MASK = UINT32_C(0x7fffffff);
|
|||
* This function changes the internal state of tinymt32.
|
||||
* @param s pointer to tinymt internal state.
|
||||
*/
|
||||
static void tinymt32_next_state (tinymt32_t* s)
|
||||
__HIGH_CODE
|
||||
void tinymt32_next_state (tinymt32_t* s)
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
|
@ -128,7 +131,8 @@ static void tinymt32_next_state (tinymt32_t* s)
|
|||
* @param s pointer to tinymt internal state.
|
||||
* @return 32-bit unsigned pseudorandom number.
|
||||
*/
|
||||
static uint32_t tinymt32_temper (tinymt32_t* s)
|
||||
__HIGH_CODE
|
||||
uint32_t tinymt32_temper (tinymt32_t* s)
|
||||
{
|
||||
uint32_t t0, t1;
|
||||
t0 = s->status[3];
|
||||
|
|
|
@ -43,7 +43,9 @@ void port_intr_cb_register(uint8_t port, uint8_t idx, void (*fn)(void))
|
|||
|
||||
void port_intr_init()
|
||||
{
|
||||
// enable port interrupt
|
||||
// clear state then enable port interrupt
|
||||
R16_PB_INT_IF = 0xff;
|
||||
PFIC_EnableIRQ(GPIO_B_IRQn);
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,8 +65,8 @@ __INTERRUPT
|
|||
__HIGH_CODE
|
||||
void GPIOB_IRQHandler(void)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t offset;
|
||||
//uint8_t i;
|
||||
//uint8_t offset;
|
||||
uint16_t flag = R16_PB_INT_IF;
|
||||
|
||||
// clear flags
|
||||
|
@ -77,6 +79,7 @@ void GPIOB_IRQHandler(void)
|
|||
}
|
||||
|
||||
// general purpose fallback
|
||||
/*
|
||||
for (i = 4; i < MAX_PIN; i++) {
|
||||
offset = i - 4;
|
||||
if (flag & (1 << i)) {
|
||||
|
@ -85,4 +88,5 @@ void GPIOB_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -21,18 +21,21 @@ uint8_t btn_held;
|
|||
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_push_cb(uint8_t idx)
|
||||
{
|
||||
btn_pushed |= (1 << idx);
|
||||
if (btn[idx].cb_push) btn[idx].cb_push(idx);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_hold_cb(uint8_t idx)
|
||||
{
|
||||
btn_held |= (1 << idx);
|
||||
if (btn[idx].cb_hold) btn[idx].cb_hold(idx);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_release_cb(uint8_t idx)
|
||||
{
|
||||
btn_pushed &= ~(1 << idx);
|
||||
|
@ -41,6 +44,7 @@ void btn_release_cb(uint8_t idx)
|
|||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_commit_hold()
|
||||
{
|
||||
uint8_t i, x;
|
||||
|
@ -66,6 +70,7 @@ void btn_commit_hold()
|
|||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void btn_intr()
|
||||
{
|
||||
uint8_t i;
|
||||
|
@ -76,7 +81,8 @@ void btn_intr()
|
|||
ch32sub_read(REG_BTN_PUSHED_LATCHED, btn_state, sizeof(btn_state));
|
||||
|
||||
// clear button interrupt flag
|
||||
ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, INT_BTN);
|
||||
// this is actually handled by the main routine so not needed here
|
||||
// ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, INT_BTN);
|
||||
|
||||
// process callbacks for new events
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
|
|
|
@ -9,12 +9,15 @@
|
|||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
MenuItem *menu;
|
||||
uint8_t menu_idx = 0;
|
||||
|
||||
uint8_t mtick;
|
||||
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_tick()
|
||||
{
|
||||
if (menu) {
|
||||
|
@ -149,6 +152,7 @@ void menu_btn_use_none()
|
|||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_draw_buttons(uint8_t mode, uint8_t mask)
|
||||
{
|
||||
uint8_t w;
|
||||
|
@ -274,6 +278,7 @@ void menu_draw_buttons(uint8_t mode, uint8_t mask)
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_draw_tabs(uint8_t active_idx)
|
||||
{
|
||||
uint8_t h;
|
||||
|
|
|
@ -95,6 +95,7 @@ static void menu_none_print_error(uint8_t *err1, uint8_t *err2, uint8_t *err3)
|
|||
return;
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_none_disp(uint8_t idx)
|
||||
{
|
||||
uint8_t i, j;
|
||||
|
@ -239,7 +240,7 @@ MENU_0_DISP_CHAR_ROTATE:
|
|||
}
|
||||
|
||||
if (uconf.flags & UCONF_FLAGS_SHOW_CPU_USAGE) {
|
||||
sprintf(txt, "%3u%%", cpu_use);
|
||||
sprintf(txt, "%3u%%", cpu_pct);
|
||||
ssd1306fb_set_cursor(90, 20);
|
||||
ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
|
||||
}
|
||||
|
@ -247,6 +248,7 @@ MENU_0_DISP_CHAR_ROTATE:
|
|||
oled.state &= ~SSD1306_STATE_STR_HALFWIDTH;
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_0_disp(uint8_t idx)
|
||||
{
|
||||
char txt[12];
|
||||
|
|
|
@ -205,6 +205,7 @@ void menu_1_font_next()
|
|||
} while (!font_table[uconf.font_idx].tag_allowed);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_1_disp(uint8_t idx)
|
||||
{
|
||||
int8_t w, x;
|
||||
|
|
|
@ -220,6 +220,7 @@ void menu_2_edit_use(uint8_t idx)
|
|||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_2_disp(uint8_t idx)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -325,6 +325,8 @@ void snek_init()
|
|||
gamemode = 17;
|
||||
}
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void snek_disp(uint8_t idx)
|
||||
{
|
||||
// uint8_t i;
|
||||
|
|
|
@ -27,6 +27,7 @@ const uint16_t sleep_times[] = {
|
|||
};
|
||||
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_5_disp(uint8_t idx)
|
||||
{
|
||||
int8_t w, x;
|
||||
|
|
|
@ -101,6 +101,7 @@ void menu_6_btn_use()
|
|||
btn_commit_hold();
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void menu_6_disp(uint8_t idx)
|
||||
{
|
||||
uint8_t i;
|
||||
|
@ -220,11 +221,11 @@ void menu_6_disp(uint8_t idx)
|
|||
break;
|
||||
}
|
||||
case 5: {
|
||||
sprintf(txt, "CPU Load: %3u%%", cpu_use);
|
||||
sprintf(txt, "CPU Load: %3u%%", cpu_pct);
|
||||
ssd1306fb_set_cursor(10, -1);
|
||||
ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
|
||||
|
||||
sprintf(txt, "CPU Max: %3u%%", cpu_max);
|
||||
sprintf(txt, "CPU Max: %3u%%", cpu_pct_max);
|
||||
ssd1306fb_set_cursor(10, 9);
|
||||
ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
|
||||
// some global options
|
||||
#define FLASH_RSVD_PAGES 16 // how many FLASH_UCONF_BYTES to reserve/check
|
||||
#define FLASH_RSVD_PAGES 8 // how many FLASH_UCONF_BYTES to reserve/check
|
||||
#define FLASH_UCONF_BYTES 256 // basically assumed everywhere
|
||||
|
||||
#define MISC_WIGGLE_RATE (7 - 4);
|
||||
|
|
|
@ -31,6 +31,7 @@ void HardFault_Handler(void)
|
|||
while (1);
|
||||
}
|
||||
|
||||
__attribute__((interrupt("WCH-Interrupt-fast")))
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
// ---- PROCESS UI AND COMMS
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
* some notes:
|
||||
* - writing does not loop; if writing to the end then new writes will cause an error interrupt.
|
||||
* - added write protection for first 16 bytes.
|
||||
* - many registers will only commit to action upon valid I2C stop received.
|
||||
* - the code don't send NACKs on invalid writes.
|
||||
* - write registers will only commit to action upon valid I2C stop received.
|
||||
*
|
||||
*
|
||||
* register map:
|
||||
|
@ -129,8 +130,8 @@ void i2cs_write_cb(uint16_t initial_reg, uint16_t last_reg)
|
|||
// error - see i2c_slave.h for error types
|
||||
void i2cs_werr_cb(uint16_t reg, uint8_t data, uint8_t error)
|
||||
{
|
||||
i2cs_reg[0x0d]++;
|
||||
if (!i2cs_reg[0x0d]) i2cs_reg[0x0c]++;
|
||||
i2cs_reg[REG_WERR_LO]++;
|
||||
if (!i2cs_reg[REG_WERR_LO]) i2cs_reg[REG_WERR_HI]++;
|
||||
}
|
||||
|
||||
// called upon every register read
|
||||
|
@ -208,7 +209,7 @@ void I2C1_EV_IRQHandler(void)
|
|||
i2cs_state.position = i2cs_state.offset; // Reset position
|
||||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_RXNE) { // Write event
|
||||
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;
|
||||
|
@ -240,7 +241,7 @@ void I2C1_EV_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (STAR1 & I2C_STAR1_TXE) { // Read event
|
||||
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];
|
||||
|
@ -262,6 +263,7 @@ void I2C1_EV_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
__attribute__((interrupt("WCH-Interrupt-fast")))
|
||||
void I2C1_ER_IRQHandler(void)
|
||||
{
|
||||
uint16_t STAR1 = I2C1->STAR1;
|
||||
|
|
|
@ -140,6 +140,7 @@ int main(void)
|
|||
exti_nvic_init();
|
||||
|
||||
// configure systick
|
||||
systick_init();
|
||||
|
||||
while (1) {
|
||||
__WFI();
|
||||
|
|
Loading…
Reference in New Issue