Rabbit Slide Show

A Beginner's Complete Guide to Microcontroller Programming with Ruby

2023-10-07

Description

Presentation slide for RubyConfTH 2023

Text

Page: 1

A Beginner's Complete
Guide to Microcontroller
Programming with Ruby
hasumikin
Bangkok, Thailand
October 6th - 7th 2023

Page: 2

Part 1
Preparation
Part 2
Getting Started with Microcontroller
Part 3
Exploring PicoRuby Further
Part 4
PicoRuby Under the Hood

Page: 3

self.inspect
Hitoshi HASUMI
hasumikin (GitHub, ex-Twitter, Bluesky and Threads)
Creator of PicoRuby and PRK Firmware
Committer of CRuby's IRB and Reline
First prize of Fukuoka Ruby Award
(2020 and 2022 )
A final nominee of Ruby Prize 2021

Page: 4

Part 1
Preparation

Page: 5

Setup (minimal)
Raspberry Pi Pico
Or other RP2040-based controller
USB cable
Terminal emulator on laptop
RP2040

Page: 6

Raspberry Pi Pico
Raspberry Pi Pico: Microcontroller board
MCU: RP2040
Cortex-Mzero+ (dual)
264 KB RAM
2 MB flash ROM
It generally runs without an OS (bere metal)
ref) Raspberry Pi: Single-board computer
It generally needs an OS like Raspberry Pi OS or
Windows for Arm

Page: 7

Terminal emulator
Linux -> GTKTerm
Windows -> Tera Term
macOS -> PuTTY (I'm not sure)
Traditional CUI/TUI tools may have CR/LF
trouble
cu
screen
minicom

Page: 8

Let's begin 1/4
Download the latest
`R2P2-*.(zip|gz)`
from GitHub
then unzip it into
`R2P2-*.uf2`
github.com/picoruby/R2P2/releases

Page: 9

Let's begin 2/4
Connect Pi Pico and PC while
pressing the BOOTSEL button
You'll find "RPI-RP2" drive
in file manager
https://www.raspberrypi.org/documentation/rp2040/getting-started

Page: 10

Let's begin 3/4
Drag & drop `R2P2-*.uf2` into RPI-RP2 drive

Page: 11

Let's begin 4/4
Open a proper
serial port on
terminal emulator

Page: 12

R2P2 Shell should start [Demo]
Unix-like shell running on Raspberry Pi Pico
You can use some
commands like `pwd`, `cd`,
`ls`, `mkdir`
It apparently has a
filesystem
(written in Ruby!)

Page: 13

PicoIRB [Demo]
PicoRuby's IRB is running within the R2P2 shell
on Raspberry Pi Pico
Your Ruby snippet is going to be compiled into
mruby VM code and executed on the fly
It means PicoRuby contains an mruby compiler
which can run on a one-chip microcontroller (will be
mentioned later)

Page: 14

Part 2
Getting Started with
Microcontroller

Page: 15

GPIO (General Purpose Input/Output)
Fundamental digital I/O
Variety of uses:
Input: Detects on-off state of switch and button
Output: Makes a voltage
You can even implement a communication protocol
by controlling GPIO in milli/micro sec

Page: 16

GPIO --- Blinking LED [Demo]
irb> led = GPIO.new(25, GPIO::OUT)
irb> 3.times do
irb*
led.write 1
irb*
sleep 1
irb*
led.write 0
irb*
sleep 1
irb* end
GPIO25 internally connects to on-board LED
through a resistor

Page: 17

GPIO --- Blinking LED by discrete parts
Parts list:
LED (RED)
Resistor (1kΩ)

Page: 18

GPIO --- Blinking LED by discrete parts
irb> pin = GPIO.new(15, GPIO::OUT)

Page: 19

GPIO --- Blinking LED by discrete parts
GPIO15 ===> 1kΩ ===> LED ===> GND
<----- 1.5V -----><--- 1.8V ---->
<------------ 3.3V ------------->
RP2040's logic level: 3.3V
LED voltage drop: 1.8V
(according to LED's datasheet)
Current: (3.3V - 1.8V) / 1kΩ = 1.5mA
(calculated by Ohm's Law)

Page: 20

Study time: Electromagnetism | Physics
Ohm's Law
V = I * R ⇔ I = V / R ⇔ R = V / I
Kirchhoff's Circuit Laws
Current law: The algebraic sum of currents in a
network of conductors meeting at a point is zero
Voltage law: The directed sum of the potential
differences (voltages) around any closed loop is zero

Page: 21

ADC (Analog to Digital Converter)
ADC handles values from 0 to logic-level by
converting an analog voltage to a digital value
e.g. RP2040's ADC has 12 bits depth and
accordingly takes a raw value from 0 (0 V) to
4095 (3.3 V)
Typical usage:
Temperature sensor
Joystick

Page: 22

ADC --- Temperature [Demo]
irb>
irb>
irb>
irb>
irb*
irb*
irb*
irb*
require 'adc'
adc = ADC.new(:temperature)
adc.read_raw
while true
voltage = adc.read_voltage
puts 27 - (voltage - 0.706) / 0.001721
sleep 1
end
RP2040 has an in-chip temperature sensor that
connects to an ADC channel

Page: 23

ADC --- Temperature by discrete parts
Parts list:
Resistor
Rref: 10kΩ
Thermistor
10kΩ (at 25℃ = 298.15K)
B const: 3950
T0: 298.15 (kelvin)

Page: 24

ADC --- Temperature by discrete parts
Parts list:
Resistor
Rref: 10kΩ
Thermistor
10kΩ (at 25℃ = 298.15K)
B const: 3950
T0: 298.15 (kelvin)

Page: 25

ADC --- Temperature by discrete parts
irb> require 'adc'
irb> Rref = 10000.0
irb> B = 3950.0
irb> T0 = 298.15
irb> def kelvin_temp(rth)
irb*
temp_inverse = 1 / B * Math.log(rth / Rref) + (1 / T0)
irb*
1 / temp_inverse
irb* end
irb> rth = (3.3 / adc.read_voltage - 1) * Rref
irb> puts "#{kelvin_temp(rth) - 273.15} C"
=> 28.1234 C

Page: 26

Part 3
Exploring PicoRuby Further

Page: 27

PicoRuby applications
R2P2
Unix-like shell system written in PicoRuby
You may want to say an Operating System in Ruby
PRK Firmware
Keyboard firmware framework for DIY keyboard
You can write your keymap and keyboard's behavior
with Ruby

Page: 28

R2P2 (again)
IRB
Multiple-line editor
Built-in commands and executables (all written
in Ruby)
You can write your own external command

Page: 29

Executables in R2P2
# date
puts Time.now.to_s
# mkdir
Dir.mkdir(ARGV[0])

Page: 30

Write a Ruby script file [Demo]
$> vim hello.rb
Edit the file and save it.
puts "Hello World!"
Then run it.
$> ./hello.rb

Page: 31

Or just drag and drop [Demo]

Page: 32

GPIO and ADC work together [Demo]
require 'adc'
def calc_temp(volt)
27 - (volt - 0.706) / 0.001721
end
adc = ADC.new(:temperature)
led = GPIO.new(25, GPIO::OUT)
while true
temp = calc_temp(adc.read_voltage)
puts "temp: #{temp} C"
led.write(30 < temp ? 1 : 0)
sleep 1
end

Page: 33

R2P2 [Demo]
`/home/app.rb` automatically runs on start up
# You can stop by Ctrl-C
led = GPIO.new(25, GPIO::OUT)
while true
led.write 1
puts "Hello World!"
sleep 1
led.write 0
sleep 1
end

Page: 34

BTW,
R2P2 stands for
Ruby on Raspberry Pi Pico

Page: 35

[FYI] Serial communication protocols
SPI: High speed, full duplex. e.g. Acceleration
sensor, Color display, etc.
I2C: Low speed, Addressing network with fewer
wires. e.g. RTC, Temperature sensor and
Charactor display, etc.
UART: Buffered asyncronous communication.
e.g. Terminal emulator, Wireless module like BLE
and LTE/5G, etc.

Page: 36

[FYI] I2C and UART
Example of I2C (RTC)
and UART (USB serial)
Watch the demo video
in README.md
It's also an example of
how to build your own app
github.com/picoruby/rp2040-peripheral-demo

Page: 37

[FYI] I2C and UART
Parts list:
PCF8523 RTC module
FTDI USB to TTL Serial
Adapter Cable (3.3V)

Page: 38

PRK Firmware - Corne (CRKBD)

Page: 39

PRK Firmware - Meishi2 (4-keys pad)
require "consumer_key"
kbd = Keyboard.new
kbd.init_pins(
# row0, row1
[ 6, 7 ],
[ 28, 27 ] # col0, col1
)
kbd.add_layer :default, %i[ ZERO_RAISE KC_1 KC_2 KC_3 ]
kbd.define_mode_key :ZERO_RAISE, [ :KC_0, :raise, 200, 200 ]
%i[ ZERO_RAISE
kbd.add_layer :raise,
KC_AUDIO_VOL_UP
KC_AUDIO_VOL_DOWN
KC_AUDIO_MUTE ]
kbd.start!

Page: 40

Part 4
PicoRuby Under the Hood

Page: 41

mruby and PicoRuby
mruby
General purpose embedded Ruby implementation
written by Matz
PicoRuby (PicoRuby compiler + mruby/c VM)
Another implementation of murby targeting on one-
chip microcontroller (smaller foot print)
The VM code specifications are common to both
So the compilers are interchangeable

Page: 42

Small foot print
$ valgrind
--tool=massif
--stacks=yes
path/to/(mruby|picoruby)
-e 'puts "Hello World!"'
\
\
\
\
`massif.out.[pid]` file will be created. Then,
$ ms_print massif.out.1234 | less

Page: 43

Small foot print
--------------------------------------------------------------------------------
Command:
mruby -e 'puts "Hello World!"'
Massif arguments:
--stacks=yes
ms_print arguments: massif.out.18391
--------------------------------------------------------------------------------
KB
133.5^
#
|
#
|
#
|
#
|
#
|
#
|
#
|
#
|
@
:@:::@:#:
|
@:@@@::::@:::@:#::
|
::@::::::@::::::::@:@@@::::@:::@:#::
|
@:::::::::@@::::@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@@@:::@:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
|
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
| @
@ :: @:::::::::@ :: :@:::@::::::@:::::: :@:@@@::::@:::@:#::
0 +----------------------------------------------------------------------->Mi
0
1.281
# Note: Measured in 64 bit Ubuntu

Page: 44

Small foot print
--------------------------------------------------------------------------------
Command:
picoruby -e 'puts "Hello World!"'
Massif arguments:
--stacks=yes
ms_print arguments: massif.out.21752
--------------------------------------------------------------------------------
KB
9.820^
#
|
@:#:::
|
@:#:::::
|
@:#:::::
|
@:#:::::
|
@
@:#:::::
|
@
@:#:::::
|
@
: @:#:::::
|
@
::: @:#:::::
|
@
: ::: @:#:::::
|
@
::@::::@:#:::::@
|
@
::@::::@:#:::::@
|
@:
:::::@::::@:#:::::@
|
@:::
:: :::@::::@:#:::::@
|
@::
::: :::@::::@:#:::::@
|
@:: :
::: :::@::::@:#:::::@
|
@:: :
::: :::@::::@:#:::::@
|
:@:: :
:
:: :@:@: :
:@@: ::@::::: ::: :::@::::@:#:::::@
|
:@:: :::::::::::::::@:@:@:::::@ ::: @:: : :::: :::@::::@:#:::::@
|::::::@::@:: :::
::: :::::@:@:@:: ::@ : : @:: : :::: :::@::::@:#:::::@
0 +----------------------------------------------------------------------->ki
0
324.5
# Note: Measured in 64 bit Ubuntu

Page: 45

Small foot print
RAM consumption of `puts "Hello World!"`
mruby: 133.5 KB (on 64 bit)
PicoRuby: 9.82 KB (on 64 bit)
RP2040 (32 bit) has 264 KB RAM
Only small applications running with mruby works
Big apps like R2P2 and PRK Firmware should be
written in PicoRuby

Page: 46

PicoRuby ecosystem
Picogems
PRK Firmware is also a Picogem
Peripheral gems
picoruby-gpio
picoruby-adc
picoruby-i2c
picoruby-spi
picoruby-uart
Peripheral interface guide
https://github.com/mruby/microcontroller-peripheral-interface-guide

Page: 47

PicoRuby ecosystem
Build system forked from mruby
You can build your application in a similar way to
mruby
You can also write your gem and host it on your
GitHub
RP2040 is the only target as of now. So,
You can port PicoRuby (Picogems) to other
microcontrollers

Page: 48

Restrictions of PicoRuby
Minimum built-in classes and methods
Doesn't support some syntax like heredoc and
numbered parameters
No meta-programming features
No strict distinction between instance methods
and singleton methods
Some bugs (because I'm lazy ).
See github.com/picoruby/picoruby/issues

Page: 49

Conclusion
PicoRuby is a Ruby implementaiton targeting on
one-chip microcontroller
Essential peripheral libraries: GPIO, ADC, I2C,
SPI, and UART are ready
You can develop your microcontroller
application step by step using the R2P2 and IRB
You need only R2P2 to write small applications
Future work:
Bluetooth for "Raspberry Pi Pico W" (soon
)

Page: 50

RubyKaigi 2024
[ad]
In Okinawa
May 15th - 17th
1000+ attendees, tons of tech talks
All Japanese talks come with simultaneous interpretation into English
Various parties
https://098free.com/photos/14262/

Page: 51

That's all! Visit repos and stargaze
github.com/picoruby/picoruby
github.com/picoruby/R2P2
github.com/picoruby/prk_firmware
github.com/picoruby/rp2040-peripheral-demo

Other slides