more i2c slave work
this code is still surely not working, is incomplete, and guaranteed has problems
This commit is contained in:
parent
6be6cee2ac
commit
52435ea3f0
|
@ -16,8 +16,8 @@
|
|||
|
||||
|
||||
|
||||
#define I2CSS_ERR_TIMEOUT 3 // timeout in bit-times before i2c slave releases control
|
||||
#define I2CSS_IDLE_TIMEOUT 4 // idle timeout required in bit-times before i2c slave can be addressed again
|
||||
#define I2CSS_ERR_TIMEOUT 10 // timeout in bit-times before i2c slave releases control
|
||||
#define I2CSS_IDLE_TIMEOUT 3 // idle timeout required in bit-times before i2c slave can be addressed again
|
||||
|
||||
|
||||
// todo: use with struct instead of hard-coding to allow for multiple slaves, but make it fast too
|
||||
|
@ -84,8 +84,8 @@ static inline int8_t i2css_ack(uint16_t bit_time)
|
|||
|
||||
SDA_OUTLO();
|
||||
|
||||
if (i2css_wait_for_scl_hi()) return I2CSS_ACK_ERROR;
|
||||
ret = i2css_wait_for_scl_lo();
|
||||
if (i2css_wait_for_scl_hi()) ret = I2CSS_ACK_ERROR;
|
||||
else ret = i2css_wait_for_scl_lo();
|
||||
|
||||
SDA_IN_HI();
|
||||
|
||||
|
@ -308,8 +308,19 @@ int8_t i2css_blocking(struct I2CSoftSlave *slave)
|
|||
__HIGH_CODE
|
||||
int8_t i2css_start(struct I2CSoftSlave *slave)
|
||||
{
|
||||
int8_t ret;
|
||||
uint8_t scl;
|
||||
|
||||
if (idle_timeout) {
|
||||
// we're still waiting for bus idle time before we reply to requests
|
||||
// this will now reset the timeout
|
||||
if (idle_timeout < I2CSS_IDLE_TIMEOUT) {
|
||||
idle_timeout = I2CSS_IDLE_TIMEOUT;
|
||||
}
|
||||
|
||||
return I2CSS_IN_TIMEOUT;
|
||||
}
|
||||
|
||||
// idle our clock and check for start/stop
|
||||
SCL_IN_HI();
|
||||
scl = SCL_GET();
|
||||
|
@ -317,14 +328,25 @@ int8_t i2css_start(struct I2CSoftSlave *slave)
|
|||
// module will use this bit time for this communication
|
||||
bit_time = slave->bit_time;
|
||||
|
||||
// ensure SDA pin will go low when set as an output
|
||||
// if SCL is high, this may be a start condition.
|
||||
if (scl) {
|
||||
ret = i2css_blocking(slave);
|
||||
} else ret = I2CSS_BUS_BUSY;
|
||||
|
||||
R16_PA_INT_IF = 1 << SDA_PIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i2css_init()
|
||||
{
|
||||
// configure GPIO
|
||||
SCL_IN_HI();
|
||||
SCL_SET_LO();
|
||||
|
||||
SDA_IN_HI();
|
||||
SDA_SET_LO();
|
||||
|
||||
// if SCL is high, this should be a start condition.
|
||||
if (scl) {
|
||||
return i2css_blocking(slave);
|
||||
}
|
||||
|
||||
// if it isn't, there must be some other communication going on, and it doesn't involve us
|
||||
return I2CSS_BUS_BUSY;
|
||||
// configure interrupt
|
||||
GPIOA_ITModeCfg(1 << SDA_PIN, GPIO_ITMode_FallEdge);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,10 @@ typedef struct I2CSoftSlave {
|
|||
uint8_t addr;
|
||||
uint8_t addr_last_seen;
|
||||
uint16_t bit_time;
|
||||
void (*start_cb)(); // call on any new read/write operation
|
||||
void (*start_cb)(); // call on any new read/write operation
|
||||
uint8_t (*rd_cb)(); // returns data
|
||||
int8_t (*wr_cb)(uint8_t data); // return 0 to ACK, all other NACK
|
||||
void (*err_cb)(uint8_t); // called if there was an error during transfer
|
||||
} I2CSoftSlave;
|
||||
|
||||
|
||||
|
@ -29,6 +30,7 @@ enum I2CSoftSlave_Error {
|
|||
I2CSS_STOP,
|
||||
I2CSS_NACK,
|
||||
I2CSS_ADDR_NO_MATCH,
|
||||
I2CSS_IN_TIMEOUT,
|
||||
// errors
|
||||
I2CSS_START_SCL_NOT_LOW = -1,
|
||||
I2CSS_ADDR_READ_ERROR = -2, // could be timeout, start or stop condition detected
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* i2c_slave_handler.c
|
||||
*
|
||||
* Created on: Oct 30, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#include "soft_i2c_slave_handler.h"
|
||||
#include "soft_i2c_slave.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
struct I2CSoftSlave addon_i2c;
|
||||
|
||||
|
||||
|
||||
void i2css_addon_init()
|
||||
{
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* soft_i2c_slave_handler.h
|
||||
*
|
||||
* Created on: Oct 30, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_
|
||||
#define USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_
|
||||
|
||||
|
||||
|
||||
extern struct I2CSoftSlave addon_i2c;
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMM_SOFT_I2C_SLAVE_HANDLER_H_ */
|
|
@ -1,15 +1,38 @@
|
|||
/*
|
||||
* gat_i2c.c
|
||||
*
|
||||
* Created on: Oct 11, 2024
|
||||
* Author: true
|
||||
*
|
||||
* implements a shoddy i2c slave.
|
||||
* implements a shoddy i2c slave for the addon header.
|
||||
* maximum speed 100KHz tested.
|
||||
* note: not yet tested.
|
||||
*
|
||||
* data is segmented by page. read always starts from byte 0 of selected page.
|
||||
*
|
||||
* write begins with 1 byte page index, followed by offset / index, followed by data.
|
||||
*
|
||||
*
|
||||
* pages:
|
||||
*
|
||||
* - general: user input emulation and config functions.
|
||||
* data size is 2 bytes.
|
||||
* - 0: button input push mask. 0b0000_TL_TR_BR_BL.
|
||||
* - 1: button release mask.
|
||||
* - 2: nametag i2c clear timeout in frames. reverts to programmed name at 0. 0xff to disable.
|
||||
* not yet implemented.
|
||||
*
|
||||
* - nametag: live update the nae shown in nametag mode.
|
||||
* data size 16 bytes. byte 0 is length, bytes 1-15 are name data.
|
||||
* this does not change the nametag in settings / nvram, only the live update.
|
||||
* any update to this page will set general[1] to 0x20 if general[1] is not set to 0xff.
|
||||
* if length == 0, normal name will be shown. for empty screen, send a space character with length = 1.
|
||||
* example data:
|
||||
* 0x84 (addr), 0x01 (nametag), 0x00 (start at first byte), 0x06 (name is 6 chars long), "Hello!"
|
||||
*
|
||||
* - raw: send raw data to the oled. send in 128 byte chunks.
|
||||
* not yet implemented.
|
||||
*/
|
||||
|
||||
#include <CH59x_common.h>
|
||||
#include "global.h"
|
||||
|
||||
#include "gat_gpio.h"
|
||||
|
||||
|
@ -19,104 +42,201 @@
|
|||
|
||||
|
||||
|
||||
#define GAT_ADDR_BASE 0x30
|
||||
#define GAT_I2C_SPEED 100000
|
||||
#define GAT_ADDR_BASE 0x30
|
||||
#define GAT_I2C_SPEED 100000
|
||||
|
||||
#define GAT_DATA_SIZE 256
|
||||
#define GAT_DATA_SIZE 128
|
||||
|
||||
#define GAT_PAGE_GENERAL 0
|
||||
#define GAT_PAGE_NAMETAG_TEXT 1
|
||||
#define GAT_PAGE_RAW1 2
|
||||
#define GAT_PAGE_RAW2 3
|
||||
#define GAT_PAGE_RAW3 4
|
||||
#define GAT_PAGE_RAW4 5
|
||||
|
||||
#define GAT_PAGESIZE_GENERAL 3
|
||||
#define GAT_PAGESIZE_NAMETAG 16
|
||||
|
||||
|
||||
|
||||
struct I2CSoftSlave gat_slave;
|
||||
struct I2CSoftSlave addon_i2c;
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
GAT_MODE_STARTING,
|
||||
GAT_MODE_READ,
|
||||
GAT_MODE_WRITE
|
||||
I2C_STATE_STARTING,
|
||||
I2C_STATE_READ,
|
||||
I2C_STATE_OFFSET,
|
||||
I2C_STATE_WRITE
|
||||
};
|
||||
|
||||
|
||||
uint8_t gat_state;
|
||||
uint16_t gat_data_idx;
|
||||
uint8_t gat_data[GAT_DATA_SIZE];
|
||||
static uint8_t i2c_state;
|
||||
|
||||
static uint8_t gat_page = 0;
|
||||
static uint8_t gat_offset;
|
||||
|
||||
static uint8_t page_general[GAT_PAGESIZE_GENERAL];
|
||||
|
||||
|
||||
|
||||
uint8_t gat_i2c_read_cb()
|
||||
// page functions
|
||||
static uint8_t gat_read(uint8_t *page, uint8_t maxlen)
|
||||
{
|
||||
uint8_t ret;
|
||||
if (gat_offset > maxlen) return 0xff;
|
||||
else return page[gat_offset++];
|
||||
}
|
||||
|
||||
switch (gat_state) {
|
||||
case GAT_MODE_STARTING: {
|
||||
gat_state = GAT_MODE_READ;
|
||||
// no break
|
||||
uint8_t gat_page_general_get(uint8_t idx)
|
||||
{
|
||||
if (idx > sizeof(page_general)) return 0;
|
||||
else return page_general[idx];
|
||||
}
|
||||
|
||||
uint8_t gat_page_general_set(uint8_t idx, uint8_t dat)
|
||||
{
|
||||
if (idx >= sizeof(page_general)) return I2CSS_NACK;
|
||||
page_general[idx] = dat;
|
||||
return I2CSS_OK;
|
||||
}
|
||||
|
||||
|
||||
// i2c comms functions
|
||||
void addon_i2c_start_cb()
|
||||
{
|
||||
i2c_state = I2C_STATE_STARTING;
|
||||
}
|
||||
|
||||
// master reading from addon
|
||||
__HIGH_CODE
|
||||
uint8_t addon_i2c_read_cb()
|
||||
{
|
||||
switch (i2c_state) {
|
||||
case I2C_STATE_STARTING: {
|
||||
i2c_state = I2C_STATE_READ;
|
||||
gat_offset = 0;
|
||||
}
|
||||
case GAT_MODE_READ: {
|
||||
// no break
|
||||
|
||||
case I2C_STATE_READ: {
|
||||
// can't read past end of buffer; just send 0xff
|
||||
if (gat_data_idx == GAT_DATA_SIZE) {
|
||||
ret = 0xff;
|
||||
} else {
|
||||
ret = gat_data[gat_data_idx & 0xff];
|
||||
if (gat_data_idx <= GAT_DATA_SIZE) gat_data_idx++;
|
||||
switch (gat_page) {
|
||||
case GAT_PAGE_GENERAL: {
|
||||
return gat_read(page_general, GAT_PAGESIZE_GENERAL);
|
||||
}
|
||||
case GAT_PAGE_NAMETAG_TEXT: {
|
||||
// to implement
|
||||
break;
|
||||
}
|
||||
case GAT_PAGE_RAW1:
|
||||
case GAT_PAGE_RAW2:
|
||||
case GAT_PAGE_RAW3:
|
||||
case GAT_PAGE_RAW4: {
|
||||
// to implement
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
// data wasn't sent above, so send empty byte
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t gat_i2c_write_cb(uint8_t dat)
|
||||
// master writing to addon
|
||||
__HIGH_CODE
|
||||
int8_t addon_i2c_write_cb(uint8_t dat)
|
||||
{
|
||||
switch (gat_state) {
|
||||
int8_t ret = I2CSS_OK;
|
||||
|
||||
case GAT_MODE_STARTING: {
|
||||
switch (i2c_state) {
|
||||
case I2C_STATE_STARTING: {
|
||||
// master wrote our address
|
||||
gat_data_idx = dat;
|
||||
gat_state = GAT_MODE_WRITE;
|
||||
gat_page = dat;
|
||||
i2c_state = I2C_STATE_OFFSET;
|
||||
break;
|
||||
}
|
||||
case GAT_MODE_WRITE: {
|
||||
if (gat_data_idx >= GAT_DATA_SIZE) {
|
||||
return I2CSS_NACK;
|
||||
} else {
|
||||
gat_data[gat_data_idx++] = dat;
|
||||
|
||||
case I2C_STATE_OFFSET: {
|
||||
gat_offset = dat;
|
||||
i2c_state = I2C_STATE_WRITE;
|
||||
|
||||
if (gat_offset > GAT_DATA_SIZE) {
|
||||
gat_offset = GAT_DATA_SIZE;
|
||||
ret = I2CSS_NACK;
|
||||
}
|
||||
return I2CSS_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case I2C_STATE_WRITE: {
|
||||
if (gat_offset >= GAT_DATA_SIZE) {
|
||||
ret = I2CSS_NACK;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (gat_page) {
|
||||
case GAT_PAGE_GENERAL: {
|
||||
ret = gat_page_general_set(gat_offset, dat);
|
||||
break;
|
||||
}
|
||||
case GAT_PAGE_NAMETAG_TEXT: {
|
||||
// to implement
|
||||
ret = I2CSS_NACK;
|
||||
break;
|
||||
}
|
||||
case GAT_PAGE_RAW1:
|
||||
case GAT_PAGE_RAW2:
|
||||
case GAT_PAGE_RAW3:
|
||||
case GAT_PAGE_RAW4: {
|
||||
// to implement
|
||||
ret = I2CSS_NACK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gat_offset++;
|
||||
}
|
||||
|
||||
default: {
|
||||
return I2CSS_NACK;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gat_i2c_start_cb()
|
||||
void addon_i2c_err_cb(uint8_t error)
|
||||
{
|
||||
gat_state = GAT_MODE_STARTING;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gat_i2c_init()
|
||||
void addon_i2c_init()
|
||||
{
|
||||
// determine I2C address from GP pin identification
|
||||
gat_slave.addr = gat_id + GAT_ADDR_BASE;
|
||||
addon_i2c.addr = gat_id + GAT_ADDR_BASE;
|
||||
|
||||
// roughly guess bit time length for expected speed
|
||||
gat_slave.bit_time = GetSysClock() / GAT_I2C_SPEED / 4;
|
||||
addon_i2c.bit_time = GetSysClock() / GAT_I2C_SPEED / 2;
|
||||
|
||||
// set up callbacks
|
||||
gat_slave.start_cb = gat_i2c_start_cb;
|
||||
gat_slave.rd_cb = gat_i2c_read_cb;
|
||||
gat_slave.wr_cb = gat_i2c_write_cb;
|
||||
addon_i2c.start_cb = addon_i2c_start_cb;
|
||||
addon_i2c.rd_cb = addon_i2c_read_cb;
|
||||
addon_i2c.wr_cb = addon_i2c_write_cb;
|
||||
addon_i2c.err_cb = addon_i2c_err_cb;
|
||||
|
||||
// enable interrupt on SDA pin to detect start condition
|
||||
// this assumes GPIO has already been configured
|
||||
// configure i2c pins and pin interrupt
|
||||
i2css_init();
|
||||
}
|
||||
|
||||
void gat_i2c_irq_cb()
|
||||
void addon_i2c_irq_cb()
|
||||
{
|
||||
i2css_start(&gat_slave);
|
||||
SetSysClock(SYSCLK_FREQ_USEI2C);
|
||||
i2css_start(&addon_i2c);
|
||||
SetSysClock(SYSCLK_FREQ_IDLE);
|
||||
}
|
||||
|
|
|
@ -10,4 +10,13 @@
|
|||
|
||||
|
||||
|
||||
void addon_i2c_init();
|
||||
|
||||
void addon_i2c_irq_cb();
|
||||
|
||||
uint8_t gat_page_general_get(uint8_t idx);
|
||||
void gat_page_general_set(uint8_t idx, uint8_t dat);
|
||||
|
||||
|
||||
|
||||
#endif /* USER_GAT_GAT_I2C_H_ */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "comm/i2c.h"
|
||||
|
||||
#include "hw/gat/gat_gpio.h"
|
||||
#include "hw/gat/gat_i2c.h"
|
||||
|
||||
#include "led/rgbled.h"
|
||||
|
||||
|
@ -133,7 +134,7 @@ void rtcisr_init()
|
|||
|
||||
rtc_reset_trig();
|
||||
|
||||
PFIC_SetPriority(RTC_IRQn, 0x10); // rtc is second highest priority interrupt
|
||||
PFIC_SetPriority(RTC_IRQn, 0x00); // rtc is highest priority interrupt
|
||||
PFIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
|
@ -403,7 +404,7 @@ int main()
|
|||
rgbled_init(); // initialize RGBLED controller
|
||||
|
||||
gat_gpio_init(); // configure GAT aux GPIOs, get gat ID
|
||||
// todo: implement // configure GAT i2c slave
|
||||
addon_i2c_init(); // 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
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
#include "CH59x_common.h"
|
||||
#include "port_intr.h"
|
||||
|
||||
#include "comm/soft_i2c_slave.h"
|
||||
#include "comm/soft_i2c_slave_handler.h"
|
||||
|
||||
#include "hw/ch32sub.h"
|
||||
#include "hw/gat/gat_i2c.h"
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -50,7 +48,7 @@ void port_intr_init()
|
|||
// clear state
|
||||
R16_PB_INT_IF = 0xff;
|
||||
|
||||
PFIC_SetPriority(GPIO_A_IRQn, 0x00); // high priority
|
||||
PFIC_SetPriority(GPIO_A_IRQn, 0x10); // high priority
|
||||
PFIC_EnableIRQ(GPIO_A_IRQn);
|
||||
|
||||
// then enable interrupt
|
||||
|
@ -72,9 +70,7 @@ void GPIOA_IRQHandler(void)
|
|||
|
||||
// addon header i2c data pin
|
||||
if (flag & (1 << 13)) {
|
||||
SetSysClock(SYSCLK_FREQ_USEI2C);
|
||||
i2css_start(&addon_i2c);
|
||||
SetSysClock(SYSCLK_FREQ_IDLE);
|
||||
addon_i2c_irq_cb();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ void uconf_defaults()
|
|||
|
||||
uconf.ledprog_rgb_idx = 4;
|
||||
|
||||
uconf.addon_i2c_addr = 0;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uconf.ledprog_rgb[i] = 0;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ typedef struct UserConf {
|
|||
uint8_t altcolor_sat;
|
||||
uint8_t altcolor_val; // 50
|
||||
uint8_t ledprog_rgb_idx;
|
||||
uint8_t padding0; // 52
|
||||
uint8_t addon_i2c_addr; // 52
|
||||
uint8_t ledprog_rgb[16]; // 68
|
||||
uint8_t ledprog_rgb_data[16][8]; // 196
|
||||
uint8_t padding1[48]; // 244
|
||||
|
|
Loading…
Reference in New Issue