Uses the C library by Mike McCauley available at http://www.airspayce.com/mikem/bcm2835/
This module targets the model B revision 1, it could be tweaked for other versions.
core :: union_find
union–find algorithm using an efficient disjoint-set data structure
# Services to control the bcm2835 chipset used in the Raspberry Pi
#
# Uses the C library by Mike McCauley available at http://www.airspayce.com/mikem/bcm2835/
#
# This module targets the model B revision 1, it could be tweaked for other versions.
module bcm2835
in "C Header" `{
#include <bcm2835.h>
`}
fun bcm2835_init: Bool `{ return bcm2835_init(); `}
fun bcm2835_close `{ bcm2835_close(); `}
fun bcm2835_debug=(v: Bool) `{ bcm2835_set_debug(v); `}
# A physical binary pin
interface Pin
# Set the output of this pin
fun write(high: Bool) is abstract
end
extern class RPiPin `{ RPiGPIOPin `}
super Pin
new p1_03 `{ return RPI_GPIO_P1_03; `}
new p1_05 `{ return RPI_GPIO_P1_05; `}
new p1_07 `{ return RPI_GPIO_P1_07; `}
new p1_11 `{ return RPI_GPIO_P1_11; `}
new p1_12 `{ return RPI_GPIO_P1_12; `}
new p1_13 `{ return RPI_GPIO_P1_13; `}
new p1_15 `{ return RPI_GPIO_P1_15; `}
new p1_16 `{ return RPI_GPIO_P1_16; `}
new p1_18 `{ return RPI_GPIO_P1_18; `}
new p1_19 `{ return RPI_GPIO_P1_19; `}
new p1_21 `{ return RPI_GPIO_P1_21; `}
new p1_22 `{ return RPI_GPIO_P1_22; `}
new p1_23 `{ return RPI_GPIO_P1_23; `}
new p1_24 `{ return RPI_GPIO_P1_24; `}
new p1_26 `{ return RPI_GPIO_P1_26; `}
# Select mode: input, output or alts
fun fsel=(mode: FunctionSelect) `{ bcm2835_gpio_fsel(self, mode); `}
# Set output
redef fun write(high) `{ bcm2835_gpio_write(self, high? HIGH: LOW); `}
# Set pull up mode
fun pud=(pud: PUDControl) `{ bcm2835_gpio_set_pud(self, pud); `}
# Falling edge detect
# Do not use on raspbian, it is bugged!
fun fen `{ bcm2835_gpio_fen(self); `}
fun clr_fen `{ bcm2835_gpio_clr_fen(self); `}
# Raising edge detect
# Do not use on raspbian, it is bugged!
fun ren `{ bcm2835_gpio_ren(self); `}
fun clr_ren `{ bcm2835_gpio_clr_ren(self); `}
# High edge detect
# Do not use on raspbian, it is bugged!
fun hen `{ bcm2835_gpio_hen(self); `}
fun clr_hen `{ bcm2835_gpio_clr_hen(self); `}
# Low edge detect
# Do not use on raspbian, it is bugged!
fun len `{ bcm2835_gpio_len(self); `}
fun clr_len `{ bcm2835_gpio_clr_len(self); `}
fun set_eds `{ bcm2835_gpio_set_eds(self); `}
fun eds: Bool `{ return bcm2835_gpio_eds(self); `}
# Return input on pin, true for high and false for low
fun lev: Bool `{ return bcm2835_gpio_lev(self); `}
end
extern class FunctionSelect `{ bcm2835FunctionSelect `}
# Input function
new inpt `{ return BCM2835_GPIO_FSEL_INPT; `}
# Output function
new outp `{ return BCM2835_GPIO_FSEL_OUTP; `}
new alt0 `{ return BCM2835_GPIO_FSEL_ALT0; `}
new alt1 `{ return BCM2835_GPIO_FSEL_ALT1; `}
new alt2 `{ return BCM2835_GPIO_FSEL_ALT2; `}
new alt3 `{ return BCM2835_GPIO_FSEL_ALT3; `}
new alt4 `{ return BCM2835_GPIO_FSEL_ALT4; `}
new alt5 `{ return BCM2835_GPIO_FSEL_ALT5; `}
new mask `{ return BCM2835_GPIO_FSEL_MASK; `}
end
extern class PUDControl `{ bcm2835PUDControl `}
new off `{ return BCM2835_GPIO_PUD_OFF; `}
new down `{ return BCM2835_GPIO_PUD_DOWN; `}
new up `{ return BCM2835_GPIO_PUD_UP; `}
end
redef universal Int
fun bcm2835_delay `{ bcm2835_delay(self); `}
fun bcm2835_delay_micros `{ bcm2835_delayMicroseconds(self); `}
end
class RotaryEncoder
var pin_a: RPiPin
var pin_b: RPiPin
var old_a= false
var old_b= false
# returns '<', '>' or null accoring to rotation or lack thereof
fun update: nullable Char
do
var new_a = pin_a.lev
var new_b = pin_b.lev
var res = null
if new_a != old_a or new_b != old_b then
if not old_a and not old_b then
# everything was on
if not new_a and new_b then
res = '<'
else if new_a and not new_b then
res = '>'
end
else if old_a and old_b then
# everything was off
if not new_a and new_b then
res = '>'
else if new_a and not new_b then
res = '<'
end
end
old_a = new_a
old_b = new_b
end
return res
end
end
# Hitachi HD44780 or similar 2-4 lines LCD displays
class HD44780
var rs: RPiPin
var en: RPiPin
var d4: RPiPin
var d5: RPiPin
var d6: RPiPin
var d7: RPiPin
var ds = new Array[RPiPin]
# commands
fun flag_clear_display: Int do return 1
fun flag_return_home: Int do return 2
fun flag_entry_mode_set: Int do return 4
fun flag_display_control: Int do return 8
fun flag_cursor_shift: Int do return 16
fun flag_function_set: Int do return 32
fun flag_set_cgram_addr: Int do return 64
fun flag_set_ggram_addr: Int do return 128
# entry mode
fun flag_entry_right: Int do return 0
fun flag_entry_left: Int do return 2
fun flag_entry_shift_increment: Int do return 1
fun flag_entry_shift_decrement: Int do return 0
# display flags
fun flag_display_on: Int do return 4
fun flag_display_off: Int do return 0
fun flag_cursor_on: Int do return 2
fun flag_cursor_off: Int do return 0
fun flag_blink_on: Int do return 1
fun flag_blink_off: Int do return 0
# display/cursor shift
fun flag_display_move: Int do return 8
fun flag_cursor_move: Int do return 0
fun flag_move_right: Int do return 4
fun flag_move_left: Int do return 0
# function set
fun flag_8bit_mode: Int do return 16
fun flag_4bit_mode: Int do return 0
fun flag_2_lines: Int do return 8
fun flag_1_line: Int do return 0
fun flag_5x10_dots: Int do return 4
fun flag_5x8_dots: Int do return 0
# last text displayed
private var last_text: nullable String = null
fun function_set(bits, lines, dots_wide: Int)
do
var fs = flag_function_set
if bits == 8 then
fs = fs | 16
else if bits != 4 then abort
if lines == 2 then
fs = fs | 8
else if lines != 1 then abort
if dots_wide == 10 then
fs = fs | 4
else if dots_wide != 8 then abort
write(true, fs)
end
fun display_control(on, cursor, blink: Bool)
do
var fs = flag_display_control
fs |= if on then flag_display_on else flag_display_off
fs |= if cursor then flag_cursor_on else flag_cursor_off
fs |= if blink then flag_blink_on else flag_blink_off
write(true, fs)
end
fun entry_mode(left, incr: Bool)
do
var fs = flag_entry_mode_set
fs |= if left then flag_entry_left else flag_entry_right
fs |= if incr then flag_entry_shift_increment else flag_entry_shift_decrement
write(true, fs)
end
fun setup_alt
do
ds = [d4,d5,d6,d7]
rs.fsel = new FunctionSelect.outp
en.fsel = new FunctionSelect.outp
d4.fsel = new FunctionSelect.outp
d5.fsel = new FunctionSelect.outp
d6.fsel = new FunctionSelect.outp
d7.fsel = new FunctionSelect.outp
rs.write(false)
en.write(false)
# wait 20ms for power up
50.bcm2835_delay
write_4bits(true,true,false,false)
write_4_bits(3)
5.bcm2835_delay
write_4bits(true,true,false,false)
write_4_bits(3)
5.bcm2835_delay
write_4bits(true,true,false,false)
write_4_bits(3)
200.bcm2835_delay_micros
write_4bits(false,true,false,false)
write_4_bits(2)
# wait 5ms
5.bcm2835_delay
# set interface
# 4bits, 2 lines
function_set(4, 2, 8)
# cursor
# don't shift & hide
display_control(true, true, true)
# clear & home
clear
# set cursor move direction
# move right
write(true, 6)
# turn on display
write(true, 4)
# set entry mode
entry_mode(true, true)
end
fun setup
do
ds = [d4,d5,d6,d7]
rs.fsel = new FunctionSelect.outp
en.fsel = new FunctionSelect.outp
d4.fsel = new FunctionSelect.outp
d5.fsel = new FunctionSelect.outp
d6.fsel = new FunctionSelect.outp
d7.fsel = new FunctionSelect.outp
rs.write(false)
en.write(false)
write(true, "33".to_hex) # init
write(true, "32".to_hex) # init
write(true, "28".to_hex) # 2 lines, 5x7
write(true, "0C".to_hex) # hide cursor
write(true, "06".to_hex) # cursor move right
write(true, "04".to_hex) # turn on display
write(true, "01".to_hex) # clear display
end
fun write_4_bits(v: Int)
do
var lb = once [1,2,4,8]
for i in [0..4[ do
var b = lb[i]
var r = b & v != 0
var d = ds[i]
d.write(r)
end
pulse_enable
end
fun write_4bits(a,b,c,d:Bool)
do
d4.write(a)
d5.write(b)
d6.write(c)
d7.write(d)
pulse_enable
end
fun pulse_enable
do
en.write(false)
1.bcm2835_delay_micros
en.write(true)
100.bcm2835_delay_micros
en.write(false)
1.bcm2835_delay_micros
end
fun write(is_cmd: Bool, cmd: Int)
do
en.write(false)
rs.write(not is_cmd)
# high byte
var hb = once [16,32,64,128]
for i in [0..4[ do
var b = hb[i]
var r = b & cmd != 0
var d = ds[i]
d.write(r)
end
pulse_enable
if is_cmd then
# wait 5ms
5.bcm2835_delay
else
# wait 200us
200.bcm2835_delay_micros
end
# low byte
var lb = once [1,2,4,8]
for i in [0..4[ do
var b = lb[i]
var r = b & cmd != 0
var d = ds[i]
d.write(r)
end
pulse_enable
if is_cmd then
# wait 5ms
5.bcm2835_delay
else
# wait 200us
200.bcm2835_delay_micros
end
end
fun clear
do
write(true,1)
2.bcm2835_delay
end
fun return_home
do
write(true,2)
2.bcm2835_delay
end
fun text=(v: String)
do
# do not redraw the samething
var last_text = last_text
if last_text != null and last_text == v then return
clear
return_home
var count = 0
for c in v.chars do
if c == '\n' then
# FIXME, this should work
#write(true, "C0".to_hex)
# instead we use the following which may not be portable
for s in [count..40[ do write(false, ' '.code_point)
count = 0
else
write(false, c.code_point)
count += 1
end
end
self.last_text = v
end
end
# Component for any kind of buttons or switches
class Switch
var pin: RPiPin
init (pin: RPiPin, pud: PUDControl)
do
self.pin = pin
pin.fsel = new FunctionSelect.inpt
pin.pud = pud
end
fun is_down: Bool do return pin.lev
var last_down: nullable Bool = null
# Returns true is state (is_down) changed since last call to `changed`
fun changed: Bool
do
var now = is_down
var last_down = last_down
if last_down == null then
self.last_down = now
return false
else if last_down != now then
self.last_down = now
return true
else return false
end
end
class StepperMotor
var pins: Sequence[RPiPin]
var delay: Int
init (delay: Int, a, b, c, d: RPiPin)
do
pins = [a, b, c, d]
self.delay = delay
for p in pins do p.fsel = new FunctionSelect.outp
end
fun forward(steps: Int)
do
for s in [0..steps[ do
set(true, false, false, false)
delay.bcm2835_delay
set(true, true, false, false)
delay.bcm2835_delay
set(false, true, false, false)
delay.bcm2835_delay
set(false, true, true, false)
delay.bcm2835_delay
set(false, false, true, false)
delay.bcm2835_delay
set(false, false, true, true)
delay.bcm2835_delay
set(false, false, false, true)
delay.bcm2835_delay
set(true, false, false, true)
delay.bcm2835_delay
end
end
fun backwards(steps: Int)
do
for s in [0..steps[ do
set(true, false, false, true)
delay.bcm2835_delay
set(false, false, false, true)
delay.bcm2835_delay
set(false, false, true, true)
delay.bcm2835_delay
set(false, false, true, false)
delay.bcm2835_delay
set(false, true, true, false)
delay.bcm2835_delay
set(false, true, false, false)
delay.bcm2835_delay
set(true, true, false, false)
delay.bcm2835_delay
set(true, false, false, false)
delay.bcm2835_delay
end
end
fun release do set(false, false, false, false)
protected fun set(a, b, c, d: Bool)
do
var bits = new Array[Bool].with_items(a, b, c, d)
for i in [0..4[ do pins[i].write(bits[i])
end
end
class Buzzer
var pin: RPiPin
fun buzz(delay: Float, times: Int)
do
assert times > 0
assert delay > 0.0
var delay_i = (delay*1000.0).to_i
for i in [0..times[ do
pin.write(true)
delay_i.bcm2835_delay_micros
pin.write(false)
delay_i.bcm2835_delay_micros
end
end
end
lib/bcm2835/bcm2835.nit:17,1--566,3