Skip to content

Commit c8e2f91

Browse files
committed
Migrate UART for STM32F303 to its own file and add better support.
1 parent c6a625c commit c8e2f91

File tree

5 files changed

+193
-165
lines changed

5 files changed

+193
-165
lines changed

port/stmicro/stm32/src/boards/STM32F3DISCOVERY.zig

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
pub const microzig = @import("microzig");
22

3-
pub const cpu_frequency = 8_000_000;
4-
53
pub const pin_map = .{
64
// circle of LEDs, connected to GPIOE bits 8..15
75

@@ -23,15 +21,17 @@ pub const pin_map = .{
2321
.LD6 = "PE15",
2422
};
2523

24+
const uart_pin: microzig.hal.uart.Pins = .{ .tx = null, .rx = null };
25+
2626
pub fn debug_write(string: []const u8) void {
27-
const uart1 = microzig.core.experimental.Uart(1, .{}).get_or_init(.{
27+
const uart1 = microzig.hal.uart.Uart(.UART1, uart_pin).get_or_init(.{
2828
.baud_rate = 9600,
29-
.data_bits = .eight,
30-
.parity = null,
31-
.stop_bits = .one,
29+
.word_bits = .eight,
30+
.parity = .none,
31+
.stop_bits = .Stop1,
3232
}) catch unreachable;
3333

34-
const writer = uart1.writer();
35-
_ = writer.write(string) catch unreachable;
36-
uart1.internal.txflush();
34+
for (string) |c| {
35+
uart1.tx(c);
36+
}
3737
}

port/stmicro/stm32/src/hals/STM32F303.zig

Lines changed: 2 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -48,34 +48,18 @@ const runtime_safety = std.debug.runtime_safety;
4848

4949
const microzig = @import("microzig");
5050
pub const gpio = @import("STM32F303/gpio.zig");
51+
pub const uart = @import("STM32F303/uart.zig");
5152

5253
const SPI1 = microzig.peripherals.SPI1;
5354
const RCC = microzig.chip.peripherals.RCC;
54-
const USART1 = microzig.chip.peripherals.USART1;
55+
5556
const GPIOA = microzig.peripherals.GPIOA;
5657
const GPIOB = microzig.peripherals.GPIOB;
5758
const GPIOC = microzig.chip.peripherals.GPIOC;
5859
const I2C1 = microzig.peripherals.I2C1;
5960

6061
pub const cpu = @import("cpu");
6162

62-
pub const clock = struct {
63-
pub const Domain = enum {
64-
cpu,
65-
ahb,
66-
apb1,
67-
apb2,
68-
};
69-
};
70-
71-
// Default clock frequencies after reset, see top comment for calculation
72-
pub const clock_frequencies = .{
73-
.cpu = 8_000_000,
74-
.ahb = 8_000_000,
75-
.apb1 = 8_000_000,
76-
.apb2 = 8_000_000,
77-
};
78-
7963
pub fn parse_pin(comptime spec: []const u8) type {
8064
const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}{Pin}\" scheme.";
8165

@@ -100,142 +84,6 @@ fn set_reg_field(reg: anytype, comptime field_name: anytype, value: anytype) voi
10084
reg.write(temp);
10185
}
10286

103-
pub const uart = struct {
104-
pub const DataBits = enum(u4) {
105-
seven = 7,
106-
eight = 8,
107-
};
108-
109-
/// uses the values of USART_CR2.STOP
110-
pub const StopBits = enum(u2) {
111-
one = 0b00,
112-
half = 0b01,
113-
two = 0b10,
114-
one_and_half = 0b11,
115-
};
116-
117-
/// uses the values of USART_CR1.PS
118-
pub const Parity = enum(u1) {
119-
even = 0,
120-
odd = 1,
121-
};
122-
};
123-
124-
pub fn Uart() type {
125-
return struct {
126-
parity_read_mask: u8,
127-
128-
const Self = @This();
129-
130-
pub fn init() !Self {
131-
// The following must all be written when the USART is disabled (UE=0).
132-
if (USART1.CR1.read().UE == 1)
133-
@panic("Trying to initialize USART1 while it is already enabled");
134-
// LATER: Alternatively, set UE=0 at this point? Then wait for something?
135-
// Or add a destroy() function which disables the USART?
136-
137-
// enable the USART1 clock
138-
RCC.APB2ENR.modify(.{ .USART1EN = 1 });
139-
// enable GPIOC clock
140-
RCC.AHBENR.modify(.{ .GPIOCEN = 1 });
141-
// set PC4+PC5 to alternate function 7, USART1_TX + USART1_RX
142-
GPIOC.MODER.modify(.{ .@"MODER[4]" = .Alternate, .@"MODER[5]" = .Alternate });
143-
GPIOC.AFR[0].modify(.{ .@"AFR[4]" = 7, .@"AFR[5]" = 7 });
144-
145-
// clear USART1 configuration to its default
146-
USART1.CR1.raw = 0;
147-
USART1.CR2.raw = 0;
148-
USART1.CR3.raw = 0;
149-
150-
// set word length
151-
// Per the reference manual, M[1:0] means
152-
// - 00: 8 bits (7 data + 1 parity, or 8 data), probably the chip default
153-
// - 01: 9 bits (8 data + 1 parity)
154-
// - 10: 7 bits (7 data)
155-
// So M1==1 means "7-bit mode" (in which
156-
// "the Smartcard mode, LIN master mode and Auto baud rate [...] are not supported");
157-
// and M0==1 means 'the 9th bit (not the 8th bit) is the parity bit'.
158-
USART1.CR1.modify(.{ .M0 = .Bit8, .M1 = .M0 });
159-
160-
// set parity
161-
USART1.CR1.modify(.{ .PCE = 0 }); // no parity, probably the chip default
162-
163-
// set number of stop bits
164-
USART1.CR2.modify(.{ .STOP = .Stop1 });
165-
166-
// set the baud rate
167-
// TODO: Do not use the _board_'s frequency, but the _U(S)ARTx_ frequency
168-
// from the chip, which can be affected by how the board configures the chip.
169-
// In our case, these are accidentally the same at chip reset,
170-
// if the board doesn't configure e.g. an HSE external crystal.
171-
// TODO: Do some checks to see if the baud rate is too high (or perhaps too low)
172-
// TODO: Do a rounding div, instead of a truncating div?
173-
const usartdiv = @as(u16, @intCast(@divTrunc(clock_frequencies.apb2, 115200)));
174-
USART1.BRR.raw = usartdiv;
175-
// Above, ignore the BRR struct fields DIV_Mantissa and DIV_Fraction,
176-
// those seem to be for another chipset; .svd file bug?
177-
// TODO: We assume the default OVER8=0 configuration above.
178-
179-
// enable USART1, and its transmitter and receiver
180-
USART1.CR1.modify(.{ .UE = 1 });
181-
USART1.CR1.modify(.{ .TE = 1 });
182-
USART1.CR1.modify(.{ .RE = 1 });
183-
184-
// For code simplicity, at cost of one or more register reads,
185-
// we read back the actual configuration from the registers,
186-
// instead of using the `config` values.
187-
return read_from_registers();
188-
}
189-
190-
pub fn get_or_init(config: microzig.uart.Config) !Self {
191-
if (USART1.CR1.read().UE == 1) {
192-
// UART1 already enabled, don't reinitialize and disturb things;
193-
// instead read and use the actual configuration.
194-
return read_from_registers();
195-
} else return init(config);
196-
}
197-
198-
fn read_from_registers() Self {
199-
const cr1 = USART1.CR1.read();
200-
// As documented in `init()`, M0==1 means 'the 9th bit (not the 8th bit) is the parity bit'.
201-
// So we always mask away the 9th bit, and if parity is enabled and it is in the 8th bit,
202-
// then we also mask away the 8th bit.
203-
return Self{ .parity_read_mask = if (cr1.PCE == 1 and cr1.M0 == .Bit8) 0x7F else 0xFF };
204-
}
205-
206-
pub fn can_write(self: Self) bool {
207-
_ = self;
208-
return switch (USART1.ISR.read().TXE) {
209-
1 => true,
210-
0 => false,
211-
};
212-
}
213-
214-
pub fn tx(self: Self, ch: u8) void {
215-
while (!self.can_write()) {} // Wait for Previous transmission
216-
USART1.TDR.modify(.{ .DR = ch });
217-
}
218-
219-
pub fn txflush(_: Self) void {
220-
while (USART1.ISR.read().TC == 0) {}
221-
}
222-
223-
pub fn can_read(self: Self) bool {
224-
_ = self;
225-
return switch (USART1.ISR.read().RXNE) {
226-
1 => true,
227-
0 => false,
228-
};
229-
}
230-
231-
pub fn rx(self: Self) u8 {
232-
while (!self.can_read()) {} // Wait till the data is received
233-
const data_with_parity_bit: u9 = USART1.RDR.read().RDR;
234-
return @as(u8, @intCast(data_with_parity_bit & self.parity_read_mask));
235-
}
236-
};
237-
}
238-
23987
const enable_stm32f303_debug = false;
24088

24189
fn debug_print(comptime format: []const u8, args: anytype) void {

port/stmicro/stm32/src/hals/STM32F303/gpio.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ pub const Pin = enum(usize) {
9292
port.MODER.write_raw((port.MODER.raw & ~modMask) | @as(u32, @intFromEnum(MODER.Alternate)) << (pin << 1));
9393
port.OTYPER.write_raw((port.OTYPER.raw & ~gpio.mask()) | @as(u32, @intFromEnum(afmode.o_type)) << pin);
9494
port.PUPDR.write_raw((port.PUPDR.raw & ~modMask) | @as(u32, @intFromEnum(afmode.resistor)) << (pin << 1));
95-
var register = if (pin > 7) port.AFR[1] else port.AFR[0];
96-
register.write_raw((register.raw & ~afrMask) | @as(u32, @intFromEnum(afmode.afr)) << (pin << 2));
95+
const register = if (pin > 7) &port.AFR[1] else &port.AFR[0];
96+
register.write_raw((register.raw & ~afrMask) | @as(u32, @intFromEnum(afmode.afr)) << ((pin % 8) << 2));
9797
},
9898
}
9999
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub const Clock = struct {
2+
sys_clk: u32,
3+
ahb: u32,
4+
apb1: u32,
5+
apb2: u32,
6+
};
7+
8+
pub var current_clock: Clock = .{
9+
.sys_clk = 8_000_000,
10+
.ahb = 8_000_000,
11+
.apb1 = 8_000_000,
12+
.apb2 = 8_000_000,
13+
};

0 commit comments

Comments
 (0)