initial WIP

lots of code copied over, things filled in to hopefully get the LED matrix lighting up. untested.
This commit is contained in:
true
2026-05-08 11:54:12 -07:00
commit d95af918fa
77 changed files with 24395 additions and 0 deletions

92
firmware/app/comms/i2c.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* i2c.h
*
* Created on: Oct 13, 2024
* Author: true
*/
#ifndef USER_COMMS_I2C_H_
#define USER_COMMS_I2C_H_
#include "ch32x035_conf.h"
#define SOFT_I2C_MASTER
#ifdef SOFT_I2C_MASTER
#include "soft_i2c_master.h"
/* known bugs / limitations:
* - there is no ack on address. code always assumes slave is responding.
*/
#define i2c_init() i2cm_init()
#define i2c_start() { SetSysClock_HSI(HCLK_24MHZ); i2cm_start(); }
#define i2c_restart() i2cm_restart()
#define i2c_stop() { i2cm_stop(); SetSysClock_HSI(HCLK_8MHZ); }
#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, s) i2cm_rdbuf(d, s); i2c_stop()
#define i2c_wrbuf(d, s) i2cm_wrbuf(d, s); i2c_stop()
#define i2c_read(a, d, s) i2c_start(); \
i2cm_addr(a, 1); \
i2cm_rdbuf(d, s); \
i2c_stop()
#define i2c_read_reg8(a, r, d, s) i2c_start(); \
i2cm_addr(a, 0); \
i2cm_wr(r); \
i2cm_restart(); \
i2cm_addr(a, 1); \
i2cm_rdbuf(d, s); \
i2c_stop()
#define i2c_read_reg16(a, r, d, s) i2c_start(); \
i2cm_addr(a, 0); \
i2cm_wr(r >> 8); \
i2cm_wr(r & 0xff); \
i2cm_restart(); \
i2cm_addr(a, 1); \
i2cm_rdbuf(d, s); \
i2c_stop()
#define i2c_write(a, d, s) i2c_start(); \
i2cm_addr(a, 0); \
i2cm_wrbuf(d, s); \
i2c_stop()
#define i2c_write_reg8(a, r, d, s) i2c_start(); \
i2cm_addr(a, 0); \
i2cm_wr(r); \
i2cm_wrbuf(d, s); \
i2c_stop()
#define i2c_write_reg16(a, r, d, s) i2c_start(); \
i2cm_addr(a, 0); \
i2cm_wr(r >> 8); \
i2cm_wr(r & 0xff); \
i2cm_wrbuf(d, s); \
i2c_stop()
#else
#error HW I2C NOT YET IMPLEMENTED!
#endif
#endif /* USER_COMMS_I2C_H_ */

View File

@@ -0,0 +1,222 @@
/*
* soft_i2c.c
*
* looked at random i2c code, used as inspiration, and wrote some
* garbage for CH59x. then ported to CH32X035.
*
* i2c hardware peripheral on CH59x is shared with debug pins or.
* USB pins. using both? touch shit, no I2C master periph for you.
*
* 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 at 32MHz on CH59x:
* 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
*
* speed settings chosen are what the lowest speed device (the sub MCU) will
* handle without faults.
*
*/
#include <ch32x035_conf.h>
#include <stdint.h>
#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 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 9
#define SDA_BIT (1 << SDA_PIN)
#define SDA_CONFOFF ((SDA_PIN % 8) * 4)
#define SDA_GPIO GPIOB
#define SDA_CFGR GPIOB->CFGHR
#define SCL_PIN 8
#define SCL_BIT (1 << SCL_PIN)
#define SCL_CONFOFF ((SCL_PIN % 8) * 4)
#define SCL_GPIO GPIOB
#define SCL_CFGR GPIOB->CFGHR
#define GPIO_CFG_LO 0x1
#define GPIO_CFG_HI 0x8
#define SDA_IN_HI() { SDA_CFGR &= ~(0xf << SDA_CONFOFF); SDA_CFGR |= (GPIO_CFG_HI << SDA_CONFOFF); }
#define SDA_OUTLO() { SDA_CFGR &= ~(0xf << SDA_CONFOFF); SDA_CFGR |= (GPIO_CFG_LO << SDA_CONFOFF); }
#define SDA_SET_LO() SDA_GPIO->BCR = SDA_BIT
#define SDA_GET() ( SDA_GPIO->INDR & SDA_BIT )
#define SCL_IN_HI() { SCL_CFGR &= ~(0xf << SCL_CONFOFF); SCL_CFGR |= (GPIO_CFG_HI << SCL_CONFOFF); }
#define SCL_OUTLO() { SCL_CFGR &= ~(0xf << SCL_CONFOFF); SCL_CFGR |= (GPIO_CFG_LO << SCL_CONFOFF); }
#define SCL_SET_LO() SCL_GPIO->BCR = SCL_BIT
#define SCL_GET() ( SCL_GPIO->INDR & SCL_BIT )
static uint16_t delay_hi, delay_lo;
static volatile uint16_t 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_TO_HI;
delay_lo = CYCLES_TO_LO;
}
__attribute__((section(".ramfunc")))
void i2cm_start()
{
SDA_IN_HI(); bit_delay_hi();
SCL_IN_HI(); bit_delay_hi();
while (!SCL_GET()) {}; // clock stretch
SDA_OUTLO(); bit_delay_lo();
SCL_OUTLO(); bit_delay_lo();
}
__attribute__((section(".ramfunc")))
void i2cm_restart()
{
SDA_IN_HI(); bit_delay_hi();
SCL_IN_HI();
while (!SCL_GET()) {}; // clock stretch
bit_delay_hi(); // attempt to fix corruption; unnecessary?
i2cm_start();
}
__attribute__((section(".ramfunc")))
void i2cm_stop()
{
SDA_OUTLO(); bit_delay_lo();
SCL_IN_HI(); bit_delay_hi();
while (!SCL_GET()) {}; // clock stretch
SDA_IN_HI(); bit_delay_hi();
bit_delay_hi();
bit_delay_hi();
bit_delay_hi();
}
// returns: data byte
__attribute__((section(".ramfunc")))
uint8_t i2cm_rd(uint8_t ack)
{
int8_t x;
uint8_t 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(); bit_delay_lo();
}
if (ack) { SDA_OUTLO(); } // ack
else { SDA_IN_HI(); } // nack
SCL_IN_HI(); bit_delay_hi();
SCL_OUTLO(); bit_delay_lo();
return in;
}
// returns: possible ack from target
__attribute__((section(".ramfunc")))
uint8_t i2cm_wr(uint8_t dat)
{
int8_t x;
uint8_t ack;
SCL_OUTLO();
for (x = 8; x; x--) {
if (dat & 0x80) { SDA_IN_HI(); }
else { SDA_OUTLO(); }
SCL_IN_HI();
while (!SCL_GET()) {}; // clock stretch
wr_delay_hi();
dat <<= 1;
SCL_OUTLO(); bit_delay_lo();
}
SDA_IN_HI(); __asm__ volatile("nop"); // slave will now try to ack
SCL_IN_HI(); bit_delay_hi();
while (!SCL_GET()); // nothing should stretch here, but...
ack = SDA_GET();
SCL_OUTLO(); bit_delay_lo();
return ack;
}
// use a left-aligned address with this implementation.
__attribute__((section(".ramfunc")))
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit)
{
addr &= 0xfe;
addr |= reading_bit ? 1 : 0;
return i2cm_wr(addr);
}
void i2cm_rdbuf(uint8_t *dat, uint16_t len)
{
while (len--) *dat++ = i2cm_rd(len > 0);
// i2cm_stop();
}
void i2cm_wrbuf(const uint8_t *dat, uint16_t len)
{
uint8_t nack;
while (len--) {
nack = i2cm_wr(*dat++);
if (nack) break;
}
// i2cm_stop();
}

View File

@@ -0,0 +1,28 @@
/*
* soft_i2c.h
*/
#ifndef USER_COMM_SOFT_I2C_MASTER_H_
#define USER_COMM_SOFT_I2C_MASTER_H_
#include <ch32x035.h>
#include <stdint.h>
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 reading_bit);
void i2cm_rdbuf(uint8_t *dat, uint16_t len);
void i2cm_wrbuf(const uint8_t *dat, uint16_t len);
#endif /* USER_COMM_SOFT_I2C_MASTER_H_ */

View File

@@ -0,0 +1,67 @@
/*
* spi_master.c
*
* manage chip select externally.
*
* current version is BLOCKING. update later to use interrupt or DMA.
*/
#include "spi_master.h"
void spim_init()
{
SPI_InitTypeDef spi = {0};
spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_DataSize = SPI_DataSize_8b;
spi.SPI_CPOL = SPI_CPOL_High;
spi.SPI_CPHA = SPI_CPHA_2Edge;
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
spi.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &spi);
SPI_Cmd(SPI1, ENABLE);
}
void spim_write_raw(const uint8_t *data, uint16_t len)
{
// todo: make non-blocking, timeout and error checking
while (len) {
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)) {
SPI_I2S_SendData(SPI1, *data);
data++;
len--;
}
}
}
void spim_write_reg8(uint8_t reg, const uint8_t *data, uint16_t len)
{
spim_write_raw(&reg, 1);
spim_write_raw(data, len);
}
void spim_read_raw(uint8_t *data, uint16_t len)
{
// todo: non-blocking, timeout and error checking
while (len) {
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)) {};
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)) {
*data++ = SPI_I2S_ReceiveData(SPI1);
len--;
}
SPI_I2S_SendData(SPI1, 0);
}
}
void spim_read_reg8(uint8_t reg, uint8_t *data, uint16_t len)
{
spim_write_raw(&reg, 1);
spim_read_raw(data, len);
}

View File

@@ -0,0 +1,20 @@
/*
*
*/
#ifndef __APP_COMMS_SPI_MASTER_H
#define __APP_COMMS_SPI_MASTER_H
#include "ch32x035_conf.h"
void spim_init();
void spim_write_reg8(uint8_t reg, const uint8_t *data, uint16_t len);
void spim_read_reg8(uint8_t reg, uint8_t *data, uint16_t len);
#endif /* __APP_COMMS_SPI_MASTER_H */