Skip to content

basic f1 HAL #431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions examples/stmicro/stm32/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub fn build(b: *std.Build) void {
const stm32 = mb.ports.stm32;

const available_examples = [_]Example{
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F103C8", .file = "src/blinky.zig" },
.{ .target = stm32.boards.stm32f3discovery, .name = "stm32f3discovery", .file = "src/blinky.zig" },
// TODO: stm32.pins.GlobalConfiguration is not available on those targets
// .{ .target = stm32.chips.stm32f303vc, .name = "stm32f303vc", .file = "src/blinky.zig" },
Expand All @@ -23,7 +22,14 @@ pub fn build(b: *std.Build) void {
// .{ .target = stm32.boards.stm32f4discovery, .name = "stm32f4discovery", .file = "src/blinky.zig" },
// .{ .target = stm32.boards.stm3240geval, .name = "stm3240geval", .file = "src/blinky.zig" },
// .{ .target = stm32.boards.stm32f429idiscovery, .name = "stm32f429idiscovery", .file = "src/blinky.zig" },
.{ .target = stm32.chips.STM32F100RB, .name = "STM32F1_semihost", .file = "src/semihosting.zig" }, //QEMU target: stm32vldiscovery
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_blink", .file = "src/blinky.zig" },
.{ .target = stm32.chips.STM32F100RB, .name = "STM32F1xx_semihost", .file = "src/semihosting.zig" }, //QEMU target: stm32vldiscovery
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_gpio", .file = "src/stm32f1xx/gpio.zig" },
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_uart_echo", .file = "src/stm32f1xx/uart_echo.zig" },
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_uart_log", .file = "src/stm32f1xx/uart_log.zig" },
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_i2c", .file = "src/stm32f1xx/i2c.zig" },
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_i2c", .file = "src/stm32f1xx/i2c_bus_scan.zig" },
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_hd44780", .file = "src/stm32f1xx/hd44780.zig" },
};

for (available_examples) |example| {
Expand Down
26 changes: 26 additions & 0 deletions examples/stmicro/stm32/src/stm32f1xx/gpio.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const std = @import("std");
const microzig = @import("microzig");

const RCC = microzig.chip.peripherals.RCC;
const stm32 = microzig.hal;
const gpio = stm32.gpio;
const timer = stm32.timer.GPTimer.TIM2;

pub fn main() !void {
RCC.APB2ENR.modify(.{
.GPIOCEN = 1,
});

RCC.APB1ENR.modify(.{
.TIM2EN = 1,
});

const led = gpio.Pin.from_port(.C, 13);
const counter = timer.into_counter(8_000_000);

led.set_output_mode(.general_purpose_push_pull, .max_50MHz);
while (true) {
counter.sleep_ms(100);
led.toggle();
}
}
105 changes: 105 additions & 0 deletions examples/stmicro/stm32/src/stm32f1xx/hd44780.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
const std = @import("std");
const microzig = @import("microzig");

const RCC = microzig.chip.peripherals.RCC;
const stm32 = microzig.hal;
const gpio = stm32.gpio;

const drivers = microzig.drivers;
const lcd_driver = drivers.display.hd44780;
const lcd = drivers.display.HD44780;
const PCF8574 = drivers.IO_expander.PCF8574;
const State = drivers.base.Digital_IO.State;

const timer = stm32.timer.GPTimer.TIM2;

const I2c = stm32.i2c;
const I2C_Device = stm32.drivers.I2C_Device;

const uart: stm32.uart.UART = @enumFromInt(0);
const TX = gpio.Pin.from_port(.A, 9);

const i2c: I2c.I2C = @enumFromInt(1);
const SCL = gpio.Pin.from_port(.B, 10);
const SDA = gpio.Pin.from_port(.B, 11);
const config = I2c.Config{
.pclk = 8_000_000,
.speed = 100_000,
.mode = .standard,
};

pub const microzig_options = microzig.Options{
.logFn = stm32.uart.logFn,
};

var global_counter: stm32.drivers.CounterDevice = undefined;

const i2c_device = I2C_Device.init(i2c, I2c.Address.new(0x27), config, &global_counter, null);

pub fn delay_us(time_delay: u32) void {
global_counter.sleep_us(time_delay);
}
pub fn main() !void {
RCC.APB2ENR.modify(.{
.GPIOBEN = 1,
.GPIOAEN = 1,
.AFIOEN = 1,
.USART1EN = 1,
});

RCC.APB1ENR.modify(.{
.I2C2EN = 1,
.TIM2EN = 1,
});

TX.set_output_mode(.alternate_function_push_pull, .max_50MHz);

//Set internal Pull-ups (not recommended for real applications)
SCL.set_input_mode(.pull);
SDA.set_input_mode(.pull);
SCL.set_pull(.up);
SDA.set_pull(.up);

//Set SCL and SDA to alternate function open drain
SCL.set_output_mode(.alternate_function_open_drain, .max_50MHz);
SDA.set_output_mode(.alternate_function_open_drain, .max_50MHz);

const counter = timer.into_counter(8_000_000);
global_counter = counter;

i2c.apply(config);

uart.apply(.{
.baud_rate = 115200,
.clock_speed = 8_000_000,
});

stm32.uart.init_logger(uart);
var expander = PCF8574(.{}).init(i2c_device.datagram_device());
const pins_config = lcd(.{}).pins_struct{
.high_pins = .{
expander.digital_IO(4),
expander.digital_IO(5),
expander.digital_IO(6),
expander.digital_IO(7),
},
.BK = expander.digital_IO(3),
.RS = expander.digital_IO(0),
.EN1 = expander.digital_IO(2),
};
var my_lcd = lcd(.{}).init(
pins_config,
delay_us,
);

try my_lcd.init_device(.{});
try my_lcd.set_backlight(1);
try my_lcd.write("hello world - From Zig");
try my_lcd.set_cursor(1, 0);
try my_lcd.write("STM32F103 - I2C LCD");

while (true) {
try my_lcd.shift_display_left();
global_counter.sleep_ms(300);
}
}
96 changes: 96 additions & 0 deletions examples/stmicro/stm32/src/stm32f1xx/i2c.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
const std = @import("std");
const microzig = @import("microzig");

const RCC = microzig.chip.peripherals.RCC;
const stm32 = microzig.hal;
const gpio = stm32.gpio;

const timer = stm32.timer.GPTimer.TIM2;

const i2c = stm32.i2c;

const uart: stm32.uart.UART = @enumFromInt(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add instance.num

const TX = gpio.Pin.from_port(.A, 9);

const i2c2: i2c.I2C = @enumFromInt(1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a instance.num() method like we do for other HALs

const SCL = gpio.Pin.from_port(.B, 10);
const SDA = gpio.Pin.from_port(.B, 11);
const ADDR = i2c.Address.new(0x27);
const config = i2c.Config{
.pclk = 8_000_000,
.speed = 100_000,
.mode = .standard,
};

pub const microzig_options = microzig.Options{
.logFn = stm32.uart.logFn,
};

pub fn main() !void {
RCC.APB2ENR.modify(.{
.GPIOBEN = 1,
.GPIOAEN = 1,
.AFIOEN = 1,
.USART1EN = 1,
});

RCC.APB1ENR.modify(.{
.I2C2EN = 1,
.TIM2EN = 1,
});

const counter = timer.into_counter(8_000_000);

TX.set_output_mode(.alternate_function_push_pull, .max_50MHz);

//Set internal Pull-ups (not recommended for real applications)
SCL.set_input_mode(.pull);
SDA.set_input_mode(.pull);
SCL.set_pull(.up);
SDA.set_pull(.up);

//Set SCL and SDA to alternate function open drain
SCL.set_output_mode(.alternate_function_open_drain, .max_50MHz);
SDA.set_output_mode(.alternate_function_open_drain, .max_50MHz);

i2c2.apply(config);

uart.apply(.{
.baud_rate = 115200,
.clock_speed = 8_000_000,
});

stm32.uart.init_logger(uart);

var to_read: [1]u8 = undefined;
std.log.info("start I2C master", .{});
while (true) {
for (0..0xFF) |val| {
std.log.info("sending {d}", .{val});
i2c2.write_blocking(ADDR, &.{@intCast(val)}, counter.make_ms_timeout(5000)) catch |err| {
std.log.err("send to send data | error {any}", .{err});
if (err == error.UnrecoverableError) {
//Reset I2C peripheral
i2c2.apply(config);
} else {
i2c2.clear_errors();
}
continue;
};

std.log.info("receiving data from the slave", .{});
i2c2.read_blocking(ADDR, &to_read, counter.make_ms_timeout(1000)) catch |err| {
std.log.err("fail to read data | error {any}", .{err});
if (err == error.UnrecoverableError) {
//Reset I2C peripheral
i2c2.apply(config);
} else {
i2c2.clear_errors();
}
continue;
};
std.log.info("data received: {}", .{to_read[0]});
counter.sleep_ms(1000);
}
}
}
81 changes: 81 additions & 0 deletions examples/stmicro/stm32/src/stm32f1xx/i2c_bus_scan.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const std = @import("std");
const microzig = @import("microzig");

const RCC = microzig.chip.peripherals.RCC;
const stm32 = microzig.hal;
const gpio = stm32.gpio;

const timer = stm32.timer.GPTimer.TIM2;

const I2c = stm32.i2c;

const uart: stm32.uart.UART = @enumFromInt(0);
const TX = gpio.Pin.from_port(.A, 9);

const i2c: I2c.I2C = @enumFromInt(1);
const SCL = gpio.Pin.from_port(.B, 10);
const SDA = gpio.Pin.from_port(.B, 11);
const config = I2c.Config{
.pclk = 8_000_000,
.speed = 100_000,
.mode = .standard,
};

pub const microzig_options = microzig.Options{
.logFn = stm32.uart.logFn,
};

pub fn main() !void {
RCC.APB2ENR.modify(.{
.GPIOBEN = 1,
.GPIOAEN = 1,
.AFIOEN = 1,
.USART1EN = 1,
});

RCC.APB1ENR.modify(.{
.I2C2EN = 1,
.TIM2EN = 1,
});

const counter = timer.into_counter(8_000_000);

TX.set_output_mode(.alternate_function_push_pull, .max_50MHz);

//Set internal Pull-ups (not recommended for real applications)
SCL.set_input_mode(.pull);
SDA.set_input_mode(.pull);
SCL.set_pull(.up);
SDA.set_pull(.up);

//Set SCL and SDA to alternate function open drain
SCL.set_output_mode(.alternate_function_open_drain, .max_50MHz);
SDA.set_output_mode(.alternate_function_open_drain, .max_50MHz);

i2c.apply(config);

uart.apply(.{
.baud_rate = 115200,
.clock_speed = 8_000_000,
});

stm32.uart.init_logger(uart);

std.log.info("start I2C master", .{});
while (true) {
std.log.info("starting i2c scan:", .{});
for (1..127) |val| {
const addr = I2c.Address.new(@intCast(val));
i2c.write_blocking(addr, &[_]u8{0}, counter.make_ms_timeout(100)) catch |err| {
if (err == error.UnrecoverableError) {
i2c.apply(config);
} else {
i2c.clear_errors();
}
continue;
};
std.log.info("found device at 0x{x}", .{val});
counter.sleep_ms(1000);
}
}
}
50 changes: 50 additions & 0 deletions examples/stmicro/stm32/src/stm32f1xx/uart_echo.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const std = @import("std");
const microzig = @import("microzig");

const RCC = microzig.chip.peripherals.RCC;
const stm32 = microzig.hal;

const timer = stm32.timer.GPTimer.TIM2;

const uart: stm32.uart.UART = @enumFromInt(0);
const gpio = stm32.gpio;
const TX = gpio.Pin.from_port(.A, 9);
const RX = gpio.Pin.from_port(.A, 10);

pub fn main() !void {
RCC.APB1ENR.modify(.{
.TIM2EN = 1,
});

RCC.APB2ENR.modify(.{
.USART1EN = 1,
.GPIOAEN = 1,
});

const counter = timer.into_counter(8_000_000);

TX.set_output_mode(.alternate_function_push_pull, .max_50MHz);
RX.set_input_mode(.pull);

uart.apply(.{
.baud_rate = 115200,
.clock_speed = 8_000_000,
});

var byte: [100]u8 = undefined;

//simple USART echo
try uart.write_blocking("START UART ECHO\n", null);
while (true) {
@memset(&byte, 0);
uart.read_blocking(&byte, counter.make_ms_timeout(100)) catch |err| {
if (err != error.Timeout) {
uart.writer().print("Got error {any}\n", .{err}) catch unreachable;
uart.clear_errors();
continue;
}
};

uart.write_blocking(&byte, null) catch unreachable;
}
}
Loading
Loading