Skip to content

Commit ae35c43

Browse files
committed
Add Elixir ESP NVS and RTC examples
1 parent 9e346ce commit ae35c43

8 files changed

Lines changed: 326 additions & 2 deletions

File tree

elixir/EspNvs/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!---
2+
Copyright 2026 Masatoshi Nishiguchi
3+
4+
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
5+
-->
6+
7+
# `EspNvs` Application
8+
9+
Welcome to the `EspNvs` AtomVM application.
10+
11+
The `EspNvs` AtomVM application uses ESP32 non-volatile storage (NVS) to store a small value.
12+
If the NVS storage has not been set for this application, it will store a default value once. The application then logs the result and restarts every 10 seconds.
13+
14+
For more information about programming on the AtomVM platform, see the [AtomVM Programmers Guide](https://doc.atomvm.org/latest/programmers-guide.html).
15+
16+
For general information about building and executing Elixir AtomVM example programs, see the Elixir example program [README](../README.md).

elixir/EspNvs/lib/esp_nvs.ex

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2026 Masatoshi Nishiguchi
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+
defmodule EspNvs do
22+
@moduledoc """
23+
Demonstrates ESP32 NVS usage by storing a small value once.
24+
"""
25+
26+
@compile {:no_warn_undefined, :atomvm}
27+
@compile {:no_warn_undefined, :esp}
28+
29+
@nvs_namespace :esp_nvs
30+
@nvs_key :word
31+
@default_word "Hello"
32+
@restart_interval_ms 10_000
33+
34+
def start do
35+
case verify_platform(:atomvm.platform()) do
36+
:ok ->
37+
case :esp.nvs_fetch_binary(@nvs_namespace, @nvs_key) do
38+
{:ok, word} when is_binary(word) ->
39+
IO.puts("Fetched word from NVS: #{word}")
40+
41+
{:error, :not_found} ->
42+
IO.puts("No word found. Storing default word to NVS once: #{@default_word}")
43+
:ok = :esp.nvs_put_binary(@nvs_namespace, @nvs_key, @default_word)
44+
45+
_ ->
46+
IO.puts("Error reading NVS. Skipping write.")
47+
end
48+
49+
IO.puts("Restarting in 10 seconds ...")
50+
Process.sleep(@restart_interval_ms)
51+
:esp.restart()
52+
53+
error ->
54+
error
55+
end
56+
end
57+
58+
defp verify_platform(:esp32), do: :ok
59+
defp verify_platform(platform), do: {:error, {:unsupported_platform, platform}}
60+
end

elixir/EspNvs/mix.exs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2026 Masatoshi Nishiguchi
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+
defmodule EspNvs.MixProject do
22+
use Mix.Project
23+
24+
def project do
25+
[
26+
app: :esp_nvs,
27+
version: "0.1.0",
28+
elixir: "~> 1.17",
29+
start_permanent: Mix.env() == :prod,
30+
deps: deps(),
31+
atomvm: [
32+
start: EspNvs,
33+
flash_offset: 0x250000
34+
]
35+
]
36+
end
37+
38+
# Run "mix help compile.app" to learn about applications.
39+
def application do
40+
[
41+
extra_applications: [:logger]
42+
]
43+
end
44+
45+
# Run "mix help deps" to learn about dependencies.
46+
defp deps do
47+
[
48+
{:exatomvm, git: "https://github.com/atomvm/ExAtomVM/", branch: "main"}
49+
]
50+
end
51+
end

elixir/EspRtcMemory/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!---
2+
Copyright 2026 Masatoshi Nishiguchi
3+
4+
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
5+
-->
6+
7+
# `EspRtcMemory` Application
8+
9+
Welcome to the `EspRtcMemory` AtomVM application.
10+
11+
The `EspRtcMemory` AtomVM application uses ESP32 RTC slow memory to record the number of times the device has restarted.
12+
If no value has been stored in RTC slow memory yet, the counter is initialized to 0. The device will then sleep for 10 seconds and restart. After each restart, the counter is incremented and stored back to RTC slow memory.
13+
14+
For more information about programming on the AtomVM platform, see the [AtomVM Programmers Guide](https://doc.atomvm.org/latest/programmers-guide.html).
15+
16+
For general information about building and executing Elixir AtomVM example programs, see the Elixir example program [README](../README.md).
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2026 Masatoshi Nishiguchi
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+
defmodule EspRtcMemory do
22+
@moduledoc """
23+
Demonstrates ESP32 RTC slow memory usage by persisting a restart counter.
24+
"""
25+
26+
@compile {:no_warn_undefined, :atomvm}
27+
@compile {:no_warn_undefined, :esp}
28+
29+
@restart_delay_ms 10_000
30+
31+
def start do
32+
case verify_platform(:atomvm.platform()) do
33+
:ok ->
34+
load_state()
35+
|> increment_state()
36+
|> save_state()
37+
38+
IO.puts("Restarting in 10 seconds ...")
39+
Process.sleep(@restart_delay_ms)
40+
:esp.restart()
41+
42+
error ->
43+
error
44+
end
45+
end
46+
47+
defp load_state do
48+
IO.puts("Loading count from RTC slow memory ...")
49+
50+
encoded_term =
51+
try do
52+
:esp.rtc_slow_get_binary()
53+
catch
54+
:error, :badarg ->
55+
IO.puts("This device has not recorded the number of starts. Initializing to 0.")
56+
:erlang.term_to_binary(%RebootState{})
57+
end
58+
59+
case safe_binary_to_term(encoded_term) do
60+
{:ok, %RebootState{count: count} = state} when is_integer(count) and count >= 0 ->
61+
state
62+
63+
_ ->
64+
IO.puts("Error: bad value, resetting to 0.")
65+
%RebootState{}
66+
end
67+
end
68+
69+
defp safe_binary_to_term(encoded_term) when is_binary(encoded_term) do
70+
try do
71+
{:ok, :erlang.binary_to_term(encoded_term)}
72+
catch
73+
:error, _ ->
74+
:error
75+
end
76+
end
77+
78+
defp save_state(current_state) do
79+
IO.puts("Saving count to RTC slow memory ...")
80+
81+
current_state
82+
|> :erlang.term_to_binary()
83+
|> :esp.rtc_slow_set_binary()
84+
end
85+
86+
defp increment_state(%RebootState{count: count} = state) when is_integer(count) and count >= 0 do
87+
new_count = count + 1
88+
IO.puts("This device has restarted #{new_count} time(s).")
89+
%RebootState{state | count: new_count}
90+
end
91+
92+
defp increment_state(_) do
93+
IO.puts("Error: bad value, resetting to 0.")
94+
%RebootState{}
95+
end
96+
97+
defp verify_platform(:esp32), do: :ok
98+
defp verify_platform(platform), do: {:error, {:unsupported_platform, platform}}
99+
end
100+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2026 Masatoshi Nishiguchi
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+
defmodule RebootState do
22+
@moduledoc """
23+
Holds the reboot counter persisted in RTC slow memory.
24+
"""
25+
26+
defstruct count: 0
27+
end
28+

elixir/EspRtcMemory/mix.exs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2026 Masatoshi Nishiguchi
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+
defmodule EspRtcMemory.MixProject do
22+
use Mix.Project
23+
24+
def project do
25+
[
26+
app: :esp_rtc_memory,
27+
version: "0.1.0",
28+
elixir: "~> 1.17",
29+
start_permanent: Mix.env() == :prod,
30+
deps: deps(),
31+
atomvm: [
32+
start: EspRtcMemory,
33+
flash_offset: 0x250000
34+
]
35+
]
36+
end
37+
38+
# Run "mix help compile.app" to learn about applications.
39+
def application do
40+
[
41+
extra_applications: [:logger]
42+
]
43+
end
44+
45+
# Run "mix help deps" to learn about dependencies.
46+
defp deps do
47+
[
48+
{:exatomvm, git: "https://github.com/atomvm/ExAtomVM/", branch: "main"}
49+
]
50+
end
51+
end

elixir/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ Some example programs can only run on specific platform. The following table su
1616
|-----------------|-------|-------|------|--------|--------------|
1717
| Blinky ||||||
1818
| HelloWorld ||||||
19-
| LEDC_Example ||||||
20-
| WifiExample ||||||
19+
| LEDC ||||||
20+
| Wifi ||||||
21+
| EspNvs ||||||
22+
| EspRtcMemory ||||||
2123

2224
✦ Works, but requires editing to use onboard LED, see the README in the examples directory.
2325

0 commit comments

Comments
 (0)