Skip to content

Commit f11b29d

Browse files
committed
Add I2C support to STM32 platform
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent e738979 commit f11b29d

File tree

12 files changed

+1275
-1
lines changed

12 files changed

+1275
-1
lines changed

.github/workflows/stm32-build.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ jobs:
149149
mkdir build-host
150150
cd build-host
151151
cmake .. -G Ninja
152-
cmake --build . -t stm32_boot_test stm32_gpio_test
152+
cmake --build . -t stm32_boot_test stm32_gpio_test stm32_i2c_test
153153
154154
- name: Install Renode
155155
if: matrix.renode_platform
@@ -190,3 +190,18 @@ jobs:
190190
--variable AVM:@$PWD/build-host/src/platforms/stm32/tests/test_erl_sources/stm32_gpio_test.avm \
191191
--variable AVM_ADDRESS:${{ matrix.avm_address }} \
192192
--variable PLATFORM:$PLATFORM
193+
194+
- name: Run Renode I2C test
195+
if: matrix.renode_platform
196+
run: |
197+
LOCAL_REPL="src/platforms/stm32/tests/renode/${{ matrix.renode_platform }}"
198+
if [ -f "$LOCAL_REPL" ]; then
199+
PLATFORM="@$PWD/$LOCAL_REPL"
200+
else
201+
PLATFORM="@platforms/cpus/${{ matrix.renode_platform }}"
202+
fi
203+
renode-test src/platforms/stm32/tests/renode/stm32_i2c_test.robot \
204+
--variable ELF:@$PWD/src/platforms/stm32/build/AtomVM-${{ matrix.device }}.elf \
205+
--variable AVM:@$PWD/build-host/src/platforms/stm32/tests/test_erl_sources/stm32_i2c_test.avm \
206+
--variable AVM_ADDRESS:${{ matrix.avm_address }} \
207+
--variable PLATFORM:$PLATFORM

examples/erlang/stm32/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ pack_runnable(blink_weact_studio_h562 blink_weact_studio_h562 eavmlib avm_stm32)
2727
pack_runnable(blink_weact_studio_h743 blink_weact_studio_h743 eavmlib avm_stm32)
2828
pack_runnable(blink_weact_studio_u585 blink_weact_studio_u585 eavmlib avm_stm32)
2929
pack_runnable(blink_weact_studio_wb55 blink_weact_studio_wb55 eavmlib avm_stm32)
30+
pack_runnable(stm32_lis3dh stm32_lis3dh eavmlib avm_stm32)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2026 Paul Guyot <pguyot@kallisys.net>
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
%%-----------------------------------------------------------------------------
22+
%% @doc LIS3DH accelerometer example for STM32.
23+
%%
24+
%% Reads X, Y, Z acceleration from a LIS3DH connected via I2C and prints
25+
%% the values every second.
26+
%%
27+
%% Default wiring (I2C1 on most STM32 boards):
28+
%% SCL -> PB6
29+
%% SDA -> PB7
30+
%%
31+
%% The alternate function number defaults to 4, which is correct for I2C1
32+
%% on most STM32 families. Adjust `af' if your chip uses a different mapping.
33+
%% @end
34+
%%-----------------------------------------------------------------------------
35+
-module(stm32_lis3dh).
36+
-export([start/0]).
37+
38+
%% I2C1 pins (PB6/PB7 are common I2C1 pins across STM32 families)
39+
-define(SCL_PIN, {b, 6}).
40+
-define(SDA_PIN, {b, 7}).
41+
42+
%% LIS3DH I2C address (0x18 when SDO/SA0 is low, 0x19 when high)
43+
-define(LIS3DH_ADDR, 16#19).
44+
45+
%% LIS3DH registers
46+
-define(WHO_AM_I, 16#0F).
47+
-define(CTRL_REG1, 16#20).
48+
-define(CTRL_REG4, 16#23).
49+
-define(OUT_X_L, 16#28).
50+
51+
%% Expected WHO_AM_I response
52+
-define(LIS3DH_ID, 16#33).
53+
54+
start() ->
55+
I2C = i2c:open([
56+
{scl, ?SCL_PIN},
57+
{sda, ?SDA_PIN},
58+
{clock_speed_hz, 400000},
59+
{peripheral, 1}
60+
]),
61+
case check_who_am_i(I2C) of
62+
ok ->
63+
configure(I2C),
64+
loop(I2C);
65+
{error, Reason} ->
66+
console:puts("LIS3DH not found: "),
67+
console:puts(erlang:atom_to_list(Reason)),
68+
console:puts("\n")
69+
end.
70+
71+
check_who_am_i(I2C) ->
72+
case i2c:read_bytes(I2C, ?LIS3DH_ADDR, ?WHO_AM_I, 1) of
73+
{ok, <<?LIS3DH_ID:8>>} ->
74+
console:puts("LIS3DH detected\n"),
75+
ok;
76+
{ok, <<Other:8>>} ->
77+
console:puts("Unexpected WHO_AM_I: "),
78+
console:puts(erlang:integer_to_list(Other, 16)),
79+
console:puts("\n"),
80+
{error, unexpected_id};
81+
{error, _} = Error ->
82+
Error
83+
end.
84+
85+
configure(I2C) ->
86+
%% CTRL_REG1: 50 Hz ODR, normal mode, X/Y/Z enabled
87+
%% Bits: ODR=0100 LPen=0 Zen=1 Yen=1 Xen=1 -> 0x47
88+
ok = i2c:write_bytes(I2C, ?LIS3DH_ADDR, ?CTRL_REG1, 16#47),
89+
%% CTRL_REG4: +/- 2g full scale, high resolution
90+
%% Bits: BDU=1 BLE=0 FS=00 HR=1 ST=00 SIM=0 -> 0x88
91+
ok = i2c:write_bytes(I2C, ?LIS3DH_ADDR, ?CTRL_REG4, 16#88).
92+
93+
loop(I2C) ->
94+
case read_acceleration(I2C) of
95+
{ok, {X, Y, Z}} ->
96+
console:puts("X="),
97+
console:puts(erlang:integer_to_list(X)),
98+
console:puts(" Y="),
99+
console:puts(erlang:integer_to_list(Y)),
100+
console:puts(" Z="),
101+
console:puts(erlang:integer_to_list(Z)),
102+
console:puts("\n");
103+
{error, Reason} ->
104+
console:puts("Read error: "),
105+
console:puts(erlang:atom_to_list(Reason)),
106+
console:puts("\n")
107+
end,
108+
timer:sleep(1000),
109+
loop(I2C).
110+
111+
read_acceleration(I2C) ->
112+
%% Read 6 bytes starting at OUT_X_L with auto-increment (bit 7 set)
113+
case i2c:read_bytes(I2C, ?LIS3DH_ADDR, ?OUT_X_L bor 16#80, 6) of
114+
{ok, <<XL:8, XH:8/signed, YL:8, YH:8/signed, ZL:8, ZH:8/signed>>} ->
115+
%% 12-bit left-justified in high-resolution mode: shift right by 4
116+
X = ((XH bsl 8) bor XL) bsr 4,
117+
Y = ((YH bsl 8) bor YL) bsr 4,
118+
Z = ((ZH bsl 8) bor ZL) bsr 4,
119+
{ok, {X, Y, Z}};
120+
{error, _} = Error ->
121+
Error
122+
end.

libs/avm_stm32/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ include(BuildErlang)
2424

2525
set(ERLANG_MODULES
2626
gpio
27+
i2c
2728
)
2829

2930
pack_archive(avm_stm32 DEPENDS_ON eavmlib ERLC_FLAGS +warnings_as_errors MODULES ${ERLANG_MODULES})

0 commit comments

Comments
 (0)