uart: allow selecting the tx/rx pins (#54)

Some microcontrollers allow routing multiple pins to the same UART peripheral.
This commit allows selecting specific pins on these platforms.
wch-ch32v003
Riccardo Binetti 2 years ago committed by GitHub
parent 7cfc924eed
commit 5cf1a4612d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,8 +2,8 @@ const std = @import("std");
const micro = @import("microzig.zig"); const micro = @import("microzig.zig");
const chip = @import("chip"); const chip = @import("chip");
pub fn Uart(comptime index: usize) type { pub fn Uart(comptime index: usize, comptime pins: Pins) type {
const SystemUart = chip.Uart(index); const SystemUart = chip.Uart(index, pins);
return struct { return struct {
const Self = @This(); const Self = @This();
@ -63,7 +63,14 @@ pub fn Uart(comptime index: usize) type {
}; };
} }
/// A UART configuration. The config defaults to the *8N1* setting, so "8 data bits, no parity, 1 stop bit" which is the /// The pin configuration. This is used to optionally configure specific pins to be used with the chosen UART.
/// This makes sense only with microcontrollers supporting multiple pins for a UART peripheral.
pub const Pins = struct {
tx: ?type = null,
rx: ?type = null,
};
/// A UART configuration. The config defaults to the *8N1* setting, so "8 data bits, no parity, 1 stop bit" which is the
/// most common serial format. /// most common serial format.
pub const Config = struct { pub const Config = struct {
/// TODO: Make this optional, to support STM32F303 et al. auto baud-rate detection? /// TODO: Make this optional, to support STM32F303 et al. auto baud-rate detection?

@ -25,7 +25,7 @@ pub const pin_map = .{
}; };
pub fn debugWrite(string: []const u8) void { pub fn debugWrite(string: []const u8) void {
const uart1 = micro.Uart(1).getOrInit(.{ const uart1 = micro.Uart(1, .{}).getOrInit(.{
.baud_rate = 9600, .baud_rate = 9600,
.data_bits = .eight, .data_bits = .eight,
.parity = null, .parity = null,

@ -94,8 +94,11 @@ pub const uart = struct {
}; };
}; };
pub fn Uart(comptime index: usize) type { pub fn Uart(comptime index: usize, comptime pins: micro.uart.Pins) type {
if (index != 0) @compileError("Atmega328p only has a single uart!"); if (index != 0) @compileError("Atmega328p only has a single uart!");
if (pins.tx != null or pins.rx != null)
@compileError("Atmega328p has fixed pins for uart!");
return struct { return struct {
const Self = @This(); const Self = @This();

@ -115,7 +115,10 @@ pub const uart = struct {
}; };
}; };
pub fn Uart(comptime index: usize) type { pub fn Uart(comptime index: usize, comptime pins: micro.uart.Pins) type {
if (pins.tx != null or pins.rx != null)
@compileError("TODO: custom pins are not currently supported");
return struct { return struct {
const UARTn = switch (index) { const UARTn = switch (index) {
0 => regs.UART0, 0 => regs.UART0,

@ -132,8 +132,10 @@ pub const uart = struct {
}; };
}; };
pub fn Uart(comptime index: usize) type { pub fn Uart(comptime index: usize, comptime pins: micro.uart.Pins) type {
if (!(index == 1)) @compileError("TODO: only USART1 is currently supported"); if (!(index == 1)) @compileError("TODO: only USART1 is currently supported");
if (pins.tx != null or pins.rx != null)
@compileError("TODO: custom pins are not currently supported");
return struct { return struct {
parity_read_mask: u8, parity_read_mask: u8,

@ -154,29 +154,85 @@ pub const uart = struct {
even = 0, even = 0,
odd = 1, odd = 1,
}; };
const PinDirection = std.meta.FieldEnum(micro.uart.Pins);
/// Checks if a pin is valid for a given uart index and direction
pub fn isValidPin(comptime pin: type, comptime index: usize, comptime direction: PinDirection) bool {
const pin_name = pin.name;
return switch (direction) {
.tx => switch (index) {
1 => std.mem.eql(u8, pin_name, "PA9") or std.mem.eql(u8, pin_name, "PB6"),
2 => std.mem.eql(u8, pin_name, "PA2") or std.mem.eql(u8, pin_name, "PD5"),
3 => std.mem.eql(u8, pin_name, "PB10") or std.mem.eql(u8, pin_name, "PC10") or std.mem.eql(u8, pin_name, "PD8"),
4 => std.mem.eql(u8, pin_name, "PA0") or std.mem.eql(u8, pin_name, "PC10"),
5 => std.mem.eql(u8, pin_name, "PC12"),
6 => std.mem.eql(u8, pin_name, "PC6") or std.mem.eql(u8, pin_name, "PG14"),
else => unreachable,
},
// Valid RX pins for the UARTs
.rx => switch (index) {
1 => std.mem.eql(u8, pin_name, "PA10") or std.mem.eql(u8, pin_name, "PB7"),
2 => std.mem.eql(u8, pin_name, "PA3") or std.mem.eql(u8, pin_name, "PD6"),
3 => std.mem.eql(u8, pin_name, "PB11") or std.mem.eql(u8, pin_name, "PC11") or std.mem.eql(u8, pin_name, "PD9"),
4 => std.mem.eql(u8, pin_name, "PA1") or std.mem.eql(u8, pin_name, "PC11"),
5 => std.mem.eql(u8, pin_name, "PD2"),
6 => std.mem.eql(u8, pin_name, "PC7") or std.mem.eql(u8, pin_name, "PG9"),
else => unreachable,
},
};
}
}; };
pub fn Uart(comptime index: usize) type { pub fn Uart(comptime index: usize, comptime pins: micro.uart.Pins) type {
if (index < 1 or index > 6) @compileError("Valid USART index are 1..6"); if (index < 1 or index > 6) @compileError("Valid USART index are 1..6");
const usart_name = std.fmt.comptimePrint("USART{d}", .{index}); const usart_name = std.fmt.comptimePrint("USART{d}", .{index});
// TODO: support alternative pins const tx_pin =
const pins = switch (index) { if (pins.tx) |tx|
1 => .{ .tx = micro.Pin("PA9"), .rx = micro.Pin("PA10") }, if (uart.isValidPin(tx, index, .tx))
2 => .{ .tx = micro.Pin("PA2"), .rx = micro.Pin("PA3") }, tx
3 => .{ .tx = micro.Pin("PD8"), .rx = micro.Pin("PD9") }, else
4 => .{ .tx = micro.Pin("PC10"), .rx = micro.Pin("PC11") }, @compileError(std.fmt.comptimePrint("Tx pin {s} is not valid for UART{}", .{ tx.name, index }))
5 => .{ .tx = micro.Pin("PC12"), .rx = micro.Pin("PD2") }, else switch (index) {
6 => .{ .tx = micro.Pin("PC6"), .rx = micro.Pin("PC7") }, // Provide default tx pins if no pin is specified
1 => micro.Pin("PA9"),
2 => micro.Pin("PA2"),
3 => micro.Pin("PB10"),
4 => micro.Pin("PA0"),
5 => micro.Pin("PC12"),
6 => micro.Pin("PC6"),
else => unreachable, else => unreachable,
}; };
const tx_gpio = micro.Gpio(pins.tx, .{
const rx_pin =
if (pins.rx) |rx|
if (uart.isValidPin(rx, index, .rx))
rx
else
@compileError(std.fmt.comptimePrint("Rx pin {s} is not valid for UART{}", .{ rx.name, index }))
else switch (index) {
// Provide default rx pins if no pin is specified
1 => micro.Pin("PA10"),
2 => micro.Pin("PA3"),
3 => micro.Pin("PB11"),
4 => micro.Pin("PA1"),
5 => micro.Pin("PD2"),
6 => micro.Pin("PC7"),
else => unreachable,
};
// USART1..3 are AF7, USART 4..6 are AF8
const alternate_function = if (index <= 3) .af7 else .af8;
const tx_gpio = micro.Gpio(tx_pin, .{
.mode = .alternate_function, .mode = .alternate_function,
.alternate_function = .af7, .alternate_function = alternate_function,
}); });
const rx_gpio = micro.Gpio(pins.rx, .{ const rx_gpio = micro.Gpio(rx_pin, .{
.mode = .alternate_function, .mode = .alternate_function,
.alternate_function = .af7, .alternate_function = alternate_function,
}); });
return struct { return struct {

@ -3,13 +3,25 @@ const micro = @import("microzig");
// Configures the led_pin and uart index // Configures the led_pin and uart index
const cfg = if (micro.config.has_board) const cfg = if (micro.config.has_board)
switch (micro.config.board_name) { switch (micro.config.board_name) {
.@"mbed LPC1768" => .{ .led_pin = micro.Pin("LED-1"), .uart_idx = 1 }, .@"mbed LPC1768" => .{
.@"STM32F3DISCOVERY" => .{ .led_pin = micro.Pin("LD3"), .uart_idx = 1 }, .led_pin = micro.Pin("LED-1"),
.@"STM32F4DISCOVERY" => .{ .led_pin = micro.Pin("LD5"), .uart_idx = 2 }, .uart_idx = 1,
.pins = .{},
},
.@"STM32F3DISCOVERY" => .{
.led_pin = micro.Pin("LD3"),
.uart_idx = 1,
.pins = .{},
},
.@"STM32F4DISCOVERY" => .{
.led_pin = micro.Pin("LD5"),
.uart_idx = 2,
.pins = .{ .tx = micro.Pin("PA2"), .rx = micro.Pin("PA3") },
},
else => @compileError("unknown board"), else => @compileError("unknown board"),
} }
else switch (micro.config.chip_name) { else switch (micro.config.chip_name) {
.@"NXP LPC1768" => .{ .led_pin = micro.Pin("P1.18"), .uart_idx = 1 }, .@"NXP LPC1768" => .{ .led_pin = micro.Pin("P1.18"), .uart_idx = 1, .pins = .{} },
else => @compileError("unknown chip"), else => @compileError("unknown chip"),
}; };
@ -20,7 +32,7 @@ pub fn main() !void {
}); });
led.init(); led.init();
var uart = micro.Uart(cfg.uart_idx).init(.{ var uart = micro.Uart(cfg.uart_idx, cfg.pins).init(.{
.baud_rate = 9600, .baud_rate = 9600,
.stop_bits = .one, .stop_bits = .one,
.parity = null, .parity = null,

Loading…
Cancel
Save