initial soft i2c routines written; AW20xxx code copied in
completely untested. i2c delay cycles are at best a guess.
This commit is contained in:
parent
b6582a599a
commit
b1bca1012f
Binary file not shown.
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* i2c.h
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_COMM_I2C_H_
|
||||
#define USER_COMM_I2C_H_
|
||||
|
||||
|
||||
|
||||
#ifdef SOFT_I2C_MASTER
|
||||
|
||||
|
||||
#include "soft_i2c_master.h"
|
||||
|
||||
|
||||
#define i2c_init() i2cm_init()
|
||||
#define i2c_start() i2cm_start()
|
||||
#define i2c_restart() i2cm_restart()
|
||||
#define i2c_stop() i2cm_stop()
|
||||
#define i2c_rd(ack) i2cm_rd(ack)
|
||||
#define i2c_wr(dat) i2cm_wr(dat)
|
||||
#define i2c_addr(a, w) i2c_start(); i2cm_addr(a, w)
|
||||
|
||||
#define i2c_rdbuf(d, x) i2cm_rdbuf(d, x)
|
||||
#define i2c_wrbuf(d, x) i2cm_wrbuf(d, x)
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#error HW I2C NOT YET IMPLEMENTED!
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMM_I2C_H_ */
|
|
@ -1,128 +1,166 @@
|
|||
/*
|
||||
* soft_i2c.c
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
* copied some random code and fixed it up for intricacies of CH59x.
|
||||
*
|
||||
* i2c hardware peripheral is shared on CH59x with debug pins and is
|
||||
* not attached to DMA. while having the peripheral would result in
|
||||
* higher speeds and less power usage, without debug it makes soft I2C
|
||||
* master a helpful tool.
|
||||
*
|
||||
* quirks and features:
|
||||
* - this implementation is blocking.
|
||||
* - this implementation uses a hardware timer.
|
||||
* - clock stretching is not supported.
|
||||
* - timings likely haven't been tested so long as this message exists.
|
||||
*/
|
||||
|
||||
|
||||
// ===================================================================================
|
||||
// Software I2C Master Functions for CH32X035/X034/X033 * v1.1 *
|
||||
// modified for CH592 by true
|
||||
// ===================================================================================
|
||||
//
|
||||
// Simple I2C bitbanging. ACK bit of the slave is ignored. Clock stretching by the
|
||||
// slave is not allowed. External pull-up resistors (4k7 - 10k) are mandatory!
|
||||
//
|
||||
// Further information: https://github.com/wagiminator/ATtiny13-TinyOLEDdemo
|
||||
// 2023 by Stefan Wagner: https://github.com/wagiminator
|
||||
//
|
||||
// This implementation requires 48MHz clock for 400KHz communication.
|
||||
|
||||
#include "soft_i2c_master.h"
|
||||
|
||||
// ===================================================================================
|
||||
// I2C Delay
|
||||
// ===================================================================================
|
||||
#define I2C_DLY_TICKS_H (((F_CPU * 9) / (I2C_CLKRATE * 25)) - 41)
|
||||
#define I2C_DLY_TICKS_L (((F_CPU * 16) / (I2C_CLKRATE * 25)) - 76)
|
||||
|
||||
#if I2C_DLY_TICKS_H >= 1
|
||||
#define I2C_DELAY_H() DLY_ticks(I2C_DLY_TICKS_H)
|
||||
#else
|
||||
#define I2C_DELAY_H()
|
||||
#endif
|
||||
|
||||
#if I2C_DLY_TICKS_L >= 1
|
||||
#define I2C_DELAY_L() DLY_ticks(I2C_DLY_TICKS_L)
|
||||
#else
|
||||
#define I2C_DELAY_L()
|
||||
#endif
|
||||
#define CYCLES_TO_HI 16
|
||||
#define CYCLES_TO_LO 16
|
||||
|
||||
// ===================================================================================
|
||||
// I2C Pin Macros
|
||||
// ===================================================================================
|
||||
#define I2C_SDA_HIGH() PIN_input(PIN_SDA) // release SDA -> pulled HIGH by resistor
|
||||
#define I2C_SDA_LOW() PIN_output(PIN_SDA) // SDA LOW -> pulled LOW by MCU
|
||||
#define I2C_SCL_HIGH() PIN_input(PIN_SCL) // release SCL -> pulled HIGH by resistor
|
||||
#define I2C_SCL_LOW() PIN_output(PIN_SCL) // SCL LOW -> pulled LOW by MCU
|
||||
#define I2C_SDA_READ() PIN_read(PIN_SDA) // read SDA pin
|
||||
#define I2C_CLOCKOUT() I2C_DELAY_L();I2C_SCL_HIGH();I2C_DELAY_H();I2C_SCL_LOW()
|
||||
#define CYCLES_RD 2 // cycles spent in read routine
|
||||
#define CYCLES_EXTRA_WR_HI 2 // extra cycles spent in write routine
|
||||
#define CYCLES_EXTRA_WR_LO 4
|
||||
|
||||
// ===================================================================================
|
||||
// I2C Functions
|
||||
// ===================================================================================
|
||||
|
||||
// I2C init function
|
||||
void I2C_init(void) {
|
||||
PIN_input(PIN_SCL); // release SCL
|
||||
PIN_input(PIN_SDA); // release SDA
|
||||
PIN_low(PIN_SCL); // preset for SCL low
|
||||
PIN_low(PIN_SDA); // preset for SDA low
|
||||
|
||||
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() spin = delay_hi - CYCLES_RD; while(spin--)
|
||||
|
||||
#define wr_delay_hi() spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
#define wr_delay_lo() spin = delay_lo - CYCLES_EXTRA_WR_LO; while(spin--)
|
||||
|
||||
|
||||
|
||||
// re-run init any time the clock speed changes to recalculate delays.
|
||||
void i2cm_init()
|
||||
{
|
||||
uint32_t sysclk;
|
||||
uint32_t cycles;
|
||||
|
||||
// configure GPIO
|
||||
SCL_IN_HI();
|
||||
SCL_SET_LO();
|
||||
|
||||
SDA_IN_HI();
|
||||
SDA_SET_LO();
|
||||
|
||||
// configure timer
|
||||
sysclk = GetSysClock();
|
||||
cycles = sysclk / 500000;
|
||||
|
||||
delay_hi = (cycles - CYCLES_TO_HI) / 4;
|
||||
delay_lo = (cycles - CYCLES_TO_LO) / 4;
|
||||
}
|
||||
|
||||
// I2C transmit one data byte to the slave, ignore ACK bit, no clock stretching allowed
|
||||
void I2C_write(uint8_t data) {
|
||||
uint8_t i;
|
||||
for(i=8; i; i--, data<<=1) { // transmit 8 bits, MSB first
|
||||
(data & 0x80) ? (I2C_SDA_HIGH()) : (I2C_SDA_LOW()); // SDA HIGH if bit is 1
|
||||
I2C_CLOCKOUT(); // clock out -> slave reads the bit
|
||||
}
|
||||
I2C_SDA_HIGH(); // release SDA for ACK bit of slave
|
||||
I2C_CLOCKOUT(); // 9th clock pulse is for the ignored ACK bit
|
||||
void i2cm_start()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
SDA_OUTLO(); bit_delay_lo();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
// I2C start transmission
|
||||
void I2C_start(uint8_t addr) {
|
||||
I2C_SDA_LOW(); // start condition: SDA goes LOW first
|
||||
I2C_DELAY_H(); // delay
|
||||
I2C_SCL_LOW(); // start condition: SCL goes LOW second
|
||||
I2C_write(addr); // send slave address
|
||||
void i2cm_restart()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI();
|
||||
i2cm_start();
|
||||
}
|
||||
|
||||
// I2C restart transmission
|
||||
void I2C_restart(uint8_t addr) {
|
||||
I2C_SDA_HIGH(); // prepare SDA for HIGH to LOW transition
|
||||
I2C_DELAY_H(); // delay
|
||||
I2C_SCL_HIGH(); // restart condition: clock HIGH
|
||||
I2C_start(addr); // start again
|
||||
void i2cm_stop()
|
||||
{
|
||||
SDA_OUTLO(); bit_delay_lo();
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
}
|
||||
|
||||
// I2C stop transmission
|
||||
void I2C_stop(void) {
|
||||
I2C_SDA_LOW(); // prepare SDA for LOW to HIGH transition
|
||||
I2C_DELAY_H(); // delay
|
||||
I2C_SCL_HIGH(); // stop condition: SCL goes HIGH first
|
||||
I2C_DELAY_H(); // delay
|
||||
I2C_SDA_HIGH(); // stop condition: SDA goes HIGH second
|
||||
// returns: data byte
|
||||
uint8_t i2cm_rd(uint8_t ack)
|
||||
{
|
||||
uint8_t x, in = 0;
|
||||
|
||||
SDA_IN_HI();
|
||||
for (x = 8; x; x--) {
|
||||
in <<= 1; // clock next bit
|
||||
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
|
||||
rd_delay();
|
||||
|
||||
if (SDA_GET()) in |= 1;
|
||||
|
||||
SCL_OUTLO();
|
||||
}
|
||||
|
||||
if (ack) { SDA_OUTLO(); } // ack
|
||||
else { SDA_IN_HI(); } // nack
|
||||
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
|
||||
SDA_IN_HI();
|
||||
SCL_OUTLO();
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
// I2C receive one data byte from the slave (ack=0 for last byte, ack>0 if more bytes to follow)
|
||||
uint8_t I2C_read(uint8_t ack) {
|
||||
uint8_t i;
|
||||
uint8_t data = 0; // variable for the received byte
|
||||
I2C_SDA_HIGH(); // release SDA -> will be toggled by slave
|
||||
for(i=8; i; i--) { // receive 8 bits
|
||||
data <<= 1; // bits shifted in right (MSB first)
|
||||
I2C_DELAY_L(); // delay
|
||||
I2C_SCL_HIGH(); // clock HIGH
|
||||
I2C_DELAY_H(); // delay
|
||||
if(I2C_SDA_READ()) data |= 1; // read bit
|
||||
I2C_SCL_LOW(); // clock LOW -> slave prepares next bit
|
||||
}
|
||||
if(ack) I2C_SDA_LOW(); // pull SDA LOW to acknowledge (ACK)
|
||||
I2C_CLOCKOUT(); // clock out -> slave reads ACK bit
|
||||
return data; // return the received byte
|
||||
// returns: possible ack from target
|
||||
uint8_t i2cm_wr(uint8_t dat)
|
||||
{
|
||||
uint8_t x;
|
||||
uint8_t ack;
|
||||
|
||||
for (x = 8; x; x--) {
|
||||
if (dat & 0x80) { SDA_IN_HI(); SCL_IN_HI(); wr_delay_hi(); }
|
||||
else { SDA_OUTLO(); SCL_OUTLO(); wr_delay_lo(); }
|
||||
|
||||
dat <<= 1;
|
||||
SCL_OUTLO();
|
||||
}
|
||||
|
||||
SDA_IN_HI();
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
|
||||
ack = SDA_GET();
|
||||
|
||||
SCL_OUTLO();
|
||||
return ack;
|
||||
}
|
||||
|
||||
// Send data buffer via I2C bus and stop
|
||||
void I2C_writeBuffer(uint8_t* buf, uint16_t len) {
|
||||
while(len--) I2C_write(*buf++); // write buffer
|
||||
I2C_stop(); // stop transmission
|
||||
// use a left-aligned address with this implementation.
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t write)
|
||||
{
|
||||
addr &= ~0x1;
|
||||
addr |= write ? 0 : 1;
|
||||
i2cm_wr(addr);
|
||||
}
|
||||
|
||||
// Read data via I2C bus to buffer and stop
|
||||
void I2C_readBuffer(uint8_t* buf, uint16_t len) {
|
||||
while(len--) *buf++ = I2C_read(len > 0);
|
||||
I2C_stop();
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint8_t len)
|
||||
{
|
||||
while(len--) *dat++ = i2cm_rd(len > 0);
|
||||
i2cm_stop();
|
||||
}
|
||||
|
||||
void i2cm_wrbuf(uint8_t *dat, uint8_t len)
|
||||
{
|
||||
uint8_t nack;
|
||||
|
||||
while(len--) {
|
||||
nack = i2cm_wr(*dat++);
|
||||
if (nack) break;
|
||||
}
|
||||
i2cm_stop();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,55 @@
|
|||
/*
|
||||
* soft_i2c.h
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_COMM_SOFT_I2C_H_
|
||||
#define USER_COMM_SOFT_I2C_H_
|
||||
#ifndef USER_COMM_SOFT_I2C_MASTER_H_
|
||||
#define USER_COMM_SOFT_I2C_MASTER_H_
|
||||
|
||||
#include <CH59x_common.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMM_SOFT_I2C_H_ */
|
||||
#define SDA_PIN 4
|
||||
#define SDA_BIT (1 << (SDA_PIN % 8))
|
||||
#define SDA_DIR_REG R8_PA_DIR_0
|
||||
#define SDA_DRV_REG R8_PA_PD_DRV_0
|
||||
#define SDA_CLR_REG R8_PA_CLR_0
|
||||
#define SDA_GET_REG R8_PA_PIN_0
|
||||
|
||||
#define SCL_PIN 12
|
||||
#define SCL_BIT (1 << (SCL_PIN % 8))
|
||||
#define SCL_DRV_REG R8_PB_PD_DRV_1
|
||||
#define SCL_DIR_REG R8_PB_DIR_1
|
||||
#define SCL_CLR_REG R8_PB_CLR_1
|
||||
#define SCL_GET_REG R8_PB_PIN_1
|
||||
|
||||
|
||||
#define SDA_IN_HI() { SDA_DRV_REG &= ~SDA_BIT; SDA_DIR_REG &= ~SDA_BIT; }
|
||||
#define SDA_OUTLO() { SDA_DIR_REG |= SDA_BIT; SDA_DRV_REG |= SDA_BIT; }
|
||||
#define SDA_SET_LO() SDA_CLR_REG = SDA_BIT
|
||||
#define SDA_GET() ( SDA_GET_REG & SDA_BIT )
|
||||
|
||||
#define SCL_IN_HI() { SCL_DRV_REG &= ~SCL_BIT; SCL_DIR_REG &= ~SCL_BIT; }
|
||||
#define SCL_OUTLO() { SCL_DIR_REG |= SCL_BIT; SCL_DRV_REG |= SCL_BIT; }
|
||||
#define SCL_SET_LO() SCL_CLR_REG = SCL_BIT
|
||||
#define SCL_GET() ( SCL_GET_REG & SCL_BIT )
|
||||
|
||||
|
||||
|
||||
void i2cm_init();
|
||||
|
||||
void i2cm_start();
|
||||
void i2cm_restart();
|
||||
void i2cm_stop();
|
||||
|
||||
uint8_t i2cm_rd(uint8_t ack);
|
||||
uint8_t i2cm_wr(uint8_t dat);
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t write);
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint8_t len);
|
||||
void i2cm_wrbuf(uint8_t *dat, uint8_t len);
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMM_SOFT_I2C_MASTER_H_ */
|
||||
|
|
|
@ -1,8 +1,217 @@
|
|||
/*
|
||||
* aw20xxx.c
|
||||
* awinic AW20108 / AW20072 / AW20054 / AW20036 LED Matrix Driver
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
* originally written by true in 2022
|
||||
* while sleep deprived for a super constrained mcu
|
||||
*
|
||||
* some bugs fixed for defcon 32 on aug 6-7, 2024
|
||||
*
|
||||
* driver assumptions:
|
||||
* - rows and columns are used in order on the chip, lowest to highest
|
||||
* (if any are skipped, just skip this data in your buffer)
|
||||
* - duty cycle will be set according to the column count
|
||||
* - all AW20xxx chips will operate on the same i2c bus
|
||||
* - the only i2c write routine does not have register arguments
|
||||
*
|
||||
* driver notices:
|
||||
* - updates only happen one column at a time, and are blocking
|
||||
* (future version may implement a callback when each column is done)
|
||||
* - this driver has not yet implemented the pattern controller
|
||||
* - this driver has not yet implemented the GAIN register, so only operates 8-bit
|
||||
* (will be implemented later to allow for beyond-8-bit operation)
|
||||
* - this driver has not yet implemented FADEDIM mode
|
||||
* - all transfers result in copies of data, which is wasteful
|
||||
* (future version may transfer LED data directly from the buffer)
|
||||
*
|
||||
* if you need anything different, write it yourself
|
||||
*/
|
||||
|
||||
#include "aw20xxx.h"
|
||||
|
||||
|
||||
|
||||
#define AW20X_THIS_PAGE (aw->state & AW20X_STATE_PAGE_MASK)
|
||||
|
||||
#define AW20X_SET_PAGE(x) if (AW20X_THIS_PAGE != (x)) { \
|
||||
aw20x_page(aw, x); \
|
||||
aw->state &= ~AW20X_STATE_PAGE_MASK; \
|
||||
aw->state |= x; }
|
||||
|
||||
|
||||
|
||||
static uint8_t aw_buf[25]; // enough bytes for register and single column FADEDIM update (1 + (12*2))
|
||||
|
||||
|
||||
|
||||
void aw20x_page(struct AW20x *aw, uint8_t page)
|
||||
{
|
||||
// the datasheet isn't clear on this. the default is zero, and only the lower
|
||||
// three bits are specified. yet the DS says to send 0xCy where y is the page bits.
|
||||
// we'll just do what the DS says even though it contradicts itself.
|
||||
aw_buf[0] = 0xc0 | (page & AW20X_PAGE_MASK);
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_PAGE, aw_buf, 1);
|
||||
}
|
||||
|
||||
void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint8_t imax)
|
||||
{
|
||||
// set config register as specified
|
||||
aw->addr = addr;
|
||||
aw->cols = cols;
|
||||
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
|
||||
aw20x_sleep(aw, 0);
|
||||
|
||||
// enabled columns
|
||||
aw_buf[0] = cols - 1;
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_SIZE, aw_buf, 1);
|
||||
|
||||
// general config
|
||||
aw_buf[0] = imax & AW20X_CONF_IMAX_MASK;
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_GCCR, aw_buf, 1);
|
||||
while (AW20X_I2C_busy());
|
||||
}
|
||||
|
||||
void aw20x_sleep(struct AW20x *aw, uint8_t sleep)
|
||||
{
|
||||
// make sure we're on the config page
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
// send sleep bit
|
||||
aw_buf[0] = sleep ? AW20X_SLPCR_SLEEP : 0;
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_SLPCR, aw_buf, 1);
|
||||
|
||||
// set state
|
||||
if (sleep) aw->state |= AW20X_STATE_SLEEP_MASK;
|
||||
else aw->state &= ~AW20X_STATE_SLEEP_MASK;
|
||||
|
||||
// burn some cycles if we woke up
|
||||
if (!sleep) PLATFORM_INIT_DELAY();
|
||||
}
|
||||
|
||||
void aw20x_imax(struct AW20x *aw, uint8_t imax)
|
||||
{
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
|
||||
// todo: implement
|
||||
}
|
||||
|
||||
/*
|
||||
* sends LED values to the chip
|
||||
*/
|
||||
void aw20x_commit_fade(struct AW20x *aw)
|
||||
{
|
||||
uint8_t c;
|
||||
uint8_t row;
|
||||
|
||||
// make sure we're on the fade page
|
||||
AW20X_SET_PAGE(AW20X_PAGE2_FADE);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
row = 0;
|
||||
for (c = 0; c < aw->cols; c++) {
|
||||
// write to chip
|
||||
AW20X_I2C_writereg(aw->addr, row, aw->fade + row, aw->rows);
|
||||
while (AW20X_I2C_busy());
|
||||
row += AW20X_MAX_ROWS;
|
||||
}
|
||||
}
|
||||
|
||||
void aw20x_commit_dim(struct AW20x *aw)
|
||||
{
|
||||
// todo: implement
|
||||
}
|
||||
|
||||
/*
|
||||
* sets all LEDs to the specified 6-bit DIM value.
|
||||
* used when just using FADE and 8-bit mode
|
||||
* to set initial and fine tune from IMAX the output current.
|
||||
*/
|
||||
void aw20x_commit_dim_global(struct AW20x *aw, uint8_t dim)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t row = 0;
|
||||
|
||||
// ceil
|
||||
if (dim > 0x3f) dim = 0x3f;
|
||||
|
||||
// make sure we're on the dim page
|
||||
AW20X_SET_PAGE(AW20X_PAGE1_DIM);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
// clear buffer
|
||||
for (i = 0; i <= aw->rows; i++) aw_buf[i] = dim;
|
||||
|
||||
// send buffer for each column
|
||||
for (i = 0; i < aw->cols; i++) {
|
||||
AW20X_I2C_writereg(aw->addr, row, aw_buf, aw->rows);
|
||||
while (AW20X_I2C_busy());
|
||||
row += AW20X_MAX_ROWS;
|
||||
}
|
||||
}
|
||||
|
||||
void aw20x_commit_fadedim(struct AW20x *aw)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* todo:
|
||||
* - read current state, and apply bitfields to the currently active state
|
||||
* - allow bypassing the readback for faster operation (such as setting all LEDs on at startup)
|
||||
* - make this more efficient (36 LEDs takes ~0.3ms on a 48MHz PIC!)
|
||||
*/
|
||||
void aw20x_led_enable(struct AW20x *aw, uint8_t first, uint8_t last)
|
||||
{
|
||||
uint8_t c, r;
|
||||
uint8_t boff;
|
||||
|
||||
// make sure we're on the config page
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
// bits are stored 6 bits per byte, 2 bytes per column, one bit for each row
|
||||
// we only want to touch bits that exist on the chip and in the correct order
|
||||
boff = 0;
|
||||
for (c = 0; c < (aw->cols * 2); c++) {
|
||||
aw_buf[c] = 0;
|
||||
for (r = 0; r < AW20X_MAX_LEDON_BITS; r++) {
|
||||
if (r+boff >= first) {
|
||||
if (r+boff <= last) {
|
||||
aw_buf[c] |= (1 << r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boff += AW20X_MAX_LEDON_BITS;
|
||||
}
|
||||
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c);
|
||||
}
|
||||
|
||||
/*
|
||||
* disables LEDs based on user LED count, zero-indexed
|
||||
* (for example, LEDs 8-12 on AW20054 would enable C0R8, C0R9, C1R0, C1R1)
|
||||
*/
|
||||
void aw20x_led_disable(struct AW20x *aw, uint8_t first, uint8_t last)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,193 @@
|
|||
/*
|
||||
* aw20xxx.h
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
* awinic AW20108 / AW20072 / AW20054 / AW20036 LED Matrix Driver
|
||||
*/
|
||||
|
||||
#ifndef USER_DEVICE_AW20XXX_H_
|
||||
#define USER_DEVICE_AW20XXX_H_
|
||||
#ifndef AW20X_LED_MATRIX_H
|
||||
#define AW20X_LED_MATRIX_H
|
||||
|
||||
|
||||
|
||||
#endif /* USER_DEVICE_AW20XXX_H_ */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../comm/i2c.h"
|
||||
|
||||
|
||||
|
||||
#define PLATFORM_INIT_DELAY() { uint16_t zz = 1000; while(zz--); }
|
||||
// burn cycles for ~200us
|
||||
|
||||
#define AW20X_MAX_COLS 9
|
||||
#define AW20X_MAX_ROWS 12
|
||||
|
||||
#define AW20X_MAX_LEDON_BITS 6
|
||||
|
||||
#define AW20X_ADDR_SCL 0x38 // AD pin tied to SCL
|
||||
#define AW20X_ADDR_SDA 0x39 // AD pin tied to SDA
|
||||
#define AW20X_ADDR_GND 0x3A // AD pin tied to GND
|
||||
#define AW20X_ADDR_VDD 0x3B // AD pin tied to VDD
|
||||
|
||||
#define AW20X_CONF_IMAX_MASK 0xf0 // 7:4
|
||||
#define AW20X_CONF_IMAX_OFFSET 4 // 7:4
|
||||
#define AW20X_CONF_ADDR_MASK 0x03 // 1:0
|
||||
#define AW20X_CONF_ADDR_OFFSET 0 // 1:0
|
||||
|
||||
#define AW20X_CONF_USE_FADEDIM 0x08 // aw20x.fade now becomes fadedim; updates are done with FADEDIM page
|
||||
// this mode uses 2 bytes per LED; dim as byte 0, fade as byte 1
|
||||
#define AW20X_CONF_USE_EXPEN 0x04 // sets GCCR.EXPEN=1; fade is now only 6 bits (not yet implemented)
|
||||
|
||||
#define AW20X_PAGE_MASK 0x07
|
||||
|
||||
#define AW20X_STATE_PAGE_MASK AW20X_PAGE_MASK
|
||||
#define AW20X_STATE_SLEEP_MASK 0x80
|
||||
|
||||
|
||||
#define AW20X_PAGE0_CONFIG 0x00 // function register
|
||||
#define AW20X_PAGE1_DIM 0x01 // 5:0 dim; 8 bits per LED
|
||||
#define AW20X_PAGE2_FADE 0x02 // 7:0 fade; 8 bits per LED
|
||||
#define AW20X_PAGE3_PATTERN 0x03 // 1:0 pattern; 8 bits per LED
|
||||
#define AW20X_PAGE4_DIMFADE 0x04 // 13:8 dim, 7:0 fade; 16 bits per LED
|
||||
#define AW20X_PAGE5_DFP 0x05 // 15:14 pat, 13:8 dim, 7:0 fade; 16 bits per LED
|
||||
|
||||
#define AW20X_REG_IDR 0x00 // R 7:0 chip ID {0x18}
|
||||
#define AW20X_REG_SLPCR 0x01 // RW 7 sleep {0x80}
|
||||
#define AW20X_REG_RSTR 0x02 // W 7:0 SW_RSTN (?)
|
||||
#define AW20X_REG_GCCR 0x03 // RW 7:3 IMAX(7:4), ALLON, -, -, EXPEN {0x10}
|
||||
#define AW20X_REG_FCD 0x04 // W 0 FCDE (fast clear display enable)
|
||||
#define AW20X_REG_CLKSYS 0x05 // RW 1:0 CLK_IO, CLK_SEL
|
||||
#define AW20X_REG_FLTCFG1 0x09 // RW 5:0 UVLOPE, OTPE, UVIE, OTIE, UVLOE, OTE
|
||||
#define AW20X_REG_FLTCFG2 0x0a // RW 3:2 UVTH
|
||||
#define AW20X_REG_ISRFLT 0x0b // RW 5:0 PAT2IS, PAT1IS, PAT0IS, -, -, UVLOIS, OTIS
|
||||
#define AW20X_REG_LEDON0 0x31 // W 5:0 ON0:ON5, same pattern through to LEDON17 (0x42)
|
||||
#define AW20X_REG_PATCR 0x43 // RW 6:0 PAT2IE, PAT1IE, PAT0IE, -, PAT2EN, PAT1EN, PAT0EN
|
||||
#define AW20X_REG_FADEH0 0x44 // RW 7:0 FADEH0
|
||||
#define AW20X_REG_FADEH1 0x45
|
||||
#define AW20X_REG_FADEH2 0x46
|
||||
#define AW20X_REG_FADEL0 0x47
|
||||
#define AW20X_REG_FADEL1 0x48
|
||||
#define AW20X_REG_FADEL2 0x49 // RW 7:0 FADEL2
|
||||
#define AW20X_REG_PAT0T0 0x4a // RW 7:0 T1[4], T2[4]
|
||||
#define AW20X_REG_PAT0T1 0x4b // RW 7:0 T3[4], T4[4]
|
||||
#define AW20X_REG_PAT0T2 0x4c // RW 7:0 LE[2], LB[2], LT(11:8)[4]
|
||||
#define AW20X_REG_PAT0T3 0x4d // RW 7:0 LT(7:0)
|
||||
#define AW20X_REG_PAT1T0 0x4e
|
||||
#define AW20X_REG_PAT1T1 0x4f
|
||||
#define AW20X_REG_PAT1T2 0x50
|
||||
#define AW20X_REG_PAT1T3 0x51
|
||||
#define AW20X_REG_PAT2T0 0x52
|
||||
#define AW20X_REG_PAT2T1 0x53
|
||||
#define AW20X_REG_PAT2T2 0x54
|
||||
#define AW20X_REG_PAT2T3 0x55
|
||||
#define AW20X_REG_PAT0CFG 0x56 // RW 2:0 SWITCH, RAMPE, PATMD
|
||||
#define AW20X_REG_PAT1CFG 0x57
|
||||
#define AW20X_REG_PAT2CFG 0x58
|
||||
#define AW20X_REG_PATGO 0x59 // RW 6:0 PAT2ST, PAT1ST, PAT0ST, -, RUN2, RUN1, RUN0
|
||||
#define AW20X_REG_SIZE 0x80 // RW 3:0 SWSEL
|
||||
#define AW20X_REG_PAGE 0xf0 // RW 2:0 page select, 0-5; available from all pages
|
||||
|
||||
#define AW20X_IDR_ID 0x18 // value for all chips in this series
|
||||
|
||||
#define AW20X_SLPCR_SLEEP 0x01 // sleep mode (default is HIGH / asleep)
|
||||
|
||||
#define AW20X_RSTR_SW_RSTN 0x01 // write value to soft reset the chip
|
||||
|
||||
#define AW20X_GCCR_IMAX 0xf0 // global current setting (default 20mA)
|
||||
#define AW20X_GCCR_ALLON 0x08 // 0=normal, 1=force all on
|
||||
#define AW20X_GCCR_EXPEN 0x01 // 0=fade is linear 8-bit, 1=fade is exponential 6-bit
|
||||
|
||||
#define AW20X_FCD_FCDE 0x01 // write value to clear display (DS doesn't specify; is this a blanker?)
|
||||
|
||||
#define AW20X_CLKSYS_CLK_IO 0x02 // 0=no clk output, 1=clk output on (output) CLKIO pin
|
||||
#define AW20X_CLKSYS_CLK_SEL 0x01 // 0=internal 4MHz, 1=use clk on (input) CLKIO pin
|
||||
|
||||
#define AW20X_FLTCFG1_UVLOPE 0x20 // 1=enable UVLO protection; chip sets SLPCR.SLEEP when ISRFLT.UVLOIS=1
|
||||
#define AW20X_FLTCFG1_OTPE 0x10 // 1=enable overtemp protection; chip sets SLPCR.SLEEP when ISRFLT.UVLOIS=1
|
||||
#define AW20X_FLTCFG1_UVIE 0x08 // 1=UVLO interrupt enable
|
||||
#define AW20X_FLTCFG1_OTIE 0x04 // 1=overtemp interrupt enable
|
||||
#define AW20X_FLTCFG1_UVLOE 0x02 // 1=enable UVLO detect
|
||||
#define AW20X_FLTCFG1_OTE 0x01 // 1=enable overtemp detect
|
||||
|
||||
#define AW20X_FLTCFG1_UVTH_2V0 (0x00 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V1 (0x01 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V2 (0x02 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V3 (0x03 << 2) // UVLO threshold voltage
|
||||
|
||||
#define AW20X_ISRFLT_PAT2IS 0x40 // pattern controller 2 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_PAT1IS 0x20 // pattern controller 1 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_PAT0IS 0x10 // pattern controller 0 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_UVLOIS 0x02 // 0=normal, 1=UVLO detected
|
||||
#define AW20X_ISRFLT_OTIS 0x01 // 0=normal, 1=overtemp detected
|
||||
|
||||
// todo: fill in all values from PATCR onward
|
||||
|
||||
|
||||
|
||||
#define AW20X_SOFT_RESET AW20X_RSTR_SW_RSTN
|
||||
|
||||
enum aw20x_imax {
|
||||
AW20X_IMAX_10MA = 0x00,
|
||||
AW20X_IMAX_20MA = 0x10,
|
||||
AW20X_IMAX_30MA = 0x20,
|
||||
AW20X_IMAX_40MA = 0x30,
|
||||
AW20X_IMAX_60MA = 0x40,
|
||||
AW20X_IMAX_80MA = 0x50,
|
||||
AW20X_IMAX_120MA = 0x60,
|
||||
AW20X_IMAX_160MA = 0x70,
|
||||
AW20X_IMAX_3_3MA = 0x80,
|
||||
AW20X_IMAX_6_7MA = 0x90,
|
||||
AW20X_IMAX_10MA_2 = 0xa0,
|
||||
AW20X_IMAX_13_3MA = 0xb0,
|
||||
AW20X_IMAX_20MA_2 = 0xc0,
|
||||
AW20X_IMAX_26_7MA = 0xd0,
|
||||
AW20X_IMAX_40MA_2 = 0xe0,
|
||||
AW20X_IMAX_53_3MA = 0xf0
|
||||
};
|
||||
|
||||
enum aw20x_size {
|
||||
AW20X_SIZE_1COL = 0,
|
||||
AW20X_SIZE_2COL,
|
||||
AW20X_SIZE_3COL,
|
||||
AW20X_SIZE_4COL,
|
||||
AW20X_SIZE_5COL,
|
||||
AW20X_SIZE_6COL,
|
||||
AW20X_SIZE_7COL,
|
||||
AW20X_SIZE_8COL,
|
||||
AW20X_SIZE_9COL
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef SOFT_I2C_MASTER
|
||||
#define AW20X_I2C_busy() (0)
|
||||
#define AW20X_I2C_writereg(adr, reg, buf, siz) i2c_addr(adr, 1); i2c_wr(reg); i2c_wrbuf(buf, siz);
|
||||
#else
|
||||
#define AW20X_I2C_busy() (0)
|
||||
#define AW20X_I2C_writereg(adr, reg, buf, siz) i2c_write_addr1b(adr, reg, buf, siz);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct AW20x {
|
||||
uint8_t addr;
|
||||
uint8_t config; // settings for the chip
|
||||
uint8_t cols; // highest column used, 1-6
|
||||
uint8_t rows; // highest row used, 1-12
|
||||
uint8_t state; // keeps track of active page, and high bit is set if asleep
|
||||
uint8_t pad[3];
|
||||
uint8_t *fade; // led buffer location for FADE (required), of size cols+rows
|
||||
uint8_t *gain; // led buffer location for GAIN (optional), of size cols+rows
|
||||
} AW20x;
|
||||
|
||||
|
||||
|
||||
void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint8_t imax);
|
||||
|
||||
void aw20x_sleep(struct AW20x *aw, uint8_t sleep);
|
||||
|
||||
void aw20x_commit_fade(struct AW20x *aw);
|
||||
void aw20x_commit_dim_global(struct AW20x *aw, uint8_t dim);
|
||||
|
||||
void aw20x_led_enable(struct AW20x *aw, uint8_t first, uint8_t last);
|
||||
|
||||
|
||||
|
||||
#endif /* AW02X_LED_MATRIX_H */
|
||||
|
|
|
@ -14,10 +14,14 @@
|
|||
#include "ch32sub.h"
|
||||
#include "port_intr.h"
|
||||
|
||||
#include "../comm/i2c.h"
|
||||
|
||||
|
||||
|
||||
volatile uint8_t intr_flag = 0;
|
||||
|
||||
|
||||
|
||||
void ch32sub_isr()
|
||||
{
|
||||
// we'll check what the MCU has to say when we're done processing
|
||||
|
@ -45,3 +49,9 @@ void ch32sub_init()
|
|||
// configure interrupt to be rising edge
|
||||
GPIOB_ITModeCfg(SUB_INTR_PIN, GPIO_ITMode_RiseEdge);
|
||||
}
|
||||
|
||||
// things to do
|
||||
void ch32sub_rgb_hwen(uint8_t en)
|
||||
{
|
||||
i2c_addr(SUB_I2C_ADDR, 1);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
|
||||
|
||||
#define SUB_I2C_ADDR 0x5e
|
||||
|
||||
#define SUB_INTR_PORT GPIOB
|
||||
#define SUB_INTR_PIN GPIO_Pin_13
|
||||
#define SUB_INTR_PIN_NR 13
|
||||
|
@ -28,6 +30,8 @@
|
|||
void ch32sub_init();
|
||||
void ch32sub_process();
|
||||
|
||||
void ch32sub_rgb_hwen(uint8_t en);
|
||||
|
||||
|
||||
|
||||
#endif /* USER_DEVICE_CH32SUB_H_ */
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
/*
|
||||
* gat_gpio.c
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
* just gets the GAT ID and does nothing else.
|
||||
* but if you wanted to do things with the GPIO, this is where you could do it.
|
||||
*
|
||||
* hardware peripherals:
|
||||
* - GP1 has UART0 TX and PWM9.
|
||||
* - GP2 has UART0 RX and PWM7.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* rgbled.c
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#include <CH59x_common.h>
|
||||
|
||||
#include "rgbled.h"
|
||||
|
||||
#include "../device/aw20xxx.h"
|
||||
|
||||
|
||||
|
||||
#define AW20X_DIM 31 // initial global current setting
|
||||
|
||||
#define AW20X_COLS 4
|
||||
#define AW20X_ROWS 9
|
||||
#define AW20X_FADE_COUNT (AW20X_ROWS * AW20X_COLS)
|
||||
|
||||
|
||||
|
||||
static const uint16_t pwm_cie_256in_1024out[] = {
|
||||
0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
|
||||
7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15,
|
||||
15, 16, 17, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44,
|
||||
45, 47, 48, 50, 51, 52, 54, 55, 57, 58, 60, 61, 63, 65, 66, 68,
|
||||
70, 71, 73, 75, 77, 79, 81, 83, 84, 86, 88, 90, 93, 95, 97, 99,
|
||||
101, 103, 106, 108, 110, 113, 115, 118, 120, 123, 125, 128, 130, 133, 136, 138,
|
||||
141, 144, 147, 149, 152, 155, 158, 161, 164, 167, 171, 174, 177, 180, 183, 187,
|
||||
190, 194, 197, 200, 204, 208, 211, 215, 218, 222, 226, 230, 234, 237, 241, 245,
|
||||
249, 254, 258, 262, 266, 270, 275, 279, 283, 288, 292, 297, 301, 306, 311, 315,
|
||||
320, 325, 330, 335, 340, 345, 350, 355, 360, 365, 370, 376, 381, 386, 392, 397,
|
||||
403, 408, 414, 420, 425, 431, 437, 443, 449, 455, 461, 467, 473, 480, 486, 492,
|
||||
499, 505, 512, 518, 525, 532, 538, 545, 552, 559, 566, 573, 580, 587, 594, 601,
|
||||
609, 616, 624, 631, 639, 646, 654, 662, 669, 677, 685, 693, 701, 709, 717, 726,
|
||||
734, 742, 751, 759, 768, 776, 785, 794, 802, 811, 820, 829, 838, 847, 857, 866,
|
||||
875, 885, 894, 903, 913, 923, 932, 942, 952, 962, 972, 982, 992, 1002, 1013, 1023,
|
||||
};
|
||||
|
||||
|
||||
AW20x awled;
|
||||
static uint8_t awled_fade[AW20X_FADE_COUNT];
|
||||
|
||||
static uint8_t led_matrix_updated = 0;
|
||||
|
||||
|
||||
|
||||
void rgbled_init()
|
||||
{
|
||||
volatile uint32_t x;
|
||||
|
||||
ch32sub_rgb_hwen(1);
|
||||
|
||||
// wait a little while to ensure controller is awake
|
||||
x = GetSysClock() / 16384;
|
||||
while (x--);
|
||||
|
||||
aw20x_init(&awled, AW20X_ADDR_GND << 1, AW20X_COLS, AW20X_ROWS, AW20X_IMAX_13_3MA);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* rgbled.h
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_LED_RGBLED_H_
|
||||
#define USER_LED_RGBLED_H_
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../comm/i2c.h"
|
||||
|
||||
#include "../device/ch32sub.h"
|
||||
|
||||
|
||||
|
||||
void rgbled_init();
|
||||
|
||||
|
||||
|
||||
#endif /* USER_LED_RGBLED_H_ */
|
|
@ -1,19 +1,31 @@
|
|||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : Main.c
|
||||
* Author : WCH
|
||||
* Version : V1.0
|
||||
* Date : 2020/08/06
|
||||
* Description : 串口1收发演示
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* true's GAT Nametag
|
||||
* Rushed SUPERCON 8 EDITION
|
||||
* main MCU firmware
|
||||
* 2024 true
|
||||
*
|
||||
* the main MCU is responsible for the following:
|
||||
* - rendering OLED UI
|
||||
* - rendering LED programs
|
||||
* - storing fonts
|
||||
* - communicating with I2C devices, including:
|
||||
* - oled display, accelerometer
|
||||
* - eeprom, sub MCU, RGBLED controller
|
||||
* - implementing USB interface
|
||||
* - implementing BLE (maybe)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CH59x_common.h"
|
||||
|
||||
#include "port_intr.h"
|
||||
|
||||
#include "comm/i2c.h"
|
||||
|
||||
#include "gat/gat_gpio.h"
|
||||
|
||||
#include "led/rgbled.h"
|
||||
|
||||
#include "device/ch32sub.h"
|
||||
|
||||
|
||||
|
@ -24,120 +36,34 @@ void ch59x_xtal_conf()
|
|||
HSECFG_Capacitance(HSECap_14p);
|
||||
}
|
||||
|
||||
uint8_t TxBuff[] = "This is a tx exam\r\n";
|
||||
uint8_t RxBuff[100];
|
||||
uint8_t trigB;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn main
|
||||
*
|
||||
* @brief 主函数
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
//uint8_t len;
|
||||
|
||||
// configure clock
|
||||
ch59x_xtal_conf();
|
||||
SetSysClock(CLK_SOURCE_PLL_32MHz);
|
||||
SetSysClock(CLK_SOURCE_HSE_16MHz);
|
||||
|
||||
// enable DC-DC converter
|
||||
// enable DC-DC converter; brings significant power saving
|
||||
PWR_DCDCCfg(ENABLE);
|
||||
|
||||
// configure port-based interrupts
|
||||
// get i2c up and running
|
||||
i2c_init();
|
||||
|
||||
// configure port-based interrupts (used for chsub interrupt, mainly)
|
||||
port_intr_init();
|
||||
|
||||
// configure aux MCU initial settings, attention interrupt
|
||||
ch32sub_init();
|
||||
// and enable RGBLED controller hardware pin so the controller can wake up
|
||||
|
||||
// configure RGBLED controller
|
||||
rgbled_init();
|
||||
|
||||
// configure GAT aux GPIOs, get gat ID
|
||||
gat_gpio_init();
|
||||
// configure GAT i2c slave
|
||||
|
||||
|
||||
/*
|
||||
// 配置串口1:先配置IO口模式,再配置串口
|
||||
GPIOA_SetBits(GPIO_Pin_9);
|
||||
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); // RXD-配置上拉输入
|
||||
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
|
||||
UART1_DefInit();
|
||||
|
||||
#if 1 // 测试串口发送字符串
|
||||
UART1_SendString(TxBuff, sizeof(TxBuff));
|
||||
|
||||
#endif
|
||||
|
||||
#if 1 // 查询方式:接收数据后发送出去
|
||||
while(1)
|
||||
{
|
||||
len = UART1_RecvString(RxBuff);
|
||||
if(len)
|
||||
{
|
||||
UART1_SendString(RxBuff, len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if 0 // 中断方式:接收数据后发送出去
|
||||
UART1_ByteTrigCfg(UART_7BYTE_TRIG);
|
||||
trigB = 7;
|
||||
UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
|
||||
PFIC_EnableIRQ(UART1_IRQn);
|
||||
#endif
|
||||
*/
|
||||
|
||||
while(1) {
|
||||
// only care about aux MCU when all other processing is done
|
||||
ch32sub_process();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn UART1_IRQHandler
|
||||
*
|
||||
* @brief UART1中断函数
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
__INTERRUPT
|
||||
__HIGH_CODE
|
||||
void UART1_IRQHandler(void)
|
||||
{
|
||||
/*
|
||||
volatile uint8_t i;
|
||||
|
||||
switch(UART1_GetITFlag())
|
||||
{
|
||||
case UART_II_LINE_STAT: // 线路状态错误
|
||||
{
|
||||
UART1_GetLinSTA();
|
||||
break;
|
||||
}
|
||||
|
||||
case UART_II_RECV_RDY: // 数据达到设置触发点
|
||||
for(i = 0; i != trigB; i++)
|
||||
{
|
||||
RxBuff[i] = UART1_RecvByte();
|
||||
UART1_SendByte(RxBuff[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
|
||||
i = UART1_RecvString(RxBuff);
|
||||
UART1_SendString(RxBuff, i);
|
||||
break;
|
||||
|
||||
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
|
||||
break;
|
||||
|
||||
case UART_II_MODEM_CHG: // 只支持串口0
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
/*
|
||||
* port_intr.c
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
* notes:
|
||||
*
|
||||
* - pins 22 and 23 are shifted into pins 9 and 10,
|
||||
* so configure these pins if you want to use them.
|
||||
*
|
||||
* - maximum real possible then is 22 entries.
|
||||
* I have no need above 15 so that's the maximum I set.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CH59x_common.h"
|
||||
|
@ -12,16 +18,25 @@
|
|||
|
||||
|
||||
|
||||
static void (*cb[2][24])(void) = {0};
|
||||
#define MAX_PIN 15+1
|
||||
|
||||
|
||||
|
||||
static void (*cb[2][MAX_PIN-4])(void) = {0};
|
||||
|
||||
|
||||
|
||||
void port_intr_cb_register(uint8_t port, uint8_t idx, void (*fn)(void))
|
||||
{
|
||||
if (idx >= 24) return;
|
||||
if (idx == 22) idx = 9;
|
||||
if (idx == 23) idx = 10;
|
||||
|
||||
if (idx < 4) return;
|
||||
if (idx > MAX_PIN) return;
|
||||
|
||||
if (port > 2) return;
|
||||
|
||||
cb[port][idx] = fn;
|
||||
cb[port][idx - 4] = fn;
|
||||
}
|
||||
|
||||
void port_intr_init()
|
||||
|
@ -46,6 +61,9 @@ void GPIOB_IRQHandler(void)
|
|||
uint8_t i;
|
||||
uint16_t flag = R16_PB_INT_IF;
|
||||
|
||||
// clear flags
|
||||
R16_PB_INT_IF = flag;
|
||||
|
||||
// high priority actions
|
||||
// none.
|
||||
|
||||
|
@ -58,6 +76,5 @@ void GPIOB_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
// clear flags
|
||||
R16_PB_INT_IF = flag;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue