aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/Cargo.toml3
-rw-r--r--examples/rp/src/bin/assign_resources.rs79
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs3
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs3
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs3
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs3
-rw-r--r--examples/rp/src/bin/sharing.rs150
-rw-r--r--examples/stm32f4/src/bin/adc.rs8
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs83
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs4
-rw-r--r--examples/stm32f7/src/bin/adc.rs4
-rw-r--r--examples/stm32g0/src/bin/adc.rs4
-rw-r--r--examples/stm32g0/src/bin/adc_dma.rs44
-rw-r--r--examples/stm32g0/src/bin/adc_oversampling.rs43
-rw-r--r--examples/stm32g4/src/bin/adc.rs2
-rw-r--r--examples/stm32h7/Cargo.toml1
-rw-r--r--examples/stm32h7/src/bin/adc.rs4
-rw-r--r--examples/stm32h7/src/bin/adc_dma.rs76
-rw-r--r--examples/stm32h7/src/bin/sai.rs186
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs12
-rw-r--r--examples/stm32h735/.cargo/config.toml8
-rw-r--r--examples/stm32h735/Cargo.toml61
-rw-r--r--examples/stm32h735/build.rs35
-rw-r--r--examples/stm32h735/memory.x5
-rw-r--r--examples/stm32h735/src/bin/ferris.bmpbin0 -> 6794 bytes
-rw-r--r--examples/stm32h735/src/bin/ltdc.rs467
-rw-r--r--examples/stm32l0/Cargo.toml2
-rw-r--r--examples/stm32l0/src/bin/dds.rs116
-rw-r--r--examples/stm32l4/src/bin/adc.rs2
-rw-r--r--examples/stm32u0/src/bin/adc.rs2
-rw-r--r--examples/stm32u5/src/bin/tsc.rs10
31 files changed, 1399 insertions, 24 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 9bd403f02..d06ab5e5a 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -29,6 +29,9 @@ reqwless = { version = "0.12.0", features = ["defmt",]}
29serde = { version = "1.0.203", default-features = false, features = ["derive"] } 29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1" 30serde-json-core = "0.5.1"
31 31
32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
34
32#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
33cortex-m = { version = "0.7.6", features = ["inline-asm"] } 36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
34cortex-m-rt = "0.7.0" 37cortex-m-rt = "0.7.0"
diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs
new file mode 100644
index 000000000..ff6eff4a2
--- /dev/null
+++ b/examples/rp/src/bin/assign_resources.rs
@@ -0,0 +1,79 @@
1//! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals.
2//! It is not about sharing the same resources between tasks, see sharing.rs for that or head to https://embassy.dev/book/#_sharing_peripherals_between_tasks)
3//! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources.
4//!
5//! There are basically two ways we demonstrate here:
6//! 1) Assigning resources to a task by passing parts of the peripherals
7//! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro
8//!
9//! using four LEDs on Pins 10, 11, 20 and 21
10
11#![no_std]
12#![no_main]
13
14use assign_resources::assign_resources;
15use defmt::*;
16use embassy_executor::Spawner;
17use embassy_rp::gpio::{Level, Output};
18use embassy_rp::peripherals::{self, PIN_20, PIN_21};
19use embassy_time::Timer;
20use {defmt_rtt as _, panic_probe as _};
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 // initialize the peripherals
25 let p = embassy_rp::init(Default::default());
26
27 // 1) Assigning a resource to a task by passing parts of the peripherals.
28 spawner
29 .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21))
30 .unwrap();
31
32 // 2) Using the assign-resources macro to assign resources to a task.
33 // we perform the split, see further below for the definition of the resources struct
34 let r = split_resources!(p);
35 // and then we can use them
36 spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap();
37}
38
39// 1) Assigning a resource to a task by passing parts of the peripherals.
40#[embassy_executor::task]
41async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) {
42 let mut led_20 = Output::new(pin_20, Level::Low);
43 let mut led_21 = Output::new(pin_21, Level::High);
44
45 loop {
46 info!("toggling leds");
47 led_20.toggle();
48 led_21.toggle();
49 Timer::after_secs(1).await;
50 }
51}
52
53// 2) Using the assign-resources macro to assign resources to a task.
54// first we define the resources we want to assign to the task using the assign_resources! macro
55// basically this will split up the peripherals struct into smaller structs, that we define here
56// naming is up to you, make sure your future self understands what you did here
57assign_resources! {
58 leds: Leds{
59 led_10: PIN_10,
60 led_11: PIN_11,
61 }
62 // add more resources to more structs if needed, for example defining one struct for each task
63}
64// this could be done in another file and imported here, but for the sake of simplicity we do it here
65// see https://github.com/adamgreig/assign-resources for more information
66
67// 2) Using the split resources in a task
68#[embassy_executor::task]
69async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) {
70 let mut led_10 = Output::new(r.led_10, Level::Low);
71 let mut led_11 = Output::new(r.led_11, Level::High);
72
73 loop {
74 info!("toggling leds");
75 led_10.toggle();
76 led_11.toggle();
77 Timer::after_secs(1).await;
78 }
79}
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index bd52cadca..def26b53d 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -63,7 +63,8 @@ async fn main(spawner: Spawner) {
63 w5500_int, 63 w5500_int,
64 w5500_reset, 64 w5500_reset,
65 ) 65 )
66 .await; 66 .await
67 .unwrap();
67 unwrap!(spawner.spawn(ethernet_task(runner))); 68 unwrap!(spawner.spawn(ethernet_task(runner)));
68 69
69 // Generate random seed 70 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 3e4fbd2e6..6c4a78361 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -66,7 +66,8 @@ async fn main(spawner: Spawner) {
66 w5500_int, 66 w5500_int,
67 w5500_reset, 67 w5500_reset,
68 ) 68 )
69 .await; 69 .await
70 .unwrap();
70 unwrap!(spawner.spawn(ethernet_task(runner))); 71 unwrap!(spawner.spawn(ethernet_task(runner)));
71 72
72 // Generate random seed 73 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 5532851f3..30a3a7463 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -65,7 +65,8 @@ async fn main(spawner: Spawner) {
65 w5500_int, 65 w5500_int,
66 w5500_reset, 66 w5500_reset,
67 ) 67 )
68 .await; 68 .await
69 .unwrap();
69 unwrap!(spawner.spawn(ethernet_task(runner))); 70 unwrap!(spawner.spawn(ethernet_task(runner)));
70 71
71 // Generate random seed 72 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index adb1d8941..1613ed887 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -63,7 +63,8 @@ async fn main(spawner: Spawner) {
63 w5500_int, 63 w5500_int,
64 w5500_reset, 64 w5500_reset,
65 ) 65 )
66 .await; 66 .await
67 .unwrap();
67 unwrap!(spawner.spawn(ethernet_task(runner))); 68 unwrap!(spawner.spawn(ethernet_task(runner)));
68 69
69 // Generate random seed 70 // Generate random seed
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs
new file mode 100644
index 000000000..5416e20ce
--- /dev/null
+++ b/examples/rp/src/bin/sharing.rs
@@ -0,0 +1,150 @@
1//! This example shows some common strategies for sharing resources between tasks.
2//!
3//! We demonstrate five different ways of sharing, covering different use cases:
4//! - Atomics: This method is used for simple values, such as bool and u8..u32
5//! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability.
6//! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points.
7//! The async Mutex has interior mutability built-in, so no RefCell is needed.
8//! - Cell: For sharing Copy types between tasks running on the same executor.
9//! - RefCell: When you want &mut access to a value shared between tasks running on the same executor.
10//!
11//! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks
12
13#![no_std]
14#![no_main]
15
16use core::cell::{Cell, RefCell};
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use cortex_m_rt::entry;
20use defmt::info;
21use embassy_executor::{Executor, InterruptExecutor};
22use embassy_rp::clocks::RoscRng;
23use embassy_rp::interrupt::{InterruptExt, Priority};
24use embassy_rp::peripherals::UART0;
25use embassy_rp::uart::{self, InterruptHandler, UartTx};
26use embassy_rp::{bind_interrupts, interrupt};
27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
28use embassy_sync::{blocking_mutex, mutex};
29use embassy_time::{Duration, Ticker};
30use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _};
33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
35
36struct MyType {
37 inner: u32,
38}
39
40static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new();
41static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
42
43// Use Atomics for simple values
44static ATOMIC: AtomicU32 = AtomicU32::new(0);
45
46// Use blocking Mutex with Cell/RefCell for sharing non-async things
47static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> =
48 blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 }));
49
50bind_interrupts!(struct Irqs {
51 UART0_IRQ => InterruptHandler<UART0>;
52});
53
54#[interrupt]
55unsafe fn SWI_IRQ_0() {
56 EXECUTOR_HI.on_interrupt()
57}
58
59#[entry]
60fn main() -> ! {
61 let p = embassy_rp::init(Default::default());
62 info!("Here we go!");
63
64 let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default());
65 // Use the async Mutex for sharing async things (built-in interior mutability)
66 static UART: StaticCell<UartAsyncMutex> = StaticCell::new();
67 let uart = UART.init(mutex::Mutex::new(uart));
68
69 // High-priority executor: runs in interrupt mode
70 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
71 let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0);
72 spawner.must_spawn(task_a(uart));
73
74 // Low priority executor: runs in thread mode
75 let executor = EXECUTOR_LOW.init(Executor::new());
76 executor.run(|spawner| {
77 // No Mutex needed when sharing between tasks running on the same executor
78
79 // Use Cell for Copy-types
80 static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4]));
81 let cell = CELL.take();
82
83 // Use RefCell for &mut access
84 static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 }));
85 let ref_cell = REF_CELL.take();
86
87 spawner.must_spawn(task_b(uart, cell, ref_cell));
88 spawner.must_spawn(task_c(cell, ref_cell));
89 });
90}
91
92#[embassy_executor::task]
93async fn task_a(uart: &'static UartAsyncMutex) {
94 let mut ticker = Ticker::every(Duration::from_secs(1));
95 loop {
96 let random = RoscRng.next_u32();
97
98 {
99 let mut uart = uart.lock().await;
100 uart.write(b"task a").await.unwrap();
101 // The uart lock is released when it goes out of scope
102 }
103
104 ATOMIC.store(random, Ordering::Relaxed);
105
106 MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random);
107
108 ticker.next().await;
109 }
110}
111
112#[embassy_executor::task]
113async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
114 let mut ticker = Ticker::every(Duration::from_secs(1));
115 loop {
116 let random = RoscRng.next_u32();
117
118 uart.lock().await.write(b"task b").await.unwrap();
119
120 cell.set(random.to_be_bytes());
121
122 ref_cell.borrow_mut().inner = random;
123
124 ticker.next().await;
125 }
126}
127
128#[embassy_executor::task]
129async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
130 let mut ticker = Ticker::every(Duration::from_secs(1));
131 loop {
132 info!("=======================");
133
134 let atomic_val = ATOMIC.load(Ordering::Relaxed);
135 info!("atomic: {}", atomic_val);
136
137 MUTEX_BLOCKING.lock(|x| {
138 let val = x.borrow().inner;
139 info!("blocking mutex: {}", val);
140 });
141
142 let cell_val = cell.get();
143 info!("cell: {:?}", cell_val);
144
145 let ref_cell_val = ref_cell.borrow().inner;
146 info!("ref_cell: {:?}", ref_cell_val);
147
148 ticker.next().await;
149 }
150}
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 9473b7b7f..423d29225 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 // Startup delay can be combined to the maximum of either 23 // Startup delay can be combined to the maximum of either
24 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); 24 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
25 25
26 let vrefint_sample = adc.read(&mut vrefint); 26 let vrefint_sample = adc.blocking_read(&mut vrefint);
27 27
28 let convert_to_millivolts = |sample| { 28 let convert_to_millivolts = |sample| {
29 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf 29 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
@@ -50,16 +50,16 @@ async fn main(_spawner: Spawner) {
50 50
51 loop { 51 loop {
52 // Read pin 52 // Read pin
53 let v = adc.read(&mut pin); 53 let v = adc.blocking_read(&mut pin);
54 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); 54 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
55 55
56 // Read internal temperature 56 // Read internal temperature
57 let v = adc.read(&mut temp); 57 let v = adc.blocking_read(&mut temp);
58 let celcius = convert_to_celcius(v); 58 let celcius = convert_to_celcius(v);
59 info!("Internal temp: {} ({} C)", v, celcius); 59 info!("Internal temp: {} ({} C)", v, celcius);
60 60
61 // Read internal voltage reference 61 // Read internal voltage reference
62 let v = adc.read(&mut vrefint); 62 let v = adc.blocking_read(&mut vrefint);
63 info!("VrefInt: {}", v); 63 info!("VrefInt: {}", v);
64 64
65 Timer::after_millis(100).await; 65 Timer::after_millis(100).await;
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
new file mode 100644
index 000000000..43a761e6d
--- /dev/null
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -0,0 +1,83 @@
1#![no_std]
2#![no_main]
3use cortex_m::singleton;
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence};
7use embassy_stm32::Peripherals;
8use embassy_time::Instant;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 spawner.must_spawn(adc_task(p));
15}
16
17#[embassy_executor::task]
18async fn adc_task(mut p: Peripherals) {
19 const ADC_BUF_SIZE: usize = 1024;
20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
22
23 let adc = Adc::new(p.ADC1);
24 let adc2 = Adc::new(p.ADC2);
25
26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_data);
27 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2);
28
29 adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
30 adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112);
31 adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112);
32 adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112);
33
34 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around
35 // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of
36 // what channel is at what index is lost. The buffer must be cleared and reset. This *is* handled here, but allowing this to happen will cause
37 // a reduction of performance as each time the buffer is reset, the adc & dma buffer must be restarted.
38
39 // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most
40 // frequently.
41 let mut tic = Instant::now();
42 let mut buffer1 = [0u16; 512];
43 let mut buffer2 = [0u16; 512];
44 let _ = adc.start();
45 let _ = adc2.start();
46 loop {
47 match adc.read(&mut buffer1).await {
48 Ok(_data) => {
49 let toc = Instant::now();
50 info!(
51 "\n adc1: {} dt = {}, n = {}",
52 buffer1[0..16],
53 (toc - tic).as_micros(),
54 _data
55 );
56 tic = toc;
57 }
58 Err(e) => {
59 warn!("Error: {:?}", e);
60 buffer1 = [0u16; 512];
61 let _ = adc.start();
62 }
63 }
64
65 match adc2.read(&mut buffer2).await {
66 Ok(_data) => {
67 let toc = Instant::now();
68 info!(
69 "\n adc2: {} dt = {}, n = {}",
70 buffer2[0..16],
71 (toc - tic).as_micros(),
72 _data
73 );
74 tic = toc;
75 }
76 Err(e) => {
77 warn!("Error: {:?}", e);
78 buffer2 = [0u16; 512];
79 let _ = adc2.start();
80 }
81 }
82 }
83}
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index c51111110..3c770a873 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -80,7 +80,9 @@ async fn main(spawner: Spawner) -> ! {
80 let mac_addr = [0x02, 234, 3, 4, 82, 231]; 80 let mac_addr = [0x02, 234, 3, 4, 82, 231];
81 static STATE: StaticCell<State<2, 2>> = StaticCell::new(); 81 static STATE: StaticCell<State<2, 2>> = StaticCell::new();
82 let state = STATE.init(State::<2, 2>::new()); 82 let state = STATE.init(State::<2, 2>::new());
83 let (device, runner) = embassy_net_wiznet::new(mac_addr, state, spi, w5500_int, w5500_reset).await; 83 let (device, runner) = embassy_net_wiznet::new(mac_addr, state, spi, w5500_int, w5500_reset)
84 .await
85 .unwrap();
84 unwrap!(spawner.spawn(ethernet_task(runner))); 86 unwrap!(spawner.spawn(ethernet_task(runner)));
85 87
86 let config = embassy_net::Config::dhcpv4(Default::default()); 88 let config = embassy_net::Config::dhcpv4(Default::default());
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 641157960..6689e3b5d 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 let mut pin = p.PA3; 16 let mut pin = p.PA3;
17 17
18 let mut vrefint = adc.enable_vrefint(); 18 let mut vrefint = adc.enable_vrefint();
19 let vrefint_sample = adc.read(&mut vrefint); 19 let vrefint_sample = adc.blocking_read(&mut vrefint);
20 let convert_to_millivolts = |sample| { 20 let convert_to_millivolts = |sample| {
21 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf 21 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
22 // 6.3.27 Reference voltage 22 // 6.3.27 Reference voltage
@@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) {
26 }; 26 };
27 27
28 loop { 28 loop {
29 let v = adc.read(&mut pin); 29 let v = adc.blocking_read(&mut pin);
30 info!("--> {} - {} mV", v, convert_to_millivolts(v)); 30 info!("--> {} - {} mV", v, convert_to_millivolts(v));
31 Timer::after_millis(100).await; 31 Timer::after_millis(100).await;
32 } 32 }
diff --git a/examples/stm32g0/src/bin/adc.rs b/examples/stm32g0/src/bin/adc.rs
index a35119e3d..6c7f3b48a 100644
--- a/examples/stm32g0/src/bin/adc.rs
+++ b/examples/stm32g0/src/bin/adc.rs
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 let mut pin = p.PA1; 17 let mut pin = p.PA1;
18 18
19 let mut vrefint = adc.enable_vrefint(); 19 let mut vrefint = adc.enable_vrefint();
20 let vrefint_sample = adc.read(&mut vrefint); 20 let vrefint_sample = adc.blocking_read(&mut vrefint);
21 let convert_to_millivolts = |sample| { 21 let convert_to_millivolts = |sample| {
22 // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf 22 // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf
23 // 6.3.3 Embedded internal reference voltage 23 // 6.3.3 Embedded internal reference voltage
@@ -27,7 +27,7 @@ async fn main(_spawner: Spawner) {
27 }; 27 };
28 28
29 loop { 29 loop {
30 let v = adc.read(&mut pin); 30 let v = adc.blocking_read(&mut pin);
31 info!("--> {} - {} mV", v, convert_to_millivolts(v)); 31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
32 Timer::after_millis(100).await; 32 Timer::after_millis(100).await;
33 } 33 }
diff --git a/examples/stm32g0/src/bin/adc_dma.rs b/examples/stm32g0/src/bin/adc_dma.rs
new file mode 100644
index 000000000..3713e5a21
--- /dev/null
+++ b/examples/stm32g0/src/bin/adc_dma.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10static mut DMA_BUF: [u16; 2] = [0; 2];
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut read_buffer = unsafe { &mut DMA_BUF[..] };
15
16 let p = embassy_stm32::init(Default::default());
17
18 info!("Hello World!");
19
20 let mut adc = Adc::new(p.ADC1);
21
22 let mut dma = p.DMA1_CH1;
23 let mut vrefint_channel = adc.enable_vrefint().degrade_adc();
24 let mut pa0 = p.PA0.degrade_adc();
25
26 loop {
27 adc.read(
28 &mut dma,
29 [
30 (&mut vrefint_channel, SampleTime::CYCLES160_5),
31 (&mut pa0, SampleTime::CYCLES160_5),
32 ]
33 .into_iter(),
34 &mut read_buffer,
35 )
36 .await;
37
38 let vrefint = read_buffer[0];
39 let measured = read_buffer[1];
40 info!("vrefint: {}", vrefint);
41 info!("measured: {}", measured);
42 Timer::after_millis(500).await;
43 }
44}
diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs
new file mode 100644
index 000000000..9c5dd872a
--- /dev/null
+++ b/examples/stm32g0/src/bin/adc_oversampling.rs
@@ -0,0 +1,43 @@
1//! adc oversampling example
2//!
3//! This example uses adc oversampling to achieve 16bit data
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_stm32::adc::{Adc, SampleTime};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17 info!("Adc oversample test");
18
19 let mut adc = Adc::new(p.ADC1);
20 adc.set_sample_time(SampleTime::CYCLES1_5);
21 let mut pin = p.PA1;
22
23 // From https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
24 // page373 15.8 Oversampler
25 // Table 76. Maximum output results vs N and M. Grayed values indicates truncation
26 // 0x00 oversampling ratio X2
27 // 0x01 oversampling ratio X4
28 // 0x02 oversampling ratio X8
29 // 0x03 oversampling ratio X16
30 // 0x04 oversampling ratio X32
31 // 0x05 oversampling ratio X64
32 // 0x06 oversampling ratio X128
33 // 0x07 oversampling ratio X256
34 adc.set_oversampling_ratio(0x03);
35 adc.set_oversampling_shift(0b0000);
36 adc.oversampling_enable(true);
37
38 loop {
39 let v = adc.blocking_read(&mut pin);
40 info!("--> {} ", v); //max 65520 = 0xFFF0
41 Timer::after_millis(100).await;
42 }
43}
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 3de38cbd6..adca846d8 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) {
32 adc.set_sample_time(SampleTime::CYCLES24_5); 32 adc.set_sample_time(SampleTime::CYCLES24_5);
33 33
34 loop { 34 loop {
35 let measured = adc.read(&mut p.PA7); 35 let measured = adc.blocking_read(&mut p.PA7);
36 info!("measured: {}", measured); 36 info!("measured: {}", measured);
37 Timer::after_millis(500).await; 37 Timer::after_millis(500).await;
38 } 38 }
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 0584f3916..78343b74f 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -34,6 +34,7 @@ stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1" 34embedded-storage = "0.3.1"
35static_cell = "2" 35static_cell = "2"
36chrono = { version = "^0.4", default-features = false } 36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
37 38
38# cargo build/run 39# cargo build/run
39[profile.dev] 40[profile.dev]
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index e9a857a74..98504ddf6 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -51,9 +51,9 @@ async fn main(_spawner: Spawner) {
51 let mut vrefint_channel = adc.enable_vrefint(); 51 let mut vrefint_channel = adc.enable_vrefint();
52 52
53 loop { 53 loop {
54 let vrefint = adc.read(&mut vrefint_channel); 54 let vrefint = adc.blocking_read(&mut vrefint_channel);
55 info!("vrefint: {}", vrefint); 55 info!("vrefint: {}", vrefint);
56 let measured = adc.read(&mut p.PC0); 56 let measured = adc.blocking_read(&mut p.PC0);
57 info!("measured: {}", measured); 57 info!("measured: {}", measured);
58 Timer::after_millis(500).await; 58 Timer::after_millis(500).await;
59 } 59 }
diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs
new file mode 100644
index 000000000..0b905d227
--- /dev/null
+++ b/examples/stm32h7/src/bin/adc_dma.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime};
7use embassy_stm32::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[link_section = ".ram_d3"]
12static mut DMA_BUF: [u16; 2] = [0; 2];
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let mut read_buffer = unsafe { &mut DMA_BUF[..] };
17
18 let mut config = Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.hsi = Some(HSIPrescaler::DIV1);
22 config.rcc.csi = true;
23 config.rcc.pll1 = Some(Pll {
24 source: PllSource::HSI,
25 prediv: PllPreDiv::DIV4,
26 mul: PllMul::MUL50,
27 divp: Some(PllDiv::DIV2),
28 divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q
29 divr: None,
30 });
31 config.rcc.pll2 = Some(Pll {
32 source: PllSource::HSI,
33 prediv: PllPreDiv::DIV4,
34 mul: PllMul::MUL50,
35 divp: Some(PllDiv::DIV8), // 100mhz
36 divq: None,
37 divr: None,
38 });
39 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
40 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
41 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
45 config.rcc.voltage_scale = VoltageScale::Scale1;
46 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
47 }
48 let p = embassy_stm32::init(config);
49
50 info!("Hello World!");
51
52 let mut adc = Adc::new(p.ADC3);
53
54 let mut dma = p.DMA1_CH1;
55 let mut vrefint_channel = adc.enable_vrefint().degrade_adc();
56 let mut pc0 = p.PC0.degrade_adc();
57
58 loop {
59 adc.read(
60 &mut dma,
61 [
62 (&mut vrefint_channel, SampleTime::CYCLES387_5),
63 (&mut pc0, SampleTime::CYCLES810_5),
64 ]
65 .into_iter(),
66 &mut read_buffer,
67 )
68 .await;
69
70 let vrefint = read_buffer[0];
71 let measured = read_buffer[1];
72 info!("vrefint: {}", vrefint);
73 info!("measured: {}", measured);
74 Timer::after_millis(500).await;
75 }
76}
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
new file mode 100644
index 000000000..f6735e235
--- /dev/null
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -0,0 +1,186 @@
1//! Daisy Seed rev.7(with PCM3060 codec)
2//! https://electro-smith.com/products/daisy-seed
3#![no_std]
4#![no_main]
5
6use embassy_executor::Spawner;
7use grounded::uninit::GroundedArrayCell;
8use hal::rcc::*;
9use hal::sai::*;
10use hal::time::Hertz;
11use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _};
12
13const BLOCK_LENGTH: usize = 32; // 32 samples
14const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels
15const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
16const SAMPLE_RATE: u32 = 48000;
17
18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
19#[link_section = ".sram1_bss"]
20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
21#[link_section = ".sram1_bss"]
22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let mut config = hal::Config::default();
27 config.rcc.pll1 = Some(Pll {
28 source: PllSource::HSE,
29 prediv: PllPreDiv::DIV4,
30 mul: PllMul::MUL200,
31 divp: Some(PllDiv::DIV2),
32 divq: Some(PllDiv::DIV5),
33 divr: Some(PllDiv::DIV2),
34 });
35 config.rcc.pll3 = Some(Pll {
36 source: PllSource::HSE,
37 prediv: PllPreDiv::DIV6,
38 mul: PllMul::MUL295,
39 divp: Some(PllDiv::DIV16),
40 divq: Some(PllDiv::DIV4),
41 divr: Some(PllDiv::DIV32),
42 });
43 config.rcc.sys = Sysclk::PLL1_P;
44 config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P;
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.hse = Some(Hse {
51 freq: Hertz::mhz(16),
52 mode: HseMode::Oscillator,
53 });
54
55 let p = hal::init(config);
56
57 let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1);
58 let kernel_clock = hal::rcc::frequency::<hal::peripherals::SAI1>().0;
59 let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8);
60
61 let mut tx_config = hal::sai::Config::default();
62 tx_config.mode = Mode::Master;
63 tx_config.tx_rx = TxRx::Transmitter;
64 tx_config.sync_output = true;
65 tx_config.clock_strobe = ClockStrobe::Falling;
66 tx_config.master_clock_divider = mclk_div;
67 tx_config.stereo_mono = StereoMono::Stereo;
68 tx_config.data_size = DataSize::Data24;
69 tx_config.bit_order = BitOrder::MsbFirst;
70 tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh;
71 tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit;
72 tx_config.frame_length = 64;
73 tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32);
74 tx_config.fifo_threshold = FifoThreshold::Quarter;
75
76 let mut rx_config = tx_config.clone();
77 rx_config.mode = Mode::Slave;
78 rx_config.tx_rx = TxRx::Receiver;
79 rx_config.sync_input = SyncInput::Internal;
80 rx_config.clock_strobe = ClockStrobe::Rising;
81 rx_config.sync_output = false;
82
83 let tx_buffer: &mut [u32] = unsafe {
84 TX_BUFFER.initialize_all_copied(0);
85 let (ptr, len) = TX_BUFFER.get_ptr_len();
86 core::slice::from_raw_parts_mut(ptr, len)
87 };
88
89 let mut sai_transmitter = Sai::new_asynchronous_with_mclk(
90 sub_block_tx,
91 p.PE5,
92 p.PE6,
93 p.PE4,
94 p.PE2,
95 p.DMA1_CH0,
96 tx_buffer,
97 tx_config,
98 );
99
100 let rx_buffer: &mut [u32] = unsafe {
101 RX_BUFFER.initialize_all_copied(0);
102 let (ptr, len) = RX_BUFFER.get_ptr_len();
103 core::slice::from_raw_parts_mut(ptr, len)
104 };
105
106 let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config);
107
108 sai_receiver.start();
109 sai_transmitter.start();
110
111 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
112
113 loop {
114 sai_receiver.read(&mut buf).await.unwrap();
115 sai_transmitter.write(&buf).await.unwrap();
116 }
117}
118
119const fn mclk_div_from_u8(v: u8) -> MasterClockDivider {
120 match v {
121 1 => MasterClockDivider::Div1,
122 2 => MasterClockDivider::Div2,
123 3 => MasterClockDivider::Div3,
124 4 => MasterClockDivider::Div4,
125 5 => MasterClockDivider::Div5,
126 6 => MasterClockDivider::Div6,
127 7 => MasterClockDivider::Div7,
128 8 => MasterClockDivider::Div8,
129 9 => MasterClockDivider::Div9,
130 10 => MasterClockDivider::Div10,
131 11 => MasterClockDivider::Div11,
132 12 => MasterClockDivider::Div12,
133 13 => MasterClockDivider::Div13,
134 14 => MasterClockDivider::Div14,
135 15 => MasterClockDivider::Div15,
136 16 => MasterClockDivider::Div16,
137 17 => MasterClockDivider::Div17,
138 18 => MasterClockDivider::Div18,
139 19 => MasterClockDivider::Div19,
140 20 => MasterClockDivider::Div20,
141 21 => MasterClockDivider::Div21,
142 22 => MasterClockDivider::Div22,
143 23 => MasterClockDivider::Div23,
144 24 => MasterClockDivider::Div24,
145 25 => MasterClockDivider::Div25,
146 26 => MasterClockDivider::Div26,
147 27 => MasterClockDivider::Div27,
148 28 => MasterClockDivider::Div28,
149 29 => MasterClockDivider::Div29,
150 30 => MasterClockDivider::Div30,
151 31 => MasterClockDivider::Div31,
152 32 => MasterClockDivider::Div32,
153 33 => MasterClockDivider::Div33,
154 34 => MasterClockDivider::Div34,
155 35 => MasterClockDivider::Div35,
156 36 => MasterClockDivider::Div36,
157 37 => MasterClockDivider::Div37,
158 38 => MasterClockDivider::Div38,
159 39 => MasterClockDivider::Div39,
160 40 => MasterClockDivider::Div40,
161 41 => MasterClockDivider::Div41,
162 42 => MasterClockDivider::Div42,
163 43 => MasterClockDivider::Div43,
164 44 => MasterClockDivider::Div44,
165 45 => MasterClockDivider::Div45,
166 46 => MasterClockDivider::Div46,
167 47 => MasterClockDivider::Div47,
168 48 => MasterClockDivider::Div48,
169 49 => MasterClockDivider::Div49,
170 50 => MasterClockDivider::Div50,
171 51 => MasterClockDivider::Div51,
172 52 => MasterClockDivider::Div52,
173 53 => MasterClockDivider::Div53,
174 54 => MasterClockDivider::Div54,
175 55 => MasterClockDivider::Div55,
176 56 => MasterClockDivider::Div56,
177 57 => MasterClockDivider::Div57,
178 58 => MasterClockDivider::Div58,
179 59 => MasterClockDivider::Div59,
180 60 => MasterClockDivider::Div60,
181 61 => MasterClockDivider::Div61,
182 62 => MasterClockDivider::Div62,
183 63 => MasterClockDivider::Div63,
184 _ => panic!(),
185 }
186}
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index b2e941078..43fb6b41c 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -10,18 +10,24 @@ use embassy_executor::Executor;
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config}; 12use embassy_stm32::{spi, Config};
13use grounded::uninit::GroundedArrayCell;
13use heapless::String; 14use heapless::String;
14use static_cell::StaticCell; 15use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
16 17
17// Defined in memory.x 18// Defined in memory.x
18#[link_section = ".ram_d3"] 19#[link_section = ".ram_d3"]
19static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
20 21
21#[embassy_executor::task] 22#[embassy_executor::task]
22async fn main_task(mut spi: spi::Spi<'static, Async>) { 23async fn main_task(mut spi: spi::Spi<'static, Async>) {
23 let read_buffer = unsafe { &mut RAM_D3[0..128] }; 24 let (read_buffer, write_buffer) = unsafe {
24 let write_buffer = unsafe { &mut RAM_D3[128..256] }; 25 RAM_D3.initialize_all_copied(0);
26 (
27 RAM_D3.get_subslice_mut_unchecked(0, 128),
28 RAM_D3.get_subslice_mut_unchecked(128, 128),
29 )
30 };
25 31
26 for n in 0u32.. { 32 for n in 0u32.. {
27 let mut write: String<128> = String::new(); 33 let mut write: String<128> = String::new();
diff --git a/examples/stm32h735/.cargo/config.toml b/examples/stm32h735/.cargo/config.toml
new file mode 100644
index 000000000..95536c6a8
--- /dev/null
+++ b/examples/stm32h735/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H735IGKx'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml
new file mode 100644
index 000000000..fc21cc894
--- /dev/null
+++ b/examples/stm32h735/Cargo.toml
@@ -0,0 +1,61 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h735-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] }
21heapless = { version = "0.8", default-features = false }
22embedded-graphics = { version = "0.8.1" }
23tinybmp = { version = "0.5" }
24
25# cargo build/run
26[profile.dev]
27codegen-units = 1
28debug = 2
29debug-assertions = true # <-
30incremental = false
31opt-level = 3 # <-
32overflow-checks = true # <-
33
34# cargo test
35[profile.test]
36codegen-units = 1
37debug = 2
38debug-assertions = true # <-
39incremental = false
40opt-level = 3 # <-
41overflow-checks = true # <-
42
43# cargo build/run --release
44[profile.release]
45codegen-units = 1
46debug = 2
47debug-assertions = false # <-
48incremental = false
49lto = 'fat'
50opt-level = 3 # <-
51overflow-checks = false # <-
52
53# cargo test --release
54[profile.bench]
55codegen-units = 1
56debug = 2
57debug-assertions = false # <-
58incremental = false
59lto = 'fat'
60opt-level = 3 # <-
61overflow-checks = false # <-
diff --git a/examples/stm32h735/build.rs b/examples/stm32h735/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h735/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/stm32h735/memory.x b/examples/stm32h735/memory.x
new file mode 100644
index 000000000..3a70d24d2
--- /dev/null
+++ b/examples/stm32h735/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x24000000, LENGTH = 320K
5} \ No newline at end of file
diff --git a/examples/stm32h735/src/bin/ferris.bmp b/examples/stm32h735/src/bin/ferris.bmp
new file mode 100644
index 000000000..7a222ab84
--- /dev/null
+++ b/examples/stm32h735/src/bin/ferris.bmp
Binary files differ
diff --git a/examples/stm32h735/src/bin/ltdc.rs b/examples/stm32h735/src/bin/ltdc.rs
new file mode 100644
index 000000000..a36fdef2c
--- /dev/null
+++ b/examples/stm32h735/src/bin/ltdc.rs
@@ -0,0 +1,467 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![allow(static_mut_refs)]
5
6/// This example demonstrates the LTDC lcd display peripheral and was tested to run on an stm32h735g-dk (embassy-stm32 feature "stm32h735ig" and probe-rs chip "STM32H735IGKx")
7/// Even though the dev kit has 16MB of attached PSRAM this example uses the 320KB of internal AXIS RAM found on the mcu itself to make the example more standalone and portable.
8/// For this reason a 256 color lookup table had to be used to keep the memory requirement down to an acceptable level.
9/// The example bounces a ferris crab bitmap around the screen while blinking an led on another task
10///
11use bouncy_box::BouncyBox;
12use defmt::{info, unwrap};
13use embassy_executor::Spawner;
14use embassy_stm32::gpio::{Level, Output, Speed};
15use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge};
16use embassy_stm32::{bind_interrupts, peripherals};
17use embassy_time::{Duration, Timer};
18use embedded_graphics::draw_target::DrawTarget;
19use embedded_graphics::geometry::{OriginDimensions, Point, Size};
20use embedded_graphics::image::Image;
21use embedded_graphics::pixelcolor::raw::RawU24;
22use embedded_graphics::pixelcolor::Rgb888;
23use embedded_graphics::prelude::*;
24use embedded_graphics::primitives::Rectangle;
25use embedded_graphics::Pixel;
26use heapless::{Entry, FnvIndexMap};
27use tinybmp::Bmp;
28use {defmt_rtt as _, panic_probe as _};
29
30const DISPLAY_WIDTH: usize = 480;
31const DISPLAY_HEIGHT: usize = 272;
32const MY_TASK_POOL_SIZE: usize = 2;
33
34// the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu
35pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
36pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
37
38bind_interrupts!(struct Irqs {
39 LTDC => ltdc::InterruptHandler<peripherals::LTDC>;
40});
41
42const NUM_COLORS: usize = 256;
43
44#[embassy_executor::main]
45async fn main(spawner: Spawner) {
46 let p = rcc_setup::stm32h735g_init();
47
48 // blink the led on another task
49 let led = Output::new(p.PC3, Level::High, Speed::Low);
50 unwrap!(spawner.spawn(led_task(led)));
51
52 // numbers from STMicroelectronics/STM32CubeH7 STM32H735G-DK C-based example
53 const RK043FN48H_HSYNC: u16 = 41; // Horizontal synchronization
54 const RK043FN48H_HBP: u16 = 13; // Horizontal back porch
55 const RK043FN48H_HFP: u16 = 32; // Horizontal front porch
56 const RK043FN48H_VSYNC: u16 = 10; // Vertical synchronization
57 const RK043FN48H_VBP: u16 = 2; // Vertical back porch
58 const RK043FN48H_VFP: u16 = 2; // Vertical front porch
59
60 let ltdc_config = LtdcConfiguration {
61 active_width: DISPLAY_WIDTH as _,
62 active_height: DISPLAY_HEIGHT as _,
63 h_back_porch: RK043FN48H_HBP - 11, // -11 from MX_LTDC_Init
64 h_front_porch: RK043FN48H_HFP,
65 v_back_porch: RK043FN48H_VBP,
66 v_front_porch: RK043FN48H_VFP,
67 h_sync: RK043FN48H_HSYNC,
68 v_sync: RK043FN48H_VSYNC,
69 h_sync_polarity: PolarityActive::ActiveLow,
70 v_sync_polarity: PolarityActive::ActiveLow,
71 data_enable_polarity: PolarityActive::ActiveHigh,
72 pixel_clock_polarity: PolarityEdge::FallingEdge,
73 };
74
75 info!("init ltdc");
76 let mut ltdc = Ltdc::new_with_pins(
77 p.LTDC, Irqs, p.PG7, p.PC6, p.PA4, p.PG14, p.PD0, p.PD6, p.PA8, p.PE12, p.PA3, p.PB8, p.PB9, p.PB1, p.PB0,
78 p.PA6, p.PE11, p.PH15, p.PH4, p.PC7, p.PD3, p.PE0, p.PH3, p.PH8, p.PH9, p.PH10, p.PH11, p.PE1, p.PE15,
79 );
80 ltdc.init(&ltdc_config);
81
82 // we only need to draw on one layer for this example (not to be confused with the double buffer)
83 info!("enable bottom layer");
84 let layer_config = LtdcLayerConfig {
85 pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel
86 layer: LtdcLayer::Layer1,
87 window_x0: 0,
88 window_x1: DISPLAY_WIDTH as _,
89 window_y0: 0,
90 window_y1: DISPLAY_HEIGHT as _,
91 };
92
93 let ferris_bmp: Bmp<Rgb888> = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap();
94 let color_map = build_color_lookup_map(&ferris_bmp);
95 let clut = build_clut(&color_map);
96
97 // enable the bottom layer with a 256 color lookup table
98 ltdc.init_layer(&layer_config, Some(&clut));
99
100 // Safety: the DoubleBuffer controls access to the statically allocated frame buffers
101 // and it is the only thing that mutates their content
102 let mut double_buffer = DoubleBuffer::new(
103 unsafe { FB1.as_mut() },
104 unsafe { FB2.as_mut() },
105 layer_config,
106 color_map,
107 );
108
109 // this allows us to perform some simple animation for every frame
110 let mut bouncy_box = BouncyBox::new(
111 ferris_bmp.bounding_box(),
112 Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)),
113 2,
114 );
115
116 loop {
117 // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen
118 double_buffer.clear();
119 let position = bouncy_box.next_point();
120 let ferris = Image::new(&ferris_bmp, position);
121 unwrap!(ferris.draw(&mut double_buffer));
122
123 // perform async dma data transfer to the lcd screen
124 unwrap!(double_buffer.swap(&mut ltdc).await);
125 }
126}
127
128/// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work.
129fn build_color_lookup_map(bmp: &Bmp<Rgb888>) -> FnvIndexMap<u32, u8, NUM_COLORS> {
130 let mut color_map: FnvIndexMap<u32, u8, NUM_COLORS> = heapless::FnvIndexMap::new();
131 let mut counter: u8 = 0;
132
133 // add black to position 0
134 color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap();
135 counter += 1;
136
137 for Pixel(_point, color) in bmp.pixels() {
138 let raw = color.into_storage();
139 if let Entry::Vacant(v) = color_map.entry(raw) {
140 v.insert(counter).expect("more than 256 colors detected");
141 counter += 1;
142 }
143 }
144 color_map
145}
146
147/// builds the color look-up table from the color map provided
148fn build_clut(color_map: &FnvIndexMap<u32, u8, NUM_COLORS>) -> [ltdc::RgbColor; NUM_COLORS] {
149 let mut clut = [ltdc::RgbColor::default(); NUM_COLORS];
150 for (color, index) in color_map.iter() {
151 let color = Rgb888::from(RawU24::new(*color));
152 clut[*index as usize] = ltdc::RgbColor {
153 red: color.r(),
154 green: color.g(),
155 blue: color.b(),
156 };
157 }
158
159 clut
160}
161
162#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)]
163async fn led_task(mut led: Output<'static>) {
164 let mut counter = 0;
165 loop {
166 info!("blink: {}", counter);
167 counter += 1;
168
169 // on
170 led.set_low();
171 Timer::after(Duration::from_millis(50)).await;
172
173 // off
174 led.set_high();
175 Timer::after(Duration::from_millis(450)).await;
176 }
177}
178
179pub type TargetPixelType = u8;
180
181// A simple double buffer
182pub struct DoubleBuffer {
183 buf0: &'static mut [TargetPixelType],
184 buf1: &'static mut [TargetPixelType],
185 is_buf0: bool,
186 layer_config: LtdcLayerConfig,
187 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
188}
189
190impl DoubleBuffer {
191 pub fn new(
192 buf0: &'static mut [TargetPixelType],
193 buf1: &'static mut [TargetPixelType],
194 layer_config: LtdcLayerConfig,
195 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
196 ) -> Self {
197 Self {
198 buf0,
199 buf1,
200 is_buf0: true,
201 layer_config,
202 color_map,
203 }
204 }
205
206 pub fn current(&mut self) -> (&FnvIndexMap<u32, u8, NUM_COLORS>, &mut [TargetPixelType]) {
207 if self.is_buf0 {
208 (&self.color_map, self.buf0)
209 } else {
210 (&self.color_map, self.buf1)
211 }
212 }
213
214 pub async fn swap<T: ltdc::Instance>(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> {
215 let (_, buf) = self.current();
216 let frame_buffer = buf.as_ptr();
217 self.is_buf0 = !self.is_buf0;
218 ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await
219 }
220
221 /// Clears the buffer
222 pub fn clear(&mut self) {
223 let (color_map, buf) = self.current();
224 let black = Rgb888::new(0, 0, 0).into_storage();
225 let color_index = color_map.get(&black).expect("no black found in the color map");
226
227 for a in buf.iter_mut() {
228 *a = *color_index; // solid black
229 }
230 }
231}
232
233// Implement DrawTarget for
234impl DrawTarget for DoubleBuffer {
235 type Color = Rgb888;
236 type Error = ();
237
238 /// Draw a pixel
239 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
240 where
241 I: IntoIterator<Item = Pixel<Self::Color>>,
242 {
243 let size = self.size();
244 let width = size.width as i32;
245 let height = size.height as i32;
246 let (color_map, buf) = self.current();
247
248 for pixel in pixels {
249 let Pixel(point, color) = pixel;
250
251 if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height {
252 let index = point.y * width + point.x;
253 let raw_color = color.into_storage();
254
255 match color_map.get(&raw_color) {
256 Some(x) => {
257 buf[index as usize] = *x;
258 }
259 None => panic!("color not found in color map: {}", raw_color),
260 };
261 } else {
262 // Ignore invalid points
263 }
264 }
265
266 Ok(())
267 }
268}
269
270impl OriginDimensions for DoubleBuffer {
271 /// Return the size of the display
272 fn size(&self) -> Size {
273 Size::new(
274 (self.layer_config.window_x1 - self.layer_config.window_x0) as _,
275 (self.layer_config.window_y1 - self.layer_config.window_y0) as _,
276 )
277 }
278}
279
280mod rcc_setup {
281
282 use embassy_stm32::rcc::{Hse, HseMode, *};
283 use embassy_stm32::time::Hertz;
284 use embassy_stm32::{Config, Peripherals};
285
286 /// Sets up clocks for the stm32h735g mcu
287 /// change this if you plan to use a different microcontroller
288 pub fn stm32h735g_init() -> Peripherals {
289 /*
290 https://github.com/STMicroelectronics/STM32CubeH7/blob/master/Projects/STM32H735G-DK/Examples/GPIO/GPIO_EXTI/Src/main.c
291 @brief System Clock Configuration
292 The system Clock is configured as follow :
293 System Clock source = PLL (HSE)
294 SYSCLK(Hz) = 520000000 (CPU Clock)
295 HCLK(Hz) = 260000000 (AXI and AHBs Clock)
296 AHB Prescaler = 2
297 D1 APB3 Prescaler = 2 (APB3 Clock 130MHz)
298 D2 APB1 Prescaler = 2 (APB1 Clock 130MHz)
299 D2 APB2 Prescaler = 2 (APB2 Clock 130MHz)
300 D3 APB4 Prescaler = 2 (APB4 Clock 130MHz)
301 HSE Frequency(Hz) = 25000000
302 PLL_M = 5
303 PLL_N = 104
304 PLL_P = 1
305 PLL_Q = 4
306 PLL_R = 2
307 VDD(V) = 3.3
308 Flash Latency(WS) = 3
309 */
310
311 // setup power and clocks for an stm32h735g-dk run from an external 25 Mhz external oscillator
312 let mut config = Config::default();
313 config.rcc.hse = Some(Hse {
314 freq: Hertz::mhz(25),
315 mode: HseMode::Oscillator,
316 });
317 config.rcc.hsi = None;
318 config.rcc.csi = false;
319 config.rcc.pll1 = Some(Pll {
320 source: PllSource::HSE,
321 prediv: PllPreDiv::DIV5, // PLL_M
322 mul: PllMul::MUL104, // PLL_N
323 divp: Some(PllDiv::DIV1),
324 divq: Some(PllDiv::DIV4),
325 divr: Some(PllDiv::DIV2),
326 });
327 // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_ospi.c
328 // MX_OSPI_ClockConfig
329 config.rcc.pll2 = Some(Pll {
330 source: PllSource::HSE,
331 prediv: PllPreDiv::DIV5, // PLL_M
332 mul: PllMul::MUL80, // PLL_N
333 divp: Some(PllDiv::DIV5),
334 divq: Some(PllDiv::DIV2),
335 divr: Some(PllDiv::DIV2),
336 });
337 // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_lcd.c
338 // MX_LTDC_ClockConfig
339 config.rcc.pll3 = Some(Pll {
340 source: PllSource::HSE,
341 prediv: PllPreDiv::DIV5, // PLL_M
342 mul: PllMul::MUL160, // PLL_N
343 divp: Some(PllDiv::DIV2),
344 divq: Some(PllDiv::DIV2),
345 divr: Some(PllDiv::DIV83),
346 });
347 config.rcc.voltage_scale = VoltageScale::Scale0;
348 config.rcc.supply_config = SupplyConfig::DirectSMPS;
349 config.rcc.sys = Sysclk::PLL1_P;
350 config.rcc.ahb_pre = AHBPrescaler::DIV2;
351 config.rcc.apb1_pre = APBPrescaler::DIV2;
352 config.rcc.apb2_pre = APBPrescaler::DIV2;
353 config.rcc.apb3_pre = APBPrescaler::DIV2;
354 config.rcc.apb4_pre = APBPrescaler::DIV2;
355 embassy_stm32::init(config)
356 }
357}
358
359mod bouncy_box {
360 use embedded_graphics::geometry::Point;
361 use embedded_graphics::primitives::Rectangle;
362
363 enum Direction {
364 DownLeft,
365 DownRight,
366 UpLeft,
367 UpRight,
368 }
369
370 pub struct BouncyBox {
371 direction: Direction,
372 child_rect: Rectangle,
373 parent_rect: Rectangle,
374 current_point: Point,
375 move_by: usize,
376 }
377
378 // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box
379 impl BouncyBox {
380 pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self {
381 let center_box = parent_rect.center();
382 let center_img = child_rect.center();
383 let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2);
384 Self {
385 direction: Direction::DownRight,
386 child_rect,
387 parent_rect,
388 current_point,
389 move_by,
390 }
391 }
392
393 pub fn next_point(&mut self) -> Point {
394 let direction = &self.direction;
395 let img_height = self.child_rect.size.height as i32;
396 let box_height = self.parent_rect.size.height as i32;
397 let img_width = self.child_rect.size.width as i32;
398 let box_width = self.parent_rect.size.width as i32;
399 let move_by = self.move_by as i32;
400
401 match direction {
402 Direction::DownLeft => {
403 self.current_point.x -= move_by;
404 self.current_point.y += move_by;
405
406 let x_out_of_bounds = self.current_point.x < 0;
407 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
408
409 if x_out_of_bounds && y_out_of_bounds {
410 self.direction = Direction::UpRight
411 } else if x_out_of_bounds && !y_out_of_bounds {
412 self.direction = Direction::DownRight
413 } else if !x_out_of_bounds && y_out_of_bounds {
414 self.direction = Direction::UpLeft
415 }
416 }
417 Direction::DownRight => {
418 self.current_point.x += move_by;
419 self.current_point.y += move_by;
420
421 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
422 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
423
424 if x_out_of_bounds && y_out_of_bounds {
425 self.direction = Direction::UpLeft
426 } else if x_out_of_bounds && !y_out_of_bounds {
427 self.direction = Direction::DownLeft
428 } else if !x_out_of_bounds && y_out_of_bounds {
429 self.direction = Direction::UpRight
430 }
431 }
432 Direction::UpLeft => {
433 self.current_point.x -= move_by;
434 self.current_point.y -= move_by;
435
436 let x_out_of_bounds = self.current_point.x < 0;
437 let y_out_of_bounds = self.current_point.y < 0;
438
439 if x_out_of_bounds && y_out_of_bounds {
440 self.direction = Direction::DownRight
441 } else if x_out_of_bounds && !y_out_of_bounds {
442 self.direction = Direction::UpRight
443 } else if !x_out_of_bounds && y_out_of_bounds {
444 self.direction = Direction::DownLeft
445 }
446 }
447 Direction::UpRight => {
448 self.current_point.x += move_by;
449 self.current_point.y -= move_by;
450
451 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
452 let y_out_of_bounds = self.current_point.y < 0;
453
454 if x_out_of_bounds && y_out_of_bounds {
455 self.direction = Direction::DownLeft
456 } else if x_out_of_bounds && !y_out_of_bounds {
457 self.direction = Direction::UpLeft
458 } else if !x_out_of_bounds && y_out_of_bounds {
459 self.direction = Direction::DownRight
460 }
461 }
462 }
463
464 self.current_point
465 }
466 }
467}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 2c599e7a3..5b0519ac4 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32l072cz to your chip name, if necessary. 8# Change stm32l072cz to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32l0/src/bin/dds.rs b/examples/stm32l0/src/bin/dds.rs
new file mode 100644
index 000000000..a54b28a93
--- /dev/null
+++ b/examples/stm32l0/src/bin/dds.rs
@@ -0,0 +1,116 @@
1#![no_std]
2#![no_main]
3
4use core::option::Option::Some;
5
6use defmt::info;
7use defmt_rtt as _; // global logger
8use embassy_executor::Spawner;
9use embassy_stm32::gpio::OutputType;
10use embassy_stm32::rcc::*;
11use embassy_stm32::time::hz;
12use embassy_stm32::timer::low_level::{Timer as LLTimer, *};
13use embassy_stm32::timer::simple_pwm::PwmPin;
14use embassy_stm32::timer::Channel;
15use embassy_stm32::{interrupt, pac, Config};
16use panic_probe as _;
17
18const DDS_SINE_DATA: [u8; 256] = [
19 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x98, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae, 0xb0, 0xb3, 0xb6,
20 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4,
21 0xe6, 0xe8, 0xea, 0xec, 0xed, 0xef, 0xf0, 0xf2, 0xf3, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd,
22 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb,
23 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf3, 0xf2, 0xf0, 0xef, 0xed, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde,
24 0xdc, 0xda, 0xd8, 0xd5, 0xd3, 0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3, 0xb0, 0xae,
25 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x98, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83, 0x80, 0x7c, 0x79, 0x76, 0x73,
26 0x70, 0x6d, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x5a, 0x57, 0x54, 0x51, 0x4f, 0x4c, 0x49, 0x46, 0x43, 0x40, 0x3e, 0x3b,
27 0x38, 0x36, 0x33, 0x31, 0x2e, 0x2c, 0x2a, 0x27, 0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x12,
28 0x10, 0x0f, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
29 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
30 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f, 0x21, 0x23, 0x25, 0x27, 0x2a, 0x2c,
31 0x2e, 0x31, 0x33, 0x36, 0x38, 0x3b, 0x3e, 0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x60,
32 0x63, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76, 0x79, 0x7c,
33];
34
35// frequency: 15625/(256/(DDS_INCR/2**24)) = 999,99999Hz
36static mut DDS_INCR: u32 = 0x10624DD2;
37
38// fractional phase accumulator
39static mut DDS_AKKU: u32 = 0x00000000;
40
41#[interrupt]
42fn TIM2() {
43 unsafe {
44 // get next value of DDS
45 DDS_AKKU = DDS_AKKU.wrapping_add(DDS_INCR);
46 let value = (DDS_SINE_DATA[(DDS_AKKU >> 24) as usize] as u16) << 3;
47
48 // set new output compare value
49 pac::TIM2.ccr(2).modify(|w| w.set_ccr(value));
50
51 // reset interrupt flag
52 pac::TIM2.sr().modify(|r| r.set_uif(false));
53 }
54}
55
56#[embassy_executor::main]
57async fn main(_spawner: Spawner) {
58 info!("Hello World!");
59
60 // configure for 32MHz (HSI16 * 6 / 3)
61 let mut config = Config::default();
62 config.rcc.sys = Sysclk::PLL1_R;
63 config.rcc.hsi = true;
64 config.rcc.pll = Some(Pll {
65 source: PllSource::HSI,
66 div: PllDiv::DIV3,
67 mul: PllMul::MUL6,
68 });
69
70 let p = embassy_stm32::init(config);
71
72 // setup PWM pin in AF mode
73 let _ch3 = PwmPin::new_ch3(p.PA2, OutputType::PushPull);
74
75 // initialize timer
76 // we cannot use SimplePWM here because the Time is privately encapsulated
77 let timer = LLTimer::new(p.TIM2);
78
79 // set counting mode
80 timer.set_counting_mode(CountingMode::EdgeAlignedUp);
81
82 // set pwm sample frequency
83 timer.set_frequency(hz(15625));
84
85 // enable outputs
86 timer.enable_outputs();
87
88 // start timer
89 timer.start();
90
91 // set output compare mode
92 timer.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
93
94 // set output compare preload
95 timer.set_output_compare_preload(Channel::Ch3, true);
96
97 // set output polarity
98 timer.set_output_polarity(Channel::Ch3, OutputPolarity::ActiveHigh);
99
100 // set compare value
101 timer.set_compare_value(Channel::Ch3, timer.get_max_compare_value() / 2);
102
103 // enable pwm channel
104 timer.enable_channel(Channel::Ch3, true);
105
106 // enable timer interrupts
107 timer.enable_update_interrupt(true);
108 unsafe { cortex_m::peripheral::NVIC::unmask(interrupt::TIM2) };
109
110 async {
111 loop {
112 embassy_time::Timer::after_millis(5000).await;
113 }
114 }
115 .await;
116}
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 7a89334e0..c557ac6d7 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -23,7 +23,7 @@ fn main() -> ! {
23 let mut channel = p.PC0; 23 let mut channel = p.PC0;
24 24
25 loop { 25 loop {
26 let v = adc.read(&mut channel); 26 let v = adc.blocking_read(&mut channel);
27 info!("--> {}", v); 27 info!("--> {}", v);
28 } 28 }
29} 29}
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
index 4410448f1..c8252e4e1 100644
--- a/examples/stm32u0/src/bin/adc.rs
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -23,7 +23,7 @@ fn main() -> ! {
23 let mut channel = p.PC0; 23 let mut channel = p.PC0;
24 24
25 loop { 25 loop {
26 let v = adc.read(&mut channel); 26 let v = adc.blocking_read(&mut channel);
27 info!("--> {}", v); 27 info!("--> {}", v);
28 embassy_time::block_for(Duration::from_millis(200)); 28 embassy_time::block_for(Duration::from_millis(200));
29 } 29 }
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
index f5593d1c4..eb15d275a 100644
--- a/examples/stm32u5/src/bin/tsc.rs
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -2,10 +2,15 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::bind_interrupts;
5use embassy_stm32::tsc::{self, *}; 6use embassy_stm32::tsc::{self, *};
6use embassy_time::Timer; 7use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
8 9
10bind_interrupts!(struct Irqs {
11 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
12});
13
9#[cortex_m_rt::exception] 14#[cortex_m_rt::exception]
10unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! { 15unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! {
11 cortex_m::peripheral::SCB::sys_reset(); 16 cortex_m::peripheral::SCB::sys_reset();
@@ -45,7 +50,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
45 g7.set_io2(context.PE3, PinType::Sample); 50 g7.set_io2(context.PE3, PinType::Sample);
46 g7.set_io3(context.PE4, PinType::Channel); 51 g7.set_io3(context.PE4, PinType::Channel);
47 52
48 let mut touch_controller = tsc::Tsc::new( 53 let mut touch_controller = tsc::Tsc::new_async(
49 context.TSC, 54 context.TSC,
50 Some(g1), 55 Some(g1),
51 Some(g2), 56 Some(g2),
@@ -56,6 +61,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
56 Some(g7), 61 Some(g7),
57 None, 62 None,
58 config, 63 config,
64 Irqs,
59 ); 65 );
60 66
61 touch_controller.discharge_io(true); 67 touch_controller.discharge_io(true);
@@ -67,7 +73,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
67 let mut group_seven_val = 0; 73 let mut group_seven_val = 0;
68 info!("Starting touch_controller interface"); 74 info!("Starting touch_controller interface");
69 loop { 75 loop {
70 touch_controller.poll_for_acquisition(); 76 touch_controller.pend_for_acquisition().await;
71 touch_controller.discharge_io(true); 77 touch_controller.discharge_io(true);
72 Timer::after_millis(1).await; 78 Timer::after_millis(1).await;
73 79