0.13.0
Pre-releaseNew Features
Board#map
- Returns a hash mapping named pins (taken from the Arduino framework) to their integer GPIO values, once the board is supported. Examples:
:A0
,:DAC0
,:MOSI
,:LED_BUILTIN
. - Pins can be given as symbols when creating peripherals. The
Board
instance converts them to integer usingBoard#convert_pin
. - This works by having the board send an identifier string (again taken from the Arduino framework) during handshake. The identifier is cross-referenced against a directory of YAML files, loading the right map for each board.
- This uses
arduino-yaml-board-maps
. See that repo for which Arduino cores / boards are supported.
- Returns a hash mapping named pins (taken from the Arduino framework) to their integer GPIO values, once the board is supported. Examples:
New Boards
-
ESP32-S2, ESP32-S3 and ESP32-C3 variants (
--target esp32
):- Newer versions of the ESP32 chip with native USB support.
- No DACs on the S3.
- No DACs or capacitive touch on the C3.
-
SAMD21 Boards, Arduino Zero (
--target samd
): -
RP2040 Based Boards, Raspberry Pi Pico (W) (
--target rp2040
):- WS2812 LED arrays don't work.
-
Raspberry Pi SBC (not Pico) built-in GPIO support, using
denko-piboard
extension gem:- Ruby needs to be running on the Pi itself.
- Only works with CRuby. No JRuby or TruffleRuby.
- Folllow install instructions from
denko-piboard
gem's readme. require "denko/piboard"
instead ofrequire "denko"
- Substitute
Denko::PiBoard
forDenko::Board
as board class. - Not all interfaces and components from
denko
are supported yet.
New Components
-
Hardware UART support:
- Class:
Denko::UART::Hardware
. - Read/write support for a board's open (not tied to a USB port) hardware UARTs. Allows interfacing with serial peripherals.
- Initialize giving
:index
as the UART's number, according to the Arduino IDE/pinout.Serial1
has index1
.Serial2
has index2
, and so on. :baud
argument can be given when initializing, or callUART::Hardware#start(YOUR_BAUD_RATE)
. Default is 9600.- No pin arguments are needed to start the UART, but peripherals must be connected properly. Refer to your board's pinout.
- UARTs 1..3 are supported, and map to "virtual pins" 251..253, for purposes of identifying bytes read from the board.
- The 0th UART (
Serial
) is never used, even on boards where it is not in use, andSerialUSB
is the Denko transport. UART::Hardware#write
accepts either a String or Array of bytes to send binary data.- The
UART::Hardware
instance itself buffers read bytes. Complete lines can be read withUART::Hardware#gets
. - Callbacks can be attached, like other input classes, to handle each batch of raw bytes as they arrive.
- Call
UART::Hardware#stop
to disable the UART and return the pins to regular GPIO. - Added
Denko::Connection::BoardUART
, allowing a board's UART to be the transport for anotherBoard
instance. See this example.
- Class:
-
ADS1118 Analog-to-Digital Converter:
- Class:
Denko::AnalogIO::ADS1118
. - Connects via SPI bus. Driver written in Ruby.
- Can be used directly by calling
ADS1118#read
with the 2 config register bytes. #read
automatically waits for conversion before reading result.- Implements
BoardProxy
interface, soAnalogIO::Input
can use it in place ofBoard
. - For each
AnalogIO::Input
subcomponent:- Negative pin (1 or 3) of differential pair can be set with the keyword argument
negative_pin:
- Gain can be set with the keyword argument
gain:
- Sample rate can be set with the keyword argument
sample_rate:
- Sample rate doesn't affect update rate. Higher sample rates oversample for a single reading, increasing resolution.
ADS1118
sets@volts_per_bit
in the subcomponent, so exact voltages can be calculated.- There is no listening interface for subcomponents.
- Negative pin (1 or 3) of differential pair can be set with the keyword argument
- Built in temperature sensor can be read with
ADS1118#temperature_read
. Only 128 SPS. No polling.
- Class:
-
Bosch BME/BMP 280 Temperature + Pressure + Humidity Sensor:
- Classes:
Denko::Sensor::BME280
andDenko::Sensor::BMP280
- Connects via I2C bus. Driver written in Ruby.
- All features in the datasheet are implemented, except status checking.
- Both are mostly identical, except for BMP280 lacking humidity.
- Classes:
-
HTU21D Temperature + Humidity Sensor:
- Class:
Denko::Sensor::HTU21D
- Connects via I2C bus. Driver written in Ruby.
- Most features implemented, except reading back the configuration register, and releasing the I2C bus during measurement. Since conversion times can vary, it's simpler to let the sensor hold the line until its data is ready to be read.
- Always uses CRC. Readings are silently ignored if CRC fails.
- Can be read with direct methods
HTU21D#read_temperature
andHTU21D#read_humidity
, but these do not accept block callbacks, and there is no polling. - For callbacks and polling, use the sub-objects accessible through
HTU21D#temperature
andHTU21D#humidity
. See examples for more info.
- Class:
-
HTU31D Temperature + Humidity Sensor:
- Class:
Denko::Sensor::HTU31D
- Connects via I2C bus. Driver written in Ruby.
- Similar to HTU21D, but temperature and humidity can be, and always are, read together.
- Always uses CRC. Readings are silently ignored if CRC fails.
- Diagnostic register reading not implemented yet.
- Class:
-
AHT10 / AHT15 Temperature + Humidity Sensors:
- Both share a compatible interface, and use the same class:
Denko::Sensor::AHT10
- Connects via I2C bus. Driver written in Ruby.
- Always uses calibrated mode.
- Both share a compatible interface, and use the same class:
-
AHT20 / AHT21 / AHT25 / AM2301B Temperature + Humidity Sensors:
- All share a compatible interface, and use the same class:
Denko::Sensor::AHT20
- Connects via I2C bus. Driver written in Ruby.
- Always uses calibrated mode.
- Always uses CRC. Readings are silently ignored if CRC fails.
- All share a compatible interface, and use the same class:
-
SSD1306 OLED Display:
- Class:
Denko::Display::SSD1306
- Connects via I2C bus. Driver written in Ruby.
- By default,
SSD1306#draw
refreshes the entire frame, using horizontal addressing mode. - Can do partial refreshes with
SSD1306#draw(x_min, x_max, y_min, y_max)
, defining a bounding box to redraw. - One 6x8 font and graphic primitves, included through
Denko::Display::Canvas
.
- Class:
-
L298 H-Bridge Motor Driver:
- Class:
Denko::Motor::L298
- Forward, reverse, idle, and brake modes implemented.
- Speed controlled by PWM output on enable pin.
- Class:
-
WS2812 / WS2812B / NeoPixel RGB LED Array:
- Class:
Denko::LED::WS2812
- No fancy functions yet. Just clear, set pixels, and show.
- Class:
-
APA102 / Dotstar RGB LED Array:
- Class:
Denko::LED::APA102
- No fancy functions yet. Just clear, set pixels, show, global and per-pixel brightness control.
- Needs its own dedicated SPI bus. Select pin is automatically set to 255 (no pin).
- Class:
See new examples in the examples folder to learn more.
Changed Components
-
Virtually every component has been renamed to bring them out of the
Denko::Components
namespace, make naming clearer.- TODO: Update here with a list of renamed components.
-
SPI peripherals now go through a
Denko::SPI::Bus
object:- Instead of giving a board directly when creating a new SPI peripheral, a bus must be created first:
board = Denko::Board.new(connection) bus = Denko::SPI::Bus.new(board: board) # board's default SPI interface output_register = Denko::SPI::OutputRegister.new(bus: bus, pin: 9) # 9 is register select pin input_register = Denko::SPI::InputRegister.new(bus: bus, pin: 10) # 10 is register select pin
- For now, this always uses the default SPI device set by the Arduino framework (
SPI
orSPI0
), but this change will allow access to multiple SPI interfaces on a single board in the future. - It also allows a peripheral to mutex lock the bus for atomic operations if needed.
- When a peripheral is added to the SPI bus, callbacks are hooked (using its select pin as identifier) directly to the board.
SPI::Bus
validates select pin uniquness among peripherals, per bus instance.SPI::Bus
treats a select (enable) pin of 255 as no select pin at all (won't toggle before and after transferring).- See the updated SPI examples to learn more.
- Instead of giving a board directly when creating a new SPI peripheral, a bus must be created first:
-
Shift In/Out features refactored into
SPI::BitBang
which is class-compatible withSPI::Bus
, except for frequency.- See SPI changes above.
-
SPI::Peripheral
has been extracted from the various SPI Register classes.- This should be used for most peripherals, and the register classes used only for simple I/O expansion registers.
-
I2C::Bus
does not automatically search when initialized. -
I2C frequency now configurable:
I2C::Peripheral
and it's subclasses take:i2c_frequency
keywoard arg when instantiating. It's stored in@i2c_frequency
and used for all reads and writes.Board#i2c_write
andBoard#i2c_read
also accept:i2c_frequency
as a keyword arg.- Valid values are:
100000, 400000, 1000000, 3400000
. Defaults to100000
at theBoard
level, when not given. - Note: This DOES NOT work if using
denko-piboard
. See the README on that gem for more info.
-
Hitachi HD44780 LCD driver rewritten in Ruby:
- New class:
Denko::Display::HD44780
#puts
changed to#print
to better represent functionality.- No longer depends on the
LiquidCrystal
Arduino library, which has been removed. - Depends only on
Denko::DigitalIO::Output
and#micro_delay
. - Old implementation in
Denko::Components::LCD
removed. - This solves compatibility with boards that the library didn't work on.
HD44780#create_char
allows 8 custom characters to be defined in memory addresses 0-7.HD44780#write
draws the custom (or standard) character from a given memory address.
- New class:
-
Denko::PulseIO::PWMOutput
(previouslyDenko::Components::Basic::AnalogOutput
):- Changed
#analog_write
to#pwm_write
. - Added
#pwm_enable
and#pwm_disable
methods. #pwm_enable
is implicit when calling#pwm_write
. Lazy initialize PWM peripherals on the chip. Never happens if only#digital_write
gets called.#pwm_disable
sets the pin mode to:output
(OUTPUT
in Arduino), disconnects and deconfigures any PWM generating peripheral.- On the ESP32
#pwm_disable
releases the LEDC channel that the pin was using, so it can be reused.
- Changed
-
Denko::AnalogIO::Output
(also previouslyDenko::Components::Basic::AnalogOutput
):- Changed
#analog_write
to#dac_write
. - Does not implement
#digital_write
at all. Analog values must be used instead ofboard.high
orboard.low
.
- Changed
-
Denko::UART::BitBang
(previouslyDenko::Components::SoftwareSerial
):- Only inclduedo on AVR boards. Cross-platform support isn't good, and isn't necessary since almost everything has extra hardware UARTs.
- Read functionality added. The board listens for incoming bytes and forwards them.
- Interface matches
Denko::UART::Hardware
except for :tx and :rx pins given when initializing. See that entry in New Components above for more info.
-
Denko::TxRx
moved toDenko::Connection
.
Board API Changes
-
microDelay
function exposed from the board:- Implements a platform independent microsecond delay.
- All calls to
delayMicroseconds()
should be replaced with this. - Exposed in Ruby via
CMD=99
. It takes one argument, uint_16 for delay length in microsceonds. Board#micro_delay
andComponent::#micro_delay
are defined.
-
dacWrite
function added to board library.aWrite
function renamed topwmWrite
. Need this to avoid conflict between DAC, PWM and regular output on some chips. -
CMD numbers for some board functions changed to accomodate dacWrite:
dacWrite -> 4 aread 4 -> 5 setListener 5 -> 6 eepromRead 6 -> 7 eepromWrite 7 -> 8 pulseread 11 -> 9 servoToggle 8 -> 10 servoWrite 9 -> 11
-
Board#analog_write
replaced byBoard#pwm_write
andBoard#dac_write
, matching the two C functions. -
Board#set_pin_mode
significantly changed to better manage pullups, pulldowns,:input_output
mode, and freeing DAC and PWM peripherals for relevant chips. -
Board#digital_write
implicitly disconnects a PWM or DAC peripheral from the pin, but does not free it. This is necessary on chips like the ATSAMD21 and ESP32 or the#digital_write
will not work. -
Board#analog_write
implicitly reconnects a PWM peripheral to the pin if one was previously assigned, or assigns a new one and connects it. -
Board#analog_resolution
has been split intoBoard#analog_write_resolution
andBoard#analog_read_resoluton
, defaulting to 8 and 10-bits respectively. Write resolution applies to both PWM and DACs. -
Board#pwm_high
,Board#dac_high
andBoard#adc_high
defined for convenience. -
I2C and SPI transfer methods on
Board
changed to avoid using the options Hash pattern. I2C uses only positional arguments, and SPI uses positional and keyword arguments. This gives a significant performance boost on lower end processors like the Raspberry Pi Zero, and reduces CPU usage in general. -
Board#i2c_read
andBoard#i2c_write
now only accept positional arguments, with frequency and repeated_start always being last, in that order, and optional. -
Board#spi_transfer
andBoard#spi_bb_transfer
now only accept:spi_mode
and:spi_frequency
keywords for the respective arguments. -
Board#spi_listen
andBoard#spi_bb_listen
now share the same listener storage on the board. Default is 4 listeners.shiftListeners
have been removed.
Minor Changes
-
When instantiating a component,
Board#convert_pin
is run immediately, then the converted integer for the pin (based on the board map), is saved in@pin
, instead of whatever form was given to#initialize
. After this, the integer is always used as-is for sending / receiving messages. This reduces CPU usage, sinceBoard#convert_pin
doesn't need to be called for every message. -
As a consequence of the above change, when
Board
methods are called directly, pins must always be given as integers. -
Poller#poll
no longer defaults to a 3 second interval and will raise an error if a numeric interval is not given. -
MultiPin
validation and proxying has changed to not use class methods. Everything is done inside#initialize_pins
per-instance instead. This reduces the amount ofeval
andrescue
going on, so it's easier to understand, and changes are more portable to mruby. -
Calling
#update
withnil
, on any object using theCallback
pattern, will prevent callbacks from being run, but still remove any one-time callbacks present in the:read
key. -
If
#pre_callback_filter
returns nil, callbacks will also not be run, behaving just as above. -
Added this example as a blink example for boards where :LED_BUILTIN maps to a single on-board WS2812 LED, instead of a regular LED.
-
Removed
Denko::Board::ESP8266
, in favor of the new board mapping functionality. See New Features above. -
Aux message size limits changed to:
- 512 + 16: When using IR output or WS2812 and not using ATmega168
- 256 + 16: When not using IR output or WS2812, any board
- 32 + 16: When all the features that use lots of aux are disabled (core sketch)
-
Denko::Connection::Serial
tries to read up to 64 bytes each time now instead of 1, reducing the number of FFI calls, and CPU usage. -
Denko::Connection::FlowControl
simplified to always wait 1ms if no bytes to read or write. This also reduces CPU usage. This might affect the time precision of values received from listeners, but they weren't guaranteed to be evenly spaced anyway. Will add a timestamped listener feature in the future if needed. -
All
Serial.print
style debugging removed from the Arduino sketch, in favor of the new debugger in the Arduino IDE. If this style of debugging is still needed, the sketch should emit lines beginning with "DBG:". These will be caught by the Ruby parser and printed to the terminal. -
Started using
simplecov
gem to track test coverage.
Bug Fixes
-
Fixed
Denko::DigitalIO::Output
not setting its state through its mutex. -
Fixed
Piezo
functionality. Frequency and duration values weren't being properly cast on the board. Duration is also limited to 16 bits now, instead of 32, as it should be to match the Arduino function. -
Added validation for I2C writes not exceeding 32 bytes, since this is a limit of the native (AVR) library buffer. May increase for boards with bigger buffers in the future.
-
Stricter regex validation in
I2C::Bus
for identifying a series of bytes coming from a specific I2C address. -
I2C::Bus
andOneWire::Bus
now validate peripheral addresses as unique, per bus instance.