Support STM32F3DISCOVERY board (#11)

* Support disabling UART test configs

* `zig build [install]` also builds .bin files

* Support one blinking LD3 on STM32F3DISCOVERY board

These changes were mostly copied from the stm32f103 already there.

But this is far from complete, many shortcuts were taken:

- Most importantly,
  only a single LED on the board, and its port/pin, is supported,
  viz. the 'north' LD3 on bit 9 of GPIOE.

- Setting RCC_AHBENR bit IOPEEN ("I/O port E clock enable") is done
  at the same as setting the mode (input or output) on one of its pins.
  No idea if that is the right place to do this.

- In cortex-m4.zig, using 'max ram' as the initial stack pointer.
  The rest is completely copied from cortex-m3.zig.

- UART test is disabled.
  (It seems to assume mbed-lpc1768 pin numbers.)

* Nicer initial stack pointer: exactly after RAM

* Fix build error

(How was this code working earlier?!?)

* stm32f30x: Allow all 16 pins, all GPIOx registers

* STM32F3DISCOVERY: map all LED pins
wch-ch32v003
Marnix Klooster 3 years ago committed by GitHub
parent f46c2e4ea9
commit 1b5cc2ad1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,29 +14,32 @@ pub fn build(b: *std.build.Builder) !void {
const test_step = b.step("test", "Builds and runs the library test suite");
const BuildConfig = struct { name: []const u8, backing: Backing };
const BuildConfig = struct { name: []const u8, backing: Backing, supports_uart: bool = true };
const all_backings = [_]BuildConfig{
//BuildConfig{ .name = "boards.arduino_nano", .backing = Backing{ .board = pkgs.boards.arduino_nano } },
BuildConfig{ .name = "boards.mbed_lpc1768", .backing = Backing{ .board = boards.mbed_lpc1768 } },
//BuildConfig{ .name = "chips.atmega328p", .backing = Backing{ .chip = pkgs.chips.atmega328p } },
BuildConfig{ .name = "chips.lpc1768", .backing = Backing{ .chip = chips.lpc1768 } },
//BuildConfig{ .name = "chips.stm32f103x8", .backing = Backing{ .chip = chips.stm32f103x8 } },
BuildConfig{ .name = "boards.stm32f3discovery", .backing = Backing{ .board = boards.stm32f3discovery }, .supports_uart = false },
};
const Test = struct { name: []const u8, source: []const u8 };
const Test = struct { name: []const u8, source: []const u8, uses_uart: bool = false };
const all_tests = [_]Test{
Test{ .name = "minimal", .source = "tests/minimal.zig" },
Test{ .name = "blinky", .source = "tests/blinky.zig" },
Test{ .name = "uart-sync", .source = "tests/uart-sync.zig" },
Test{ .name = "uart-sync", .source = "tests/uart-sync.zig", .uses_uart = true },
};
const filter = b.option(std.Target.Cpu.Arch, "filter-target", "Filters for a certain cpu target");
inline for (all_backings) |cfg| {
inline for (all_tests) |tst| {
if (tst.uses_uart and !cfg.supports_uart) continue;
const exe = try microzig.addEmbeddedExecutable(
b,
"test-" ++ tst.name ++ "-" ++ cfg.name,
"test-" ++ tst.name ++ "-" ++ cfg.name ++ ".elf",
tst.source,
cfg.backing,
);
@ -46,6 +49,13 @@ pub fn build(b: *std.build.Builder) !void {
exe.install();
test_step.dependOn(&exe.step);
const bin = b.addInstallRaw(
exe,
"test-" ++ tst.name ++ "-" ++ cfg.name ++ ".bin",
.{},
);
b.getInstallStep().dependOn(&bin.step);
}
}
}

@ -19,3 +19,9 @@ pub const mbed_lpc1768 = Board{
.path = root_path ++ "boards/mbed-lpc1768/mbed-lpc1768.zig",
.chip = chips.lpc1768,
};
pub const stm32f3discovery = Board{
.name = "STM32F3DISCOVERY",
.path = root_path ++ "boards/stm32f3discovery/stm32f3discovery.zig",
.chip = chips.stm32f30x,
};

@ -0,0 +1,24 @@
pub const chip = @import("chip");
pub const cpu_frequency = 8_000_000;
pub const pin_map = .{
// circle of LEDs, connected to GPIOE bits 8..15
// NW blue
.@"LD4" = "PE8",
// N red
.@"LD3" = "PE9",
// NE orange
.@"LD5" = "PE10",
// E green
.@"LD7" = "PE11",
// SE blue
.@"LD9" = "PE12",
// S red
.@"LD10" = "PE13",
// SW orange
.@"LD8" = "PE14",
// W green
.@"LD6" = "PE15",
};

@ -39,3 +39,13 @@ pub const stm32f103x8 = Chip{
MemoryRegion{ .offset = 0x10000000, .length = 20 * 1024, .kind = .ram },
},
};
pub const stm32f30x = Chip{
.name = "STM32F30x",
.path = root_path ++ "chips/stm32f30x/stm32f30x.zig",
.cpu = cpus.cortex_m4,
.memory_regions = &.{
MemoryRegion{ .offset = 0x08000000, .length = 256 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x20000000, .length = 40 * 1024, .kind = .ram },
},
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,55 @@
const std = @import("std");
const micro = @import("microzig");
pub const cpu = @import("cpu");
pub const registers = @import("registers.zig");
pub fn parsePin(comptime spec: []const u8) type {
const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}{Pin}\" scheme.";
if (spec[0] != 'P')
@compileError(invalid_format_msg);
if (spec[1] < 'A' or spec[1] > 'H')
@compileError(invalid_format_msg);
const pin_number: comptime_int = std.fmt.parseInt(u4, spec[2..], 10) catch @compileError(invalid_format_msg);
return struct {
/// 'A'...'H'
const gpio_port_name = spec[1..2];
const gpio_port = @field(registers, "GPIO" ++ gpio_port_name);
const suffix = std.fmt.comptimePrint("{d}", .{pin_number});
};
}
fn setRegField(reg: anytype, comptime field_name: anytype, value: anytype) void {
var temp = reg.read();
@field(temp, field_name) = value;
reg.write(temp);
}
pub const gpio = struct {
pub fn setOutput(comptime pin: type) void {
setRegField(registers.RCC.AHBENR, "IOP" ++ pin.gpio_port_name ++ "EN", 1);
setRegField(@field(pin.gpio_port, "MODER"), "MODER" ++ pin.suffix, 0b01);
}
pub fn setInput(comptime pin: type) void {
setRegField(registers.RCC.AHBENR, "IOP" ++ pin.gpio_port_name ++ "EN", 1);
setRegField(@field(pin.gpio_port, "MODER"), "MODER" ++ pin.suffix, 0b00);
}
pub fn read(comptime pin: type) micro.gpio.State {
const idr_reg = pin.gpio_port.IDR;
const reg_value = @field(idr_reg.read(), "IDR" ++ pin.suffix); // TODO extract to getRegField()?
return @intToEnum(micro.gpio.State, reg_value);
}
pub fn write(comptime pin: type, state: micro.gpio.State) void {
_ = pin;
switch (state) {
.low => setRegField(pin.gpio_port.BRR, "BR" ++ pin.suffix, 1),
.high => setRegField(pin.gpio_port.BSRR, "BS" ++ pin.suffix, 1),
}
}
};

@ -28,3 +28,14 @@ pub const cortex_m3 = Cpu{
.abi = .none,
},
};
pub const cortex_m4 = Cpu{
.name = "ARM Cortex-M4",
.path = root_path ++ "cpus/cortex-m4/cortex-m4.zig",
.target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
.os_tag = .freestanding,
.abi = .none,
},
};

@ -0,0 +1,103 @@
const std = @import("std");
pub fn sei() void {
asm volatile ("cpsie i");
}
pub fn cli() void {
asm volatile ("cpsid i");
}
pub fn enable_fault_irq() void {
asm volatile ("cpsie f");
}
pub fn disable_fault_irq() void {
asm volatile ("cpsid f");
}
pub fn nop() void {
asm volatile ("nop");
}
pub fn wfi() void {
asm volatile ("wfi");
}
pub fn wfe() void {
asm volatile ("wfe");
}
pub fn sev() void {
asm volatile ("sev");
}
pub fn isb() void {
asm volatile ("isb");
}
pub fn dsb() void {
asm volatile ("dsb");
}
pub fn dmb() void {
asm volatile ("dmb");
}
pub fn clrex() void {
asm volatile ("clrex");
}
pub const startup_logic = struct {
const InterruptVector = fn () callconv(.C) void;
const VectorTable = extern struct {
initial_stack_pointer: u32,
reset: InterruptVector,
nmi: InterruptVector = makeUnhandledHandler("nmi"),
hard_fault: InterruptVector = makeUnhandledHandler("hard_fault"),
mpu_fault: InterruptVector = makeUnhandledHandler("mpu_fault"),
bus_fault: InterruptVector = makeUnhandledHandler("bus_fault"),
usage_fault: InterruptVector = makeUnhandledHandler("usage_fault"),
reserved: u32 = 0,
};
export const vectors linksection("microzig_flash_start") = VectorTable{
// TODO: How to compute/get the initial stack pointer?
.initial_stack_pointer = 0x2000_A000, // HACK: hardcoded, do not keep!
.reset = _start,
};
fn makeUnhandledHandler(comptime str: []const u8) fn () callconv(.C) noreturn {
return struct {
fn unhandledInterrupt() callconv(.C) noreturn {
@panic("unhandled interrupt: " ++ str);
}
}.unhandledInterrupt;
}
extern fn microzig_main() noreturn;
extern var microzig_data_start: anyopaque;
extern var microzig_data_end: anyopaque;
extern var microzig_bss_start: anyopaque;
extern var microzig_bss_end: anyopaque;
extern const microzig_data_load_start: anyopaque;
fn _start() callconv(.C) noreturn {
// fill .bss with zeroes
{
const bss_start = @ptrCast([*]u8, &microzig_bss_start);
const bss_end = @ptrCast([*]u8, &microzig_bss_end);
const bss_len = @ptrToInt(bss_end) - @ptrToInt(bss_start);
std.mem.set(u8, bss_start[0..bss_len], 0);
}
// load .data from flash
{
const data_start = @ptrCast([*]u8, &microzig_data_start);
const data_end = @ptrCast([*]u8, &microzig_data_end);
const data_len = @ptrToInt(data_end) - @ptrToInt(data_start);
const data_src = @ptrCast([*]const u8, &microzig_data_load_start);
std.mem.copy(u8, data_start[0..data_len], data_src[0..data_len]);
}
microzig_main();
}
};

@ -8,6 +8,7 @@ const led_pin = if (micro.config.has_board)
switch (micro.config.board_name) {
.@"Arduino Nano" => micro.Pin("D13"),
.@"mbed LPC1768" => micro.Pin("LED-1"),
.@"STM32F3DISCOVERY" => micro.Pin("LD3"),
else => @compileError("unknown board"),
}
else switch (micro.config.chip_name) {

Loading…
Cancel
Save