Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cores/arduino/stm32/stm32yyxx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
#undef HAL_I2S_MODULE_ENABLED
#endif

#if !defined(HAL_I3C_MODULE_DISABLED)
#define HAL_I3C_MODULE_ENABLED
#else
#undef HAL_I3C_MODULE_ENABLED
#endif

#if !defined(HAL_RTC_MODULE_DISABLED)
#define HAL_RTC_MODULE_ENABLED
#else
Expand Down
1 change: 1 addition & 0 deletions libraries/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ add_subdirectory(SrcWrapper)
add_subdirectory(USBDevice)
add_subdirectory(VirtIO)
add_subdirectory(Wire)
add_subdirectory(I3C_Controller)
33 changes: 33 additions & 0 deletions libraries/I3C_Controller/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# v3.21 implemented semantic changes regarding $<TARGET_OBJECTS:...>
# See https://cmake.org/cmake/help/v3.21/command/target_link_libraries.html#linking-object-libraries-via-target-objects
cmake_minimum_required(VERSION 3.21)

add_library(I3C_Controller INTERFACE)
add_library(I3C_usage INTERFACE)

target_include_directories(I3C_usage INTERFACE
src
)


target_link_libraries(I3C_usage INTERFACE
base_config
)

target_link_libraries(I3C_Controller INTERFACE I3C_usage)



add_library(I3C_bin OBJECT EXCLUDE_FROM_ALL
src/I3C_Controller.cpp
${BUILD_SYSTEM_PATH}/Drivers/STM32H5xx_HAL_Driver/Src/stm32h5xx_util_i3c.c
# ${BUILD_SYSTEM_PATH}/Drivers/STM32U3xx_HAL_Driver/Src/stm32u3xx_util_i3c.c


)
target_link_libraries(I3C_bin PUBLIC I3C_usage)

target_link_libraries(I3C_Controller INTERFACE
I3C_bin
$<TARGET_OBJECTS:I3C_bin>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "I3C_Controller.h"
#include "lps22df.h"

#if defined(STM32H5xx)
#define I3C_BUS I3C1Bus
#define I3C_SDA_PIN PB7
#define I3C_SCL_PIN PB6
#elif defined(STM32U3xx)
#define I3C_BUS I3C2Bus
#define I3C_SDA_PIN PB14
#define I3C_SCL_PIN PB13_ALT1
#else
#error "Unsupported STM32 family"
#endif

Lps22dfI3cCtx g_lpsCtx;
lps22df_ctx_t g_lpsDrvCtx;
uint8_t g_dynAddr = 0;

void setup()
{
Serial.begin(115200);
while (!Serial) {}
Serial.println("\n=== Test ENTDAA begin ===");

if (!I3C_BUS.begin(I3C_SDA_PIN, I3C_SCL_PIN, 1000000)) {
Serial.println("I3CBus.begin FAILED");
while (1) {}
}
Serial.println("I3CBus initialized");

// ENTDAA + init LPS22DF driver C
if (!LPS22DF_I3C_EntdaaInit(I3C_BUS,
0x30, // first DA to use
g_dynAddr,
g_lpsDrvCtx,
g_lpsCtx)) {
Serial.println("LPS22DF ENTDAA init FAILED");
while (1) {}
}

Serial.print("LPS22DF ready at DA=0x");
Serial.println(g_dynAddr, HEX);
}

void loop()
{
lps22df_data_t data;

if (lps22df_data_get(&g_lpsDrvCtx, &data) == LPS22DF_OK) {
Serial.print("P = ");
Serial.print(data.pressure.hpa, 3);
Serial.print(" hPa | T = ");
Serial.print(data.heat.deg_c, 2);
Serial.println(" °C");
} else {
Serial.println("lps22df_data_get FAILED");
}

delay(500);
}
98 changes: 98 additions & 0 deletions libraries/I3C_Controller/examples/Entdaa-LPS22DF/lps22df.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "lps22df.h"

// limit the discovery
static const size_t MAX_I3C_DEVICES = 4;

// Low-level callbacks for C driver
static int32_t lps_i3c_write(void *handle, uint8_t reg, uint8_t *buf, uint16_t len)
{
auto *ctx = static_cast<Lps22dfI3cCtx*>(handle);
int rc = ctx->bus->writeRegisterBlock(ctx->dynAddr, reg, buf, len, 1000);
return (rc == 0) ? 0 : -1;
}

static int32_t lps_i3c_read(void *handle, uint8_t reg, uint8_t *buf, uint16_t len)
{
auto *ctx = static_cast<Lps22dfI3cCtx*>(handle);
int rc = ctx->bus->readRegisterBlock(ctx->dynAddr, reg, buf, len, 1000);
return (rc == 0) ? 0 : -1;
}

bool LPS22DF_I3C_EntdaaInit(I3CBus &bus,
uint8_t firstDynAddr,
uint8_t &outDynAddr,
lps22df_ctx_t &outDrvCtx,
Lps22dfI3cCtx &outCtx)
{
outDynAddr = 0;

// 1) Optional: global RSTDAA
bus.rstdaaOnce();

for (uint8_t addr = 1; addr < 0x7F; ++addr) {
bus.isI2CDeviceReady(addr, 2, 10);
}


// 2) ENTDAA: discovery of I3C devices on the bus
I3CDiscoveredDevice devices[MAX_I3C_DEVICES];
int n = bus.entdaa(devices, MAX_I3C_DEVICES, firstDynAddr, 1000);
if (n < 0) {
Serial.print("ENTDAA FAILED, rc=");
Serial.println(n);
return false;
}

Serial.print("ENTDAA found ");
Serial.print(n);
Serial.println(" I3C device(s)");

// 3) Identify the LPS22DF via WHO_AM_I
for (int i = 0; i < n; ++i) {
uint8_t id = 0;
int rc = bus.readRegister(devices[i].dynAddr, LPS22DF_WHO_AM_I, id, 1000);
Serial.print("WHO_AM_I @DA 0x"); Serial.print(devices[i].dynAddr, HEX);
Serial.print(" rc="); Serial.print(rc);
Serial.print(" id=0x"); Serial.println(id, HEX);

if (rc == 0 && id == LPS22DF_ID) {
outDynAddr = devices[i].dynAddr;
Serial.print("LPS22DF detected at DA=0x");
Serial.println(outDynAddr, HEX);
break;
}
}

if (outDynAddr == 0) {
Serial.println("No LPS22DF detected via ENTDAA");
return false;
}

// 4) Prepare contexts for the C driver
outCtx.bus = &bus;
outCtx.dynAddr = outDynAddr;

outDrvCtx.write_reg = lps_i3c_write;
outDrvCtx.read_reg = lps_i3c_read;
outDrvCtx.handle = &outCtx;

// 5) Recommended init (BDU + IF_INC etc.)
if (lps22df_init_set(&outDrvCtx, LPS22DF_DRV_RDY) != LPS22DF_OK) {
Serial.println("lps22df_init_set FAILED");
return false;
}

// 6) Configure mode (ODR, AVG, LPF)
lps22df_md_t md;
md.odr = lps22df_md_t::LPS22DF_25Hz;
md.avg = lps22df_md_t::LPS22DF_4_AVG;
md.lpf = lps22df_md_t::LPS22DF_LPF_ODR_DIV_4;

if (lps22df_mode_set(&outDrvCtx, &md) != LPS22DF_OK) {
Serial.println("lps22df_mode_set FAILED");
return false;
}

Serial.println("LPS22DF configured via ENTDAA path.");
return true;
}
24 changes: 24 additions & 0 deletions libraries/I3C_Controller/examples/Entdaa-LPS22DF/lps22df.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "I3C_Controller.h"
#include "LPS22DFSensor.h"


// Context for LPS22DF in I3C mode (C driver)
struct Lps22dfI3cCtx {
I3CBus *bus; // pointer to the I3C bus used
uint8_t dynAddr; // dynamic address assigned via ENTDAA
};

// Initialize LPS22DF via ENTDAA + C driver on dynamic address.
//
// - bus : I3CBus instance (I3C1Bus or I3C2Bus)
// - firstDynAddr : first DA to try
// - outDynAddr : receives the DA that was ultimately assigned
// - outDrvCtx : C driver context lps22df_ctx_t
// - outCtx : backend context (bus + dynAddr) to keep globally
//
// Return:
// true : LPS22DF detected and initialized
// false : ENTDAA, WHO_AM_I or driver init failed
bool LPS22DF_I3C_EntdaaInit(I3CBus &bus, uint8_t firstDynAddr, uint8_t &outDynAddr, lps22df_ctx_t &outDrvCtx, Lps22dfI3cCtx &outCtx);
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <Arduino.h>
#include "I3C_Controller.h"
#include "LPS22DFSensor.h"

static const uint8_t LPS22DF_STATIC_ADDR_7BIT = 0x5D;
static const uint8_t LPS22DF_DYN_ADDR_7BIT = 0x30;

#if defined(STM32H5xx)
LPS22DFSensor ps(&I3C1Bus, LPS22DF_STATIC_ADDR_7BIT, LPS22DF_DYN_ADDR_7BIT);
#define I3C_BUS I3C1Bus
#define I3C_SCL PB6
#define I3C_SDA PB7
#elif defined(STM32U3xx)
LPS22DFSensor ps(&I3C2Bus, LPS22DF_STATIC_ADDR_7BIT, LPS22DF_DYN_ADDR_7BIT);
#define I3C_BUS I3C2Bus
#define I3C_SCL PB13_ALT1
#define I3C_SDA PB14
#endif

void setup()
{
Serial.begin(115200);
while (!Serial) {}
Serial.println("\n=== Test SetDASA Begin ===");

#if defined(STM32H5xx)
if (!I3C_BUS.begin(I3C_SDA, I3C_SCL, 1000000)) {
#elif defined(STM32U3xx)
if (!I3C_BUS.begin(I3C_SDA, I3C_SCL, 1000000)) {
#endif

Serial.println("I3C_BUS.begin FAILED");
while (1) {}
}


Serial.println("I3CBus initialized");

if (ps.begin() != LPS22DF_OK) {
Serial.println("LPS22DF begin FAILED");
while (1) {}
}
Serial.println("LPS22DF begin OK");

if (ps.Enable() != LPS22DF_OK) {
Serial.println("LPS22DF Enable FAILED");
while (1) {}
}
Serial.println("LPS22DF Enable OK");

}


void loop()
{
float p, t;

if (ps.GetPressure(&p) == LPS22DF_OK &&
ps.GetTemperature(&t) == LPS22DF_OK) {
Serial.print("P = ");
Serial.print(p, 3);
Serial.print(" hPa | T = ");
Serial.print(t, 2);
Serial.println(" °C");
} else {
Serial.println("Read failed");
}

delay(500);
}
23 changes: 23 additions & 0 deletions libraries/I3C_Controller/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
I3CBus KEYWORD1
I3CDiscoveredDevice KEYWORD1
I3CAddressController KEYWORD1
LPS22DFSensor KEYWORD1

begin KEYWORD2
writeRegister KEYWORD2
readRegister KEYWORD2
writeRegisterBlock KEYWORD2
readRegisterBlock KEYWORD2
isI2CDeviceReady KEYWORD2
isI3CDeviceReady KEYWORD2
rstdaaOnce KEYWORD2
disecOnce KEYWORD2
setdasa KEYWORD2
entdaa KEYWORD2
setBusFrequency KEYWORD2

GetPressure KEYWORD2
GetTemperature KEYWORD2
Enable KEYWORD2
Disable KEYWORD2
ReadID KEYWORD2
10 changes: 10 additions & 0 deletions libraries/I3C_Controller/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name=STM32 I3C Controller
version=0.1.0
author=Bahssain Aymane
maintainer=stm32duino
sentence=Arduino-friendly I3C controller for STM32 (H5/U3) with LPS22DF I3C support.
paragraph=Provides a lightweight I3C bus controller class (I3CBus).
category=Communication
url=https://github.com/STMicroelectronics/STM32I3C
architectures=stm32
depends=STM32duino LPS22DF
Loading
Loading