stm32/i2cslave: Add functions to read/write I2C data.

Instead of requiring the callback to consume/provide the data.  This allows
the data to be consumed/provided later on, which will stretch the I2C clock
until that occurs.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2025-08-01 17:02:53 +10:00
parent a4ca42f094
commit 17d0449ac8
3 changed files with 38 additions and 12 deletions

View file

@ -45,10 +45,12 @@ void i2c_slave_irq_handler(i2c_slave_t *i2c) {
i2c_slave_process_addr_match(i2c, (sr2 >> I2C_SR2_TRA_Pos) & 1);
}
if (sr1 & I2C_SR1_TXE) {
i2c->DR = i2c_slave_process_tx_byte(i2c);
// This callback must call i2c_slave_write_byte.
i2c_slave_process_tx_byte(i2c);
}
if (sr1 & I2C_SR1_RXNE) {
i2c_slave_process_rx_byte(i2c, i2c->DR);
// This callback must call i2c_slave_read_byte.
i2c_slave_process_rx_byte(i2c);
}
if (sr1 & I2C_SR1_STOPF) {
// STOPF only set at end of RX mode (in TX mode AF is set on NACK)
@ -80,10 +82,12 @@ void i2c_slave_irq_handler(i2c_slave_t *i2c) {
i2c_slave_process_addr_match(i2c, (i2c->ISR >> I2C_ISR_DIR_Pos) & 1);
}
if (isr & I2C_ISR_TXIS) {
i2c->TXDR = i2c_slave_process_tx_byte(i2c);
// This callback must call i2c_slave_write_byte.
i2c_slave_process_tx_byte(i2c);
}
if (isr & I2C_ISR_RXNE) {
i2c_slave_process_rx_byte(i2c, i2c->RXDR);
// This callback must call i2c_slave_read_byte.
i2c_slave_process_rx_byte(i2c);
}
if (isr & I2C_ISR_STOPF) {
// STOPF only set for STOP condition, not a repeated START

View file

@ -28,6 +28,8 @@
#include STM32_HAL_H
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32WB)
#if !defined(I2C2_BASE)
// This MCU doesn't have I2C2_BASE, define it so that the i2c_idx calculation works.
#define I2C2_BASE (I2C1_BASE + ((I2C3_BASE - I2C1_BASE) / 2))
@ -78,13 +80,31 @@ static inline void i2c_slave_shutdown(i2c_slave_t *i2c, int irqn) {
NVIC_DisableIRQ(irqn);
}
static inline void i2c_slave_write_byte(i2c_slave_t *i2c, uint8_t value) {
#if defined(STM32F4)
i2c->DR = value;
#else
i2c->TXDR = value;
#endif
}
static inline uint8_t i2c_slave_read_byte(i2c_slave_t *i2c) {
#if defined(STM32F4)
return i2c->DR;
#else
return i2c->RXDR;
#endif
}
void i2c_slave_irq_handler(i2c_slave_t *i2c);
// These should be provided externally
int i2c_slave_process_addr_match(i2c_slave_t *i2c, int rw);
int i2c_slave_process_rx_byte(i2c_slave_t *i2c, uint8_t val);
int i2c_slave_process_rx_byte(i2c_slave_t *i2c);
void i2c_slave_process_rx_end(i2c_slave_t *i2c);
uint8_t i2c_slave_process_tx_byte(i2c_slave_t *i2c);
void i2c_slave_process_tx_byte(i2c_slave_t *i2c);
void i2c_slave_process_tx_end(i2c_slave_t *i2c);
#endif
#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H

View file

@ -805,9 +805,9 @@ int i2c_slave_process_addr_match(i2c_slave_t *i2c, int rw) {
return 0; // ACK
}
int i2c_slave_process_rx_byte(i2c_slave_t *i2c, uint8_t val) {
int i2c_slave_process_rx_byte(i2c_slave_t *i2c) {
if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) {
i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = val;
i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = i2c_slave_read_byte(i2c);
}
return 0; // ACK
}
@ -909,15 +909,17 @@ void i2c_slave_process_rx_end(i2c_slave_t *i2c) {
i2c_obj.cmd_arg_sent = false;
}
uint8_t i2c_slave_process_tx_byte(i2c_slave_t *i2c) {
void i2c_slave_process_tx_byte(i2c_slave_t *i2c) {
uint8_t value;
if (i2c_obj.cmd_send_arg) {
i2c_obj.cmd_arg_sent = true;
return i2c_obj.cmd_arg;
value = i2c_obj.cmd_arg;
} else if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) {
return i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++];
value = i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++];
} else {
return 0;
value = 0;
}
i2c_slave_write_byte(i2c, value);
}
void i2c_slave_process_tx_end(i2c_slave_t *i2c) {