Skip to content

Use updated gems and littlefs #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 11, 2023
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dependencies.lock
build/
sdkconfig.old

Expand All @@ -7,5 +8,6 @@ main/spiffs/*.pem.key
main/spiffs/*.pem.crt

components/mruby_component/esp32_build_config.rb.lock
managed_components

.vscode
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "mruby"]
path = components/mruby_component/mruby
url = https://github.com/mruby/mruby.git
[submodule "components/esp_littlefs"]
path = components/esp_littlefs
url = https://github.com/joltwallet/esp_littlefs.git
117 changes: 86 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,112 @@
# Example of mruby on the ESP32
# mruby on the ESP32

Before you get started you will need to follow the setup documentation from
the [esp-idf](https://github.com/espressif/esp-idf/tree/master/docs) project
for your specific operating system.
This is an ESP-IDF project template running mruby on the ESP32 microcontroller.

I have only tested this on macOS and using a certain version of
[esp-idf](https://github.com/espressif/esp-idf/tree/release/v5.0).
You should try to use [more recent version](https://github.com/espressif/esp-idf#setting-up-esp-idf) if you have failed.
To get started, you need to install the ESP-IDF, by following the instructions
[here](https://docs.espressif.com/projects/esp-idf/en/release-v5.1/esp32/get-started/index.html),
for your operating system.

You will need to recursively clone this project with the recursive flag
because it includes mruby as a submodule:
This has been tested on macOS and Ubuntu Linux, using
[ESP-IDF 5.1](https://github.com/espressif/esp-idf/tree/release/v5.1).

## Usage

Recursively clone this repo to ensure the mruby (3.2.0) submodule gets downloaded:

```
git clone --recursive https://github.com/mruby-esp32/mruby-esp32.git
```

The main ruby program can be found in the `main/simplest_mrb.rb` file. The
makefile configuration in `main/component.mk` and the main entry point source
file `mruby_main.c` will also be of interest if you want to change the name of
the ruby script. The examples included are very simple scripts that only print
to the ESP32's debug console.
The makefile configuration is in `main/component.mk`. The entry point source
file is `mruby_main.c`. Once that starts, it looks for `storage/main.rb` and runs it in mruby.
You can change the expected filename in `mruby_main.c`, or simply save your scripts as `main.rb`
inside the `storage` subfolder.

I'm assuming you have followed all the steps in the install documentation and
are at least somewhat familiar with the building steps. With that in mind you
can do something like the following and see the example running:
### First Build

```
cp main/examples/$(YOU_WISH_TO_TRY_FILE) main/spiffs/main.rb
idf.py build
idf.py -p $(YOUR_SERIAL_PORT) flash monitor
```
Your ESP32 should write 2 lines of numbers to the console.

The valiable `YOU_WISH_TO_TRY_FILE` can be replaced with one of the following:
### Examples

* _simplest_mrb.rb_ - Simply prints two strings
* _gpio.rb_ - An example of using GPIO
* _wifi_example_mrb.rb_ - An example of connecting to WiFi, you will need to
modify this file to include your SSID and password
* _mqtt_publish.rb_ - An sample of publishing to MQTT broker
* _system_mrb.rb_ - Examples of most of the system APIs
The folder `main/examples` includes simple scripts demonstrating functionality.

The clean command will clean both the ESP32 build and the mruby build:
Once you are familiar with the build process, try them with:

```
idf.py fullclean
cp main/examples/$(EXAMPLE_FILENAME) main/storage/main.rb
idf.py build
idf.py -p $(YOUR_SERIAL_PORT) flash monitor
```

There are multiple GEMS that can be turned on and off via the mruby
Replace `EXAMPLE_FILENAME` with one of the following:

* `simplest.rb` - Prints two strings
* `system.rb` - Demonstrates most system APIs
* `gpio.rb` - GPIO blink example
* `wifi_connect.rb` - Connects to WiFi
* `wifi_socket.rb` - Connects to WiFi and makes a TCPSocket connection
* `mqtt_publish.rb` - Connects to WiFi and publishes to MQTT broker
* `filesystem.rb` - Write/append/read a file on the virtual filesystem
* `ledc_breathe.rb` - Gradually fades the brightness of an LED up and down
* `ledc_buzzer.rb` - Plays a melody on a piezo-electric buzzer
* `ledc_servo.rb` - Controls position of a 180 degree hobby servo motor

**Note**: Edit GPIO numbers to match ones you are connected to, insert your WiFI credentials, customize MQTT settings etc.

### Build Customization

There are multiple gems that can be turned on and off via the mruby
configuration file found in
`components/mruby_component/esp32_build_config.rb`:

* _mruby-esp32-system_ - ESP32 system calls
* _mruby-esp32-wifi_ - ESP32 WiFi
* _mruby-esp32-mqtt_ - ESP32 MQTT library
* [_mruby-socket_](https://github.com/mruby-esp32/mruby-socket/tree/0.5) - ESP32 Socket library (modified from mruby)
* [_mruby-esp32-system_](https://github.com/mruby-esp32/mruby-esp32-system/tree/0.5) - ESP32 system calls
* [_mruby-esp32-wifi_](https://github.com/mruby-esp32/mruby-esp32-wifi/tree/0.5) - ESP32 WiFi
* [_mruby-esp32-mqtt_](https://github.com/mruby-esp32/mruby-esp32-mqtt/tree/0.5) - ESP32 MQTT library
* [_mruby-esp32-gpio_](https://github.com/mruby-esp32/mruby-esp32-gpio/tree/0.5) - ESP32 GPIO library
* [_mruby-esp32-ledc_](https://github.com/mruby-esp32/mruby-esp32-ledc/tree/0.5) - ESP32 LEDC (PWM) library

To get gem changes to reflect in the build, `fullclean` the previous build, then build again:
```
idf.py fullclean
idf.py build
```

All gems are enabled by default, so you can try out the examples, but it's a good idea to disable ones you don't need.

## Hardware

Everything works on:
- Original ESP32: `idf.py set-target esp32`

Everything except gpio gem works on:
- ESP32-S2: `idf.py set-target esp32s2`
- ESP32-S3: `idf.py set-target esp32s3`

If you followed the IDF installation instructions correctly for your chip,
you can switch the project target with the corresponding command above.

You will probably not be able to build again, until the project partition table is reset to `partitions.csv`. To do this:

```
idf.py menuconfig
# Partition Table -> Partition Table (1st option) -> Custom partition Table CSV (Last options)
# Enter to select. Q to exit. Y to save
```

## Troubleshooting

The following files and folders are safe to delete when trying to solve build issues:
- `build`
- `components/mruby_component/build`
- `components/mruby_component/esp32_build_config.rb.lock`
- `managed_components`
- `dependencies.lock`

This project uses [littlefs](https://github.com/littlefs-project/littlefs) through IDF component
manager. If you see errors about files on disk changing, try deleting the last 2 items on this list.

1 change: 1 addition & 0 deletions components/esp_littlefs
Submodule esp_littlefs added at 8fb029
4 changes: 2 additions & 2 deletions components/mruby_component/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set(MRUBY_CONFIG ${COMPONENT_DIR}/esp32_build_config.rb)

idf_component_register(
INCLUDE_DIRS mruby/include
REQUIRES esp_wifi esp_hw_support esp_rom mqtt driver esp_timer
REQUIRES esp_hw_support esp_rom esp_timer esp_wifi driver mqtt
)

add_custom_command(
Expand All @@ -17,7 +17,7 @@ add_custom_command(

add_prebuilt_library(
libmruby ${LIBMRUBY_FILE}
PRIV_REQUIRES esp_wifi esp_hw_support esp_rom mqtt driver
PRIV_REQUIRES esp_hw_support esp_rom esp_timer esp_wifi driver mqtt
)
target_link_libraries(${COMPONENT_LIB} INTERFACE libmruby)

Expand Down
15 changes: 10 additions & 5 deletions components/mruby_component/esp32_build_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,14 @@

conf.gem :core => "mruby-print"
conf.gem :core => "mruby-compiler"
conf.gem :github => "mruby-esp32/mruby-esp32-system"
conf.gem :github => "mruby-esp32/mruby-esp32-wifi"
conf.gem :github => "mruby-esp32/mruby-esp32-mqtt"
conf.gem :github => "mruby-esp32/mruby-io", :branch => 'esp32'
conf.gem :github => "mruby-esp32/mruby-esp32-gpio"
conf.gem :github => "mruby-esp32/mruby-io", :branch => '0.5'
conf.gem :github => "mruby-esp32/mruby-fileio", :branch => '0.5'
conf.gem :github => "mruby-esp32/mruby-socket", :branch => '0.5'

conf.gem :github => "mruby-esp32/mruby-esp32-system", :branch => '0.5'
conf.gem :github => "mruby-esp32/mruby-esp32-wifi", :branch => '0.5'
conf.gem :github => "mruby-esp32/mruby-esp32-mqtt", :branch => '0.5'

conf.gem :github => "mruby-esp32/mruby-esp32-gpio", :branch => '0.5'
conf.gem :github => "mruby-esp32/mruby-esp32-ledc", :branch => '0.5'
end
4 changes: 2 additions & 2 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ idf_component_register(
SRCS mruby_main.c
INCLUDE_DIRS .
REQUIRES mruby_component
PRIV_REQUIRES nvs_flash spiffs
PRIV_REQUIRES nvs_flash esp_littlefs
)

spiffs_create_partition_image(storage ./spiffs FLASH_IN_PROJECT)
littlefs_create_partition_image(storage ./storage FLASH_IN_PROJECT)
42 changes: 42 additions & 0 deletions main/examples/filesystem.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Get the number of previous boots from a file.
boot_count = nil
File.open('/storage/boot_count.txt', 'a+') { |f| boot_count = f.gets }

# Increment it.
boot_count = 0 unless boot_count
boot_count = boot_count.to_i
boot_count += 1

# Write new count back to file.
File.open('/storage/boot_count.txt', 'w') { |f| f.puts(boot_count) }

# Display it.
puts "Boot count: #{boot_count}"

# PERSISTENCE DEMO
persistence_file = "/storage/test.txt"

# If first boot, write then append to the test file.
if boot_count == 1
string1 = "testing "
string2 = "1,2,3..."

puts "Writing to #{persistence_file}: \"#{string1}#{string2}\""

File.open(persistence_file, 'w') { |f| f.write(string1) }
File.open(persistence_file, 'a') { |f| f.write(string2) }
end

# Read the file back on every boot.
print "Read from #{persistence_file}: "
File.open(persistence_file, 'r') { |f| f.each_line { |l| puts l } }

# OVERWRITE DEMO
overwrite_file = '/storage/overwrite.txt'

File.open(overwrite_file, 'w') { |f| f.puts "12345678" }
File.open(overwrite_file, 'w') { |f| f.puts "1234" }

puts "#{overwrite_file} should contain: 1234"
print "#{overwrite_file} contains: "
File.open(overwrite_file, 'r') { |f| f.each_line { |l| puts l } }
26 changes: 26 additions & 0 deletions main/examples/ledc_breathe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
group = ESP32::LEDC_LOW_SPEED_MODE
channel = ESP32::LEDC_CHANNEL_0
timer = ESP32::LEDC_TIMER_0
resolution = ESP32::LEDC_TIMER_8_BIT
frequency = 1000
pin = ESP32::GPIO::GPIO_NUM_2 # Built in LED on original ESP32 devkit.

ESP32::LEDC.timer_config(group, timer, resolution, frequency)
ESP32::LEDC.channel_config(pin, group, timer, channel)

# Fade the LED up and down.
loop do
i = 0
while (i < 256) do
ESP32::LEDC.set_duty(group, channel, i)
i += 1
ESP32::System.delay(10)
end

i=255
while (i > -1) do
ESP32::LEDC.set_duty(group, channel, i)
i -= 1
ESP32::System.delay(10)
end
end
39 changes: 39 additions & 0 deletions main/examples/ledc_buzzer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
group = ESP32::LEDC_LOW_SPEED_MODE
channel = ESP32::LEDC_CHANNEL_0
timer = ESP32::LEDC_TIMER_0
resolution = ESP32::LEDC_TIMER_8_BIT
pin = ESP32::GPIO::GPIO_NUM_4

# Configure the channel once.
ESP32::LEDC.channel_config(pin, group, timer, channel)

# Note frequencies.
C4 = 262
D4 = 294
E4 = 330

# Melody to play.
notes = [
[E4, 1], [D4, 1], [C4, 1], [D4, 1], [E4, 1], [E4, 1], [E4, 2],
[D4, 1], [D4, 1], [D4, 2], [E4, 1], [E4, 1], [E4, 2],
[E4, 1], [D4, 1], [C4, 1], [D4, 1], [E4, 1], [E4, 1], [E4, 1], [E4, 1],
[D4, 1], [D4, 1], [E4, 1], [D4, 1], [C4, 4],
]

# Calculate length of one beat in milliseconds.
bpm = 180
beat_time = 60000.to_f / bpm

# Play the melody.
notes.each do |note|
# Set timer frequency to 0th element of the note array.
ESP32::LEDC.timer_config(group, timer, resolution, note[0])
# Duty cycle to 50% for square wave.
ESP32::LEDC.set_duty(group, channel, 128)

# Wait for length of the note, 1st element.
ESP32::System.delay(note[1] * beat_time)

# Duty cycle to 0 to stop note.
ESP32::LEDC.set_duty(group, channel, 0)
end
37 changes: 37 additions & 0 deletions main/examples/ledc_servo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
group = ESP32::LEDC_LOW_SPEED_MODE
channel = ESP32::LEDC_CHANNEL_0
timer = ESP32::LEDC_TIMER_0
resolution = ESP32::LEDC_TIMER_14_BIT
pin = ESP32::GPIO::GPIO_NUM_4
frequency = 50

# Configure the channel and timer.
ESP32::LEDC.channel_config(pin, group, timer, channel)
ESP32::LEDC.timer_config(group, timer, resolution, frequency)

# Using 14-bit PWM @ 50Hz, 0-16383 maps from 0 to 20 milliseconds.
# Calculate how many microseconds each LSB of duty cycle represents.
US_PER_BIT = (1000000.0 / frequency) / (2 ** resolution)

# Convert from microseconds to duty cycle.
def microseconds_to_duty(us)
(us / US_PER_BIT).round
end

# This is for a 180 degree MG995 motor. Values will differ for other sweep angles,
# or continuous rotation servos / ESCs. Values may vary between individual motors.
#
# Make sure to connect your servo motor to a separate power source!
#
5.times do
# Send 500us pulses for 2 seconds. Should map to 0 degrees.
ESP32::LEDC.set_duty(group, channel, microseconds_to_duty(500))
ESP32::System.delay(2000)

# Send 2500us pulses for 2 seconds. Should map to 180 degrees.
ESP32::LEDC.set_duty(group, channel, microseconds_to_duty(2500))
ESP32::System.delay(2000)
end

# Turn it off.
ESP32::LEDC.set_duty(group, channel, 0)
File renamed without changes.
File renamed without changes.
File renamed without changes.
38 changes: 38 additions & 0 deletions main/examples/wifi_socket.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Stack sizes may need to be increased.
# See: https://github.com/mruby-esp32/mruby-socket/blob/0.4/README.md
#
puts "Getting ready to start Wi-Fi"

wifi = ESP32::WiFi.new

wifi.on_connected do |ip|
puts "Wi-Fi Connected: #{ip} (#{Socket.gethostname})"
soc = TCPSocket.open("www.kame.net", 80)
msg = "HEAD / HTTP/1.1\r\nHost: www.kame.net\r\nConnection: close\r\n\r\n"
msg.split("\r\n").each do |e|
puts ">>> #{e}"
end
soc.send(msg, 0)
puts "--------------------------------------------------------------------------------"
loop do
buf = soc.recv(128, 0)
break if buf.length == 0
print buf
end
puts ""
puts "--------------------------------------------------------------------------------"
end

wifi.on_disconnected do
puts "Wi-Fi Disconnected"
end

puts "Connecting to Wi-Fi"
wifi.connect('SSID', 'PASSWORD')

#
# Loop forever otherwise the script ends
#
while true do
ESP32::System.delay(1000)
end
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy