Skip to content

Commit b929a50

Browse files
committed
Initial setup for RCC.
1 parent b10f802 commit b929a50

File tree

5 files changed

+190
-16
lines changed

5 files changed

+190
-16
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
pub const microzig = @import("microzig");
2+
pub const hal = microzig.hal;
3+
pub const rcc = hal.rcc;
4+
pub const pins = hal.pins;
25

36
pub const pin_map = .{
47
// circle of LEDs, connected to GPIOE bits 8..15
@@ -20,3 +23,26 @@ pub const pin_map = .{
2023
// W green
2124
.LD6 = "PE15",
2225
};
26+
27+
pub fn init() void {
28+
hal.enable_fpu();
29+
rcc.enable_hse(8_000_000);
30+
rcc.enable_pll(.HSE, .Div1, .Mul6) catch {
31+
@panic("PLL faile to enable");
32+
};
33+
rcc.select_pll_for_sysclk() catch {
34+
@panic("Faile to select sysclk");
35+
};
36+
}
37+
38+
// Init should come first or the baud_rate would be too fast for the default HSI.
39+
pub fn init_log() void {
40+
_ = (pins.GlobalConfiguration{
41+
.GPIOC = .{
42+
.PIN4 = .{ .mode = .{ .alternate_function = .{ .afr = .AF7 } } },
43+
.PIN5 = .{ .mode = .{ .alternate_function = .{ .afr = .AF7 } } },
44+
},
45+
}).apply();
46+
const uart = try microzig.hal.uart.Uart(.UART1).init(.{ .baud_rate = 115200 });
47+
microzig.hal.uart.init_logger(&uart);
48+
}

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ const runtime_safety = std.debug.runtime_safety;
4949
const microzig = @import("microzig");
5050
pub const gpio = @import("STM32F303/gpio.zig");
5151
pub const uart = @import("STM32F303/uart.zig");
52+
pub const rcc = @import("STM32F303/rcc.zig");
53+
pub const i2c = @import("STM32F303/i2c.zig");
5254

5355
const SPI1 = microzig.peripherals.SPI1;
5456
const RCC = microzig.chip.peripherals.RCC;
@@ -92,6 +94,52 @@ fn debug_print(comptime format: []const u8, args: anytype) void {
9294
}
9395
}
9496

97+
// Those are missing from the cortex_m4
98+
// Maybe a specificity from STM that have those FPU unit.
99+
const CPACP = microzig.mmio.Mmio(packed struct(u32) {
100+
reserved1: u20 = 0,
101+
CP10: u2,
102+
CP11: u2,
103+
reserved2: u8 = 0,
104+
});
105+
106+
pub const FPCCR = microzig.mmio.Mmio(packed struct(u32) {
107+
LSPACT: u1,
108+
USER: u1,
109+
S: u1,
110+
THREAD: u1,
111+
HFRDY: u1,
112+
MMRDY: u1,
113+
BFRDY: u1,
114+
SFRDY: u1,
115+
MONRDY: u1,
116+
SPLIMVIOL: u1,
117+
UFRDY: u1,
118+
reserved0: u15 = 0,
119+
TS: u1,
120+
CLRONRETS: u1,
121+
CLRONRET: u1,
122+
LSPENS: u1,
123+
LSPEN: u1,
124+
ASPEN: u1,
125+
});
126+
127+
pub const missing_peripherals = .{
128+
.cpacr = @as(*volatile CPACP, @ptrFromInt(0xE000ED88)),
129+
.fpccr = @as(*volatile FPCCR, @ptrFromInt(0xE000EF34)),
130+
};
131+
132+
pub fn enable_fpu() void {
133+
missing_peripherals.cpacr.modify(.{
134+
.CP10 = 0b11,
135+
.CP11 = 0b11,
136+
});
137+
missing_peripherals.fpccr.modify(.{
138+
.ASPEN = 1,
139+
.LSPEN = 1,
140+
});
141+
}
142+
95143
/// This implementation does not use AUTOEND=1
96144
pub fn I2CController(comptime index: usize, comptime source_pins: microzig.i2c.Pins) type {
97145
if (!(index == 1)) @compileError("TODO: only I2C1 is currently supported");

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ pub const OutputGPIO = struct {
5757
}
5858
}
5959

60+
pub inline fn low(self: @This()) void {
61+
self.put(0);
62+
}
63+
64+
pub inline fn high(self: @This()) void {
65+
self.put(1);
66+
}
67+
6068
pub inline fn toggle(self: @This()) void {
6169
var port = self.pin.get_port();
6270
port.ODR.raw ^= self.pin.mask();
Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,108 @@
1-
pub const Clock = struct {
2-
sys_clk: u32,
3-
ahb: u32,
4-
apb1: u32,
5-
apb2: u32,
1+
const microzig = @import("microzig");
2+
const RCC = microzig.chip.peripherals.RCC;
3+
const GPIOF = microzig.chip.peripherals.GPIOF;
4+
const FLASH = microzig.chip.peripherals.FLASH;
5+
const PREDIV = microzig.chip.types.peripherals.rcc_f3v1.PREDIV;
6+
const PLLMUL = microzig.chip.types.peripherals.rcc_f3v1.PLLMUL;
7+
8+
pub const ClockName = enum {
9+
HSE,
10+
HSI,
11+
PLLCLK,
12+
SYSCLK,
13+
14+
fn is_for_pll(self: @This()) bool {
15+
return self == .HSE or self == .HSI;
16+
}
17+
18+
fn is_for_sysclk(self: @This()) bool {
19+
return self != .SYSCLK;
20+
}
21+
};
22+
23+
pub const RccErrorConfig = error{
24+
WrongClockSource,
25+
SourceClockNotInitialized,
26+
OutputPllTooHigh,
27+
PllMustBeEnableFirst,
628
};
729

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,
30+
pub const Clock = struct {
31+
sys_clk: u32 = 8_000_000,
32+
h_clk: u32 = 8_000_000,
33+
p1_clk: u32 = 8_000_000,
34+
p2_clk: u32 = 8_000_000,
35+
hse: u32 = 0,
36+
hsi: u32 = 8_000_000,
37+
pllout: u32 = 0,
38+
usart1_clk: u32 = 8_000_000,
1339
};
40+
41+
pub var current_clock: Clock = .{};
42+
43+
pub fn enable_pll(comptime source: ClockName, div: PREDIV, mul: PLLMUL) RccErrorConfig!void {
44+
if (!source.is_for_pll()) {
45+
return RccErrorConfig.WrongClockSource;
46+
}
47+
48+
if (source == .HSE and current_clock.hse == 0) {
49+
return RccErrorConfig.SourceClockNotInitialized;
50+
}
51+
52+
const inputClock = if (source == .HSE) current_clock.hse else (current_clock.hsi >> 1);
53+
54+
const inputDiv = @intFromEnum(div) + 1;
55+
const outputMul = @intFromEnum(mul) + 2;
56+
57+
const expectedPllOut = @divTrunc(inputClock, inputDiv) * outputMul;
58+
if (expectedPllOut > 72_000_000) {
59+
return RccErrorConfig.OutputPllTooHigh;
60+
}
61+
62+
RCC.CFGR.modify(.{ .PLLSRC = comptime if (source == .HSE) .HSE_Div_PREDIV else .HSI_Div2, .PLLMUL = mul });
63+
RCC.CR.modify(.{ .PLLON = 1 });
64+
65+
while (RCC.CR.read().PLLRDY != 1) {
66+
asm volatile ("" ::: .{ .memory = true });
67+
}
68+
69+
current_clock.pllout = expectedPllOut;
70+
}
71+
72+
pub fn enable_hse(speed: u32) void {
73+
RCC.CR.modify(.{ .HSEON = 1, .HSEBYP = 1 });
74+
75+
while (RCC.CR.read().HSERDY != 1) {
76+
asm volatile ("" ::: .{ .memory = true });
77+
}
78+
current_clock.hse = speed;
79+
}
80+
81+
pub fn select_pll_for_sysclk() RccErrorConfig!void {
82+
if (current_clock.pllout == 0) {
83+
return RccErrorConfig.PllMustBeEnableFirst;
84+
}
85+
// Maximum APB low speed domain is 36Nhz, let's divide by 2
86+
if (current_clock.pllout > 36_000_000) {
87+
RCC.CFGR.modify(.{ .PPRE1 = .Div2 });
88+
current_clock.p1_clk = current_clock.pllout >> 1;
89+
} else {
90+
current_clock.p1_clk = current_clock.pllout;
91+
}
92+
RCC.CFGR.modify(.{ .SW = .PLL1_P });
93+
current_clock.sys_clk = current_clock.pllout;
94+
current_clock.h_clk = current_clock.pllout;
95+
current_clock.p2_clk = current_clock.pllout;
96+
current_clock.usart1_clk = current_clock.pllout;
97+
adjust_flash();
98+
}
99+
100+
fn adjust_flash() void {
101+
if (current_clock.sys_clk < 24_000_000) {
102+
FLASH.ACR.modify(.{ .LATENCY = .WS0 });
103+
} else if (current_clock.sys_clk < 42_000_000) {
104+
FLASH.ACR.modify(.{ .LATENCY = .WS1, .PRFTBE = 1 });
105+
} else {
106+
FLASH.ACR.modify(.{ .LATENCY = .WS2, .PRFTBE = 1 });
107+
}
108+
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,10 @@ pub fn Uart(comptime index: UartNum) type {
9797

9898
// set the baud rate
9999
// TODO: Do not use the _board_'s frequency, but the _U(S)ARTx_ frequency
100-
// from the chip, which can be affected by how the board configures the chip.
101-
// In our case, these are accidentally the same at chip reset,
102-
// if the board doesn't configure e.g. an HSE external crystal.
100+
// from the chip
103101
// TODO: Do some checks to see if the baud rate is too high (or perhaps too low)
104-
// TODO: Do a rounding div, instead of a truncating div?
105-
const usartdiv = @as(u16, @intCast(@divTrunc(if (index == .UART1) rcc.current_clock.apb2 else rcc.current_clock.apb1, 9600)));
106-
regs.BRR.raw = usartdiv;
102+
const usartdiv = @divTrunc(if (index == .UART1) rcc.current_clock.usart1_clk else rcc.current_clock.p1_clk, config.baud_rate);
103+
regs.BRR.raw = @as(u16, @intCast(usartdiv));
107104
// TODO: We assume the default OVER8=0 configuration above.
108105

109106
// enable USART1, and its transmitter and receiver

0 commit comments

Comments
 (0)