Skip to content

Commit 1589adc

Browse files
committed
feat(I3C): Add I3C Controller library
Signed-off-by: Aymane Bahssain <aymane.bahssain@st.com>
1 parent 9b73dd3 commit 1589adc

File tree

11 files changed

+1093
-0
lines changed

11 files changed

+1093
-0
lines changed

cores/arduino/stm32/stm32yyxx_hal_conf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
#undef HAL_I2S_MODULE_ENABLED
4747
#endif
4848

49+
#if !defined(HAL_I3C_MODULE_DISABLED)
50+
#define HAL_I3C_MODULE_ENABLED
51+
#else
52+
#undef HAL_I3C_MODULE_ENABLED
53+
#endif
54+
4955
#if !defined(HAL_RTC_MODULE_DISABLED)
5056
#define HAL_RTC_MODULE_ENABLED
5157
#else

libraries/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ add_subdirectory(SrcWrapper)
1313
add_subdirectory(USBDevice)
1414
add_subdirectory(VirtIO)
1515
add_subdirectory(Wire)
16+
add_subdirectory(I3C_Controller)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# v3.21 implemented semantic changes regarding $<TARGET_OBJECTS:...>
2+
# See https://cmake.org/cmake/help/v3.21/command/target_link_libraries.html#linking-object-libraries-via-target-objects
3+
cmake_minimum_required(VERSION 3.21)
4+
5+
add_library(I3C_Controller INTERFACE)
6+
add_library(I3C_usage INTERFACE)
7+
8+
target_include_directories(I3C_usage INTERFACE
9+
src
10+
)
11+
12+
13+
target_link_libraries(I3C_usage INTERFACE
14+
base_config
15+
)
16+
17+
target_link_libraries(I3C_Controller INTERFACE I3C_usage)
18+
19+
20+
21+
add_library(I3C_bin OBJECT EXCLUDE_FROM_ALL
22+
src/I3C_Controller.cpp
23+
${BUILD_SYSTEM_PATH}/Drivers/STM32H5xx_HAL_Driver/Src/stm32h5xx_util_i3c.c
24+
# ${BUILD_SYSTEM_PATH}/Drivers/STM32U3xx_HAL_Driver/Src/stm32u3xx_util_i3c.c
25+
26+
27+
)
28+
target_link_libraries(I3C_bin PUBLIC I3C_usage)
29+
30+
target_link_libraries(I3C_Controller INTERFACE
31+
I3C_bin
32+
$<TARGET_OBJECTS:I3C_bin>
33+
)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include "I3C_Controller.h"
2+
#include "lps22df.h"
3+
4+
#if defined(STM32H5xx)
5+
#define I3C_BUS I3C1Bus
6+
#define I3C_SDA_PIN PB7
7+
#define I3C_SCL_PIN PB6
8+
#elif defined(STM32U3xx)
9+
#define I3C_BUS I3C2Bus
10+
#define I3C_SDA_PIN PB14
11+
#define I3C_SCL_PIN PB13_ALT1
12+
#else
13+
#error "Unsupported STM32 family"
14+
#endif
15+
16+
Lps22dfI3cCtx g_lpsCtx;
17+
lps22df_ctx_t g_lpsDrvCtx;
18+
uint8_t g_dynAddr = 0;
19+
20+
void setup()
21+
{
22+
Serial.begin(115200);
23+
while (!Serial) {}
24+
Serial.println("\n=== Test ENTDAA begin ===");
25+
26+
if (!I3C_BUS.begin(I3C_SDA_PIN, I3C_SCL_PIN, 1000000)) {
27+
Serial.println("I3CBus.begin FAILED");
28+
while (1) {}
29+
}
30+
Serial.println("I3CBus initialized");
31+
32+
// ENTDAA + init LPS22DF driver C
33+
if (!LPS22DF_I3C_EntdaaInit(I3C_BUS,
34+
0x30, // first DA to use
35+
g_dynAddr,
36+
g_lpsDrvCtx,
37+
g_lpsCtx)) {
38+
Serial.println("LPS22DF ENTDAA init FAILED");
39+
while (1) {}
40+
}
41+
42+
Serial.print("LPS22DF ready at DA=0x");
43+
Serial.println(g_dynAddr, HEX);
44+
}
45+
46+
void loop()
47+
{
48+
lps22df_data_t data;
49+
50+
if (lps22df_data_get(&g_lpsDrvCtx, &data) == LPS22DF_OK) {
51+
Serial.print("P = ");
52+
Serial.print(data.pressure.hpa, 3);
53+
Serial.print(" hPa | T = ");
54+
Serial.print(data.heat.deg_c, 2);
55+
Serial.println(" °C");
56+
} else {
57+
Serial.println("lps22df_data_get FAILED");
58+
}
59+
60+
delay(500);
61+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "lps22df.h"
2+
3+
// limit the discovery
4+
static const size_t MAX_I3C_DEVICES = 4;
5+
6+
// Low-level callbacks for C driver
7+
static int32_t lps_i3c_write(void *handle, uint8_t reg, uint8_t *buf, uint16_t len)
8+
{
9+
auto *ctx = static_cast<Lps22dfI3cCtx*>(handle);
10+
int rc = ctx->bus->writeRegisterBlock(ctx->dynAddr, reg, buf, len, 1000);
11+
return (rc == 0) ? 0 : -1;
12+
}
13+
14+
static int32_t lps_i3c_read(void *handle, uint8_t reg, uint8_t *buf, uint16_t len)
15+
{
16+
auto *ctx = static_cast<Lps22dfI3cCtx*>(handle);
17+
int rc = ctx->bus->readRegisterBlock(ctx->dynAddr, reg, buf, len, 1000);
18+
return (rc == 0) ? 0 : -1;
19+
}
20+
21+
bool LPS22DF_I3C_EntdaaInit(I3CBus &bus,
22+
uint8_t firstDynAddr,
23+
uint8_t &outDynAddr,
24+
lps22df_ctx_t &outDrvCtx,
25+
Lps22dfI3cCtx &outCtx)
26+
{
27+
outDynAddr = 0;
28+
29+
// 1) Optional: global RSTDAA
30+
bus.rstdaaOnce();
31+
32+
for (uint8_t addr = 1; addr < 0x7F; ++addr) {
33+
bus.isI2CDeviceReady(addr, 2, 10);
34+
}
35+
36+
37+
// 2) ENTDAA: discovery of I3C devices on the bus
38+
I3CDiscoveredDevice devices[MAX_I3C_DEVICES];
39+
int n = bus.entdaa(devices, MAX_I3C_DEVICES, firstDynAddr, 1000);
40+
if (n < 0) {
41+
Serial.print("ENTDAA FAILED, rc=");
42+
Serial.println(n);
43+
return false;
44+
}
45+
46+
Serial.print("ENTDAA found ");
47+
Serial.print(n);
48+
Serial.println(" I3C device(s)");
49+
50+
// 3) Identify the LPS22DF via WHO_AM_I
51+
for (int i = 0; i < n; ++i) {
52+
uint8_t id = 0;
53+
int rc = bus.readRegister(devices[i].dynAddr, LPS22DF_WHO_AM_I, id, 1000);
54+
Serial.print("WHO_AM_I @DA 0x"); Serial.print(devices[i].dynAddr, HEX);
55+
Serial.print(" rc="); Serial.print(rc);
56+
Serial.print(" id=0x"); Serial.println(id, HEX);
57+
58+
if (rc == 0 && id == LPS22DF_ID) {
59+
outDynAddr = devices[i].dynAddr;
60+
Serial.print("LPS22DF detected at DA=0x");
61+
Serial.println(outDynAddr, HEX);
62+
break;
63+
}
64+
}
65+
66+
if (outDynAddr == 0) {
67+
Serial.println("No LPS22DF detected via ENTDAA");
68+
return false;
69+
}
70+
71+
// 4) Prepare contexts for the C driver
72+
outCtx.bus = &bus;
73+
outCtx.dynAddr = outDynAddr;
74+
75+
outDrvCtx.write_reg = lps_i3c_write;
76+
outDrvCtx.read_reg = lps_i3c_read;
77+
outDrvCtx.handle = &outCtx;
78+
79+
// 5) Recommended init (BDU + IF_INC etc.)
80+
if (lps22df_init_set(&outDrvCtx, LPS22DF_DRV_RDY) != LPS22DF_OK) {
81+
Serial.println("lps22df_init_set FAILED");
82+
return false;
83+
}
84+
85+
// 6) Configure mode (ODR, AVG, LPF)
86+
lps22df_md_t md;
87+
md.odr = lps22df_md_t::LPS22DF_25Hz;
88+
md.avg = lps22df_md_t::LPS22DF_4_AVG;
89+
md.lpf = lps22df_md_t::LPS22DF_LPF_ODR_DIV_4;
90+
91+
if (lps22df_mode_set(&outDrvCtx, &md) != LPS22DF_OK) {
92+
Serial.println("lps22df_mode_set FAILED");
93+
return false;
94+
}
95+
96+
Serial.println("LPS22DF configured via ENTDAA path.");
97+
return true;
98+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include "I3C_Controller.h"
4+
#include "LPS22DFSensor.h"
5+
6+
7+
// Context for LPS22DF in I3C mode (C driver)
8+
struct Lps22dfI3cCtx {
9+
I3CBus *bus; // pointer to the I3C bus used
10+
uint8_t dynAddr; // dynamic address assigned via ENTDAA
11+
};
12+
13+
// Initialize LPS22DF via ENTDAA + C driver on dynamic address.
14+
//
15+
// - bus : I3CBus instance (I3C1Bus or I3C2Bus)
16+
// - firstDynAddr : first DA to try
17+
// - outDynAddr : receives the DA that was ultimately assigned
18+
// - outDrvCtx : C driver context lps22df_ctx_t
19+
// - outCtx : backend context (bus + dynAddr) to keep globally
20+
//
21+
// Return:
22+
// true : LPS22DF detected and initialized
23+
// false : ENTDAA, WHO_AM_I or driver init failed
24+
bool LPS22DF_I3C_EntdaaInit(I3CBus &bus, uint8_t firstDynAddr, uint8_t &outDynAddr, lps22df_ctx_t &outDrvCtx, Lps22dfI3cCtx &outCtx);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include <Arduino.h>
2+
#include "I3C_Controller.h"
3+
#include "LPS22DFSensor.h"
4+
5+
static const uint8_t LPS22DF_STATIC_ADDR_7BIT = 0x5D;
6+
static const uint8_t LPS22DF_DYN_ADDR_7BIT = 0x30;
7+
8+
#if defined(STM32H5xx)
9+
LPS22DFSensor ps(&I3C1Bus, LPS22DF_STATIC_ADDR_7BIT, LPS22DF_DYN_ADDR_7BIT);
10+
#define I3C_BUS I3C1Bus
11+
#define I3C_SCL PB6
12+
#define I3C_SDA PB7
13+
#elif defined(STM32U3xx)
14+
LPS22DFSensor ps(&I3C2Bus, LPS22DF_STATIC_ADDR_7BIT, LPS22DF_DYN_ADDR_7BIT);
15+
#define I3C_BUS I3C2Bus
16+
#define I3C_SCL PB13_ALT1
17+
#define I3C_SDA PB14
18+
#endif
19+
20+
void setup()
21+
{
22+
Serial.begin(115200);
23+
while (!Serial) {}
24+
Serial.println("\n=== Test SetDASA Begin ===");
25+
26+
#if defined(STM32H5xx)
27+
if (!I3C_BUS.begin(I3C_SDA, I3C_SCL, 1000000)) {
28+
#elif defined(STM32U3xx)
29+
if (!I3C_BUS.begin(I3C_SDA, I3C_SCL, 1000000)) {
30+
#endif
31+
32+
Serial.println("I3C_BUS.begin FAILED");
33+
while (1) {}
34+
}
35+
36+
37+
Serial.println("I3CBus initialized");
38+
39+
if (ps.begin() != LPS22DF_OK) {
40+
Serial.println("LPS22DF begin FAILED");
41+
while (1) {}
42+
}
43+
Serial.println("LPS22DF begin OK");
44+
45+
if (ps.Enable() != LPS22DF_OK) {
46+
Serial.println("LPS22DF Enable FAILED");
47+
while (1) {}
48+
}
49+
Serial.println("LPS22DF Enable OK");
50+
51+
}
52+
53+
54+
void loop()
55+
{
56+
float p, t;
57+
58+
if (ps.GetPressure(&p) == LPS22DF_OK &&
59+
ps.GetTemperature(&t) == LPS22DF_OK) {
60+
Serial.print("P = ");
61+
Serial.print(p, 3);
62+
Serial.print(" hPa | T = ");
63+
Serial.print(t, 2);
64+
Serial.println(" °C");
65+
} else {
66+
Serial.println("Read failed");
67+
}
68+
69+
delay(500);
70+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
I3CBus KEYWORD1
2+
I3CDiscoveredDevice KEYWORD1
3+
I3CAddressController KEYWORD1
4+
LPS22DFSensor KEYWORD1
5+
6+
begin KEYWORD2
7+
writeRegister KEYWORD2
8+
readRegister KEYWORD2
9+
writeRegisterBlock KEYWORD2
10+
readRegisterBlock KEYWORD2
11+
isI2CDeviceReady KEYWORD2
12+
isI3CDeviceReady KEYWORD2
13+
rstdaaOnce KEYWORD2
14+
disecOnce KEYWORD2
15+
setdasa KEYWORD2
16+
entdaa KEYWORD2
17+
setBusFrequency KEYWORD2
18+
19+
GetPressure KEYWORD2
20+
GetTemperature KEYWORD2
21+
Enable KEYWORD2
22+
Disable KEYWORD2
23+
ReadID KEYWORD2
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name=STM32 I3C Controller
2+
version=0.1.0
3+
author=Bahssain Aymane
4+
maintainer=stm32duino
5+
sentence=Arduino-friendly I3C controller for STM32 (H5/U3) with LPS22DF I3C support.
6+
paragraph=Provides a lightweight I3C bus controller class (I3CBus).
7+
category=Communication
8+
url=https://github.com/STMicroelectronics/STM32I3C
9+
architectures=stm32
10+
depends=STM32duino LPS22DF

0 commit comments

Comments
 (0)