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); i2c_slave_process_addr_match(i2c, (sr2 >> I2C_SR2_TRA_Pos) & 1);
} }
if (sr1 & I2C_SR1_TXE) { 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) { 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) { if (sr1 & I2C_SR1_STOPF) {
// STOPF only set at end of RX mode (in TX mode AF is set on NACK) // 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); i2c_slave_process_addr_match(i2c, (i2c->ISR >> I2C_ISR_DIR_Pos) & 1);
} }
if (isr & I2C_ISR_TXIS) { 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) { 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) { if (isr & I2C_ISR_STOPF) {
// STOPF only set for STOP condition, not a repeated START // STOPF only set for STOP condition, not a repeated START

View File

@@ -28,6 +28,8 @@
#include STM32_HAL_H #include STM32_HAL_H
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32WB)
#if !defined(I2C2_BASE) #if !defined(I2C2_BASE)
// This MCU doesn't have I2C2_BASE, define it so that the i2c_idx calculation works. // 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)) #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); 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); void i2c_slave_irq_handler(i2c_slave_t *i2c);
// These should be provided externally // These should be provided externally
int i2c_slave_process_addr_match(i2c_slave_t *i2c, int rw); 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); 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); void i2c_slave_process_tx_end(i2c_slave_t *i2c);
#endif
#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H #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 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)) { 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 return 0; // ACK
} }
@@ -909,15 +909,17 @@ void i2c_slave_process_rx_end(i2c_slave_t *i2c) {
i2c_obj.cmd_arg_sent = false; 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) { if (i2c_obj.cmd_send_arg) {
i2c_obj.cmd_arg_sent = true; 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)) { } 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 { } else {
return 0; value = 0;
} }
i2c_slave_write_byte(i2c, value);
} }
void i2c_slave_process_tx_end(i2c_slave_t *i2c) { void i2c_slave_process_tx_end(i2c_slave_t *i2c) {