From 01287dd68db70950b901c056f76453e767b0cfa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Sat, 23 Sep 2023 18:16:10 +0200 Subject: [PATCH] Rough file architecture --- .github/workflows/build.yml | 2 + .gitignore | 9 +- espressif-esp/blinky/blinky.zig | 57 ++++++++ build.zig => espressif-esp/build.zig | 0 espressif-esp/build.zig.zon | 14 ++ ezpkg.sh | 13 -- generic/build.zig | 84 +++++++++++ build.zig.zon => generic/build.zig.zon | 2 +- {src => generic/src}/blinky.zig | 0 {src => generic/src}/empty.zig | 0 gigadevice-gd32/build.zig | 84 +++++++++++ gigadevice-gd32/build.zig.zon | 14 ++ microchip-atmega/build.zig | 84 +++++++++++ microchip-atmega/build.zig.zon | 14 ++ nordic-nrf5x/README.adoc | 11 ++ nordic-nrf5x/build.zig | 84 +++++++++++ nordic-nrf5x/build.zig.zon | 14 ++ nxp-lpc/build.zig | 84 +++++++++++ nxp-lpc/build.zig.zon | 14 ++ nxp-lpc/src/blinky.zig | 0 rp2040/build.zig | 84 +++++++++++ rp2040/build.zig.zon | 14 ++ rp2040/scripts/hid_test.py | 29 ++++ rp2040/scripts/usb_device_loopback.py | 48 +++++++ rp2040/src/adc.zig | 40 ++++++ rp2040/src/blinky.zig | 20 +++ rp2040/src/blinky_core1.zig | 28 ++++ rp2040/src/flash_program.zig | 81 +++++++++++ rp2040/src/gpio_clk.zig | 16 +++ rp2040/src/i2c_bus_scan.zig | 44 ++++++ rp2040/src/pwm.zig | 23 +++ rp2040/src/random.zig | 68 +++++++++ rp2040/src/spi_master.zig | 26 ++++ rp2040/src/squarewave.zig | 84 +++++++++++ rp2040/src/uart.zig | 49 +++++++ rp2040/src/usb_device.zig | 172 +++++++++++++++++++++++ rp2040/src/usb_hid.zig | 187 +++++++++++++++++++++++++ rp2040/src/ws2812.zig | 94 +++++++++++++ shell.nix | 9 -- stmicro-stm32/build.zig | 84 +++++++++++ stmicro-stm32/build.zig.zon | 14 ++ 41 files changed, 1773 insertions(+), 25 deletions(-) create mode 100644 espressif-esp/blinky/blinky.zig rename build.zig => espressif-esp/build.zig (100%) create mode 100644 espressif-esp/build.zig.zon delete mode 100755 ezpkg.sh create mode 100644 generic/build.zig rename build.zig.zon => generic/build.zig.zon (98%) rename {src => generic/src}/blinky.zig (100%) rename {src => generic/src}/empty.zig (100%) create mode 100644 gigadevice-gd32/build.zig create mode 100644 gigadevice-gd32/build.zig.zon create mode 100644 microchip-atmega/build.zig create mode 100644 microchip-atmega/build.zig.zon create mode 100644 nordic-nrf5x/README.adoc create mode 100644 nordic-nrf5x/build.zig create mode 100644 nordic-nrf5x/build.zig.zon create mode 100644 nxp-lpc/build.zig create mode 100644 nxp-lpc/build.zig.zon create mode 100644 nxp-lpc/src/blinky.zig create mode 100644 rp2040/build.zig create mode 100644 rp2040/build.zig.zon create mode 100755 rp2040/scripts/hid_test.py create mode 100755 rp2040/scripts/usb_device_loopback.py create mode 100644 rp2040/src/adc.zig create mode 100644 rp2040/src/blinky.zig create mode 100644 rp2040/src/blinky_core1.zig create mode 100644 rp2040/src/flash_program.zig create mode 100644 rp2040/src/gpio_clk.zig create mode 100644 rp2040/src/i2c_bus_scan.zig create mode 100644 rp2040/src/pwm.zig create mode 100644 rp2040/src/random.zig create mode 100644 rp2040/src/spi_master.zig create mode 100644 rp2040/src/squarewave.zig create mode 100644 rp2040/src/uart.zig create mode 100644 rp2040/src/usb_device.zig create mode 100644 rp2040/src/usb_hid.zig create mode 100644 rp2040/src/ws2812.zig delete mode 100644 shell.nix create mode 100644 stmicro-stm32/build.zig create mode 100644 stmicro-stm32/build.zig.zon diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af725e6..ee9f1bb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ jobs: strategy: matrix: os: [windows-latest, macos-latest, ubuntu-latest] + dir: espressif-esp generic gigadevice-gd32 microchip-atmega nordic-nrf5x nxp-lpc rp2040 stmicro-stm32 steps: - name: Checkout uses: actions/checkout@v2 @@ -21,4 +22,5 @@ jobs: version: 0.11.0 - name: Build examples + working-directory: ${{ matrix.dir }} run: zig build diff --git a/.gitignore b/.gitignore index f975728..5855061 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ zig-cache/ -dev-scripts/ -zig-out +zig-out/ + +ezpkg.sh + +.vscode + .envrc +shell.nix diff --git a/espressif-esp/blinky/blinky.zig b/espressif-esp/blinky/blinky.zig new file mode 100644 index 0000000..811b048 --- /dev/null +++ b/espressif-esp/blinky/blinky.zig @@ -0,0 +1,57 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const peripherals = microzig.chip.peripherals; +const TIMG0 = peripherals.TIMG0; +const RTC_CNTL = peripherals.RTC_CNTL; +const INTERRUPT_CORE0 = peripherals.INTERRUPT_CORE0; +const GPIO = peripherals.GPIO; + +const dogfood: u32 = 0x50D83AA1; +const super_dogfood: u32 = 0x8F1D312A; + +pub fn main() !void { + TIMG0.WDTWPROTECT.raw = dogfood; + TIMG0.WDTCONFIG0.raw = 0; + TIMG0.WDTWPROTECT.raw = 0; + + RTC_CNTL.WDTWPROTECT.raw = dogfood; + RTC_CNTL.WDTCONFIG0.raw = 0; + RTC_CNTL.WDTWPROTECT.raw = 0; + + RTC_CNTL.SWD_WPROTECT.raw = super_dogfood; + RTC_CNTL.SWD_CONF.modify(.{ .SWD_DISABLE = 1 }); + RTC_CNTL.SWD_WPROTECT.raw = 0; + + INTERRUPT_CORE0.CPU_INT_ENABLE.raw = 0; + + microzig.hal.gpio.init(LED_R_PIN, .{ + .direction = .output, + .direct_io = true, + }); + microzig.hal.gpio.init(LED_G_PIN, .{ + .direction = .output, + .direct_io = true, + }); + microzig.hal.gpio.init(LED_B_PIN, .{ + .direction = .output, + .direct_io = true, + }); + + microzig.hal.uart.write(0, "Hello from Zig!\r\n"); + + while (true) { + GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_R_PIN) }); + microzig.hal.uart.write(0, "R"); + microzig.core.experimental.debug.busy_sleep(100_000); + GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_G_PIN) }); + microzig.hal.uart.write(0, "G"); + microzig.core.experimental.debug.busy_sleep(100_000); + GPIO.OUT.modify(.{ .DATA_ORIG = (1 << LED_B_PIN) }); + microzig.hal.uart.write(0, "B"); + microzig.core.experimental.debug.busy_sleep(100_000); + } +} + +const LED_R_PIN = 3; // GPIO +const LED_G_PIN = 16; // GPIO +const LED_B_PIN = 17; // GPIO diff --git a/build.zig b/espressif-esp/build.zig similarity index 100% rename from build.zig rename to espressif-esp/build.zig diff --git a/espressif-esp/build.zig.zon b/espressif-esp/build.zig.zon new file mode 100644 index 0000000..a729ce6 --- /dev/null +++ b/espressif-esp/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-espressif-esp-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .esp = .{ + .url = "https://github.com/ZigEmbeddedGroup/espressif-esp/archive/59b8ca028915c0d6224ec88dbf4db19afbb559c0.tar.gz", + .hash = "1220f6e5f22416fdc63442cd8869fcaa35f9abf30d878ea3d80073176677dc6f8a65", + }, + }, +} diff --git a/ezpkg.sh b/ezpkg.sh deleted file mode 100755 index caafa03..0000000 --- a/ezpkg.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -exec ezpkg \ - microzig=/home/felix/projects/zeg/microzig \ - microzig.uf2=/home/felix/projects/zeg/uf2 \ - microzig.regz=/home/felix/projects/zeg/regz \ - rp2040=/home/felix/projects/zeg/device-support-package/rp2040 \ - stm32=/home/felix/projects/zeg/device-support-package/stmicro-stm32 \ - lpc=/home/felix/projects/zeg/device-support-package/nxp-lpc \ - gd32=/home/felix/projects/zeg/device-support-package/gigadevice-gd32 \ - esp=/home/felix/projects/zeg/device-support-package/espressif-esp \ - nrf5x=/home/felix/projects/zeg/device-support-package/nordic-nrf5x \ - atmega=/home/felix/projects/zeg/device-support-package/microchip-atmega \ No newline at end of file diff --git a/generic/build.zig b/generic/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/generic/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/build.zig.zon b/generic/build.zig.zon similarity index 98% rename from build.zig.zon rename to generic/build.zig.zon index 7166259..fba280d 100644 --- a/build.zig.zon +++ b/generic/build.zig.zon @@ -1,5 +1,5 @@ .{ - .name = "microzig-examples", + .name = "microzig-generic-examples", .version = "0.1.0", .dependencies = .{ .microzig = .{ diff --git a/src/blinky.zig b/generic/src/blinky.zig similarity index 100% rename from src/blinky.zig rename to generic/src/blinky.zig diff --git a/src/empty.zig b/generic/src/empty.zig similarity index 100% rename from src/empty.zig rename to generic/src/empty.zig diff --git a/gigadevice-gd32/build.zig b/gigadevice-gd32/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/gigadevice-gd32/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/gigadevice-gd32/build.zig.zon b/gigadevice-gd32/build.zig.zon new file mode 100644 index 0000000..2cfeaae --- /dev/null +++ b/gigadevice-gd32/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-gigadevice-gd32-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .gd32 = .{ + .url = "https://github.com/ZigEmbeddedGroup/gigadevice-gd32/archive/9324753cc3b8e7afe83fcda085bcfe76681a3be3.tar.gz", + .hash = "122043ff4dcbc342f25dbb936b0d9eaa701ac3509e2cbe6764be37b90d31c7a385d0", + }, + }, +} diff --git a/microchip-atmega/build.zig b/microchip-atmega/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/microchip-atmega/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/microchip-atmega/build.zig.zon b/microchip-atmega/build.zig.zon new file mode 100644 index 0000000..f3c3bdf --- /dev/null +++ b/microchip-atmega/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-microchip-atmega-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .atmega = .{ + .url = "https://github.com/ZigEmbeddedGroup/microchip-atmega/archive/feefcb87a63c0aae31afb783d4e388e90c4d922f.tar.gz", + .hash = "1220048dc5d22729ee119a496f8b8ca3556838af1f3bd32ce6acd5f76480ec942965", + }, + }, +} diff --git a/nordic-nrf5x/README.adoc b/nordic-nrf5x/README.adoc new file mode 100644 index 0000000..7c2fa2f --- /dev/null +++ b/nordic-nrf5x/README.adoc @@ -0,0 +1,11 @@ += Nordic nrf5x + +HALs and register definitions for nrf5x devices + +== What version of Zig to use + +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. + +== Renode supports: + +- nrf52840 development kit diff --git a/nordic-nrf5x/build.zig b/nordic-nrf5x/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/nordic-nrf5x/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/nordic-nrf5x/build.zig.zon b/nordic-nrf5x/build.zig.zon new file mode 100644 index 0000000..2034409 --- /dev/null +++ b/nordic-nrf5x/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-nordic-nrf5x-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .nrf5x = .{ + .url = "https://github.com/ZigEmbeddedGroup/nordic-nrf5x/archive/0ab136860ccf7eb1d07969c3ef523f3cd898e2ff.tar.gz", + .hash = "1220980da06f9634dcff06afefa7aa111bd030018fea49f79e86657dab69621e1d08", + }, + }, +} diff --git a/nxp-lpc/build.zig b/nxp-lpc/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/nxp-lpc/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/nxp-lpc/build.zig.zon b/nxp-lpc/build.zig.zon new file mode 100644 index 0000000..aa5a11a --- /dev/null +++ b/nxp-lpc/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-nxp-lpc-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .lpc = .{ + .url = "https://github.com/ZigEmbeddedGroup/nxp-lpc/archive/130a1316c0892415e7da958a5e9548ed87bba54d.tar.gz", + .hash = "1220165879f85a1d51656d35b3963a95f3585dc665fc7414f76aa6aad4e6635536cf", + }, + }, +} diff --git a/nxp-lpc/src/blinky.zig b/nxp-lpc/src/blinky.zig new file mode 100644 index 0000000..e69de29 diff --git a/rp2040/build.zig b/rp2040/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/rp2040/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/rp2040/build.zig.zon b/rp2040/build.zig.zon new file mode 100644 index 0000000..255be3f --- /dev/null +++ b/rp2040/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-raspberrypi-rp2040-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .rp2040 = .{ + .url = "https://github.com/ZigEmbeddedGroup/raspberrypi-rp2040/archive/67d36eebb0fbd89633db1a51d6d2bcb049f2066a.tar.gz", + .hash = "122094bf268f45b188f3916f9e5964f4257414afaafba98a455ac47d25389a456832", + }, + }, +} diff --git a/rp2040/scripts/hid_test.py b/rp2040/scripts/hid_test.py new file mode 100755 index 0000000..ccc2dd0 --- /dev/null +++ b/rp2040/scripts/hid_test.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +# Install python3 HID package https://pypi.org/project/hid/ +import hid + +# default is TinyUSB (0xcafe), Adafruit (0x239a), RaspberryPi (0x2e8a), Espressif (0x303a) VID +USB_VID = (0xcafe, 0x239a, 0x2e8a, 0x303a) + +print("VID list: " + ", ".join('%02x' % v for v in USB_VID)) + +for vid in USB_VID: + for dict in hid.enumerate(vid): + print(dict) + dev = hid.Device(dict['vendor_id'], dict['product_id']) + if dev: + while True: + inp = input("Send text to HID Device : ").encode('utf-8') + dev.write(inp) + + x = 0 + l = len(inp) + r = b"" + while (x < l): + str_in = dev.read(64) + r += str_in + x += 64 + + print("Received from HID Device:\n", r) + print("hex:\n", r.hex()) diff --git a/rp2040/scripts/usb_device_loopback.py b/rp2040/scripts/usb_device_loopback.py new file mode 100755 index 0000000..82bf478 --- /dev/null +++ b/rp2040/scripts/usb_device_loopback.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# sudo pip3 install pyusb + +import usb.core +import usb.util + +# find our device +dev = usb.core.find(idVendor=0x0000, idProduct=0x0001) + +# was it found? +if dev is None: + raise ValueError('Device not found') + +# get an endpoint instance +cfg = dev.get_active_configuration() +intf = cfg[(0, 0)] + +outep = usb.util.find_descriptor( + intf, + # match the first OUT endpoint + custom_match= \ + lambda e: \ + usb.util.endpoint_direction(e.bEndpointAddress) == \ + usb.util.ENDPOINT_OUT) + +inep = usb.util.find_descriptor( + intf, + # match the first IN endpoint + custom_match= \ + lambda e: \ + usb.util.endpoint_direction(e.bEndpointAddress) == \ + usb.util.ENDPOINT_IN) + +assert inep is not None +assert outep is not None + +test_string = "Hello World!" +outep.write(test_string) +from_device = inep.read(len(test_string)) + +print("Device Says: {}".format(''.join([chr(x) for x in from_device]))) diff --git a/rp2040/src/adc.zig b/rp2040/src/adc.zig new file mode 100644 index 0000000..ff180dd --- /dev/null +++ b/rp2040/src/adc.zig @@ -0,0 +1,40 @@ +//! This example takes periodic samples of the temperature sensor and +//! prints it to the UART using the stdlib logging facility. +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const adc = rp2040.adc; +const time = rp2040.time; + +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +pub const std_options = struct { + pub const logFn = rp2040.uart.log; +}; + +pub fn main() void { + adc.apply(.{ + .temp_sensor_enabled = true, + }); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + rp2040.uart.init_logger(uart); + while (true) : (time.sleep_ms(1000)) { + const sample = adc.convert_one_shot_blocking(.temp_sensor) catch { + std.log.err("conversion failed!", .{}); + continue; + }; + + std.log.info("temp value: {}", .{sample}); + } +} diff --git a/rp2040/src/blinky.zig b/rp2040/src/blinky.zig new file mode 100644 index 0000000..5632fe3 --- /dev/null +++ b/rp2040/src/blinky.zig @@ -0,0 +1,20 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const time = rp2040.time; + +const pin_config = rp2040.pins.GlobalConfiguration{ + .GPIO25 = .{ + .name = "led", + .direction = .out, + }, +}; + +pub fn main() !void { + const pins = pin_config.apply(); + + while (true) { + pins.led.toggle(); + time.sleep_ms(250); + } +} diff --git a/rp2040/src/blinky_core1.zig b/rp2040/src/blinky_core1.zig new file mode 100644 index 0000000..0615729 --- /dev/null +++ b/rp2040/src/blinky_core1.zig @@ -0,0 +1,28 @@ +const std = @import("std"); + +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const time = rp2040.time; +const multicore = rp2040.multicore; + +const led = gpio.num(25); + +fn core1() void { + while (true) { + led.put(1); + time.sleep_ms(250); + led.put(0); + time.sleep_ms(250); + } +} + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + multicore.launch_core1(core1); + + while (true) { + microzig.cpu.wfi(); + } +} diff --git a/rp2040/src/flash_program.zig b/rp2040/src/flash_program.zig new file mode 100644 index 0000000..9fd13be --- /dev/null +++ b/rp2040/src/flash_program.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const flash = rp2040.flash; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; + +const led = gpio.num(25); +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +const flash_target_offset: u32 = 256 * 1024; +const flash_target_contents = @as([*]const u8, @ptrFromInt(rp2040.flash.XIP_BASE + flash_target_offset)); + +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { + std.log.err("panic: {s}", .{message}); + @breakpoint(); + while (true) {} +} + +pub const std_options = struct { + pub const log_level = .debug; + pub const logFn = rp2040.uart.log; +}; + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + led.put(1); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + rp2040.uart.init_logger(uart); + + var data: [flash.PAGE_SIZE]u8 = undefined; + var i: usize = 0; + var j: u8 = 0; + while (i < flash.PAGE_SIZE) : (i += 1) { + data[i] = j; + + if (j == 255) j = 0; + j += 1; + } + + std.log.info("Generate data", .{}); + std.log.info("data: {s}", .{&data}); + + // Note that a whole number of sectors (4096 bytes) must be erased at a time + std.log.info("Erasing target region...", .{}); + flash.range_erase(flash_target_offset, flash.SECTOR_SIZE); + std.log.info("Done. Read back target region:", .{}); + std.log.info("data: {s}", .{flash_target_contents[0..flash.PAGE_SIZE]}); + + // Note that a whole number of pages (256 bytes) must be written at a time + std.log.info("Programming target region...", .{}); + flash.range_program(flash_target_offset, data[0..]); + std.log.info("Done. Read back target region:", .{}); + std.log.info("data: {s}", .{flash_target_contents[0..flash.PAGE_SIZE]}); + + var mismatch: bool = false; + i = 0; + while (i < flash.PAGE_SIZE) : (i += 1) { + if (data[i] != flash_target_contents[i]) + mismatch = true; + } + + if (mismatch) { + std.log.info("Programming failed!", .{}); + } else { + std.log.info("Programming successful!", .{}); + } +} diff --git a/rp2040/src/gpio_clk.zig b/rp2040/src/gpio_clk.zig new file mode 100644 index 0000000..dd28102 --- /dev/null +++ b/rp2040/src/gpio_clk.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; + +const gpout0_pin = gpio.num(21); +const clock_config = clocks.GlobalConfiguration.init(.{ + .sys = .{ .source = .src_xosc }, + .gpout0 = .{ .source = .clk_sys }, +}); + +pub fn main() !void { + gpout0_pin.set_function(.gpck); + while (true) {} +} diff --git a/rp2040/src/i2c_bus_scan.zig b/rp2040/src/i2c_bus_scan.zig new file mode 100644 index 0000000..702bcef --- /dev/null +++ b/rp2040/src/i2c_bus_scan.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const i2c = rp2040.i2c; +const gpio = rp2040.gpio; +const peripherals = microzig.chip.peripherals; + +pub const std_options = struct { + pub const log_level = .info; + pub const logFn = rp2040.uart.log; +}; + +const uart = rp2040.uart.num(0); +const i2c0 = i2c.num(0); + +pub fn main() !void { + uart.apply(.{ + .baud_rate = 115200, + .tx_pin = gpio.num(0), + .rx_pin = gpio.num(1), + .clock_config = rp2040.clock_config, + }); + rp2040.uart.init_logger(uart); + + _ = i2c0.apply(.{ + .clock_config = rp2040.clock_config, + .scl_pin = gpio.num(4), + .sda_pin = gpio.num(5), + }); + + for (0..std.math.maxInt(u7)) |addr| { + const a: i2c.Address = @enumFromInt(addr); + + // Skip over any reserved addresses. + if (a.is_reserved()) continue; + + var rx_data: [1]u8 = undefined; + _ = i2c0.read_blocking(a, &rx_data) catch continue; + + std.log.info("I2C device found at address {X}.", .{addr}); + } +} + diff --git a/rp2040/src/pwm.zig b/rp2040/src/pwm.zig new file mode 100644 index 0000000..d372ef4 --- /dev/null +++ b/rp2040/src/pwm.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; +const time = rp2040.time; +const regs = microzig.chip.registers; +const multicore = rp2040.multicore; + +const pin_config = rp2040.pins.GlobalConfiguration{ + .GPIO25 = .{ .name = "led", .function = .PWM4_B }, +}; + +pub fn main() !void { + const pins = pin_config.apply(); + pins.led.slice().set_wrap(100); + pins.led.set_level(10); + pins.led.slice().enable(); + + while (true) { + time.sleep_ms(250); + } +} diff --git a/rp2040/src/random.zig b/rp2040/src/random.zig new file mode 100644 index 0000000..34d03d1 --- /dev/null +++ b/rp2040/src/random.zig @@ -0,0 +1,68 @@ +//! Example that generates a 4 byte random number every second and outputs the result over UART + +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const flash = rp2040.flash; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; +const rand = rp2040.rand; + +const led = gpio.num(25); +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { + std.log.err("panic: {s}", .{message}); + @breakpoint(); + while (true) {} +} + +pub const std_options = struct { + pub const log_level = .debug; + pub const logFn = rp2040.uart.log; +}; + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + led.put(1); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + var ascon = rand.Ascon.init(); + var rng = ascon.random(); + + rp2040.uart.init_logger(uart); + + var buffer: [8]u8 = undefined; + var dist: [256]usize = .{0} ** 256; + var counter: usize = 0; + + while (true) { + rng.bytes(buffer[0..]); + counter += 8; + for (buffer) |byte| { + dist[@as(usize, @intCast(byte))] += 1; + } + std.log.info("Generate random number: {any}", .{buffer}); + + if (counter % 256 == 0) { + var i: usize = 0; + std.log.info("Distribution:", .{}); + while (i < 256) : (i += 1) { + std.log.info("{} -> {}, {d:2}%", .{ i, dist[i], @as(f32, @floatFromInt(dist[i])) / @as(f32, @floatFromInt(counter)) }); + } + } + time.sleep_ms(1000); + } +} diff --git a/rp2040/src/spi_master.zig b/rp2040/src/spi_master.zig new file mode 100644 index 0000000..c160fee --- /dev/null +++ b/rp2040/src/spi_master.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; +const peripherals = microzig.chip.peripherals; + +const BUF_LEN = 0x100; +const spi = rp2040.spi.num(0); + +// Communicate with another RP2040 over spi +// Slave implementation: https://github.com/raspberrypi/pico-examples/blob/master/spi/spi_master_slave/spi_slave/spi_slave.c +pub fn main() !void { + spi.apply(.{ + .clock_config = rp2040.clock_config, + }); + var out_buf: [BUF_LEN]u8 = .{ 0xAA, 0xBB, 0xCC, 0xDD } ** (BUF_LEN / 4); + var in_buf: [BUF_LEN]u8 = undefined; + + while (true) { + _ = spi.transceive(&out_buf, &in_buf); + time.sleep_ms(1 * 1000); + } +} diff --git a/rp2040/src/squarewave.zig b/rp2040/src/squarewave.zig new file mode 100644 index 0000000..0894d9a --- /dev/null +++ b/rp2040/src/squarewave.zig @@ -0,0 +1,84 @@ +//! Hello world for the PIO module: generating a square wave +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const Pio = rp2040.pio.Pio; +const StateMachine = rp2040.pio.StateMachine; + +const squarewave_program = blk: { + @setEvalBranchQuota(2000); + break :blk rp2040.pio.assemble( + \\; + \\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + \\; + \\; SPDX-License-Identifier: BSD-3-Clause + \\; + \\.program squarewave + \\ set pindirs, 1 ; Set pin to output + \\again: + \\ set pins, 1 [1] ; Drive pin high and then delay for one cycle + \\ set pins, 0 ; Drive pin low + \\ jmp again ; Set PC to label `again` + , .{}).get_program_by_name("squarewave"); +}; + +// Pick one PIO instance arbitrarily. We're also arbitrarily picking state +// machine 0 on this PIO instance (the state machines are numbered 0 to 3 +// inclusive). +const pio: Pio = .pio0; +const sm: StateMachine = .sm0; + +pub fn main() void { + pio.gpio_init(gpio.num(2)); + pio.sm_load_and_start_program(sm, squarewave_program, .{ + .clkdiv = rp2040.pio.ClkDivOptions.from_float(125), + .pin_mappings = .{ + .set = .{ + .base = 2, + .count = 1, + }, + }, + }) catch unreachable; + + pio.sm_set_enabled(sm, true); + + while (true) {} + + //// Load the assembled program directly into the PIO's instruction memory. + //// Each PIO instance has a 32-slot instruction memory, which all 4 state + //// machines can see. The system has write-only access. + //for (squarewave_program.instructions, 0..) |insn, i| + // pio.get_instruction_memory()[i] = insn; + + //// Configure state machine 0 to run at sysclk/2.5. The state machines can + //// run as fast as one instruction per clock cycle, but we can scale their + //// speed down uniformly to meet some precise frequency target, e.g. for a + //// UART baud rate. This register has 16 integer divisor bits and 8 + //// fractional divisor bits. + //pio.sm_set_clkdiv(sm, .{ + // .int = 2, + // .frac = 0x80, + //}); + + //// There are five pin mapping groups (out, in, set, side-set, jmp pin) + //// which are used by different instructions or in different circumstances. + //// Here we're just using SET instructions. Configure state machine 0 SETs + //// to affect GPIO 0 only; then configure GPIO0 to be controlled by PIO0, + //// as opposed to e.g. the processors. + //pio.gpio_init(2); + //pio.sm_set_pin_mappings(sm, .{ + // .out = .{ + // .base = 2, + // .count = 1, + // }, + //}); + + //// Set the state machine running. The PIO CTRL register is global within a + //// PIO instance, so you can start/stop multiple state machines + //// simultaneously. We're using the register's hardware atomic set alias to + //// make one bit high without doing a read-modify-write on the register. + //pio.sm_set_enabled(sm, true); + + //while (true) {} +} diff --git a/rp2040/src/uart.zig b/rp2040/src/uart.zig new file mode 100644 index 0000000..914b9ae --- /dev/null +++ b/rp2040/src/uart.zig @@ -0,0 +1,49 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; + +const led = gpio.num(25); +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { + std.log.err("panic: {s}", .{message}); + @breakpoint(); + while (true) {} +} + +pub const std_options = struct { + pub const log_level = .debug; + pub const logFn = rp2040.uart.log; +}; + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + led.put(1); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + rp2040.uart.init_logger(uart); + + var i: u32 = 0; + while (true) : (i += 1) { + led.put(1); + std.log.info("what {}", .{i}); + time.sleep_ms(500); + + led.put(0); + time.sleep_ms(500); + } +} diff --git a/rp2040/src/usb_device.zig b/rp2040/src/usb_device.zig new file mode 100644 index 0000000..8f2d74e --- /dev/null +++ b/rp2040/src/usb_device.zig @@ -0,0 +1,172 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const flash = rp2040.flash; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; +const usb = rp2040.usb; + +const led = gpio.num(25); +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +// First we define two callbacks that will be used by the endpoints we define next... +fn ep1_in_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { + _ = data; + // The host has collected the data we repeated onto + // EP1! Set up to receive more data on EP1. + usb.Usb.callbacks.usb_start_rx( + dc.endpoints[2], // EP1_OUT_CFG, + 64, + ); +} + +fn ep1_out_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { + // We've gotten data from the host on our custom + // EP1! Set up EP1 to repeat it. + usb.Usb.callbacks.usb_start_tx( + dc.endpoints[3], // EP1_IN_CFG, + data, + ); +} + +// The endpoints EP0_IN and EP0_OUT are already defined but you can +// add your own endpoints to... +pub var EP1_OUT_CFG: usb.EndpointConfiguration = .{ + .descriptor = &usb.EndpointDescriptor{ + .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), + .descriptor_type = usb.DescType.Endpoint, + .endpoint_address = usb.Dir.Out.endpoint(1), + .attributes = @intFromEnum(usb.TransferType.Bulk), + .max_packet_size = 64, + .interval = 0, + }, + .endpoint_control_index = 2, + .buffer_control_index = 3, + .data_buffer_index = 2, + .next_pid_1 = false, + // The callback will be executed if we got an interrupt on EP1_OUT + .callback = ep1_out_callback, +}; + +pub var EP1_IN_CFG: usb.EndpointConfiguration = .{ + .descriptor = &usb.EndpointDescriptor{ + .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), + .descriptor_type = usb.DescType.Endpoint, + .endpoint_address = usb.Dir.In.endpoint(1), + .attributes = @intFromEnum(usb.TransferType.Bulk), + .max_packet_size = 64, + .interval = 0, + }, + .endpoint_control_index = 1, + .buffer_control_index = 2, + .data_buffer_index = 3, + .next_pid_1 = false, + // The callback will be executed if we got an interrupt on EP1_IN + .callback = ep1_in_callback, +}; + +// This is our device configuration +pub var DEVICE_CONFIGURATION: usb.DeviceConfiguration = .{ + .device_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.DeviceDescriptor))), + .descriptor_type = usb.DescType.Device, + .bcd_usb = 0x0110, + .device_class = 0, + .device_subclass = 0, + .device_protocol = 0, + .max_packet_size0 = 64, + .vendor = 0, + .product = 1, + .bcd_device = 0, + .manufacturer_s = 1, + .product_s = 2, + .serial_s = 0, + .num_configurations = 1, + }, + .interface_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.InterfaceDescriptor))), + .descriptor_type = usb.DescType.Interface, + .interface_number = 0, + .alternate_setting = 0, + // We have two endpoints (EP0 IN/OUT don't count) + .num_endpoints = 2, + .interface_class = 0xff, + .interface_subclass = 0, + .interface_protocol = 0, + .interface_s = 0, + }, + .config_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor))), + .descriptor_type = usb.DescType.Config, + .total_length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor) + @sizeOf(usb.InterfaceDescriptor) + @sizeOf(usb.EndpointDescriptor) + @sizeOf(usb.EndpointDescriptor))), + .num_interfaces = 1, + .configuration_value = 1, + .configuration_s = 0, + .attributes = 0xc0, + .max_power = 0x32, + }, + .lang_descriptor = "\x04\x03\x09\x04", // length || string descriptor (0x03) || Engl (0x0409) + .descriptor_strings = &.{ + // ugly unicode :| + "R\x00a\x00s\x00p\x00b\x00e\x00r\x00r\x00y\x00 \x00P\x00i\x00", + "P\x00i\x00c\x00o\x00 \x00T\x00e\x00s\x00t\x00 \x00D\x00e\x00v\x00i\x00c\x00e\x00", + }, + // Here we pass all endpoints to the config + // Dont forget to pass EP0_[IN|OUT] in the order seen below! + .endpoints = .{ + &usb.EP0_OUT_CFG, + &usb.EP0_IN_CFG, + &EP1_OUT_CFG, + &EP1_IN_CFG, + }, +}; + +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { + std.log.err("panic: {s}", .{message}); + @breakpoint(); + while (true) {} +} + +pub const std_options = struct { + pub const log_level = .debug; + pub const logFn = rp2040.uart.log; +}; + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + led.put(1); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + rp2040.uart.init_logger(uart); + + // First we initialize the USB clock + rp2040.usb.Usb.init_clk(); + // Then initialize the USB device using the configuration defined above + rp2040.usb.Usb.init_device(&DEVICE_CONFIGURATION) catch unreachable; + var old: u64 = time.get_time_since_boot().to_us(); + var new: u64 = 0; + while (true) { + // You can now poll for USB events + rp2040.usb.Usb.task( + false, // debug output over UART [Y/n] + ) catch unreachable; + + new = time.get_time_since_boot().to_us(); + if (new - old > 500000) { + old = new; + led.toggle(); + } + } +} diff --git a/rp2040/src/usb_hid.zig b/rp2040/src/usb_hid.zig new file mode 100644 index 0000000..752111a --- /dev/null +++ b/rp2040/src/usb_hid.zig @@ -0,0 +1,187 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const rp2040 = microzig.hal; +const flash = rp2040.flash; +const time = rp2040.time; +const gpio = rp2040.gpio; +const clocks = rp2040.clocks; +const usb = rp2040.usb; + +const led = gpio.num(25); +const uart = rp2040.uart.num(0); +const baud_rate = 115200; +const uart_tx_pin = gpio.num(0); +const uart_rx_pin = gpio.num(1); + +// First we define two callbacks that will be used by the endpoints we define next... +fn ep1_in_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { + _ = data; + // The host has collected the data we repeated onto + // EP1! Set up to receive more data on EP1. + usb.Usb.callbacks.usb_start_rx( + dc.endpoints[2], // EP1_OUT_CFG, + 64, + ); +} + +fn ep1_out_callback(dc: *usb.DeviceConfiguration, data: []const u8) void { + // We've gotten data from the host on our custom + // EP1! Set up EP1 to repeat it. + usb.Usb.callbacks.usb_start_tx( + dc.endpoints[3], // EP1_IN_CFG, + data, + ); +} + +// The endpoints EP0_IN and EP0_OUT are already defined but you can +// add your own endpoints to... +pub var EP1_OUT_CFG: usb.EndpointConfiguration = .{ + .descriptor = &usb.EndpointDescriptor{ + .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), + .descriptor_type = usb.DescType.Endpoint, + .endpoint_address = usb.Dir.Out.endpoint(1), + .attributes = @intFromEnum(usb.TransferType.Interrupt), + .max_packet_size = 64, + .interval = 0, + }, + .endpoint_control_index = 2, + .buffer_control_index = 3, + .data_buffer_index = 2, + .next_pid_1 = false, + // The callback will be executed if we got an interrupt on EP1_OUT + .callback = ep1_out_callback, +}; + +pub var EP1_IN_CFG: usb.EndpointConfiguration = .{ + .descriptor = &usb.EndpointDescriptor{ + .length = @as(u8, @intCast(@sizeOf(usb.EndpointDescriptor))), + .descriptor_type = usb.DescType.Endpoint, + .endpoint_address = usb.Dir.In.endpoint(1), + .attributes = @intFromEnum(usb.TransferType.Interrupt), + .max_packet_size = 64, + .interval = 0, + }, + .endpoint_control_index = 1, + .buffer_control_index = 2, + .data_buffer_index = 3, + .next_pid_1 = false, + // The callback will be executed if we got an interrupt on EP1_IN + .callback = ep1_in_callback, +}; + +// This is our device configuration +pub var DEVICE_CONFIGURATION: usb.DeviceConfiguration = .{ + .device_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.DeviceDescriptor))), + .descriptor_type = usb.DescType.Device, + .bcd_usb = 0x0200, + .device_class = 0, + .device_subclass = 0, + .device_protocol = 0, + .max_packet_size0 = 64, + .vendor = 0xCafe, + .product = 1, + .bcd_device = 0x0100, + // Those are indices to the descriptor strings + // Make sure to provide enough string descriptors! + .manufacturer_s = 1, + .product_s = 2, + .serial_s = 3, + .num_configurations = 1, + }, + .interface_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.InterfaceDescriptor))), + .descriptor_type = usb.DescType.Interface, + .interface_number = 0, + .alternate_setting = 0, + // We have two endpoints (EP0 IN/OUT don't count) + .num_endpoints = 2, + .interface_class = 3, + .interface_subclass = 0, + .interface_protocol = 0, + .interface_s = 0, + }, + .config_descriptor = &.{ + .length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor))), + .descriptor_type = usb.DescType.Config, + .total_length = @as(u8, @intCast(@sizeOf(usb.ConfigurationDescriptor) + @sizeOf(usb.InterfaceDescriptor) + @sizeOf(usb.EndpointDescriptor) + @sizeOf(usb.EndpointDescriptor))), + .num_interfaces = 1, + .configuration_value = 1, + .configuration_s = 0, + .attributes = 0xc0, + .max_power = 0x32, + }, + .lang_descriptor = "\x04\x03\x09\x04", // length || string descriptor (0x03) || Engl (0x0409) + .descriptor_strings = &.{ + // ugly unicode :| + //"R\x00a\x00s\x00p\x00b\x00e\x00r\x00r\x00y\x00 \x00P\x00i\x00", + &usb.utf8ToUtf16Le("Raspberry Pi"), + //"P\x00i\x00c\x00o\x00 \x00T\x00e\x00s\x00t\x00 \x00D\x00e\x00v\x00i\x00c\x00e\x00", + &usb.utf8ToUtf16Le("Pico Test Device"), + //"c\x00a\x00f\x00e\x00b\x00a\x00b\x00e\x00", + &usb.utf8ToUtf16Le("cafebabe"), + }, + .hid = .{ + .hid_descriptor = &.{ + .bcd_hid = 0x0111, + .country_code = 0, + .num_descriptors = 1, + .report_length = 34, + }, + .report_descriptor = &usb.hid.ReportDescriptorFidoU2f, + }, + // Here we pass all endpoints to the config + // Dont forget to pass EP0_[IN|OUT] in the order seen below! + .endpoints = .{ + &usb.EP0_OUT_CFG, + &usb.EP0_IN_CFG, + &EP1_OUT_CFG, + &EP1_IN_CFG, + }, +}; + +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { + std.log.err("panic: {s}", .{message}); + @breakpoint(); + while (true) {} +} + +pub const std_options = struct { + pub const log_level = .debug; + pub const logFn = rp2040.uart.log; +}; + +pub fn main() !void { + led.set_function(.sio); + led.set_direction(.out); + led.put(1); + + uart.apply(.{ + .baud_rate = baud_rate, + .tx_pin = uart_tx_pin, + .rx_pin = uart_rx_pin, + .clock_config = rp2040.clock_config, + }); + + rp2040.uart.init_logger(uart); + + // First we initialize the USB clock + rp2040.usb.Usb.init_clk(); + // Then initialize the USB device using the configuration defined above + rp2040.usb.Usb.init_device(&DEVICE_CONFIGURATION) catch unreachable; + var old: u64 = time.get_time_since_boot().to_us(); + var new: u64 = 0; + while (true) { + // You can now poll for USB events + rp2040.usb.Usb.task( + true, // debug output over UART [Y/n] + ) catch unreachable; + + new = time.get_time_since_boot().to_us(); + if (new - old > 500000) { + old = new; + led.toggle(); + } + } +} diff --git a/rp2040/src/ws2812.zig b/rp2040/src/ws2812.zig new file mode 100644 index 0000000..64fbac2 --- /dev/null +++ b/rp2040/src/ws2812.zig @@ -0,0 +1,94 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const rp2040 = microzig.hal; +const gpio = rp2040.gpio; +const Pio = rp2040.pio.Pio; +const StateMachine = rp2040.pio.StateMachine; + +const ws2812_program = blk: { + @setEvalBranchQuota(5000); + break :blk rp2040.pio.assemble( + \\; + \\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + \\; + \\; SPDX-License-Identifier: BSD-3-Clause + \\; + \\.program ws2812 + \\.side_set 1 + \\ + \\.define public T1 2 + \\.define public T2 5 + \\.define public T3 3 + \\ + \\.wrap_target + \\bitloop: + \\ out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls + \\ jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse + \\do_one: + \\ jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse + \\do_zero: + \\ nop side 0 [T2 - 1] ; Or drive low, for a short pulse + \\.wrap + , .{}).get_program_by_name("ws2812"); +}; + +const pio: Pio = .pio0; +const sm: StateMachine = .sm0; +const led_pin = gpio.num(23); + +pub fn main() void { + pio.gpio_init(led_pin); + sm_set_consecutive_pindirs(pio, sm, @intFromEnum(led_pin), 1, true); + + const cycles_per_bit: comptime_int = ws2812_program.defines[0].value + //T1 + ws2812_program.defines[1].value + //T2 + ws2812_program.defines[2].value; //T3 + const div = @as(f32, @floatFromInt(rp2040.clock_config.sys.?.output_freq)) / + (800_000 * cycles_per_bit); + + pio.sm_load_and_start_program(sm, ws2812_program, .{ + .clkdiv = rp2040.pio.ClkDivOptions.from_float(div), + .pin_mappings = .{ + .side_set = .{ + .base = @intFromEnum(led_pin), + .count = 1, + }, + }, + .shift = .{ + .out_shiftdir = .left, + .autopull = true, + .pull_threshold = 24, + .join_tx = true, + }, + }) catch unreachable; + pio.sm_set_enabled(sm, true); + + while (true) { + pio.sm_blocking_write(sm, 0x00ff00 << 8); //red + rp2040.time.sleep_ms(1000); + pio.sm_blocking_write(sm, 0xff0000 << 8); //green + rp2040.time.sleep_ms(1000); + pio.sm_blocking_write(sm, 0x0000ff << 8); //blue + rp2040.time.sleep_ms(1000); + } +} + +fn sm_set_consecutive_pindirs(_pio: Pio, _sm: StateMachine, pin: u5, count: u3, is_out: bool) void { + const sm_regs = _pio.get_sm_regs(_sm); + const pinctrl_saved = sm_regs.pinctrl.raw; + sm_regs.pinctrl.modify(.{ + .SET_BASE = pin, + .SET_COUNT = count, + }); + _pio.sm_exec(_sm, rp2040.pio.Instruction{ + .tag = .set, + .delay_side_set = 0, + .payload = .{ + .set = .{ + .data = @intFromBool(is_out), + .destination = .pindirs, + }, + }, + }); + sm_regs.pinctrl.raw = pinctrl_saved; +} diff --git a/shell.nix b/shell.nix deleted file mode 100644 index b1724c4..0000000 --- a/shell.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs ? import {}}: -pkgs.mkShell { - nativeBuildInputs = [ - pkgs.zig_0_11_0 - pkgs.picotool - pkgs.llvmPackages_16.bintools - ]; - buildInputs = []; -} diff --git a/stmicro-stm32/build.zig b/stmicro-stm32/build.zig new file mode 100644 index 0000000..4064772 --- /dev/null +++ b/stmicro-stm32/build.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const rp2040 = @import("rp2040"); +const stm32 = @import("stm32"); +const lpc = @import("lpc"); +const gd32 = @import("gd32"); +const nrf5x = @import("nrf5x"); +const esp = @import("esp"); +const atmega = @import("atmega"); + +pub fn build(b: *std.Build) void { + const microzig = @import("microzig").init(b, "microzig"); + const optimize = b.standardOptimizeOption(.{}); + + const TargetDesc = struct { + target: @import("microzig").Target, + name: []const u8, + }; + + const available_targets = [_]TargetDesc{ + // RP2040 + .{ .name = "pico", .target = rp2040.boards.raspberry_pi.pico }, + .{ .name = "rp2040-eth", .target = rp2040.boards.waveshare.rp2040_eth }, + .{ .name = "rp2040-plus-4m", .target = rp2040.boards.waveshare.rp2040_plus_4m }, + .{ .name = "rp2040-plus-16m", .target = rp2040.boards.waveshare.rp2040_plus_16m }, + .{ .name = "rp2040-matrix", .target = rp2040.boards.waveshare.rp2040_matrix }, + + // STM32 + .{ .name = "stm32f103x8", .target = stm32.chips.stm32f103x8 }, + .{ .name = "stm32f303vc", .target = stm32.chips.stm32f303vc }, + .{ .name = "stm32f407vg", .target = stm32.chips.stm32f407vg }, + .{ .name = "stm32f429zit6u", .target = stm32.chips.stm32f429zit6u }, + .{ .name = "stm32f3discovery", .target = stm32.boards.stm32f3discovery }, + .{ .name = "stm32f4discovery", .target = stm32.boards.stm32f4discovery }, + .{ .name = "stm3240geval", .target = stm32.boards.stm3240geval }, + .{ .name = "stm32f429idiscovery", .target = stm32.boards.stm32f429idiscovery }, + + // NXP LPC + .{ .name = "lpc176x5x", .target = lpc.chips.lpc176x5x }, + .{ .name = "mbed-lpc1768", .target = lpc.boards.mbed.lpc1768 }, + + // GigaDevice GD32 + .{ .name = "gd32vf103xb", .target = gd32.chips.gd32vf103xb }, + .{ .name = "gd32vf103x8", .target = gd32.chips.gd32vf103x8 }, + .{ .name = "sipeed-longan_nano", .target = gd32.boards.sipeed.longan_nano }, + + // Nordic Nrf5x + .{ .name = "nrf52832", .target = nrf5x.chips.nrf52832 }, + .{ .name = "nrf52840", .target = nrf5x.chips.nrf52840 }, + .{ .name = "nrf52840-dongle", .target = nrf5x.boards.nordic.nRF52840_Dongle }, // TODO: Add support for DFU files! + + // RISC-V Espressif ESP + .{ .name = "esp32-c3", .target = esp.chips.esp32_c3 }, // TODO: Add support for Espressif Update Binaries + + // Microchip ATmega + // TODO: Fix compiler bugs + // - https://github.com/ziglang/zig/issues/17219 + // .{ .name = "atmega328p", .target = atmega.chips.atmega328p }, + // .{ .name = "arduino-nano", .target = atmega.boards.arduino.nano }, + // .{ .name = "arduino-uno-rev3", .target = atmega.boards.arduino.uno_rev3 }, + }; + + for (available_targets) |dest| { + // `addFirmware` basically works like addExecutable, but takes a + // `microzig.Target` for target instead of a `std.zig.CrossTarget`. + // + // The target will convey all necessary information on the chip, + // cpu and potentially the board as well. + const firmware = microzig.addFirmware(b, .{ + .name = b.fmt("empty-{s}", .{dest.name}), + .target = dest.target, + .optimize = optimize, + .source_file = .{ .path = "src/empty.zig" }, + }); + + // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` + // and allows installing the firmware as a typical firmware file. + // + // This will also install into `$prefix/firmware` instead of `$prefix/bin`. + microzig.installFirmware(b, firmware, .{}); + + // For debugging, we also always install the firmware as an ELF file + microzig.installFirmware(b, firmware, .{ .format = .elf }); + } +} diff --git a/stmicro-stm32/build.zig.zon b/stmicro-stm32/build.zig.zon new file mode 100644 index 0000000..e54d44f --- /dev/null +++ b/stmicro-stm32/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "microzig-stmicro-stm32-examples", + .version = "0.1.0", + .dependencies = .{ + .microzig = .{ + .url = "https://github.com/ZigEmbeddedGroup/microzig/archive/c6c9ec4516f57638e751141085c9d76120990312.tar.gz", + .hash = "1220af58bdaa721b8189f3a7adfda660517dd354463463388e96d69fe4ceccf80b92", + }, + .stm32 = .{ + .url = "https://github.com/ZigEmbeddedGroup/stmicro-stm32/archive/cb2893707efa6aa289fa72f02959ad5f2d9db2a1.tar.gz", + .hash = "12208cab5f60ef97cac4165ad694f3ba0c7b28f279538c1539b74f7c152f34fe306d", + }, + }, +}