Skip to content

Commit b2f8496

Browse files
gautierg-stkartben
authored andcommitted
drivers: i2c: stm32 i2cv1 controller driver using rtio
Adds the simplest possible I2Cv1 controller driver for STM32 with the RTIO interface. Currently only interrupt driven transfers are supported. Signed-off-by: Guillaume Gautier <guillaume.gautier-ext@st.com>
1 parent e8bd35e commit b2f8496

File tree

3 files changed

+384
-0
lines changed

3 files changed

+384
-0
lines changed

drivers/i2c/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ if(CONFIG_I2C_RTIO)
8484
zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim_common.c)
8585
zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim_rtio.c)
8686
zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs_rtio.c)
87+
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_common.c)
88+
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_rtio.c)
89+
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_v1_rtio.c)
8790
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_common.c)
8891
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_rtio.c)
8992
zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_v2_rtio.c)

drivers/i2c/i2c_ll_stm32.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ struct i2c_stm32_data {
7575
uint8_t *xfer_buf;
7676
uint8_t xfer_len;
7777
uint8_t xfer_flags;
78+
#ifdef CONFIG_I2C_STM32_V1
79+
uint8_t msg_len;
80+
uint8_t is_restart;
81+
uint16_t slave_address;
82+
#endif /* CONFIG_I2C_STM32_V1 */
7883
#else /* CONFIG_I2C_RTIO */
7984
#ifdef CONFIG_I2C_STM32_INTERRUPT
8085
struct k_sem device_sync_sem;

drivers/i2c/i2c_ll_stm32_v1_rtio.c

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
/*
2+
* Copyright (c) 2025 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <errno.h>
8+
#include <soc.h>
9+
#include <stm32_ll_i2c.h>
10+
#include <stm32_ll_rcc.h>
11+
#include <zephyr/drivers/clock_control.h>
12+
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
13+
#include <zephyr/drivers/i2c.h>
14+
#include <zephyr/drivers/i2c/rtio.h>
15+
#include <zephyr/drivers/pinctrl.h>
16+
#include <zephyr/kernel.h>
17+
#include <zephyr/pm/device.h>
18+
#include <zephyr/pm/device_runtime.h>
19+
#include <zephyr/sys/util.h>
20+
21+
#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
22+
#include <zephyr/logging/log.h>
23+
LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
24+
25+
#include "i2c_ll_stm32.h"
26+
#include "i2c-priv.h"
27+
28+
#define I2C_REQUEST_WRITE 0x00
29+
#define I2C_REQUEST_READ 0x01
30+
#define HEADER 0xF0
31+
32+
static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
33+
{
34+
const struct i2c_stm32_config *cfg = dev->config;
35+
I2C_TypeDef *i2c = cfg->i2c;
36+
37+
LL_I2C_DisableIT_TX(i2c);
38+
LL_I2C_DisableIT_RX(i2c);
39+
LL_I2C_DisableIT_EVT(i2c);
40+
LL_I2C_DisableIT_BUF(i2c);
41+
}
42+
43+
static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
44+
{
45+
const struct i2c_stm32_config *cfg = dev->config;
46+
I2C_TypeDef *i2c = cfg->i2c;
47+
48+
LL_I2C_EnableIT_ERR(i2c);
49+
LL_I2C_EnableIT_EVT(i2c);
50+
LL_I2C_EnableIT_BUF(i2c);
51+
}
52+
53+
static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
54+
{
55+
uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
56+
57+
if ((cr1 & I2C_CR1_STOP) != 0) {
58+
LOG_DBG("%s: START while STOP active!", __func__);
59+
LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
60+
}
61+
62+
LL_I2C_GenerateStartCondition(i2c);
63+
}
64+
65+
static void i2c_stm32_master_mode_end(const struct device *dev)
66+
{
67+
const struct i2c_stm32_config *cfg = dev->config;
68+
struct i2c_stm32_data *data = dev->data;
69+
struct i2c_rtio *ctx = data->ctx;
70+
I2C_TypeDef *i2c = cfg->i2c;
71+
72+
i2c_stm32_disable_transfer_interrupts(dev);
73+
LL_I2C_Disable(i2c);
74+
if ((data->xfer_len == 0) && i2c_rtio_complete(ctx, 0)) {
75+
i2c_stm32_start(dev);
76+
}
77+
}
78+
79+
static void handle_sb(const struct device *dev)
80+
{
81+
const struct i2c_stm32_config *cfg = dev->config;
82+
struct i2c_stm32_data *data = dev->data;
83+
I2C_TypeDef *i2c = cfg->i2c;
84+
85+
uint16_t saddr = data->slave_address;
86+
uint8_t slave;
87+
88+
if ((data->xfer_flags & I2C_MSG_ADDR_10_BITS) != 0) {
89+
slave = ((saddr & 0x0300) >> 7) & 0xFF;
90+
slave |= HEADER;
91+
92+
if (data->is_restart == 0U) {
93+
data->is_restart = 1U;
94+
} else {
95+
slave |= I2C_REQUEST_READ;
96+
data->is_restart = 0U;
97+
}
98+
LL_I2C_TransmitData8(i2c, slave);
99+
} else {
100+
slave = (saddr << 1) & 0xFF;
101+
if ((data->xfer_flags & I2C_MSG_READ) != 0) {
102+
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
103+
if (data->xfer_len == 2) {
104+
LL_I2C_EnableBitPOS(i2c);
105+
}
106+
} else {
107+
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
108+
}
109+
}
110+
}
111+
112+
static void handle_addr(const struct device *dev)
113+
{
114+
const struct i2c_stm32_config *cfg = dev->config;
115+
struct i2c_stm32_data *data = dev->data;
116+
I2C_TypeDef *i2c = cfg->i2c;
117+
118+
if ((data->xfer_flags & I2C_MSG_ADDR_10_BITS) != 0) {
119+
if (((data->xfer_flags & I2C_MSG_READ) != 0) && (data->is_restart != 0)) {
120+
data->is_restart = 0U;
121+
LL_I2C_ClearFlag_ADDR(i2c);
122+
i2c_stm32_generate_start_condition(i2c);
123+
return;
124+
}
125+
}
126+
127+
if ((data->xfer_flags & I2C_MSG_READ) == 0) {
128+
LL_I2C_ClearFlag_ADDR(i2c);
129+
return;
130+
}
131+
/* According to STM32F1 errata we need to handle these corner cases in
132+
* a specific way.
133+
* Please ref to STM32F10xxC/D/E I2C peripheral Errata sheet 2.14.1
134+
*/
135+
if ((data->xfer_len == 0U) && IS_ENABLED(CONFIG_SOC_SERIES_STM32F1X)) {
136+
LL_I2C_GenerateStopCondition(i2c);
137+
} else if (data->xfer_len == 1U) {
138+
/* Single byte reception: enable NACK and clear POS */
139+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
140+
#ifdef CONFIG_SOC_SERIES_STM32F1X
141+
LL_I2C_ClearFlag_ADDR(i2c);
142+
LL_I2C_GenerateStopCondition(i2c);
143+
#endif
144+
} else if (data->xfer_len == 2U) {
145+
#ifdef CONFIG_SOC_SERIES_STM32F1X
146+
LL_I2C_ClearFlag_ADDR(i2c);
147+
#endif
148+
/* 2-byte reception: enable NACK and set POS */
149+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
150+
LL_I2C_EnableBitPOS(i2c);
151+
}
152+
LL_I2C_ClearFlag_ADDR(i2c);
153+
}
154+
155+
static void handle_txe(const struct device *dev)
156+
{
157+
const struct i2c_stm32_config *cfg = dev->config;
158+
struct i2c_stm32_data *data = dev->data;
159+
I2C_TypeDef *i2c = cfg->i2c;
160+
161+
if (data->xfer_len != 0) {
162+
data->xfer_len--;
163+
if (data->xfer_len == 0U) {
164+
/*
165+
* This is the last byte to transmit disable Buffer
166+
* interrupt and wait for a BTF interrupt
167+
*/
168+
LL_I2C_DisableIT_BUF(i2c);
169+
}
170+
LL_I2C_TransmitData8(i2c, *data->xfer_buf);
171+
data->xfer_buf++;
172+
} else {
173+
if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
174+
LL_I2C_GenerateStopCondition(i2c);
175+
}
176+
if (LL_I2C_IsActiveFlag_BTF(i2c)) {
177+
/* Read DR to clear BTF flag */
178+
LL_I2C_ReceiveData8(i2c);
179+
}
180+
i2c_stm32_master_mode_end(dev);
181+
}
182+
}
183+
184+
static void handle_rxne(const struct device *dev)
185+
{
186+
const struct i2c_stm32_config *cfg = dev->config;
187+
struct i2c_stm32_data *data = dev->data;
188+
I2C_TypeDef *i2c = cfg->i2c;
189+
190+
switch (data->xfer_len) {
191+
case 0:
192+
if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
193+
LL_I2C_GenerateStopCondition(i2c);
194+
}
195+
i2c_stm32_master_mode_end(dev);
196+
break;
197+
case 1:
198+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
199+
LL_I2C_DisableBitPOS(i2c);
200+
/* Single byte reception */
201+
if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
202+
LL_I2C_GenerateStopCondition(i2c);
203+
}
204+
LL_I2C_DisableIT_BUF(i2c);
205+
data->xfer_len--;
206+
*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
207+
data->xfer_buf++;
208+
i2c_stm32_master_mode_end(dev);
209+
break;
210+
case 2:
211+
/*
212+
* 2-byte reception for N > 3 has already set the NACK
213+
* bit, and must not set the POS bit. See pg. 854 in
214+
* the F4 reference manual (RM0090).
215+
*/
216+
if (data->msg_len > 2) {
217+
break;
218+
}
219+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
220+
LL_I2C_EnableBitPOS(i2c);
221+
__fallthrough;
222+
case 3:
223+
/*
224+
* 2-byte, 3-byte reception and for N-2, N-1,
225+
* N when N > 3
226+
*/
227+
LL_I2C_DisableIT_BUF(i2c);
228+
break;
229+
default:
230+
/* N byte reception when N > 3 */
231+
data->xfer_len--;
232+
*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
233+
data->xfer_buf++;
234+
}
235+
}
236+
237+
static void handle_btf(const struct device *dev)
238+
{
239+
const struct i2c_stm32_config *cfg = dev->config;
240+
struct i2c_stm32_data *data = dev->data;
241+
I2C_TypeDef *i2c = cfg->i2c;
242+
243+
if ((data->xfer_flags & I2C_MSG_READ) == 0) {
244+
handle_txe(dev);
245+
} else {
246+
uint32_t counter = 0U;
247+
248+
switch (data->xfer_len) {
249+
case 2:
250+
/*
251+
* Stop condition must be generated before reading the
252+
* last two bytes.
253+
*/
254+
if (data->xfer_flags & I2C_MSG_STOP) {
255+
LL_I2C_GenerateStopCondition(i2c);
256+
}
257+
258+
for (counter = 2U; counter > 0; counter--) {
259+
data->xfer_len--;
260+
*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
261+
data->xfer_buf++;
262+
}
263+
i2c_stm32_master_mode_end(dev);
264+
break;
265+
case 3:
266+
/* Set NACK before reading N-2 byte*/
267+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
268+
data->xfer_len--;
269+
*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
270+
data->xfer_buf++;
271+
break;
272+
default:
273+
handle_rxne(dev);
274+
}
275+
}
276+
}
277+
278+
void i2c_stm32_event(const struct device *dev)
279+
{
280+
const struct i2c_stm32_config *cfg = dev->config;
281+
struct i2c_stm32_data *data = dev->data;
282+
I2C_TypeDef *i2c = cfg->i2c;
283+
284+
if (LL_I2C_IsActiveFlag_SB(i2c)) {
285+
handle_sb(dev);
286+
} else if (LL_I2C_IsActiveFlag_ADD10(i2c)) {
287+
LL_I2C_TransmitData8(i2c, data->slave_address);
288+
} else if (LL_I2C_IsActiveFlag_ADDR(i2c)) {
289+
handle_addr(dev);
290+
} else if (LL_I2C_IsActiveFlag_BTF(i2c)) {
291+
handle_btf(dev);
292+
} else if (LL_I2C_IsActiveFlag_TXE(i2c) && ((data->xfer_flags & I2C_MSG_READ) == 0)) {
293+
handle_txe(dev);
294+
} else if (LL_I2C_IsActiveFlag_RXNE(i2c) && ((data->xfer_flags & I2C_MSG_READ) != 0)) {
295+
handle_rxne(dev);
296+
}
297+
}
298+
299+
int i2c_stm32_error(const struct device *dev)
300+
{
301+
const struct i2c_stm32_config *cfg = dev->config;
302+
I2C_TypeDef *i2c = cfg->i2c;
303+
304+
if (LL_I2C_IsActiveFlag_AF(i2c)) {
305+
LL_I2C_ClearFlag_AF(i2c);
306+
LL_I2C_GenerateStopCondition(i2c);
307+
return -EIO;
308+
}
309+
if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
310+
LL_I2C_ClearFlag_ARLO(i2c);
311+
return -EIO;
312+
}
313+
314+
if (LL_I2C_IsActiveFlag_BERR(i2c)) {
315+
LL_I2C_ClearFlag_BERR(i2c);
316+
return -EIO;
317+
}
318+
319+
return 0;
320+
}
321+
322+
int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
323+
uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
324+
{
325+
const struct i2c_stm32_config *cfg = dev->config;
326+
struct i2c_stm32_data *data = dev->data;
327+
I2C_TypeDef *i2c = cfg->i2c;
328+
329+
data->xfer_buf = buf;
330+
data->xfer_len = buf_len;
331+
data->xfer_flags = flags;
332+
data->msg_len = buf_len;
333+
data->is_restart = 0;
334+
data->slave_address = i2c_addr;
335+
336+
/* TODO deal with larger than 255 byte transfers correctly */
337+
if (buf_len > UINT8_MAX) {
338+
/* TODO LL_I2C_EnableReloadMode(i2c); */
339+
return -EINVAL;
340+
}
341+
342+
LL_I2C_Enable(i2c);
343+
344+
LL_I2C_DisableBitPOS(i2c);
345+
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
346+
i2c_stm32_generate_start_condition(i2c);
347+
348+
i2c_stm32_enable_transfer_interrupts(dev);
349+
if (flags & I2C_MSG_READ) {
350+
LL_I2C_EnableIT_RX(i2c);
351+
} else {
352+
LL_I2C_EnableIT_TX(i2c);
353+
}
354+
355+
return 0;
356+
}
357+
358+
int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
359+
{
360+
const struct i2c_stm32_config *cfg = dev->config;
361+
struct i2c_stm32_data *data = dev->data;
362+
I2C_TypeDef *i2c = cfg->i2c;
363+
364+
switch (I2C_SPEED_GET(data->dev_config)) {
365+
case I2C_SPEED_STANDARD:
366+
LL_I2C_ConfigSpeed(i2c, clock, 100000, LL_I2C_DUTYCYCLE_2);
367+
break;
368+
case I2C_SPEED_FAST:
369+
LL_I2C_ConfigSpeed(i2c, clock, 400000, LL_I2C_DUTYCYCLE_2);
370+
break;
371+
default:
372+
return -EINVAL;
373+
}
374+
375+
return 0;
376+
}

0 commit comments

Comments
 (0)