diff --git a/raspberrypi-rp2040/README.md b/raspberrypi-rp2040/README.md index dbb4e72..e5c8293 100644 --- a/raspberrypi-rp2040/README.md +++ b/raspberrypi-rp2040/README.md @@ -1,5 +1,9 @@ # Examples for the BSP `raspberrypi-rp2040` +## Demos + +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. + - [adc](src/adc.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) This example takes periodic samples of the temperature sensor and prints it to the UART using the stdlib logging facility. - [blinky](src/blinky.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) @@ -28,4 +32,19 @@ 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. - [ws2812](src/ws2812.zig) on [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) Showcases how to control one WS2812 LED attached to GPIO23. +- [tiles](src/tiles.zig) on [RP2040-Matrix](https://www.waveshare.com/rp2040-matrix.htm) + Showcases how to control the LED matrix on the development board to do a simple color flipper effect. + +## Flashing + +You can flash all examples using either your file browser by dragging the example `.uf2` file from `zig-out/firmware/` to the directory. + +Or you can use [`picotool`](https://github.com/raspberrypi/picotool) to flash a uf2 file: +```sh-session +[user@host] raspberrypi-rp2040/ $ picotool load -x zig-out/firmware/${file}.uf2 +Loading into Flash: [==============================] 100% + +The device was rebooted to start the application. +[user@host] raspberrypi-rp2040/ $ +``` diff --git a/raspberrypi-rp2040/build.zig b/raspberrypi-rp2040/build.zig index 1128c69..6e91de0 100644 --- a/raspberrypi-rp2040/build.zig +++ b/raspberrypi-rp2040/build.zig @@ -17,10 +17,11 @@ const available_examples = [_]Example{ .{ .name = "pico_usb-hid", .target = rp2040.boards.raspberry_pi.pico, .file = "src/usb_hid.zig" }, .{ .name = "pico_ws2812", .target = rp2040.boards.raspberry_pi.pico, .file = "src/ws2812.zig" }, + .{ .name = "rp2040-matrix_tiles", .target = rp2040.boards.waveshare.rp2040_matrix, .file = "src/tiles.zig" }, + // .{ .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 }, }; pub fn build(b: *std.Build) void { diff --git a/raspberrypi-rp2040/src/tiles.zig b/raspberrypi-rp2040/src/tiles.zig new file mode 100644 index 0000000..b55f791 --- /dev/null +++ b/raspberrypi-rp2040/src/tiles.zig @@ -0,0 +1,147 @@ +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(16); + +const brightness: [256]u8 = blk: { + @setEvalBranchQuota(10_000); + + const gamma = 2.2; + + const max_brightness = 0x10; + + var data: [256]u8 = undefined; + for (&data, 0..) |*bit, i| { + const raw_index: f32 = @floatFromInt(i); + + const gamma_brightness = std.math.pow(f32, raw_index / 255.0, gamma); + + bit.* = @intFromFloat(max_brightness * gamma_brightness); + } + // @compileLog(data); + break :blk data; +}; + +const RGB = extern struct { + x: u8 = 0x00, + b: u8, + g: u8, + r: u8, +}; + +inline fn floatToBright(f: f32) u8 { + return brightness[ + @intFromFloat( + std.math.clamp(255.0 * f, 0.0, 255.0), + ) + ]; +} + +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); + + var rng_src = std.rand.DefaultPrng.init(0x1234); + + const rng = rng_src.random(); + + var screen: [5][5]RGB = undefined; + for (&screen) |*row| { + for (row) |*pix| { + pix.* = RGB{ + .r = brightness[rng.int(u8)], + .g = brightness[rng.int(u8)], + .b = brightness[rng.int(u8)], + }; + } + } + + while (true) { + screen[rng.intRangeLessThan(u8, 0, 5)][rng.intRangeLessThan(u8, 0, 5)] = RGB{ + .r = brightness[rng.int(u8)], + .g = brightness[rng.int(u8)], + .b = brightness[rng.int(u8)], + }; + + for (@as([25]RGB, @bitCast(screen))) |color| { + pio.sm_blocking_write(sm, @bitCast(color)); + } + rp2040.time.sleep_ms(50); + } +} + +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; +}