microzig
package exports all functions and types available in the HAL as well as microzig.mcu
which will provide access to the MCU. All functions in microzig
which are not generic will be inline-forwarded to the board
or mcu
package.
root
|- std
|- microzig
| |- mcu (should be specified if "board" does not exit)
| |- build_options (defines if "mcu" and/or "board" exists)
| \- board (must export ".mcu")
| \- mcu
\- mcu (user decision)
Declaring panic
in the root file will cause builtin
to reference the proper package which will then instantiate microzig which will reference mcu
package which will instantiate reset
(or similar) which will invoke microzig.main()
which will invoke root.main()
. Oh boy 😆
const micro = @import("micro");
pub const panic = micro.panic; // this will instantiate microzig
comptime { _ = micro }; // this should not be necessary
pub fn main() void {
}
microzig
exports a symbol mcu
which will provide access to the MCU, CPU and board features
// mcu.zig in microzig.zig
const config = @import("build_options");
usingnamespace if(config.has_board)
@import("board").mcu
else
@import("mcu");
pub const has_board = config.has_board;
pub const board = @import("board");
All interrupt handlers are static and will be collected from root.interrupt_handlers
. Each symbol will be verified if it's a valid interrupt vector.
A symbol can be a function fn() void
, or a anonymous enum literal .hang
or .reset
.
microzig.interrupts.enable
and microzig.interrupts.disable
will allow masking/unmasking those interrupts, .cli()
and .sei()
will globally disable/enable interrupts
microzig.interrupts
also provides some handling of critical sections
pub fn main() void {
micro.interrupts.enable(.WDT); // enables the WDT interrupt
micro.interrupts.disable(.WDT); // enables the WDT interrupt
micro.interrupts.enable(.WTF); // yields compile error "WTF is not a valid interrupt"
micro.interrupts.enable(.PCINT0); // yields compile error "PCINT0 has no defined interrupt handler"
micro.interrupts.enable(.NMI); // yields compile error "NMI cannot be masked"
micro.interrupts.enableAll();
micro.interrupts.batchEnable(.{ .NMI, .WDT });
micro.interrupts.cli(); // set interrupt enabled (global enable)
{ // critical section
var crit = micro.interrupts.enterCriticalSection();
defer crit.leave();
}
}
var TIMER2_OVF_RUNTIME: fn()void = foo;
pub const interrupt_handlers = struct {
// AVR
pub fn TIMER2_OVF() void { TIMER2_OVF_RUNTIME(); }
pub fn WDT() void { }
pub const PCINT1 = .reset;
pub const PCINT2 = .hang;
// cortex-mX exceptions
pub fn NMI() void { }
pub fn HardFault() void {}
// LPC 1768 interrupt/irq
pub fn SSP1() void { }
};
microzig should allow having a general purpose timer mechanism
pub var cpu_frequency = 16.0 * micro.clock.mega_hertz;
pub const sleep_mode = .timer; // timer, busyloop, whatever
pub fn main() !void {
led.init();
while(true) {
led.toggle();
micro.sleep(100_000); // sleep 100ms
}
}
microzig.Pin
parses a pin definition and returns a type that encodes all relevant info and functions to route that pin.
microzig.Gpio
is a GPIO port/pin configuration that allows modifying pin levels.
// micro.Pin returns a type containing all relevant pin information
const status_led_pin = micro.Pin("PA3");
// generate a runtime possible pin that cannot be used in all APIs
var generic_pic: micro.RuntimePin.init(status_led_pin);
// 4 Bit IEEE-488 bit banging register
const serial_out = micro.GpioOutputRegister(.{
micro.Pin("PA0"),
micro.Pin("PA1"),
micro.Pin("PA3"), // whoopsies, i miswired, let the software fix that
micro.Pin("PA2"),
});
pub fn bitBang(nibble: u4) void {
serial_out.write(nibble);
}
pub fn main() !void {
// Route all gpio pins from the bit bang register
inline for(serial_out.pins) |pin| {
pin.route(".gpio");
}
serial_out.init();
// route that pin to UART.RXD
status_led_pin.route(.uart0_rxd);
//var uart_read_dma_channel = micro.Dma.init(.{.channel = 1});
const status_led = micro.Gpio(status_led_pin, .{
.mode = .output, // { input, output, input_output, open_drain, generic }
.initial_state = .unspecificed, // { unspecified, low, high, floating, driven }
});
status_led.init();
switch(status_led.mode) {
// only reading API is available
.input => {
_ = status_led.read();
},
// reading and writing is available
.output => {
_ = status_led.read();
status_led.write(.high);
// "subvariant" of the write
status_led.toggle();
status_led.setToHigh();
status_led.setToLow();
},
// reading, writing and changing direction is available
.input_output => {
status_led.setDirection(.input, undefined);
_ = status_led.read();
status_led.setDirection(.output, .high); // reqires a defined state after setting the direction
status_led.write(.high);
},
// reading and setDive is available
.open_drain => {
status_led.setDrive(.disabled);
_ = status_led.read();
status_led.setDrive(.enabled);
},
// will have all available APIs enabled
.generic => {},
}
// AVR: PORTA[3] => "PA3"
// NXP: PORT[1][3] => "P1.3"
// PICO: PORT[1] => "P3"
// STM: PORT[A][3] => "A3"
// ESP32: PORT[1] => "P3"
const std = @import("std");
const micro = @import("µzig");
// if const it can be comptime-optimized
pub var cpu_frequency = 100.0 * micro.clock.mega_hertz;
// if this is enabled, a event loop will run
// in microzig.main() that allows using `async`/`await` "just like that" *grin*
pub const io_mode = .evented;
pub fn main() !void {
var debug_port = micro.Uart.init(0, .{
.baud_rate = 9600,
.stop_bits = .@"2",
.parity = .none, // { none, even, odd, mark, space }
.data_bits = .@"8", // 5, 6, 7, 8, or 9 data bits
//.in_dma_channel = 0,
//.out_dma_channel = 0,
});
debug_port.configureDMA(???);
try debug_port.writer().writeAll("Hello, World!");
var line_buffer: [64]u8 = undefined;
const len = try debug_port.reader().readUntilDelimiter(&line_buffer, '\n');
}
somewhere inside micro.zig
extern fn reset() noreturn {
if(@hasDecl(mcu, "mcu_reset")) {
mcu.mcu_reset();
@unreachable();
}
// zeroing bss, copying .data, setting stack address
if(@hasDecl(root, "early_main")) // idk about the name
root.early_main();
else {
mcu.init();
if(@hasDecl(root, "main"))
root.main();
else
@compileError("main or entry_main missing")
}
}