├── .gitattributes ├── .gitignore ├── all-platforms ├── src │ ├── empty.zig │ └── blinky.zig ├── build.zig.zon └── build.zig ├── README.md ├── nordic-nrf5x ├── src │ └── blinky.zig ├── README.adoc ├── build.zig.zon └── build.zig ├── espressif-esp ├── README.md ├── build.zig.zon ├── build.zig └── src │ └── blinky.zig ├── nxp-lpc ├── README.md ├── build.zig.zon ├── src │ └── blinky.zig └── build.zig ├── microchip-atmega ├── src │ └── blinky.zig ├── build.zig.zon └── build.zig ├── raspberrypi-rp2040 ├── src │ ├── gpio_clk.zig │ ├── blinky.zig │ ├── blinky_core1.zig │ ├── spi_master.zig │ ├── pwm.zig │ ├── adc.zig │ ├── i2c_bus_scan.zig │ ├── uart.zig │ ├── random.zig │ ├── flash_program.zig │ ├── ws2812.zig │ ├── squarewave.zig │ ├── tiles.zig │ ├── usb_device.zig │ └── usb_hid.zig ├── build.zig.zon ├── scripts │ ├── hid_test.py │ └── usb_device_loopback.py ├── build.zig └── README.md ├── stmicro-stm32 ├── src │ └── blinky.zig ├── build.zig.zon └── build.zig ├── gigadevice-gd32 ├── build.zig.zon └── build.zig ├── .github └── workflows │ └── build.yml └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | *.zig text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | zig-out/ 3 | 4 | ezpkg.sh 5 | 6 | .vscode 7 | 8 | .envrc 9 | shell.nix 10 | -------------------------------------------------------------------------------- /all-platforms/src/empty.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | pub fn main() void { 5 | // 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WE MOVED BACK TO A MONOREPO HERE: https://github.com/ZigEmbeddedGroup/microzig 2 | 3 | ## Future contributions go the main repository 4 | -------------------------------------------------------------------------------- /nordic-nrf5x/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | pub fn main() !void { 5 | // TODO: Implement the blinky 6 | } 7 | -------------------------------------------------------------------------------- /espressif-esp/README.md: -------------------------------------------------------------------------------- 1 | # Examples for the BSP `espressif-esp` 2 | 3 | - [Blinky](src/blinky.zig) on [ESP32-C3-32S-Kit](https://www.waveshare.com/wiki/ESP-C3-32S-Kit) 4 | Showcases how to do a simple RGB cycling. 5 | -------------------------------------------------------------------------------- /nxp-lpc/README.md: -------------------------------------------------------------------------------- 1 | # Examples for the BSP `nxp-lpc` 2 | 3 | - [Blinky](src/blinky.zig) on [nRF52840 Dongle](https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle) 4 | TODO: Implement this! 5 | 6 | -------------------------------------------------------------------------------- /nordic-nrf5x/README.adoc: -------------------------------------------------------------------------------- 1 | = Nordic nrf5x 2 | 3 | HALs and register definitions for nrf5x devices 4 | 5 | == What version of Zig to use 6 | 7 | Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig. 8 | 9 | == Renode supports: 10 | 11 | - nrf52840 development kit 12 | -------------------------------------------------------------------------------- /microchip-atmega/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | // LED is PB5 5 | const port = microzig.chip.peripherals.PORTB; 6 | 7 | pub fn main() void { 8 | port.DDRB |= (1 << 5); 9 | port.PORTB |= 0x00; 10 | 11 | while (true) { 12 | microzig.core.experimental.debug.busy_sleep(1_000); 13 | port.PINB |= (1 << 5); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/gpio_clk.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const gpio = rp2040.gpio; 5 | const clocks = rp2040.clocks; 6 | 7 | const gpout0_pin = gpio.num(21); 8 | const clock_config = clocks.GlobalConfiguration.init(.{ 9 | .sys = .{ .source = .src_xosc }, 10 | .gpout0 = .{ .source = .clk_sys }, 11 | }); 12 | 13 | pub fn main() !void { 14 | gpout0_pin.set_function(.gpck); 15 | while (true) {} 16 | } 17 | -------------------------------------------------------------------------------- /all-platforms/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const time = rp2040.time; 5 | 6 | const pin_config = rp2040.pins.GlobalConfiguration{ 7 | .GPIO25 = .{ 8 | .name = "led", 9 | .direction = .out, 10 | }, 11 | }; 12 | 13 | pub fn main() !void { 14 | const pins = pin_config.apply(); 15 | 16 | while (true) { 17 | pins.led.toggle(); 18 | time.sleep_ms(250); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const time = rp2040.time; 5 | 6 | const pin_config = rp2040.pins.GlobalConfiguration{ 7 | .GPIO25 = .{ 8 | .name = "led", 9 | .direction = .out, 10 | }, 11 | }; 12 | 13 | pub fn main() !void { 14 | const pins = pin_config.apply(); 15 | 16 | while (true) { 17 | pins.led.toggle(); 18 | time.sleep_ms(250); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /stmicro-stm32/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const stm32 = microzig.hal; 4 | 5 | const pin_config = stm32.pins.GlobalConfiguration{ 6 | .GPIOC = .{ 7 | .PIN13 = .{ .name = "led", .mode = .{ .output = .general_purpose_push_pull } }, 8 | }, 9 | }; 10 | 11 | pub fn main() !void { 12 | const pins = pin_config.apply(); 13 | 14 | while (true) { 15 | var i: u32 = 0; 16 | while (i < 800_000) { 17 | asm volatile ("nop"); 18 | i += 1; 19 | } 20 | pins.led.toggle(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /nxp-lpc/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-nxp-lpc-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .lpc = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/nxp-lpc/archive/130a1316c0892415e7da958a5e9548ed87bba54d.tar.gz", 11 | .hash = "1220165879f85a1d51656d35b3963a95f3585dc665fc7414f76aa6aad4e6635536cf", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /espressif-esp/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-espressif-esp-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .esp = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/espressif-esp/archive/59b8ca028915c0d6224ec88dbf4db19afbb559c0.tar.gz", 11 | .hash = "1220f6e5f22416fdc63442cd8869fcaa35f9abf30d878ea3d80073176677dc6f8a65", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /nordic-nrf5x/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-nordic-nrf5x-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .nrf5x = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/nordic-nrf5x/archive/0ab136860ccf7eb1d07969c3ef523f3cd898e2ff.tar.gz", 11 | .hash = "1220980da06f9634dcff06afefa7aa111bd030018fea49f79e86657dab69621e1d08", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/blinky_core1.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const microzig = @import("microzig"); 4 | const rp2040 = microzig.hal; 5 | const gpio = rp2040.gpio; 6 | const time = rp2040.time; 7 | const multicore = rp2040.multicore; 8 | 9 | const led = gpio.num(25); 10 | 11 | fn core1() void { 12 | while (true) { 13 | led.put(1); 14 | time.sleep_ms(250); 15 | led.put(0); 16 | time.sleep_ms(250); 17 | } 18 | } 19 | 20 | pub fn main() !void { 21 | led.set_function(.sio); 22 | led.set_direction(.out); 23 | multicore.launch_core1(core1); 24 | 25 | while (true) { 26 | microzig.cpu.wfi(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /stmicro-stm32/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-stmicro-stm32-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .stm32 = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/stmicro-stm32/archive/237890d49ee795110a63df2c45bdd6f6a0029a72.tar.gz", 11 | .hash = "1220960897777f9713fa1055ffdf1fbad1518b2f62bd2f2ae39b887821dbf0781df0", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /gigadevice-gd32/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-gigadevice-gd32-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .gd32 = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/gigadevice-gd32/archive/9324753cc3b8e7afe83fcda085bcfe76681a3be3.tar.gz", 11 | .hash = "122043ff4dcbc342f25dbb936b0d9eaa701ac3509e2cbe6764be37b90d31c7a385d0", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /microchip-atmega/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-microchip-atmega-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .atmega = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/microchip-atmega/archive/feefcb87a63c0aae31afb783d4e388e90c4d922f.tar.gz", 11 | .hash = "1220048dc5d22729ee119a496f8b8ca3556838af1f3bd32ce6acd5f76480ec942965", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-raspberrypi-rp2040-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .rp2040 = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/raspberrypi-rp2040/archive/67d36eebb0fbd89633db1a51d6d2bcb049f2066a.tar.gz", 11 | .hash = "122094bf268f45b188f3916f9e5964f4257414afaafba98a455ac47d25389a456832", 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/spi_master.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const time = rp2040.time; 6 | const gpio = rp2040.gpio; 7 | const clocks = rp2040.clocks; 8 | const peripherals = microzig.chip.peripherals; 9 | 10 | const BUF_LEN = 0x100; 11 | const spi = rp2040.spi.num(0); 12 | 13 | // Communicate with another RP2040 over spi 14 | // Slave implementation: https://github.com/raspberrypi/pico-examples/blob/master/spi/spi_master_slave/spi_slave/spi_slave.c 15 | pub fn main() !void { 16 | spi.apply(.{ 17 | .clock_config = rp2040.clock_config, 18 | }); 19 | var out_buf: [BUF_LEN]u8 = .{ 0xAA, 0xBB, 0xCC, 0xDD } ** (BUF_LEN / 4); 20 | var in_buf: [BUF_LEN]u8 = undefined; 21 | 22 | while (true) { 23 | _ = spi.transceive(&out_buf, &in_buf); 24 | time.sleep_ms(1 * 1000); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/pwm.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const gpio = rp2040.gpio; 5 | const clocks = rp2040.clocks; 6 | const time = rp2040.time; 7 | const regs = microzig.chip.registers; 8 | const multicore = rp2040.multicore; 9 | 10 | const pin_config = rp2040.pins.GlobalConfiguration{ 11 | .GPIO25 = .{ .name = "led", .function = .PWM4_B }, 12 | }; 13 | 14 | pub fn main() !void { 15 | const pins = pin_config.apply(); 16 | pins.led.slice().set_wrap(100); 17 | pins.led.slice().enable(); 18 | 19 | while (true) { 20 | for (0..101) |level| { 21 | pins.led.set_level(@truncate(level)); 22 | time.sleep_ms(10); 23 | } 24 | for (1..100) |level| { 25 | pins.led.set_level(@truncate(100 - level)); 26 | time.sleep_ms(10); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | dir: 15 | - all-platforms 16 | - raspberrypi-rp2040 17 | - espressif-esp 18 | - nxp-lpc 19 | - microchip-atmega 20 | - gigadevice-gd32 21 | - nordic-nrf5x 22 | - stmicro-stm32 23 | os: 24 | - windows-latest 25 | - macos-latest 26 | - ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | 31 | - name: Setup Zig 32 | uses: goto-bus-stop/setup-zig@v2 33 | with: 34 | version: 0.11.0 35 | 36 | - name: Build examples 37 | working-directory: ${{ matrix.dir }} 38 | run: zig build 39 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/scripts/hid_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Install python3 HID package https://pypi.org/project/hid/ 4 | import hid 5 | 6 | # default is TinyUSB (0xcafe), Adafruit (0x239a), RaspberryPi (0x2e8a), Espressif (0x303a) VID 7 | USB_VID = (0xcafe, 0x239a, 0x2e8a, 0x303a) 8 | 9 | print("VID list: " + ", ".join('%02x' % v for v in USB_VID)) 10 | 11 | for vid in USB_VID: 12 | for dict in hid.enumerate(vid): 13 | print(dict) 14 | dev = hid.Device(dict['vendor_id'], dict['product_id']) 15 | if dev: 16 | while True: 17 | inp = input("Send text to HID Device : ").encode('utf-8') 18 | dev.write(inp) 19 | 20 | x = 0 21 | l = len(inp) 22 | r = b"" 23 | while (x < l): 24 | str_in = dev.read(64) 25 | r += str_in 26 | x += 64 27 | 28 | print("Received from HID Device:\n", r) 29 | print("hex:\n", r.hex()) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Zig Embedded Group 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/adc.zig: -------------------------------------------------------------------------------- 1 | //! This example takes periodic samples of the temperature sensor and 2 | //! prints it to the UART using the stdlib logging facility. 3 | const std = @import("std"); 4 | const microzig = @import("microzig"); 5 | const rp2040 = microzig.hal; 6 | const gpio = rp2040.gpio; 7 | const adc = rp2040.adc; 8 | const time = rp2040.time; 9 | 10 | const uart = rp2040.uart.num(0); 11 | const baud_rate = 115200; 12 | const uart_tx_pin = gpio.num(0); 13 | const uart_rx_pin = gpio.num(1); 14 | 15 | pub const std_options = struct { 16 | pub const logFn = rp2040.uart.log; 17 | }; 18 | 19 | pub fn main() void { 20 | adc.apply(.{ 21 | .temp_sensor_enabled = true, 22 | }); 23 | 24 | uart.apply(.{ 25 | .baud_rate = baud_rate, 26 | .tx_pin = uart_tx_pin, 27 | .rx_pin = uart_rx_pin, 28 | .clock_config = rp2040.clock_config, 29 | }); 30 | 31 | rp2040.uart.init_logger(uart); 32 | while (true) : (time.sleep_ms(1000)) { 33 | const sample = adc.convert_one_shot_blocking(.temp_sensor) catch { 34 | std.log.err("conversion failed!", .{}); 35 | continue; 36 | }; 37 | 38 | std.log.info("temp value: {}", .{sample}); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/i2c_bus_scan.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const i2c = rp2040.i2c; 6 | const gpio = rp2040.gpio; 7 | const peripherals = microzig.chip.peripherals; 8 | 9 | pub const std_options = struct { 10 | pub const log_level = .info; 11 | pub const logFn = rp2040.uart.log; 12 | }; 13 | 14 | const uart = rp2040.uart.num(0); 15 | const i2c0 = i2c.num(0); 16 | 17 | pub fn main() !void { 18 | uart.apply(.{ 19 | .baud_rate = 115200, 20 | .tx_pin = gpio.num(0), 21 | .rx_pin = gpio.num(1), 22 | .clock_config = rp2040.clock_config, 23 | }); 24 | rp2040.uart.init_logger(uart); 25 | 26 | _ = i2c0.apply(.{ 27 | .clock_config = rp2040.clock_config, 28 | .scl_pin = gpio.num(4), 29 | .sda_pin = gpio.num(5), 30 | }); 31 | 32 | for (0..std.math.maxInt(u7)) |addr| { 33 | const a: i2c.Address = @enumFromInt(addr); 34 | 35 | // Skip over any reserved addresses. 36 | if (a.is_reserved()) continue; 37 | 38 | var rx_data: [1]u8 = undefined; 39 | _ = i2c0.read_blocking(a, &rx_data) catch continue; 40 | 41 | std.log.info("I2C device found at address {X}.", .{addr}); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/scripts/usb_device_loopback.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 5 | # 6 | # SPDX-License-Identifier: BSD-3-Clause 7 | # 8 | 9 | # sudo pip3 install pyusb 10 | 11 | import usb.core 12 | import usb.util 13 | 14 | # find our device 15 | dev = usb.core.find(idVendor=0x0000, idProduct=0x0001) 16 | 17 | # was it found? 18 | if dev is None: 19 | raise ValueError('Device not found') 20 | 21 | # get an endpoint instance 22 | cfg = dev.get_active_configuration() 23 | intf = cfg[(0, 0)] 24 | 25 | outep = usb.util.find_descriptor( 26 | intf, 27 | # match the first OUT endpoint 28 | custom_match= \ 29 | lambda e: \ 30 | usb.util.endpoint_direction(e.bEndpointAddress) == \ 31 | usb.util.ENDPOINT_OUT) 32 | 33 | inep = usb.util.find_descriptor( 34 | intf, 35 | # match the first IN endpoint 36 | custom_match= \ 37 | lambda e: \ 38 | usb.util.endpoint_direction(e.bEndpointAddress) == \ 39 | usb.util.ENDPOINT_IN) 40 | 41 | assert inep is not None 42 | assert outep is not None 43 | 44 | test_string = "Hello World!" 45 | outep.write(test_string) 46 | from_device = inep.read(len(test_string)) 47 | 48 | print("Device Says: {}".format(''.join([chr(x) for x in from_device]))) 49 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/uart.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const time = rp2040.time; 6 | const gpio = rp2040.gpio; 7 | const clocks = rp2040.clocks; 8 | 9 | const led = gpio.num(25); 10 | const uart = rp2040.uart.num(0); 11 | const baud_rate = 115200; 12 | const uart_tx_pin = gpio.num(0); 13 | const uart_rx_pin = gpio.num(1); 14 | 15 | pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { 16 | std.log.err("panic: {s}", .{message}); 17 | @breakpoint(); 18 | while (true) {} 19 | } 20 | 21 | pub const std_options = struct { 22 | pub const log_level = .debug; 23 | pub const logFn = rp2040.uart.log; 24 | }; 25 | 26 | pub fn main() !void { 27 | led.set_function(.sio); 28 | led.set_direction(.out); 29 | led.put(1); 30 | 31 | uart.apply(.{ 32 | .baud_rate = baud_rate, 33 | .tx_pin = uart_tx_pin, 34 | .rx_pin = uart_rx_pin, 35 | .clock_config = rp2040.clock_config, 36 | }); 37 | 38 | rp2040.uart.init_logger(uart); 39 | 40 | var i: u32 = 0; 41 | while (true) : (i += 1) { 42 | led.put(1); 43 | std.log.info("what {}", .{i}); 44 | time.sleep_ms(500); 45 | 46 | led.put(0); 47 | time.sleep_ms(500); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nxp-lpc/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const chip = microzig.chip; 5 | 6 | // LED-1: P1.18 7 | // LED-2: P1.20 8 | // LED-3: P1.21 9 | // LED-4: P1.23 10 | 11 | const conn = chip.peripherals.PINCONNECT; 12 | const gpio: *volatile [5]PatchedGpio = @ptrCast(@alignCast(chip.peripherals.GPIO)); 13 | 14 | const led_mask = [4]u32{ 15 | (1 << 18), 16 | (1 << 20), 17 | (1 << 21), 18 | (1 << 23), 19 | }; 20 | const all_mask = led_mask[0] | led_mask[1] | led_mask[2] | led_mask[3]; 21 | 22 | pub fn main() !void { 23 | conn.PINSEL3.modify(.{ 24 | .P1_18 = .{ .value = .GPIO_P1 }, 25 | .P1_20 = .{ .value = .GPIO_P1 }, 26 | .P1_21 = .{ .value = .GPIO_P1 }, 27 | .P1_23 = .{ .value = .GPIO_P1 }, 28 | }); 29 | 30 | const p1 = &gpio[1]; 31 | 32 | p1.dir = all_mask; 33 | 34 | while (true) { 35 | for (led_mask) |mask| { 36 | p1.pin_clr = (all_mask & ~mask); 37 | p1.pin_set = mask; 38 | microzig.core.experimental.debug.busy_sleep(100_000); 39 | } 40 | } 41 | } 42 | 43 | const PatchedGpio = extern struct { 44 | dir: u32, // 0x2009 C000 45 | __padding0: u32, // 0x2009 C004 46 | __padding1: u32, // 0x2009 C008 47 | __padding2: u32, // 0x2009 C00C 48 | mask: u32, // 0x2009 C010 49 | pin: u32, // 0x2009 C014 50 | pin_set: u32, // 0x2009 C018 51 | pin_clr: u32, // 0x2009 C01C 52 | 53 | comptime { 54 | std.debug.assert(@sizeOf(PatchedGpio) == 0x20); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /nxp-lpc/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const lpc = @import("lpc"); 3 | 4 | const available_examples = [_]ExampleDesc{ 5 | .{ .name = "mbed-lpc1768_blinky", .target = lpc.boards.mbed.lpc1768, .file = "src/blinky.zig" }, 6 | }; 7 | 8 | pub fn build(b: *std.Build) void { 9 | const microzig = @import("microzig").init(b, "microzig"); 10 | const optimize = b.standardOptimizeOption(.{}); 11 | 12 | for (available_examples) |example| { 13 | // `addFirmware` basically works like addExecutable, but takes a 14 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 15 | // 16 | // The target will convey all necessary information on the chip, 17 | // cpu and potentially the board as well. 18 | const firmware = microzig.addFirmware(b, .{ 19 | .name = example.name, 20 | .target = example.target, 21 | .optimize = optimize, 22 | .source_file = .{ .path = example.file }, 23 | }); 24 | 25 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 26 | // and allows installing the firmware as a typical firmware file. 27 | // 28 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 29 | microzig.installFirmware(b, firmware, .{}); 30 | 31 | // For debugging, we also always install the firmware as an ELF file 32 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 33 | } 34 | } 35 | 36 | const ExampleDesc = struct { 37 | target: @import("microzig").Target, 38 | name: []const u8, 39 | file: []const u8, 40 | }; 41 | -------------------------------------------------------------------------------- /nordic-nrf5x/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const nrf5x = @import("nrf5x"); 3 | 4 | const available_examples = [_]Example{ 5 | .{ .name = "nrf52480-dongle_blinky", .target = nrf5x.boards.nordic.nRF52840_Dongle, .file = "src/blinky.zig" }, 6 | }; 7 | 8 | pub fn build(b: *std.Build) void { 9 | const microzig = @import("microzig").init(b, "microzig"); 10 | const optimize = b.standardOptimizeOption(.{}); 11 | 12 | for (available_examples) |example| { 13 | // `addFirmware` basically works like addExecutable, but takes a 14 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 15 | // 16 | // The target will convey all necessary information on the chip, 17 | // cpu and potentially the board as well. 18 | const firmware = microzig.addFirmware(b, .{ 19 | .name = example.name, 20 | .target = example.target, 21 | .optimize = optimize, 22 | .source_file = .{ .path = example.file }, 23 | }); 24 | 25 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 26 | // and allows installing the firmware as a typical firmware file. 27 | // 28 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 29 | microzig.installFirmware(b, firmware, .{}); 30 | 31 | // For debugging, we also always install the firmware as an ELF file 32 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 33 | } 34 | } 35 | 36 | const Example = struct { 37 | target: @import("microzig").Target, 38 | name: []const u8, 39 | file: []const u8, 40 | }; 41 | -------------------------------------------------------------------------------- /microchip-atmega/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const atmega = @import("atmega"); 3 | 4 | const available_examples = [_]Example{ 5 | // TODO: .{ .name = "arduino-nano_blinky", .target = atmega.boards.arduino.nano, .file = "src/blinky.zig" }, 6 | }; 7 | 8 | pub fn build(b: *std.Build) void { 9 | const microzig = @import("microzig").init(b, "microzig"); 10 | const optimize = .ReleaseSmall; // The others are not really an option on AVR 11 | 12 | for (available_examples) |example| { 13 | // `addFirmware` basically works like addExecutable, but takes a 14 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 15 | // 16 | // The target will convey all necessary information on the chip, 17 | // cpu and potentially the board as well. 18 | const firmware = microzig.addFirmware(b, .{ 19 | .name = example.name, 20 | .target = example.target, 21 | .optimize = optimize, 22 | .source_file = .{ .path = example.file }, 23 | }); 24 | 25 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 26 | // and allows installing the firmware as a typical firmware file. 27 | // 28 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 29 | microzig.installFirmware(b, firmware, .{}); 30 | 31 | // For debugging, we also always install the firmware as an ELF file 32 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 33 | } 34 | } 35 | 36 | const Example = struct { 37 | target: @import("microzig").Target, 38 | name: []const u8, 39 | file: []const u8, 40 | }; 41 | -------------------------------------------------------------------------------- /espressif-esp/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const esp = @import("esp"); 3 | 4 | const available_targets = [_]TargetDesc{ 5 | .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, 6 | }; 7 | 8 | const available_examples = [_][]const u8{ 9 | "src/blinky.zig", 10 | }; 11 | 12 | pub fn build(b: *std.Build) void { 13 | const microzig = @import("microzig").init(b, "microzig"); 14 | const optimize = b.standardOptimizeOption(.{}); 15 | 16 | for (available_targets) |target| { 17 | for (available_examples) |example| { 18 | // `addFirmware` basically works like addExecutable, but takes a 19 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 20 | // 21 | // The target will convey all necessary information on the chip, 22 | // cpu and potentially the board as well. 23 | const firmware = microzig.addFirmware(b, .{ 24 | .name = b.fmt("{s}-{s}", .{ std.fs.path.stem(example), target.name }), 25 | .target = target.target, 26 | .optimize = optimize, 27 | .source_file = .{ .path = example }, 28 | }); 29 | 30 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 31 | // and allows installing the firmware as a typical firmware file. 32 | // 33 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 34 | microzig.installFirmware(b, firmware, .{}); 35 | 36 | // For debugging, we also always install the firmware as an ELF file 37 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 38 | } 39 | } 40 | } 41 | 42 | const TargetDesc = struct { 43 | target: @import("microzig").Target, 44 | name: []const u8, 45 | }; 46 | -------------------------------------------------------------------------------- /gigadevice-gd32/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const gd32 = @import("gd32"); 3 | 4 | const available_examples = [_]Example{ 5 | // .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb, .file = "src/blinky.zig" }, 6 | // .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8, .file = "src/blinky.zig" }, 7 | // .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano, .file = "src/blinky.zig" }, 8 | }; 9 | 10 | pub fn build(b: *std.Build) void { 11 | const microzig = @import("microzig").init(b, "microzig"); 12 | const optimize = .ReleaseSmall; // The others are not really an option on AVR 13 | 14 | for (available_examples) |example| { 15 | // `addFirmware` basically works like addExecutable, but takes a 16 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 17 | // 18 | // The target will convey all necessary information on the chip, 19 | // cpu and potentially the board as well. 20 | const firmware = microzig.addFirmware(b, .{ 21 | .name = example.name, 22 | .target = example.target, 23 | .optimize = optimize, 24 | .source_file = .{ .path = example.file }, 25 | }); 26 | 27 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 28 | // and allows installing the firmware as a typical firmware file. 29 | // 30 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 31 | microzig.installFirmware(b, firmware, .{}); 32 | 33 | // For debugging, we also always install the firmware as an ELF file 34 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 35 | } 36 | } 37 | 38 | const Example = struct { 39 | target: @import("microzig").Target, 40 | name: []const u8, 41 | file: []const u8, 42 | }; 43 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/random.zig: -------------------------------------------------------------------------------- 1 | //! Example that generates a 4 byte random number every second and outputs the result over UART 2 | 3 | const std = @import("std"); 4 | const microzig = @import("microzig"); 5 | 6 | const rp2040 = microzig.hal; 7 | const flash = rp2040.flash; 8 | const time = rp2040.time; 9 | const gpio = rp2040.gpio; 10 | const clocks = rp2040.clocks; 11 | const rand = rp2040.rand; 12 | 13 | const led = gpio.num(25); 14 | const uart = rp2040.uart.num(0); 15 | const baud_rate = 115200; 16 | const uart_tx_pin = gpio.num(0); 17 | const uart_rx_pin = gpio.num(1); 18 | 19 | pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { 20 | std.log.err("panic: {s}", .{message}); 21 | @breakpoint(); 22 | while (true) {} 23 | } 24 | 25 | pub const std_options = struct { 26 | pub const log_level = .debug; 27 | pub const logFn = rp2040.uart.log; 28 | }; 29 | 30 | pub fn main() !void { 31 | led.set_function(.sio); 32 | led.set_direction(.out); 33 | led.put(1); 34 | 35 | uart.apply(.{ 36 | .baud_rate = baud_rate, 37 | .tx_pin = uart_tx_pin, 38 | .rx_pin = uart_rx_pin, 39 | .clock_config = rp2040.clock_config, 40 | }); 41 | 42 | var ascon = rand.Ascon.init(); 43 | var rng = ascon.random(); 44 | 45 | rp2040.uart.init_logger(uart); 46 | 47 | var buffer: [8]u8 = undefined; 48 | var dist: [256]usize = .{0} ** 256; 49 | var counter: usize = 0; 50 | 51 | while (true) { 52 | rng.bytes(buffer[0..]); 53 | counter += 8; 54 | for (buffer) |byte| { 55 | dist[@as(usize, @intCast(byte))] += 1; 56 | } 57 | std.log.info("Generate random number: {any}", .{buffer}); 58 | 59 | if (counter % 256 == 0) { 60 | var i: usize = 0; 61 | std.log.info("Distribution:", .{}); 62 | while (i < 256) : (i += 1) { 63 | std.log.info("{} -> {}, {d:2}%", .{ i, dist[i], @as(f32, @floatFromInt(dist[i])) / @as(f32, @floatFromInt(counter)) }); 64 | } 65 | } 66 | time.sleep_ms(1000); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /all-platforms/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "microzig-all-platforms-examples", 3 | .version = "0.1.0", 4 | .dependencies = .{ 5 | .microzig = .{ 6 | .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", 7 | .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", 8 | }, 9 | .rp2040 = .{ 10 | .url = "https://github.com/ZigEmbeddedGroup/raspberrypi-rp2040/archive/67d36eebb0fbd89633db1a51d6d2bcb049f2066a.tar.gz", 11 | .hash = "122094bf268f45b188f3916f9e5964f4257414afaafba98a455ac47d25389a456832", 12 | }, 13 | .stm32 = .{ 14 | .url = "https://github.com/ZigEmbeddedGroup/stmicro-stm32/archive/cb2893707efa6aa289fa72f02959ad5f2d9db2a1.tar.gz", 15 | .hash = "12208cab5f60ef97cac4165ad694f3ba0c7b28f279538c1539b74f7c152f34fe306d", 16 | }, 17 | .lpc = .{ 18 | .url = "https://github.com/ZigEmbeddedGroup/nxp-lpc/archive/130a1316c0892415e7da958a5e9548ed87bba54d.tar.gz", 19 | .hash = "1220165879f85a1d51656d35b3963a95f3585dc665fc7414f76aa6aad4e6635536cf", 20 | }, 21 | .gd32 = .{ 22 | .url = "https://github.com/ZigEmbeddedGroup/gigadevice-gd32/archive/9324753cc3b8e7afe83fcda085bcfe76681a3be3.tar.gz", 23 | .hash = "122043ff4dcbc342f25dbb936b0d9eaa701ac3509e2cbe6764be37b90d31c7a385d0", 24 | }, 25 | .nrf5x = .{ 26 | .url = "https://github.com/ZigEmbeddedGroup/nordic-nrf5x/archive/0ab136860ccf7eb1d07969c3ef523f3cd898e2ff.tar.gz", 27 | .hash = "1220980da06f9634dcff06afefa7aa111bd030018fea49f79e86657dab69621e1d08", 28 | }, 29 | .esp = .{ 30 | .url = "https://github.com/ZigEmbeddedGroup/espressif-esp/archive/59b8ca028915c0d6224ec88dbf4db19afbb559c0.tar.gz", 31 | .hash = "1220f6e5f22416fdc63442cd8869fcaa35f9abf30d878ea3d80073176677dc6f8a65", 32 | }, 33 | .atmega = .{ 34 | .url = "https://github.com/ZigEmbeddedGroup/microchip-atmega/archive/feefcb87a63c0aae31afb783d4e388e90c4d922f.tar.gz", 35 | .hash = "1220048dc5d22729ee119a496f8b8ca3556838af1f3bd32ce6acd5f76480ec942965", 36 | }, 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /stmicro-stm32/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const stm32 = @import("stm32"); 3 | 4 | const available_examples = [_]Example{ 5 | .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8, .file = "src/blinky.zig" }, 6 | // TODO: .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc, .file = "src/blinky.zig" }, 7 | // TODO: .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg, .file = "src/blinky.zig" }, 8 | // TODO: .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u, .file = "src/blinky.zig" }, 9 | // TODO: .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery, .file = "src/blinky.zig" }, 10 | // TODO: .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery, .file = "src/blinky.zig" }, 11 | // TODO: .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval, .file = "src/blinky.zig" }, 12 | // TODO: .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery, .file = "src/blinky.zig" }, 13 | }; 14 | 15 | pub fn build(b: *std.Build) void { 16 | const microzig = @import("microzig").init(b, "microzig"); 17 | const optimize = .ReleaseSmall; // The others are not really an option on AVR 18 | 19 | for (available_examples) |example| { 20 | // `addFirmware` basically works like addExecutable, but takes a 21 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 22 | // 23 | // The target will convey all necessary information on the chip, 24 | // cpu and potentially the board as well. 25 | const firmware = microzig.addFirmware(b, .{ 26 | .name = example.name, 27 | .target = example.target, 28 | .optimize = optimize, 29 | .source_file = .{ .path = example.file }, 30 | }); 31 | 32 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 33 | // and allows installing the firmware as a typical firmware file. 34 | // 35 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 36 | microzig.installFirmware(b, firmware, .{}); 37 | 38 | // For debugging, we also always install the firmware as an ELF file 39 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 40 | } 41 | } 42 | 43 | const Example = struct { 44 | target: @import("microzig").Target, 45 | name: []const u8, 46 | file: []const u8, 47 | }; 48 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/flash_program.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const flash = rp2040.flash; 6 | const time = rp2040.time; 7 | const gpio = rp2040.gpio; 8 | const clocks = rp2040.clocks; 9 | 10 | const led = gpio.num(25); 11 | const uart = rp2040.uart.num(0); 12 | const baud_rate = 115200; 13 | const uart_tx_pin = gpio.num(0); 14 | const uart_rx_pin = gpio.num(1); 15 | 16 | const flash_target_offset: u32 = 256 * 1024; 17 | const flash_target_contents = @as([*]const u8, @ptrFromInt(rp2040.flash.XIP_BASE + flash_target_offset)); 18 | 19 | pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { 20 | std.log.err("panic: {s}", .{message}); 21 | @breakpoint(); 22 | while (true) {} 23 | } 24 | 25 | pub const std_options = struct { 26 | pub const log_level = .debug; 27 | pub const logFn = rp2040.uart.log; 28 | }; 29 | 30 | pub fn main() !void { 31 | led.set_function(.sio); 32 | led.set_direction(.out); 33 | led.put(1); 34 | 35 | uart.apply(.{ 36 | .baud_rate = baud_rate, 37 | .tx_pin = uart_tx_pin, 38 | .rx_pin = uart_rx_pin, 39 | .clock_config = rp2040.clock_config, 40 | }); 41 | 42 | rp2040.uart.init_logger(uart); 43 | 44 | var data: [flash.PAGE_SIZE]u8 = undefined; 45 | var i: usize = 0; 46 | var j: u8 = 0; 47 | while (i < flash.PAGE_SIZE) : (i += 1) { 48 | data[i] = j; 49 | 50 | if (j == 255) j = 0; 51 | j += 1; 52 | } 53 | 54 | std.log.info("Generate data", .{}); 55 | std.log.info("data: {s}", .{&data}); 56 | 57 | // Note that a whole number of sectors (4096 bytes) must be erased at a time 58 | std.log.info("Erasing target region...", .{}); 59 | flash.range_erase(flash_target_offset, flash.SECTOR_SIZE); 60 | std.log.info("Done. Read back target region:", .{}); 61 | std.log.info("data: {s}", .{flash_target_contents[0..flash.PAGE_SIZE]}); 62 | 63 | // Note that a whole number of pages (256 bytes) must be written at a time 64 | std.log.info("Programming target region...", .{}); 65 | flash.range_program(flash_target_offset, data[0..]); 66 | std.log.info("Done. Read back target region:", .{}); 67 | std.log.info("data: {s}", .{flash_target_contents[0..flash.PAGE_SIZE]}); 68 | 69 | var mismatch: bool = false; 70 | i = 0; 71 | while (i < flash.PAGE_SIZE) : (i += 1) { 72 | if (data[i] != flash_target_contents[i]) 73 | mismatch = true; 74 | } 75 | 76 | if (mismatch) { 77 | std.log.info("Programming failed!", .{}); 78 | } else { 79 | std.log.info("Programming successful!", .{}); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/ws2812.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const gpio = rp2040.gpio; 5 | const Pio = rp2040.pio.Pio; 6 | const StateMachine = rp2040.pio.StateMachine; 7 | 8 | const ws2812_program = blk: { 9 | @setEvalBranchQuota(5000); 10 | break :blk rp2040.pio.assemble( 11 | \\; 12 | \\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 13 | \\; 14 | \\; SPDX-License-Identifier: BSD-3-Clause 15 | \\; 16 | \\.program ws2812 17 | \\.side_set 1 18 | \\ 19 | \\.define public T1 2 20 | \\.define public T2 5 21 | \\.define public T3 3 22 | \\ 23 | \\.wrap_target 24 | \\bitloop: 25 | \\ out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls 26 | \\ jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse 27 | \\do_one: 28 | \\ jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse 29 | \\do_zero: 30 | \\ nop side 0 [T2 - 1] ; Or drive low, for a short pulse 31 | \\.wrap 32 | , .{}).get_program_by_name("ws2812"); 33 | }; 34 | 35 | const pio: Pio = .pio0; 36 | const sm: StateMachine = .sm0; 37 | const led_pin = gpio.num(23); 38 | 39 | pub fn main() void { 40 | pio.gpio_init(led_pin); 41 | sm_set_consecutive_pindirs(pio, sm, @intFromEnum(led_pin), 1, true); 42 | 43 | const cycles_per_bit: comptime_int = ws2812_program.defines[0].value + //T1 44 | ws2812_program.defines[1].value + //T2 45 | ws2812_program.defines[2].value; //T3 46 | const div = @as(f32, @floatFromInt(rp2040.clock_config.sys.?.output_freq)) / 47 | (800_000 * cycles_per_bit); 48 | 49 | pio.sm_load_and_start_program(sm, ws2812_program, .{ 50 | .clkdiv = rp2040.pio.ClkDivOptions.from_float(div), 51 | .pin_mappings = .{ 52 | .side_set = .{ 53 | .base = @intFromEnum(led_pin), 54 | .count = 1, 55 | }, 56 | }, 57 | .shift = .{ 58 | .out_shiftdir = .left, 59 | .autopull = true, 60 | .pull_threshold = 24, 61 | .join_tx = true, 62 | }, 63 | }) catch unreachable; 64 | pio.sm_set_enabled(sm, true); 65 | 66 | while (true) { 67 | pio.sm_blocking_write(sm, 0x00ff00 << 8); //red 68 | rp2040.time.sleep_ms(1000); 69 | pio.sm_blocking_write(sm, 0xff0000 << 8); //green 70 | rp2040.time.sleep_ms(1000); 71 | pio.sm_blocking_write(sm, 0x0000ff << 8); //blue 72 | rp2040.time.sleep_ms(1000); 73 | } 74 | } 75 | 76 | fn sm_set_consecutive_pindirs(_pio: Pio, _sm: StateMachine, pin: u5, count: u3, is_out: bool) void { 77 | const sm_regs = _pio.get_sm_regs(_sm); 78 | const pinctrl_saved = sm_regs.pinctrl.raw; 79 | sm_regs.pinctrl.modify(.{ 80 | .SET_BASE = pin, 81 | .SET_COUNT = count, 82 | }); 83 | _pio.sm_exec(_sm, rp2040.pio.Instruction{ 84 | .tag = .set, 85 | .delay_side_set = 0, 86 | .payload = .{ 87 | .set = .{ 88 | .data = @intFromBool(is_out), 89 | .destination = .pindirs, 90 | }, 91 | }, 92 | }); 93 | sm_regs.pinctrl.raw = pinctrl_saved; 94 | } 95 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/squarewave.zig: -------------------------------------------------------------------------------- 1 | //! Hello world for the PIO module: generating a square wave 2 | const std = @import("std"); 3 | const microzig = @import("microzig"); 4 | const rp2040 = microzig.hal; 5 | const gpio = rp2040.gpio; 6 | const Pio = rp2040.pio.Pio; 7 | const StateMachine = rp2040.pio.StateMachine; 8 | 9 | const squarewave_program = blk: { 10 | @setEvalBranchQuota(2000); 11 | break :blk rp2040.pio.assemble( 12 | \\; 13 | \\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 14 | \\; 15 | \\; SPDX-License-Identifier: BSD-3-Clause 16 | \\; 17 | \\.program squarewave 18 | \\ set pindirs, 1 ; Set pin to output 19 | \\again: 20 | \\ set pins, 1 [1] ; Drive pin high and then delay for one cycle 21 | \\ set pins, 0 ; Drive pin low 22 | \\ jmp again ; Set PC to label `again` 23 | , .{}).get_program_by_name("squarewave"); 24 | }; 25 | 26 | // Pick one PIO instance arbitrarily. We're also arbitrarily picking state 27 | // machine 0 on this PIO instance (the state machines are numbered 0 to 3 28 | // inclusive). 29 | const pio: Pio = .pio0; 30 | const sm: StateMachine = .sm0; 31 | 32 | pub fn main() void { 33 | pio.gpio_init(gpio.num(2)); 34 | pio.sm_load_and_start_program(sm, squarewave_program, .{ 35 | .clkdiv = rp2040.pio.ClkDivOptions.from_float(125), 36 | .pin_mappings = .{ 37 | .set = .{ 38 | .base = 2, 39 | .count = 1, 40 | }, 41 | }, 42 | }) catch unreachable; 43 | 44 | pio.sm_set_enabled(sm, true); 45 | 46 | while (true) {} 47 | 48 | //// Load the assembled program directly into the PIO's instruction memory. 49 | //// Each PIO instance has a 32-slot instruction memory, which all 4 state 50 | //// machines can see. The system has write-only access. 51 | //for (squarewave_program.instructions, 0..) |insn, i| 52 | // pio.get_instruction_memory()[i] = insn; 53 | 54 | //// Configure state machine 0 to run at sysclk/2.5. The state machines can 55 | //// run as fast as one instruction per clock cycle, but we can scale their 56 | //// speed down uniformly to meet some precise frequency target, e.g. for a 57 | //// UART baud rate. This register has 16 integer divisor bits and 8 58 | //// fractional divisor bits. 59 | //pio.sm_set_clkdiv(sm, .{ 60 | // .int = 2, 61 | // .frac = 0x80, 62 | //}); 63 | 64 | //// There are five pin mapping groups (out, in, set, side-set, jmp pin) 65 | //// which are used by different instructions or in different circumstances. 66 | //// Here we're just using SET instructions. Configure state machine 0 SETs 67 | //// to affect GPIO 0 only; then configure GPIO0 to be controlled by PIO0, 68 | //// as opposed to e.g. the processors. 69 | //pio.gpio_init(2); 70 | //pio.sm_set_pin_mappings(sm, .{ 71 | // .out = .{ 72 | // .base = 2, 73 | // .count = 1, 74 | // }, 75 | //}); 76 | 77 | //// Set the state machine running. The PIO CTRL register is global within a 78 | //// PIO instance, so you can start/stop multiple state machines 79 | //// simultaneously. We're using the register's hardware atomic set alias to 80 | //// make one bit high without doing a read-modify-write on the register. 81 | //pio.sm_set_enabled(sm, true); 82 | 83 | //while (true) {} 84 | } 85 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const rp2040 = @import("rp2040"); 3 | 4 | const available_examples = [_]Example{ 5 | .{ .name = "pico_adc", .target = rp2040.boards.raspberry_pi.pico, .file = "src/adc.zig" }, 6 | .{ .name = "pico_blinky", .target = rp2040.boards.raspberry_pi.pico, .file = "src/blinky.zig" }, 7 | // TODO: Fix multicore hal! .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico , .file = "src/blinky_core1.zig" }, 8 | .{ .name = "pico_flash-program", .target = rp2040.boards.raspberry_pi.pico, .file = "src/flash_program.zig" }, 9 | .{ .name = "pico_gpio-clk", .target = rp2040.boards.raspberry_pi.pico, .file = "src/gpio_clk.zig" }, 10 | .{ .name = "pico_i2c-bus-scan", .target = rp2040.boards.raspberry_pi.pico, .file = "src/i2c_bus_scan.zig" }, 11 | .{ .name = "pico_pwm", .target = rp2040.boards.raspberry_pi.pico, .file = "src/pwm.zig" }, 12 | .{ .name = "pico_random", .target = rp2040.boards.raspberry_pi.pico, .file = "src/random.zig" }, 13 | .{ .name = "pico_spi-master", .target = rp2040.boards.raspberry_pi.pico, .file = "src/spi_master.zig" }, 14 | .{ .name = "pico_squarewave", .target = rp2040.boards.raspberry_pi.pico, .file = "src/squarewave.zig" }, 15 | .{ .name = "pico_uart", .target = rp2040.boards.raspberry_pi.pico, .file = "src/uart.zig" }, 16 | .{ .name = "pico_usb-device", .target = rp2040.boards.raspberry_pi.pico, .file = "src/usb_device.zig" }, 17 | .{ .name = "pico_usb-hid", .target = rp2040.boards.raspberry_pi.pico, .file = "src/usb_hid.zig" }, 18 | .{ .name = "pico_ws2812", .target = rp2040.boards.raspberry_pi.pico, .file = "src/ws2812.zig" }, 19 | 20 | .{ .name = "rp2040-matrix_tiles", .target = rp2040.boards.waveshare.rp2040_matrix, .file = "src/tiles.zig" }, 21 | 22 | // .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, 23 | // .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, 24 | // .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, 25 | }; 26 | 27 | pub fn build(b: *std.Build) void { 28 | const microzig = @import("microzig").init(b, "microzig"); 29 | const optimize = b.standardOptimizeOption(.{}); 30 | 31 | for (available_examples) |example| { 32 | // `addFirmware` basically works like addExecutable, but takes a 33 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 34 | // 35 | // The target will convey all necessary information on the chip, 36 | // cpu and potentially the board as well. 37 | const firmware = microzig.addFirmware(b, .{ 38 | .name = example.name, 39 | .target = example.target, 40 | .optimize = optimize, 41 | .source_file = .{ .path = example.file }, 42 | }); 43 | 44 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 45 | // and allows installing the firmware as a typical firmware file. 46 | // 47 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 48 | microzig.installFirmware(b, firmware, .{}); 49 | 50 | // For debugging, we also always install the firmware as an ELF file 51 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 52 | } 53 | } 54 | 55 | const Example = struct { 56 | target: @import("microzig").Target, 57 | name: []const u8, 58 | file: []const u8, 59 | }; 60 | -------------------------------------------------------------------------------- /espressif-esp/src/blinky.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const peripherals = microzig.chip.peripherals; 4 | const TIMG0 = peripherals.TIMG0; 5 | const RTC_CNTL = peripherals.RTC_CNTL; 6 | const INTERRUPT_CORE0 = peripherals.INTERRUPT_CORE0; 7 | const GPIO = peripherals.GPIO; 8 | const IO_MUX = peripherals.IO_MUX; 9 | 10 | const dogfood: u32 = 0x50D83AA1; 11 | const super_dogfood: u32 = 0x8F1D312A; 12 | 13 | const LED_R_PIN = 3; // GPIO 14 | const LED_G_PIN = 4; // GPIO 15 | const LED_B_PIN = 5; // GPIO 16 | 17 | const led_pins = [_]u32{ 18 | LED_R_PIN, 19 | LED_G_PIN, 20 | LED_B_PIN, 21 | }; 22 | 23 | pub fn main() !void { 24 | // Feed and disable watchdog 0 25 | TIMG0.WDTWPROTECT.raw = dogfood; 26 | TIMG0.WDTCONFIG0.raw = 0; 27 | TIMG0.WDTWPROTECT.raw = 0; 28 | 29 | // Feed and disable rtc watchdog 30 | RTC_CNTL.WDTWPROTECT.raw = dogfood; 31 | RTC_CNTL.WDTCONFIG0.raw = 0; 32 | RTC_CNTL.WDTWPROTECT.raw = 0; 33 | 34 | // Feed and disable rtc super watchdog 35 | RTC_CNTL.SWD_WPROTECT.raw = super_dogfood; 36 | RTC_CNTL.SWD_CONF.modify(.{ .SWD_DISABLE = 1 }); 37 | RTC_CNTL.SWD_WPROTECT.raw = 0; 38 | 39 | // Disable all interrupts 40 | INTERRUPT_CORE0.CPU_INT_ENABLE.raw = 0; 41 | 42 | GPIO.ENABLE.modify(.{ 43 | .DATA = (1 << LED_R_PIN) | 44 | (1 << LED_G_PIN) | 45 | (1 << LED_B_PIN), 46 | }); 47 | 48 | for (led_pins) |pin| { 49 | IO_MUX.GPIO[pin].modify(.{ 50 | .MCU_OE = 1, // 1: output enabled 51 | .SLP_SEL = 0, // Set to 1 to put the pin in sleep mode. (R/W) 52 | .MCU_WPD = 0, // 0: internal pull-down disabled. (R/W) 53 | .MCU_WPU = 0, // 0: internal pull-up disabled. (R/W) 54 | .MCU_IE = 0, // 0: input disabled. (R/W) 55 | .FUN_WPD = 0, // 0: internal pull-down disabled. (R/W) 56 | .FUN_WPU = 0, // 0: internal pull-up disabled. (R/W) 57 | .FUN_IE = 0, // 0: input disabled. (R/W) 58 | .FUN_DRV = 3, // Select the drive strength of the pin. 0: ~5 mA; 1: ~ 10 mA; 2: ~ 20 mA; 3: ~40mA. (R/W) 59 | .MCU_SEL = 1, // 1: GPIO 60 | .FILTER_EN = 0, // 0: Filter disabled. (R/W) 61 | }); 62 | 63 | GPIO.FUNC_OUT_SEL_CFG[pin].write(.{ 64 | // If a value 128 is written to this field, bit n of GPIO_OUT_REG and GPIO_ENABLE_REG will be selected as the output value and output enable. (R/W) 65 | .OUT_SEL = 0x80, 66 | 67 | .INV_SEL = 0x00, // 0: Do not invert the output value 68 | .OEN_SEL = 0x01, // 1: Force the output enable signal to be sourced from bit n of GPIO_ENABLE_REG. (R/W) 69 | .OEN_INV_SEL = 0x00, // 0: Do not invert the output enable signal 70 | 71 | .padding = 0, 72 | }); 73 | } 74 | 75 | microzig.hal.uart.write(0, "Hello from Zig!\r\n"); 76 | 77 | while (true) { 78 | GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_R_PIN) }); 79 | microzig.hal.uart.write(0, "R"); 80 | microzig.core.experimental.debug.busy_sleep(100_000); 81 | 82 | GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_G_PIN) }); 83 | microzig.hal.uart.write(0, "G"); 84 | microzig.core.experimental.debug.busy_sleep(100_000); 85 | 86 | GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_B_PIN) }); 87 | microzig.hal.uart.write(0, "B"); 88 | microzig.core.experimental.debug.busy_sleep(100_000); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/README.md: -------------------------------------------------------------------------------- 1 | # Examples for the BSP `raspberrypi-rp2040` 2 | 3 | ## Demos 4 | 5 | All demos that run on the [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) can also be run on the [RP2040-Plus](https://www.waveshare.com/rp2040-plus.htm) without modification. 6 | 7 | - [adc](src/adc.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 8 | This example takes periodic samples of the temperature sensor and prints it to the UART using the stdlib logging facility. 9 | - [blinky](src/blinky.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 10 | Blinks the LED on the board. 11 | - [blinky core1](src/blinky_core1.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 12 | Blinks the LED on the board using the second CPU. 13 | - [flash program](src/flash_program.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 14 | Writes and reads data into the flash. 15 | - [gpio clk](src/gpio_clk.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 16 | Enables a `CLKOUT` mode on GPIO0. 17 | - [i2c bus scan](src/i2c_bus_scan.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 18 | Prints all I²C devices on UART0 (Pin 0,1) attached to I²C on SCL=GPIO4, SDA=GPIO5. 19 | - [pwm](src/pwm.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 20 | Slowly blinks the LED on the Pico with a smooth blinking using PWM. 21 | - [random](src/random.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 22 | Showcases how to use the internal random generator. 23 | - [spi master](src/spi_master.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 24 | Showcases how to use the SPI host controller. 25 | - [squarewave](src/squarewave.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 26 | Showcases how to use the PIO to emit a basic square wave. 27 | - [uart](src/uart.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 28 | Showcases how to use the UART together with `std.log`. 29 | - [usb device](src/usb_device.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 30 | A really basic example for a raw USB device. You can use the Python 3 script [`scripts/usb_device_loopback.py`](scripts/usb_device_loopback.py) to test the USB device. 31 | - [usb hid](src/usb_hid.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 32 | A really basic example how to implement a USB HID device. You can use the Python 3 script [`scripts/hid_test.py`](scripts/hid_test.py) to test the HID device. 33 | - [ws2812](src/ws2812.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) 34 | Showcases how to control one WS2812 LED attached to GPIO23. 35 | - [tiles](src/tiles.zig) on [RP2040-Matrix](https://www.waveshare.com/rp2040-matrix.htm) 36 | Showcases how to control the LED matrix on the development board to do a simple color flipper effect. 37 | 38 | ## Flashing 39 | 40 | You can flash all examples using either your file browser by dragging the example `.uf2` file from `zig-out/firmware/` to the directory. 41 | 42 | Or you can use [`picotool`](https://github.com/raspberrypi/picotool) to flash a uf2 file: 43 | ```sh-session 44 | [user@host] raspberrypi-rp2040/ $ picotool load -x zig-out/firmware/${file}.uf2 45 | Loading into Flash: [==============================] 100% 46 | 47 | The device was rebooted to start the application. 48 | [user@host] raspberrypi-rp2040/ $ 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /all-platforms/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const rp2040 = @import("rp2040"); 3 | const stm32 = @import("stm32"); 4 | const lpc = @import("lpc"); 5 | const gd32 = @import("gd32"); 6 | const nrf5x = @import("nrf5x"); 7 | const esp = @import("esp"); 8 | const atmega = @import("atmega"); 9 | 10 | const available_targets = [_]TargetDesc{ 11 | // RP2040 12 | .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, 13 | .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, 14 | .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, 15 | .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, 16 | .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, 17 | 18 | // STM32 19 | .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, 20 | .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, 21 | .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, 22 | .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, 23 | .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, 24 | .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, 25 | .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, 26 | .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, 27 | 28 | // NXP LPC 29 | .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, 30 | .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, 31 | 32 | // GigaDevice GD32 33 | .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, 34 | .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, 35 | .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, 36 | 37 | // Nordic Nrf5x 38 | .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, 39 | .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, 40 | .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! 41 | 42 | // RISC-V Espressif ESP 43 | .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries 44 | 45 | // Microchip ATmega 46 | // TODO: Fix compiler bugs 47 | // - https://github.com/ziglang/zig/issues/17219 48 | // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, 49 | // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, 50 | // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, 51 | }; 52 | 53 | pub fn build(b: *std.Build) void { 54 | const microzig = @import("microzig").init(b, "microzig"); 55 | const optimize = b.standardOptimizeOption(.{}); 56 | 57 | for (available_targets) |dest| { 58 | // `addFirmware` basically works like addExecutable, but takes a 59 | // `microzig.Target` for target instead of a `std.zig.CrossTarget`. 60 | // 61 | // The target will convey all necessary information on the chip, 62 | // cpu and potentially the board as well. 63 | const firmware = microzig.addFirmware(b, .{ 64 | .name = b.fmt("empty-{s}", .{dest.name}), 65 | .target = dest.target, 66 | .optimize = optimize, 67 | .source_file = .{ .path = "src/empty.zig" }, 68 | }); 69 | 70 | // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` 71 | // and allows installing the firmware as a typical firmware file. 72 | // 73 | // This will also install into `$prefix/firmware` instead of `$prefix/bin`. 74 | microzig.installFirmware(b, firmware, .{}); 75 | 76 | // For debugging, we also always install the firmware as an ELF file 77 | microzig.installFirmware(b, firmware, .{ .format = .elf }); 78 | } 79 | } 80 | 81 | const TargetDesc = struct { 82 | target: @import("microzig").Target, 83 | name: []const u8, 84 | }; 85 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/tiles.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | const rp2040 = microzig.hal; 4 | const gpio = rp2040.gpio; 5 | const Pio = rp2040.pio.Pio; 6 | const StateMachine = rp2040.pio.StateMachine; 7 | 8 | const ws2812_program = blk: { 9 | @setEvalBranchQuota(5000); 10 | break :blk rp2040.pio.assemble( 11 | \\; 12 | \\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 13 | \\; 14 | \\; SPDX-License-Identifier: BSD-3-Clause 15 | \\; 16 | \\.program ws2812 17 | \\.side_set 1 18 | \\ 19 | \\.define public T1 2 20 | \\.define public T2 5 21 | \\.define public T3 3 22 | \\ 23 | \\.wrap_target 24 | \\bitloop: 25 | \\ out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls 26 | \\ jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse 27 | \\do_one: 28 | \\ jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse 29 | \\do_zero: 30 | \\ nop side 0 [T2 - 1] ; Or drive low, for a short pulse 31 | \\.wrap 32 | , .{}).get_program_by_name("ws2812"); 33 | }; 34 | 35 | const pio: Pio = .pio0; 36 | const sm: StateMachine = .sm0; 37 | const led_pin = gpio.num(16); 38 | 39 | const brightness: [256]u8 = blk: { 40 | @setEvalBranchQuota(10_000); 41 | 42 | const gamma = 2.2; 43 | 44 | const max_brightness = 0x10; 45 | 46 | var data: [256]u8 = undefined; 47 | for (&data, 0..) |*bit, i| { 48 | const raw_index: f32 = @floatFromInt(i); 49 | 50 | const gamma_brightness = std.math.pow(f32, raw_index / 255.0, gamma); 51 | 52 | bit.* = @intFromFloat(max_brightness * gamma_brightness); 53 | } 54 | // @compileLog(data); 55 | break :blk data; 56 | }; 57 | 58 | const RGB = extern struct { 59 | x: u8 = 0x00, 60 | b: u8, 61 | g: u8, 62 | r: u8, 63 | }; 64 | 65 | inline fn floatToBright(f: f32) u8 { 66 | return brightness[ 67 | @intFromFloat( 68 | std.math.clamp(255.0 * f, 0.0, 255.0), 69 | ) 70 | ]; 71 | } 72 | 73 | pub fn main() void { 74 | pio.gpio_init(led_pin); 75 | sm_set_consecutive_pindirs(pio, sm, @intFromEnum(led_pin), 1, true); 76 | 77 | const cycles_per_bit: comptime_int = ws2812_program.defines[0].value + //T1 78 | ws2812_program.defines[1].value + //T2 79 | ws2812_program.defines[2].value; //T3 80 | const div = @as(f32, @floatFromInt(rp2040.clock_config.sys.?.output_freq)) / 81 | (800_000 * cycles_per_bit); 82 | 83 | pio.sm_load_and_start_program(sm, ws2812_program, .{ 84 | .clkdiv = rp2040.pio.ClkDivOptions.from_float(div), 85 | .pin_mappings = .{ 86 | .side_set = .{ 87 | .base = @intFromEnum(led_pin), 88 | .count = 1, 89 | }, 90 | }, 91 | .shift = .{ 92 | .out_shiftdir = .left, 93 | .autopull = true, 94 | .pull_threshold = 24, 95 | .join_tx = true, 96 | }, 97 | }) catch unreachable; 98 | pio.sm_set_enabled(sm, true); 99 | 100 | var rng_src = std.rand.DefaultPrng.init(0x1234); 101 | 102 | const rng = rng_src.random(); 103 | 104 | var screen: [5][5]RGB = undefined; 105 | for (&screen) |*row| { 106 | for (row) |*pix| { 107 | pix.* = RGB{ 108 | .r = brightness[rng.int(u8)], 109 | .g = brightness[rng.int(u8)], 110 | .b = brightness[rng.int(u8)], 111 | }; 112 | } 113 | } 114 | 115 | while (true) { 116 | screen[rng.intRangeLessThan(u8, 0, 5)][rng.intRangeLessThan(u8, 0, 5)] = RGB{ 117 | .r = brightness[rng.int(u8)], 118 | .g = brightness[rng.int(u8)], 119 | .b = brightness[rng.int(u8)], 120 | }; 121 | 122 | for (@as([25]RGB, @bitCast(screen))) |color| { 123 | pio.sm_blocking_write(sm, @bitCast(color)); 124 | } 125 | rp2040.time.sleep_ms(50); 126 | } 127 | } 128 | 129 | fn sm_set_consecutive_pindirs(_pio: Pio, _sm: StateMachine, pin: u5, count: u3, is_out: bool) void { 130 | const sm_regs = _pio.get_sm_regs(_sm); 131 | const pinctrl_saved = sm_regs.pinctrl.raw; 132 | sm_regs.pinctrl.modify(.{ 133 | .SET_BASE = pin, 134 | .SET_COUNT = count, 135 | }); 136 | _pio.sm_exec(_sm, rp2040.pio.Instruction{ 137 | .tag = .set, 138 | .delay_side_set = 0, 139 | .payload = .{ 140 | .set = .{ 141 | .data = @intFromBool(is_out), 142 | .destination = .pindirs, 143 | }, 144 | }, 145 | }); 146 | sm_regs.pinctrl.raw = pinctrl_saved; 147 | } 148 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/usb_device.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const flash = rp2040.flash; 6 | const time = rp2040.time; 7 | const gpio = rp2040.gpio; 8 | const clocks = rp2040.clocks; 9 | const usb = rp2040.usb; 10 | 11 | const led = gpio.num(25); 12 | const uart = rp2040.uart.num(0); 13 | const baud_rate = 115200; 14 | const uart_tx_pin = gpio.num(0); 15 | const uart_rx_pin = gpio.num(1); 16 | 17 | // First we define two callbacks that will be used by the endpoints we define next... 18 | fn ep1_in_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { 19 | _ = data; 20 | // The host has collected the data we repeated onto 21 | // EP1! Set up to receive more data on EP1. 22 | usb.Usb.callbacks.usb_start_rx( 23 | dc.endpoints[2], // EP1_OUT_CFG, 24 | 64, 25 | ); 26 | } 27 | 28 | fn ep1_out_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { 29 | // We've gotten data from the host on our custom 30 | // EP1! Set up EP1 to repeat it. 31 | usb.Usb.callbacks.usb_start_tx( 32 | dc.endpoints[3], // EP1_IN_CFG, 33 | data, 34 | ); 35 | } 36 | 37 | // The endpoints EP0_IN and EP0_OUT are already defined but you can 38 | // add your own endpoints to... 39 | pub var EP1_OUT_CFG: usb.EndpointConfiguration = .{ 40 | .descriptor = &usb.EndpointDescriptor{ 41 | .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), 42 | .descriptor_type = usb.DescType.Endpoint, 43 | .endpoint_address = usb.Dir.Out.endpoint(1), 44 | .attributes = @intFromEnum(usb.TransferType.Bulk), 45 | .max_packet_size = 64, 46 | .interval = 0, 47 | }, 48 | .endpoint_control_index = 2, 49 | .buffer_control_index = 3, 50 | .data_buffer_index = 2, 51 | .next_pid_1 = false, 52 | // The callback will be executed if we got an interrupt on EP1_OUT 53 | .callback = ep1_out_callback, 54 | }; 55 | 56 | pub var EP1_IN_CFG: usb.EndpointConfiguration = .{ 57 | .descriptor = &usb.EndpointDescriptor{ 58 | .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), 59 | .descriptor_type = usb.DescType.Endpoint, 60 | .endpoint_address = usb.Dir.In.endpoint(1), 61 | .attributes = @intFromEnum(usb.TransferType.Bulk), 62 | .max_packet_size = 64, 63 | .interval = 0, 64 | }, 65 | .endpoint_control_index = 1, 66 | .buffer_control_index = 2, 67 | .data_buffer_index = 3, 68 | .next_pid_1 = false, 69 | // The callback will be executed if we got an interrupt on EP1_IN 70 | .callback = ep1_in_callback, 71 | }; 72 | 73 | // This is our device configuration 74 | pub var DEVICE_CONFIGURATION: usb.DeviceConfiguration = .{ 75 | .device_descriptor = &.{ 76 | .length = @as(u8, @intCast(@sizeOf(usb.DeviceDescriptor))), 77 | .descriptor_type = usb.DescType.Device, 78 | .bcd_usb = 0x0110, 79 | .device_class = 0, 80 | .device_subclass = 0, 81 | .device_protocol = 0, 82 | .max_packet_size0 = 64, 83 | .vendor = 0, 84 | .product = 1, 85 | .bcd_device = 0, 86 | .manufacturer_s = 1, 87 | .product_s = 2, 88 | .serial_s = 0, 89 | .num_configurations = 1, 90 | }, 91 | .interface_descriptor = &.{ 92 | .length = @as(u8, @intCast(@sizeOf(usb.InterfaceDescriptor))), 93 | .descriptor_type = usb.DescType.Interface, 94 | .interface_number = 0, 95 | .alternate_setting = 0, 96 | // We have two endpoints (EP0 IN/OUT don't count) 97 | .num_endpoints = 2, 98 | .interface_class = 0xff, 99 | .interface_subclass = 0, 100 | .interface_protocol = 0, 101 | .interface_s = 0, 102 | }, 103 | .config_descriptor = &.{ 104 | .length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor))), 105 | .descriptor_type = usb.DescType.Config, 106 | .total_length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor) + @sizeOf(usb.InterfaceDescriptor) + @sizeOf(usb.EndpointDescriptor) + @sizeOf(usb.EndpointDescriptor))), 107 | .num_interfaces = 1, 108 | .configuration_value = 1, 109 | .configuration_s = 0, 110 | .attributes = 0xc0, 111 | .max_power = 0x32, 112 | }, 113 | .lang_descriptor = "\x04\x03\x09\x04", // length || string descriptor (0x03) || Engl (0x0409) 114 | .descriptor_strings = &.{ 115 | // ugly unicode :| 116 | "R\x00a\x00s\x00p\x00b\x00e\x00r\x00r\x00y\x00 \x00P\x00i\x00", 117 | "P\x00i\x00c\x00o\x00 \x00T\x00e\x00s\x00t\x00 \x00D\x00e\x00v\x00i\x00c\x00e\x00", 118 | }, 119 | // Here we pass all endpoints to the config 120 | // Dont forget to pass EP0_[IN|OUT] in the order seen below! 121 | .endpoints = .{ 122 | &usb.EP0_OUT_CFG, 123 | &usb.EP0_IN_CFG, 124 | &EP1_OUT_CFG, 125 | &EP1_IN_CFG, 126 | }, 127 | }; 128 | 129 | pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { 130 | std.log.err("panic: {s}", .{message}); 131 | @breakpoint(); 132 | while (true) {} 133 | } 134 | 135 | pub const std_options = struct { 136 | pub const log_level = .debug; 137 | pub const logFn = rp2040.uart.log; 138 | }; 139 | 140 | pub fn main() !void { 141 | led.set_function(.sio); 142 | led.set_direction(.out); 143 | led.put(1); 144 | 145 | uart.apply(.{ 146 | .baud_rate = baud_rate, 147 | .tx_pin = uart_tx_pin, 148 | .rx_pin = uart_rx_pin, 149 | .clock_config = rp2040.clock_config, 150 | }); 151 | 152 | rp2040.uart.init_logger(uart); 153 | 154 | // First we initialize the USB clock 155 | rp2040.usb.Usb.init_clk(); 156 | // Then initialize the USB device using the configuration defined above 157 | rp2040.usb.Usb.init_device(&DEVICE_CONFIGURATION) catch unreachable; 158 | var old: u64 = time.get_time_since_boot().to_us(); 159 | var new: u64 = 0; 160 | while (true) { 161 | // You can now poll for USB events 162 | rp2040.usb.Usb.task( 163 | false, // debug output over UART [Y/n] 164 | ) catch unreachable; 165 | 166 | new = time.get_time_since_boot().to_us(); 167 | if (new - old > 500000) { 168 | old = new; 169 | led.toggle(); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /raspberrypi-rp2040/src/usb_hid.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const microzig = @import("microzig"); 3 | 4 | const rp2040 = microzig.hal; 5 | const flash = rp2040.flash; 6 | const time = rp2040.time; 7 | const gpio = rp2040.gpio; 8 | const clocks = rp2040.clocks; 9 | const usb = rp2040.usb; 10 | 11 | const led = gpio.num(25); 12 | const uart = rp2040.uart.num(0); 13 | const baud_rate = 115200; 14 | const uart_tx_pin = gpio.num(0); 15 | const uart_rx_pin = gpio.num(1); 16 | 17 | // First we define two callbacks that will be used by the endpoints we define next... 18 | fn ep1_in_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { 19 | _ = data; 20 | // The host has collected the data we repeated onto 21 | // EP1! Set up to receive more data on EP1. 22 | usb.Usb.callbacks.usb_start_rx( 23 | dc.endpoints[2], // EP1_OUT_CFG, 24 | 64, 25 | ); 26 | } 27 | 28 | fn ep1_out_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { 29 | // We've gotten data from the host on our custom 30 | // EP1! Set up EP1 to repeat it. 31 | usb.Usb.callbacks.usb_start_tx( 32 | dc.endpoints[3], // EP1_IN_CFG, 33 | data, 34 | ); 35 | } 36 | 37 | // The endpoints EP0_IN and EP0_OUT are already defined but you can 38 | // add your own endpoints to... 39 | pub var EP1_OUT_CFG: usb.EndpointConfiguration = .{ 40 | .descriptor = &usb.EndpointDescriptor{ 41 | .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), 42 | .descriptor_type = usb.DescType.Endpoint, 43 | .endpoint_address = usb.Dir.Out.endpoint(1), 44 | .attributes = @intFromEnum(usb.TransferType.Interrupt), 45 | .max_packet_size = 64, 46 | .interval = 0, 47 | }, 48 | .endpoint_control_index = 2, 49 | .buffer_control_index = 3, 50 | .data_buffer_index = 2, 51 | .next_pid_1 = false, 52 | // The callback will be executed if we got an interrupt on EP1_OUT 53 | .callback = ep1_out_callback, 54 | }; 55 | 56 | pub var EP1_IN_CFG: usb.EndpointConfiguration = .{ 57 | .descriptor = &usb.EndpointDescriptor{ 58 | .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), 59 | .descriptor_type = usb.DescType.Endpoint, 60 | .endpoint_address = usb.Dir.In.endpoint(1), 61 | .attributes = @intFromEnum(usb.TransferType.Interrupt), 62 | .max_packet_size = 64, 63 | .interval = 0, 64 | }, 65 | .endpoint_control_index = 1, 66 | .buffer_control_index = 2, 67 | .data_buffer_index = 3, 68 | .next_pid_1 = false, 69 | // The callback will be executed if we got an interrupt on EP1_IN 70 | .callback = ep1_in_callback, 71 | }; 72 | 73 | // This is our device configuration 74 | pub var DEVICE_CONFIGURATION: usb.DeviceConfiguration = .{ 75 | .device_descriptor = &.{ 76 | .length = @as(u8, @intCast(@sizeOf(usb.DeviceDescriptor))), 77 | .descriptor_type = usb.DescType.Device, 78 | .bcd_usb = 0x0200, 79 | .device_class = 0, 80 | .device_subclass = 0, 81 | .device_protocol = 0, 82 | .max_packet_size0 = 64, 83 | .vendor = 0xCafe, 84 | .product = 1, 85 | .bcd_device = 0x0100, 86 | // Those are indices to the descriptor strings 87 | // Make sure to provide enough string descriptors! 88 | .manufacturer_s = 1, 89 | .product_s = 2, 90 | .serial_s = 3, 91 | .num_configurations = 1, 92 | }, 93 | .interface_descriptor = &.{ 94 | .length = @as(u8, @intCast(@sizeOf(usb.InterfaceDescriptor))), 95 | .descriptor_type = usb.DescType.Interface, 96 | .interface_number = 0, 97 | .alternate_setting = 0, 98 | // We have two endpoints (EP0 IN/OUT don't count) 99 | .num_endpoints = 2, 100 | .interface_class = 3, 101 | .interface_subclass = 0, 102 | .interface_protocol = 0, 103 | .interface_s = 0, 104 | }, 105 | .config_descriptor = &.{ 106 | .length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor))), 107 | .descriptor_type = usb.DescType.Config, 108 | .total_length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor) + @sizeOf(usb.InterfaceDescriptor) + @sizeOf(usb.EndpointDescriptor) + @sizeOf(usb.EndpointDescriptor))), 109 | .num_interfaces = 1, 110 | .configuration_value = 1, 111 | .configuration_s = 0, 112 | .attributes = 0xc0, 113 | .max_power = 0x32, 114 | }, 115 | .lang_descriptor = "\x04\x03\x09\x04", // length || string descriptor (0x03) || Engl (0x0409) 116 | .descriptor_strings = &.{ 117 | // ugly unicode :| 118 | //"R\x00a\x00s\x00p\x00b\x00e\x00r\x00r\x00y\x00 \x00P\x00i\x00", 119 | &usb.utf8ToUtf16Le("Raspberry Pi"), 120 | //"P\x00i\x00c\x00o\x00 \x00T\x00e\x00s\x00t\x00 \x00D\x00e\x00v\x00i\x00c\x00e\x00", 121 | &usb.utf8ToUtf16Le("Pico Test Device"), 122 | //"c\x00a\x00f\x00e\x00b\x00a\x00b\x00e\x00", 123 | &usb.utf8ToUtf16Le("cafebabe"), 124 | }, 125 | .hid = .{ 126 | .hid_descriptor = &.{ 127 | .bcd_hid = 0x0111, 128 | .country_code = 0, 129 | .num_descriptors = 1, 130 | .report_length = 34, 131 | }, 132 | .report_descriptor = &usb.hid.ReportDescriptorFidoU2f, 133 | }, 134 | // Here we pass all endpoints to the config 135 | // Dont forget to pass EP0_[IN|OUT] in the order seen below! 136 | .endpoints = .{ 137 | &usb.EP0_OUT_CFG, 138 | &usb.EP0_IN_CFG, 139 | &EP1_OUT_CFG, 140 | &EP1_IN_CFG, 141 | }, 142 | }; 143 | 144 | pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { 145 | std.log.err("panic: {s}", .{message}); 146 | @breakpoint(); 147 | while (true) {} 148 | } 149 | 150 | pub const std_options = struct { 151 | pub const log_level = .debug; 152 | pub const logFn = rp2040.uart.log; 153 | }; 154 | 155 | pub fn main() !void { 156 | led.set_function(.sio); 157 | led.set_direction(.out); 158 | led.put(1); 159 | 160 | uart.apply(.{ 161 | .baud_rate = baud_rate, 162 | .tx_pin = uart_tx_pin, 163 | .rx_pin = uart_rx_pin, 164 | .clock_config = rp2040.clock_config, 165 | }); 166 | 167 | rp2040.uart.init_logger(uart); 168 | 169 | // First we initialize the USB clock 170 | rp2040.usb.Usb.init_clk(); 171 | // Then initialize the USB device using the configuration defined above 172 | rp2040.usb.Usb.init_device(&DEVICE_CONFIGURATION) catch unreachable; 173 | var old: u64 = time.get_time_since_boot().to_us(); 174 | var new: u64 = 0; 175 | while (true) { 176 | // You can now poll for USB events 177 | rp2040.usb.Usb.task( 178 | true, // debug output over UART [Y/n] 179 | ) catch unreachable; 180 | 181 | new = time.get_time_since_boot().to_us(); 182 | if (new - old > 500000) { 183 | old = new; 184 | led.toggle(); 185 | } 186 | } 187 | } 188 | --------------------------------------------------------------------------------