Skip to content

Commit d138762

Browse files
STM32F103 Small APIS and changes (#639)
* Add CRC and Power for STM32F103 * Add RTC and backup domain support for STM32F103 * Fix typos * fix typo * remove master/slave from some API * rename clock_init to apply_clock * Add SSD1306 display driver example for STM32F103 * remove unnecessary spaces in comments * Add Bus reset * Add EXTI example and HAL support for STM32F1xx * fix typo * Add basic DMA support for STM32F1xx and update ADC examples to use DMA controller * Refactor get_regs() to use comptime parameters and removed implicit pointer types * Add EVENTOUT support and GPIO remapping functionality for STM32F103 * Remove unused RCC imports from I2C, SPI, UART Echo, and UART Log examples * fix endpoint control and status handling
1 parent 61223e3 commit d138762

34 files changed

Lines changed: 1735 additions & 303 deletions

examples/stmicro/stm32/build.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ pub fn build(b: *std.Build) void {
3333
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_i2c", .file = "src/stm32f1xx/i2c.zig" },
3434
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_i2c_bus_scan", .file = "src/stm32f1xx/i2c_bus_scan.zig" },
3535
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_hd44780", .file = "src/stm32f1xx/hd44780.zig" },
36+
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_ssd1306", .file = "src/stm32f1xx/ssd1306.zig" },
3637
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_spi", .file = "src/stm32f1xx/spi.zig" },
3738
.{ .target = stm32.chips.STM32F103C8, .name = "STM32F1xx_usb_hid", .file = "src/stm32f1xx/usb_hid.zig" },
3839
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_usb_cdc", .file = "src/stm32f1xx/usb_cdc.zig" },
3940
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_rcc", .file = "src/stm32f1xx/rcc.zig" },
4041
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_timer", .file = "src/stm32f1xx/timer.zig" },
4142
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_timer_capture", .file = "src/stm32f1xx/timer_capture.zig" },
43+
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_rtc", .file = "src/stm32f1xx/rtc.zig" },
44+
.{ .target = stm32.chips.STM32F103CB, .name = "STM32F1xx_EXTI", .file = "src/stm32f1xx/EXTI.zig" },
4245
};
4346

4447
for (available_examples) |example| {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//External Interrupts (exti) Example for STM32F1xx
2+
//This example demonstrates how to configure an external interrupt on a GPIO pin
3+
//and toggle an LED when the interrupt is triggered.
4+
5+
const microzig = @import("microzig");
6+
const hal = microzig.hal;
7+
const gpio = hal.gpio;
8+
const rcc = hal.rcc;
9+
const exti = hal.exti;
10+
11+
const led = hal.gpio.Pin.from_port(.B, 2);
12+
const input = hal.gpio.Pin.from_port(.B, 9);
13+
14+
//define the EXTI handler
15+
pub const microzig_options: microzig.Options = .{
16+
.interrupts = .{
17+
.EXTI9_5 = .{ .c = EXTI_handler },
18+
},
19+
};
20+
21+
fn EXTI_handler() callconv(.C) void {
22+
// we have only one line configured, so we can just clear it
23+
// if you have more than one line configured, you should check the pending lines
24+
exti.clear_pending(exti.pending());
25+
led.toggle();
26+
}
27+
28+
pub fn main() !void {
29+
// Enable clocks for GPIOB and AFIO
30+
hal.rcc.enable_clock(.AFIO);
31+
hal.rcc.enable_clock(.GPIOB);
32+
33+
// Configure the LED pin as output
34+
led.set_output_mode(.general_purpose_push_pull, .max_50MHz);
35+
36+
// Configure the input pin as input with pull-up
37+
input.set_input_mode(.pull);
38+
input.set_pull(.up);
39+
40+
// Configure the EXTI line for PB9 with falling edge trigger
41+
exti.apply_line(.{
42+
.line = 9,
43+
.port = .B,
44+
.trigger = .falling,
45+
.interrupt = true, //enable interrupt imamediately (you can also enable it later if you want)
46+
.event = false, //no event for this example
47+
});
48+
49+
//enable NVIC for EXTI9_5 and enable interrupts globally
50+
microzig.interrupt.enable(.EXTI9_5);
51+
microzig.interrupt.enable_interrupts();
52+
53+
// Main loop does nothing, waiting for interrupts
54+
while (true) {
55+
asm volatile ("wfi"); // Wait for interrupt
56+
}
57+
}

examples/stmicro/stm32/src/stm32f1xx/adc.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub fn main() !void {
5656
while (true) {
5757
const adc_buf: []const u16 = try adc.read_multiple_channels(&adc_out_buf);
5858
counter.sleep_ms(100);
59-
std.log.info("\x1B[2J\x1B[H", .{}); // Clear screen and move cursor to 1,1
59+
std.log.info("\x1B[2J\x1B[H", .{}); //Clear screen and move cursor to 1,1
6060
std.log.info("CPU temp: {d:.1}C", .{adc_to_temp(adc_buf[0])});
6161
std.log.info("Vref: {d:0>4}", .{adc_buf[1]});
6262
std.log.info("CH1: {d:0>4}", .{adc_buf[2]});

examples/stmicro/stm32/src/stm32f1xx/adc_dualmode.zig

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22
//here it shows how to configure and use the Dual ADC mode using the advanced ADC API
33

44
const std = @import("std");
5-
const microzig = @import("microzig");
6-
const DMA = microzig.chip.peripherals.DMA1;
7-
const DMA_t = microzig.chip.types.peripherals.bdma_v1;
85

6+
const microzig = @import("microzig");
97
const stm32 = microzig.hal;
108
const rcc = stm32.rcc;
9+
const gpio = stm32.gpio;
10+
const dma = stm32.dma;
11+
const AdvancedADC = stm32.adc.AdvancedADC;
1112

12-
const timer = microzig.hal.timer.GPTimer.init(.TIM2).into_counter_mode();
13-
13+
const dma_controller = dma.DMAController.init(.DMA1);
14+
const timer = stm32.timer.GPTimer.init(.TIM2).into_counter_mode();
1415
const uart = stm32.uart.UART.init(.USART1);
15-
const gpio = stm32.gpio;
16-
const TX = gpio.Pin.from_port(.A, 9);
1716

18-
const AdvancedADC = microzig.hal.adc.AdvancedADC;
17+
const TX = gpio.Pin.from_port(.A, 9);
1918
const ADC_pin1 = gpio.Pin.from_port(.A, 1);
2019
const ADC_pin2 = gpio.Pin.from_port(.A, 2);
2120

@@ -36,26 +35,6 @@ fn adc_to_temp(val: usize) f32 {
3635
return ((v25 - temp_mv) / avg_slope) + 25; //convert to celsius
3736
}
3837

39-
fn DMA_init(arr_addr: u32, adc_addr: u32) void {
40-
const CH1: *volatile DMA_t.CH = @ptrCast(&DMA.CH);
41-
CH1.CR.raw = 0; //disable channel
42-
CH1.NDTR.raw = 0;
43-
CH1.CR.modify(.{
44-
.DIR = DMA_t.DIR.FromPeripheral,
45-
.CIRC = 1, //disable circular mode
46-
.PL = DMA_t.PL.High, //high priority
47-
.MSIZE = DMA_t.SIZE.Bits32,
48-
.PSIZE = DMA_t.SIZE.Bits32,
49-
.MINC = 1, //memory increment mode
50-
.PINC = 0, //peripheral not incremented
51-
});
52-
53-
CH1.NDTR.modify(.{ .NDT = 2 }); //number of data to transfer, 2 samples
54-
CH1.PAR = adc_addr; //peripheral address
55-
CH1.MAR = arr_addr; //memory address
56-
CH1.CR.modify(.{ .EN = 1 }); //enable channel
57-
}
58-
5938
pub fn main() !void {
6039
rcc.enable_clock(.DMA1);
6140
rcc.enable_clock(.TIM2);
@@ -68,10 +47,22 @@ pub fn main() !void {
6847
const counter = timer.counter_device(rcc.get_clock(.TIM2));
6948
const adc1 = AdvancedADC.init(.ADC1);
7049
const adc2 = AdvancedADC.init(.ADC2);
71-
72-
const adc_data_addr: u32 = @intFromPtr(&adc1.regs.DR);
7350
var adc_buf: [2]AdcData = undefined;
74-
const adc_buf_addr: u32 = @intFromPtr(&adc_buf[0]);
51+
52+
dma_controller.apply_channel(0, .{
53+
.circular_mode = true,
54+
.memory_increment = true,
55+
56+
.direction = .FromPeripheral,
57+
.priority = .High,
58+
.memory_size = .Bits32,
59+
.peripheral_size = .Bits32,
60+
61+
.transfer_count = 2,
62+
.periph_address = @intFromPtr(&adc1.regs.DR),
63+
.mem_address = @intFromPtr(&adc_buf),
64+
});
65+
dma_controller.start_channel(0);
7566

7667
TX.set_output_mode(.alternate_function_push_pull, .max_50MHz);
7768
ADC_pin1.set_input_mode(.analog);
@@ -90,23 +81,22 @@ pub fn main() !void {
9081

9182
try adc1.configure_dual_mode(.{ .Regular = .{
9283
.dma = true,
93-
.master_seq = &.{ 16, 17 },
94-
.slave_seq = &.{ 1, 2 },
84+
.primary_seq = &.{ 16, 17 },
85+
.secondary_seq = &.{ 1, 2 },
9586
.rate_seq = &.{ .@"239.5", .@"239.5" },
9687
.trigger = .SWSTART,
9788
.mode = .{ .Continuous = {} },
9889
} });
9990

10091
std.log.info("start Dual ADC scan", .{});
101-
DMA_init(adc_buf_addr, adc_data_addr);
10292
adc1.software_trigger(); //start conversion
10393
while (true) {
10494
counter.sleep_ms(250);
10595
const temp = adc_buf[0].adc1;
10696
const vref = adc_buf[1].adc1;
10797
const ch1 = adc_buf[0].adc2;
10898
const ch2 = adc_buf[1].adc2;
109-
std.log.info("\x1B[2J\x1B[H", .{}); // Clear screen and move cursor to 1,1
99+
std.log.info("\x1B[2J\x1B[H", .{}); //Clear screen and move cursor to 1,1
110100
std.log.info("CPU temp: {d:.1}C", .{adc_to_temp(temp)});
111101
std.log.info("Vref: {d}", .{vref});
112102
std.log.info("CH1: {d}", .{ch1});

examples/stmicro/stm32/src/stm32f1xx/advanced_adc.zig

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,34 @@
55
//before creating a program using ADC from older ST families, such as in this case STM32F1
66
//be aware of possible hardware bugs and limitations
77
//for example:
8-
// temperature sensor/VREF cannot be read in interleaved mode as it requires a sample time greater than 17
9-
// readings after 1ms from the previous reading may contain more noise than expected
8+
//temperature sensor/VREF cannot be read in interleaved mode as it requires a sample time greater than 17
9+
//readings after 1ms from the previous reading may contain more noise than expected
1010
//Voltage glitch on ADC input 0
1111

1212
const std = @import("std");
1313
const microzig = @import("microzig");
14-
1514
const interrupt = microzig.interrupt;
16-
const DMA = microzig.chip.peripherals.DMA1;
17-
const DMA_t = microzig.chip.types.peripherals.bdma_v1;
18-
1915
const stm32 = microzig.hal;
2016
const rcc = stm32.rcc;
21-
const timer = microzig.hal.timer.GPTimer.init(.TIM2).into_counter_mode();
17+
const gpio = stm32.gpio;
18+
const dma = stm32.dma;
19+
const AdvancedADC = stm32.adc.AdvancedADC;
2220

21+
const dma_controller = dma.DMAController.init(.DMA1);
22+
const timer = stm32.timer.GPTimer.init(.TIM2).into_counter_mode();
2323
const uart = stm32.uart.UART.init(.USART1);
24-
const gpio = stm32.gpio;
24+
const adc = AdvancedADC.init(.ADC1);
25+
2526
const TX = gpio.Pin.from_port(.A, 9);
27+
const ADC_pin1 = gpio.Pin.from_port(.A, 1);
28+
const ADC_pin2 = gpio.Pin.from_port(.A, 2);
29+
const ADC_pin3 = gpio.Pin.from_port(.A, 3);
2630

2731
pub const microzig_options = microzig.Options{
2832
.logFn = stm32.uart.log,
2933
.interrupts = .{ .ADC1_2 = .{ .c = watchdog_handler } },
3034
};
3135

32-
const AdvancedADC = microzig.hal.adc.AdvancedADC;
33-
const adc = AdvancedADC.init(.ADC1);
34-
const ADC_pin1 = gpio.Pin.from_port(.A, 1);
35-
const ADC_pin2 = gpio.Pin.from_port(.A, 2);
36-
const ADC_pin3 = gpio.Pin.from_port(.A, 3);
37-
3836
const v25 = 1.43;
3937
const avg_slope = 0.0043; //4.3mV/°C
4038

@@ -49,28 +47,8 @@ fn adc_to_temp(val: usize) f32 {
4947
return ((v25 - temp_mv) / avg_slope) + 25; //convert to celsius
5048
}
5149

52-
fn DMA_init(arr_addr: u32, adc_addr: u32) void {
53-
const CH1: *volatile DMA_t.CH = @ptrCast(&DMA.CH);
54-
CH1.CR.raw = 0; //disable channel
55-
CH1.NDTR.raw = 0;
56-
CH1.CR.modify(.{
57-
.DIR = DMA_t.DIR.FromPeripheral,
58-
.CIRC = 1, //disable circular mode
59-
.PL = DMA_t.PL.High, //high priority
60-
.MSIZE = DMA_t.SIZE.Bits16,
61-
.PSIZE = DMA_t.SIZE.Bits16,
62-
.MINC = 1, //memory increment mode
63-
.PINC = 0, //peripheral not incremented
64-
});
65-
66-
CH1.NDTR.modify(.{ .NDT = 4 }); //number of data to transfer, 4 samples
67-
CH1.PAR = adc_addr; //peripheral address
68-
CH1.MAR = arr_addr; //memory address
69-
CH1.CR.modify(.{ .EN = 1 }); //enable channel
70-
}
71-
7250
pub fn main() !void {
73-
try rcc.clock_init(.{ .ADCprescaler = .RCC_ADCPCLK2_DIV2 });
51+
try rcc.apply_clock(.{ .ADCprescaler = .RCC_ADCPCLK2_DIV2 });
7452

7553
rcc.enable_clock(.DMA1);
7654
rcc.enable_clock(.TIM2);
@@ -80,11 +58,23 @@ pub fn main() !void {
8058
rcc.enable_clock(.ADC1);
8159

8260
const counter = timer.counter_device(rcc.get_clock(.TIM2));
83-
84-
const adc_data_addr: u32 = @intFromPtr(&adc.regs.DR);
85-
var adc_buf: [10]u16 = .{0} ** 10;
86-
const adc_buf_addr: u32 = @intFromPtr(&adc_buf);
8761
const ref_ovf_flag: *volatile bool = &ovf_flag;
62+
var adc_buf: [10]u16 = .{0} ** 10;
63+
64+
dma_controller.apply_channel(0, .{
65+
.circular_mode = true,
66+
.memory_increment = true,
67+
68+
.direction = .FromPeripheral,
69+
.priority = .High,
70+
.memory_size = .Bits16,
71+
.peripheral_size = .Bits16,
72+
73+
.transfer_count = 4,
74+
.periph_address = @intFromPtr(&adc.regs.DR),
75+
.mem_address = @intFromPtr(&adc_buf),
76+
});
77+
dma_controller.start_channel(0);
8878

8979
//configure UART log
9080

@@ -142,13 +132,10 @@ pub fn main() !void {
142132
);
143133

144134
std.log.info("start Advanced ADC scan", .{});
145-
146-
DMA_init(adc_buf_addr, adc_data_addr);
147-
148135
while (true) {
149136
adc.software_trigger(); //start conversion
150137
counter.sleep_ms(100);
151-
std.log.info("\x1B[2J\x1B[H", .{}); // Clear screen and move cursor to 1,1
138+
std.log.info("\x1B[2J\x1B[H", .{}); //Clear screen and move cursor to 1,1
152139
std.log.info("CPU temp: {d:.1}C", .{adc_to_temp(adc_buf[0])});
153140
std.log.info("Vref: {d:0>4}", .{adc_buf[1]});
154141
std.log.info("CH1: {d:0>4}", .{adc_buf[2]});

examples/stmicro/stm32/src/stm32f1xx/i2c.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn main() !void {
7272
continue;
7373
};
7474

75-
std.log.info("receiving data from the slave", .{});
75+
std.log.info("receiving data from the device", .{});
7676
i2c2.read_blocking(ADDR, &to_read, counter.make_ms_timeout(1000)) catch |err| {
7777
std.log.err("fail to read data | error {any}", .{err});
7878
if (err == error.UnrecoverableError) {

examples/stmicro/stm32/src/stm32f1xx/i2c_bus_scan.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const std = @import("std");
22
const microzig = @import("microzig");
33

4-
const RCC = microzig.chip.peripherals.RCC;
54
const stm32 = microzig.hal;
65
const rcc = stm32.rcc;
76
const gpio = stm32.gpio;

examples/stmicro/stm32/src/stm32f1xx/rcc.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const clk_config = rcc.Config{
2424
};
2525

2626
pub fn main() !void {
27-
try rcc.clock_init(clk_config);
27+
try rcc.apply_clock(clk_config);
2828
rcc.enable_clock(.GPIOA);
2929
rcc.enable_clock(.AFIO);
3030
rcc.enable_clock(.USART1);

0 commit comments

Comments
 (0)