aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorPeter Krull <[email protected]>2024-09-23 19:02:59 +0200
committerGitHub <[email protected]>2024-09-23 19:02:59 +0200
commita2c473306f4a7c8e99add2546450ab3a7a97436e (patch)
tree5522a708e492db7d4632dc0a56fe5057244f03f0 /examples
parente02a987bafd4f0fcf9d80e7c4f6e1504b8b02cec (diff)
parent2935290a6222536d6341103f91bfd732165d3862 (diff)
Merge branch 'embassy-rs:main' into multi-signal
Diffstat (limited to 'examples')
-rw-r--r--examples/boot/application/nrf/Cargo.toml21
-rw-r--r--examples/boot/application/nrf/build.rs3
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs11
-rw-r--r--examples/boot/application/rp/Cargo.toml12
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml9
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f3/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml9
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f7/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml9
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32h7/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml9
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l0/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml9
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l1/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml9
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l4/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml10
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml9
-rw-r--r--examples/boot/application/stm32wl/memory.x11
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs10
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs10
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml4
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml6
-rw-r--r--examples/boot/bootloader/rp/memory.x2
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml5
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/README.md8
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml4
-rw-r--r--examples/boot/bootloader/stm32/memory.x2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml6
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml9
-rw-r--r--examples/nrf51/Cargo.toml6
-rw-r--r--examples/nrf52810/.cargo/config.toml9
-rw-r--r--examples/nrf52810/Cargo.toml24
-rw-r--r--examples/nrf52810/build.rs35
-rw-r--r--examples/nrf52810/memory.x7
-rw-r--r--examples/nrf52810/src/bin/blinky.rs20
-rw-r--r--examples/nrf52840-rtic/Cargo.toml7
-rw-r--r--examples/nrf52840/Cargo.toml13
-rw-r--r--examples/nrf52840/src/bin/channel.rs4
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs4
-rw-r--r--examples/nrf52840/src/bin/egu.rs43
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs23
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs2
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs4
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs15
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs14
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs2
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs20
-rw-r--r--examples/nrf5340/Cargo.toml13
-rw-r--r--examples/nrf5340/src/bin/gpiote_channel.rs2
-rw-r--r--examples/nrf9151/ns/.cargo/config.toml9
-rw-r--r--examples/nrf9151/ns/Cargo.toml20
-rw-r--r--examples/nrf9151/ns/README.md4
-rw-r--r--examples/nrf9151/ns/build.rs35
-rw-r--r--examples/nrf9151/ns/flash_tfm.sh2
-rw-r--r--examples/nrf9151/ns/memory.x7
-rw-r--r--examples/nrf9151/ns/src/bin/blinky.rs22
-rw-r--r--examples/nrf9151/ns/src/bin/uart.rs37
-rw-r--r--examples/nrf9151/ns/tfm.hex1543
-rw-r--r--examples/nrf9151/s/.cargo/config.toml8
-rw-r--r--examples/nrf9151/s/Cargo.toml20
-rw-r--r--examples/nrf9151/s/build.rs35
-rw-r--r--examples/nrf9151/s/memory.x5
-rw-r--r--examples/nrf9151/s/src/bin/blinky.rs22
-rw-r--r--examples/nrf9160/.cargo/config.toml4
-rw-r--r--examples/nrf9160/Cargo.toml12
-rw-r--r--examples/nrf9160/memory.x8
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs198
-rw-r--r--examples/rp/Cargo.toml54
-rw-r--r--examples/rp/src/bin/adc_dma.rs54
-rw-r--r--examples/rp/src/bin/assign_resources.rs79
-rw-r--r--examples/rp/src/bin/bluetooth.rs150
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs24
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs20
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs20
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs20
-rw-r--r--examples/rp/src/bin/i2c_async_embassy.rs85
-rw-r--r--examples/rp/src/bin/i2c_slave.rs2
-rw-r--r--examples/rp/src/bin/interrupt.rs94
-rw-r--r--examples/rp/src/bin/multicore.rs12
-rw-r--r--examples/rp/src/bin/multiprio.rs4
-rw-r--r--examples/rp/src/bin/orchestrate_tasks.rs318
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs2
-rw-r--r--examples/rp/src/bin/pio_onewire.rs155
-rw-r--r--examples/rp/src/bin/pio_pwm.rs118
-rw-r--r--examples/rp/src/bin/pio_servo.rs208
-rw-r--r--examples/rp/src/bin/pio_stepper.rs2
-rw-r--r--examples/rp/src/bin/pio_uart.rs2
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs7
-rw-r--r--examples/rp/src/bin/pwm.rs2
-rw-r--r--examples/rp/src/bin/pwm_input.rs3
-rw-r--r--examples/rp/src/bin/shared_bus.rs115
-rw-r--r--examples/rp/src/bin/sharing.rs150
-rw-r--r--examples/rp/src/bin/spi_sdmmc.rs83
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp/src/bin/uart_r503.rs158
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs25
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs16
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs173
-rw-r--r--examples/rp/src/bin/usb_midi.rs2
-rw-r--r--examples/rp/src/bin/usb_raw.rs2
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs2
-rw-r--r--examples/rp/src/bin/usb_serial.rs102
-rw-r--r--examples/rp/src/bin/usb_serial_with_logger.rs2
-rw-r--r--examples/rp/src/bin/usb_webusb.rs155
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs33
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs8
-rw-r--r--examples/rp/src/bin/wifi_scan.rs13
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs42
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs190
-rw-r--r--examples/rp/src/bin/zerocopy.rs94
-rw-r--r--examples/rp23/.cargo/config.toml10
-rw-r--r--examples/rp23/Cargo.toml79
-rw-r--r--examples/rp23/assets/ferris.rawbin0 -> 11008 bytes
-rw-r--r--examples/rp23/build.rs35
-rw-r--r--examples/rp23/memory.x74
-rw-r--r--examples/rp23/src/bin/adc.rs63
-rw-r--r--examples/rp23/src/bin/adc_dma.rs69
-rw-r--r--examples/rp23/src/bin/assign_resources.rs94
-rw-r--r--examples/rp23/src/bin/blinky.rs44
-rw-r--r--examples/rp23/src/bin/blinky_two_channels.rs65
-rw-r--r--examples/rp23/src/bin/blinky_two_tasks.rs64
-rw-r--r--examples/rp23/src/bin/button.rs43
-rw-r--r--examples/rp23/src/bin/debounce.rs95
-rw-r--r--examples/rp23/src/bin/flash.rs140
-rw-r--r--examples/rp23/src/bin/gpio_async.rs55
-rw-r--r--examples/rp23/src/bin/gpout.rs52
-rw-r--r--examples/rp23/src/bin/i2c_async.rs125
-rw-r--r--examples/rp23/src/bin/i2c_async_embassy.rs100
-rw-r--r--examples/rp23/src/bin/i2c_blocking.rs89
-rw-r--r--examples/rp23/src/bin/i2c_slave.rs132
-rw-r--r--examples/rp23/src/bin/interrupt.rs109
-rw-r--r--examples/rp23/src/bin/multicore.rs81
-rw-r--r--examples/rp23/src/bin/multiprio.rs160
-rw-r--r--examples/rp23/src/bin/otp.rs46
-rw-r--r--examples/rp23/src/bin/pio_async.rs145
-rw-r--r--examples/rp23/src/bin/pio_dma.rs98
-rw-r--r--examples/rp23/src/bin/pio_hd44780.rs255
-rw-r--r--examples/rp23/src/bin/pio_i2s.rs140
-rw-r--r--examples/rp23/src/bin/pio_pwm.rs133
-rw-r--r--examples/rp23/src/bin/pio_rotary_encoder.rs95
-rw-r--r--examples/rp23/src/bin/pio_servo.rs223
-rw-r--r--examples/rp23/src/bin/pio_stepper.rs183
-rw-r--r--examples/rp23/src/bin/pio_ws2812.rs176
-rw-r--r--examples/rp23/src/bin/pwm.rs44
-rw-r--r--examples/rp23/src/bin/pwm_input.rs41
-rw-r--r--examples/rp23/src/bin/rosc.rs46
-rw-r--r--examples/rp23/src/bin/shared_bus.rs130
-rw-r--r--examples/rp23/src/bin/sharing.rs165
-rw-r--r--examples/rp23/src/bin/spi.rs61
-rw-r--r--examples/rp23/src/bin/spi_async.rs46
-rw-r--r--examples/rp23/src/bin/spi_display.rs327
-rw-r--r--examples/rp23/src/bin/spi_sdmmc.rs98
-rw-r--r--examples/rp23/src/bin/trng.rs64
-rw-r--r--examples/rp23/src/bin/uart.rs40
-rw-r--r--examples/rp23/src/bin/uart_buffered_split.rs73
-rw-r--r--examples/rp23/src/bin/uart_r503.rs173
-rw-r--r--examples/rp23/src/bin/uart_unidir.rs65
-rw-r--r--examples/rp23/src/bin/usb_webusb.rs170
-rw-r--r--examples/rp23/src/bin/watchdog.rs66
-rw-r--r--examples/rp23/src/bin/zerocopy.rs109
-rw-r--r--examples/std/Cargo.toml6
-rw-r--r--examples/std/src/bin/net.rs18
-rw-r--r--examples/std/src/bin/net_dns.rs18
-rw-r--r--examples/std/src/bin/net_ppp.rs19
-rw-r--r--examples/std/src/bin/net_udp.rs16
-rw-r--r--examples/std/src/bin/tcp_accept.rs17
-rw-r--r--examples/stm32c0/Cargo.toml7
-rw-r--r--examples/stm32f0/Cargo.toml8
-rw-r--r--examples/stm32f0/src/bin/adc.rs12
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs9
-rw-r--r--examples/stm32f1/Cargo.toml10
-rw-r--r--examples/stm32f1/src/bin/adc.rs6
-rw-r--r--examples/stm32f1/src/bin/can.rs124
-rw-r--r--examples/stm32f1/src/bin/hello.rs4
-rw-r--r--examples/stm32f1/src/bin/input_capture.rs52
-rw-r--r--examples/stm32f1/src/bin/pwm_input.rs54
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs22
-rw-r--r--examples/stm32f2/Cargo.toml7
-rw-r--r--examples/stm32f2/src/bin/pll.rs2
-rw-r--r--examples/stm32f3/Cargo.toml9
-rw-r--r--examples/stm32f3/src/bin/blocking-tsc.rs98
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs9
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f334/.cargo/config.toml2
-rw-r--r--examples/stm32f334/Cargo.toml9
-rw-r--r--examples/stm32f334/src/bin/adc.rs8
-rw-r--r--examples/stm32f334/src/bin/opamp.rs8
-rw-r--r--examples/stm32f334/src/bin/pwm.rs3
-rw-r--r--examples/stm32f4/Cargo.toml16
-rw-r--r--examples/stm32f4/src/bin/adc.rs10
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs83
-rw-r--r--examples/stm32f4/src/bin/can.rs24
-rw-r--r--examples/stm32f4/src/bin/dac.rs2
-rw-r--r--examples/stm32f4/src/bin/eth.rs24
-rw-r--r--examples/stm32f4/src/bin/eth_compliance_test.rs77
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs134
-rw-r--r--examples/stm32f4/src/bin/i2c.rs18
-rw-r--r--examples/stm32f4/src/bin/i2c_comparison.rs2
-rw-r--r--examples/stm32f4/src/bin/i2s_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/input_capture.rs52
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs9
-rw-r--r--examples/stm32f4/src/bin/pwm_input.rs54
-rw-r--r--examples/stm32f4/src/bin/rtc.rs2
-rw-r--r--examples/stm32f4/src/bin/spi.rs3
-rw-r--r--examples/stm32f4/src/bin/usart.rs3
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs42
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs232
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs158
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs24
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs26
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs5
-rw-r--r--examples/stm32f4/src/bin/ws2812_spi.rs6
-rw-r--r--examples/stm32f469/.cargo/config.toml9
-rw-r--r--examples/stm32f469/Cargo.toml22
-rw-r--r--examples/stm32f469/build.rs5
-rw-r--r--examples/stm32f469/src/bin/dsi_bsp.rs694
-rw-r--r--examples/stm32f469/src/bin/ferris.bin70
-rw-r--r--examples/stm32f7/Cargo.toml12
-rw-r--r--examples/stm32f7/src/bin/adc.rs8
-rw-r--r--examples/stm32f7/src/bin/can.rs37
-rw-r--r--examples/stm32f7/src/bin/cryp.rs80
-rw-r--r--examples/stm32f7/src/bin/eth.rs24
-rw-r--r--examples/stm32f7/src/bin/hash.rs24
-rw-r--r--examples/stm32f7/src/bin/qspi.rs301
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs26
-rw-r--r--examples/stm32g0/Cargo.toml11
-rw-r--r--examples/stm32g0/src/bin/adc.rs34
-rw-r--r--examples/stm32g0/src/bin/adc_dma.rs44
-rw-r--r--examples/stm32g0/src/bin/adc_oversampling.rs43
-rw-r--r--examples/stm32g0/src/bin/hf_timer.rs45
-rw-r--r--examples/stm32g0/src/bin/i2c_async.rs48
-rw-r--r--examples/stm32g0/src/bin/input_capture.rs67
-rw-r--r--examples/stm32g0/src/bin/pwm_complementary.rs57
-rw-r--r--examples/stm32g0/src/bin/pwm_input.rs65
-rw-r--r--examples/stm32g0/src/bin/rtc.rs31
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs3
-rw-r--r--examples/stm32g0/src/bin/usart.rs25
-rw-r--r--examples/stm32g0/src/bin/usart_buffered.rs34
-rw-r--r--examples/stm32g0/src/bin/usart_dma.rs27
-rw-r--r--examples/stm32g0/src/bin/usb_serial.rs12
-rw-r--r--examples/stm32g4/Cargo.toml13
-rw-r--r--examples/stm32g4/src/bin/adc.rs37
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs47
-rw-r--r--examples/stm32g4/src/bin/adc_oversampling.rs57
-rw-r--r--examples/stm32g4/src/bin/can.rs212
-rw-r--r--examples/stm32g4/src/bin/pll.rs28
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs86
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs47
-rw-r--r--examples/stm32h5/Cargo.toml12
-rw-r--r--examples/stm32h5/src/bin/can.rs92
-rw-r--r--examples/stm32h5/src/bin/cordic.rs78
-rw-r--r--examples/stm32h5/src/bin/eth.rs20
-rw-r--r--examples/stm32h5/src/bin/stop.rs71
-rw-r--r--examples/stm32h5/src/bin/usart.rs8
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs17
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs11
-rw-r--r--examples/stm32h7/Cargo.toml14
-rw-r--r--examples/stm32h7/build.rs30
-rw-r--r--examples/stm32h7/memory.x14
-rw-r--r--examples/stm32h7/src/bin/adc.rs12
-rw-r--r--examples/stm32h7/src/bin/adc_dma.rs76
-rw-r--r--examples/stm32h7/src/bin/camera.rs4
-rw-r--r--examples/stm32h7/src/bin/can.rs92
-rw-r--r--examples/stm32h7/src/bin/dac.rs2
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs42
-rw-r--r--examples/stm32h7/src/bin/eth.rs38
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs22
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs22
-rw-r--r--examples/stm32h7/src/bin/i2c_shared.rs111
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs71
-rw-r--r--examples/stm32h7/src/bin/multiprio.rs150
-rw-r--r--examples/stm32h7/src/bin/rtc.rs4
-rw-r--r--examples/stm32h7/src/bin/sai.rs186
-rw-r--r--examples/stm32h7/src/bin/spi.rs7
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs84
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs4
-rw-r--r--examples/stm32h7/src/bin/usart.rs8
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs17
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs26
-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/stm32h755cm4/.cargo/config.toml8
-rw-r--r--examples/stm32h755cm4/Cargo.toml75
-rw-r--r--examples/stm32h755cm4/build.rs35
-rw-r--r--examples/stm32h755cm4/memory.x15
-rw-r--r--examples/stm32h755cm4/src/bin/blinky.rs32
-rw-r--r--examples/stm32h755cm7/.cargo/config.toml8
-rw-r--r--examples/stm32h755cm7/Cargo.toml75
-rw-r--r--examples/stm32h755cm7/build.rs35
-rw-r--r--examples/stm32h755cm7/memory.x15
-rw-r--r--examples/stm32h755cm7/src/bin/blinky.rs54
-rw-r--r--examples/stm32h7rs/.cargo/config.toml8
-rw-r--r--examples/stm32h7rs/Cargo.toml73
-rw-r--r--examples/stm32h7rs/build.rs5
-rw-r--r--examples/stm32h7rs/src/bin/blinky.rs51
-rw-r--r--examples/stm32h7rs/src/bin/button_exti.rs25
-rw-r--r--examples/stm32h7rs/src/bin/can.rs98
-rw-r--r--examples/stm32h7rs/src/bin/i2c.rs42
-rw-r--r--examples/stm32h7rs/src/bin/mco.rs29
-rw-r--r--examples/stm32h7rs/src/bin/multiprio.rs150
-rw-r--r--examples/stm32h7rs/src/bin/rng.rs26
-rw-r--r--examples/stm32h7rs/src/bin/rtc.rs36
-rw-r--r--examples/stm32h7rs/src/bin/signal.rs36
-rw-r--r--examples/stm32h7rs/src/bin/spi.rs49
-rw-r--r--examples/stm32h7rs/src/bin/spi_dma.rs46
-rw-r--r--examples/stm32h7rs/src/bin/usart.rs39
-rw-r--r--examples/stm32h7rs/src/bin/usart_dma.rs47
-rw-r--r--examples/stm32h7rs/src/bin/usart_split.rs47
-rw-r--r--examples/stm32h7rs/src/bin/usb_serial.rs140
-rw-r--r--examples/stm32l0/Cargo.toml9
-rw-r--r--examples/stm32l0/src/bin/adc.rs12
-rw-r--r--examples/stm32l0/src/bin/async-tsc.rs122
-rw-r--r--examples/stm32l0/src/bin/blocking-tsc.rs116
-rw-r--r--examples/stm32l0/src/bin/dds.rs116
-rw-r--r--examples/stm32l0/src/bin/spi.rs3
-rw-r--r--examples/stm32l1/Cargo.toml10
-rw-r--r--examples/stm32l1/src/bin/spi.rs3
-rw-r--r--examples/stm32l1/src/bin/usb_serial.rs6
-rw-r--r--examples/stm32l4/.cargo/config.toml2
-rw-r--r--examples/stm32l4/Cargo.toml11
-rw-r--r--examples/stm32l4/src/bin/adc.rs21
-rw-r--r--examples/stm32l4/src/bin/can.rs68
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs40
-rw-r--r--examples/stm32l4/src/bin/i2c.rs18
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs18
-rw-r--r--examples/stm32l4/src/bin/rng.rs4
-rw-r--r--examples/stm32l4/src/bin/rtc.rs6
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs52
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs3
-rw-r--r--examples/stm32l4/src/bin/usart.rs3
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs53
-rw-r--r--examples/stm32l5/Cargo.toml11
-rw-r--r--examples/stm32l5/src/bin/rng.rs4
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs48
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs42
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs30
-rw-r--r--examples/stm32u0/.cargo/config.toml9
-rw-r--r--examples/stm32u0/Cargo.toml29
-rw-r--r--examples/stm32u0/build.rs5
-rw-r--r--examples/stm32u0/src/bin/adc.rs30
-rw-r--r--examples/stm32u0/src/bin/blinky.rs26
-rw-r--r--examples/stm32u0/src/bin/button.rs24
-rw-r--r--examples/stm32u0/src/bin/button_exti.rs25
-rw-r--r--examples/stm32u0/src/bin/crc.rs31
-rw-r--r--examples/stm32u0/src/bin/dac.rs35
-rw-r--r--examples/stm32u0/src/bin/flash.rs43
-rw-r--r--examples/stm32u0/src/bin/i2c.rs21
-rw-r--r--examples/stm32u0/src/bin/rng.rs43
-rw-r--r--examples/stm32u0/src/bin/rtc.rs49
-rw-r--r--examples/stm32u0/src/bin/spi.rs30
-rw-r--r--examples/stm32u0/src/bin/usart.rs25
-rw-r--r--examples/stm32u0/src/bin/usb_serial.rs109
-rw-r--r--examples/stm32u0/src/bin/wdt.rs41
-rw-r--r--examples/stm32u5/Cargo.toml14
-rw-r--r--examples/stm32u5/src/bin/flash.rs55
-rw-r--r--examples/stm32u5/src/bin/i2c.rs25
-rw-r--r--examples/stm32u5/src/bin/rng.rs25
-rw-r--r--examples/stm32u5/src/bin/tsc.rs95
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs44
-rw-r--r--examples/stm32wb/.cargo/config.toml2
-rw-r--r--examples/stm32wb/Cargo.toml7
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs1
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs1
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs1
-rw-r--r--examples/stm32wb/src/bin/mac_ffd_net.rs1
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs1
-rw-r--r--examples/stm32wba/Cargo.toml7
-rw-r--r--examples/stm32wl/Cargo.toml9
-rw-r--r--examples/stm32wl/memory.x15
-rw-r--r--examples/stm32wl/src/bin/blinky.rs8
-rw-r--r--examples/stm32wl/src/bin/button.rs8
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs8
-rw-r--r--examples/stm32wl/src/bin/flash.rs8
-rw-r--r--examples/stm32wl/src/bin/random.rs11
-rw-r--r--examples/stm32wl/src/bin/rtc.rs15
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs11
-rw-r--r--examples/wasm/Cargo.toml7
403 files changed, 17890 insertions, 1389 deletions
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 86f6676cb..93e49faef 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -5,13 +5,13 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } 12embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] }
13embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } 13embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] }
14embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
15 15
16defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
17defmt-rtt = { version = "0.4", optional = true } 17defmt-rtt = { version = "0.4", optional = true }
@@ -25,3 +25,10 @@ cortex-m-rt = "0.7.0"
25ed25519-dalek = ["embassy-boot/ed25519-dalek"] 25ed25519-dalek = ["embassy-boot/ed25519-dalek"]
26ed25519-salty = ["embassy-boot/ed25519-salty"] 26ed25519-salty = ["embassy-boot/ed25519-salty"]
27skip-include = [] 27skip-include = []
28defmt = [
29 "dep:defmt",
30 "dep:defmt-rtt",
31 "embassy-nrf/defmt",
32 "embassy-boot-nrf/defmt",
33 "embassy-sync/defmt",
34]
diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs
index cd1a264c4..e1da69328 100644
--- a/examples/boot/application/nrf/build.rs
+++ b/examples/boot/application/nrf/build.rs
@@ -31,4 +31,7 @@ fn main() {
31 31
32 println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36 }
34} 37}
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 851a3d721..2c1d1a7bb 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -2,6 +2,9 @@
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4 4
5#[cfg(feature = "defmt")]
6use defmt_rtt as _;
7use embassy_boot::State;
5use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
6use embassy_embedded_hal::adapter::BlockingAsync; 9use embassy_embedded_hal::adapter::BlockingAsync;
7use embassy_executor::Spawner; 10use embassy_executor::Spawner;
@@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) {
22 25
23 let mut button = Input::new(p.P0_11, Pull::Up); 26 let mut button = Input::new(p.P0_11, Pull::Up);
24 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 27 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
28 let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard);
25 29
26 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 30 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
27 //let mut button = Input::new(p.P1_02, Pull::Up); 31 //let mut button = Input::new(p.P1_02, Pull::Up);
@@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) {
53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); 57 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
54 let mut magic = [0; 4]; 58 let mut magic = [0; 4];
55 let mut updater = FirmwareUpdater::new(config, &mut magic); 59 let mut updater = FirmwareUpdater::new(config, &mut magic);
60 let state = updater.get_state().await.unwrap();
61 if state == State::Revert {
62 led_reverted.set_low();
63 } else {
64 led_reverted.set_high();
65 }
66
56 loop { 67 loop {
57 led.set_low(); 68 led.set_low();
58 button.wait_for_any_edge().await; 69 button.wait_for_any_edge().await;
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index 70741a0ce..8bb8afdfe 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } 11embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
12embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } 12embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 1cb143820..1c2934298 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 8858ae3da..b608b2e01 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32f3/src/bin/b.rs b/examples/boot/application/stm32f3/src/bin/b.rs
index 22ba82d5e..b1a505631 100644
--- a/examples/boot/application/stm32f3/src/bin/b.rs
+++ b/examples/boot/application/stm32f3/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index c4ae461a5..09e34c7df 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-stm32/defmt", 28 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 29 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt", 30 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index d3df11fe4..172b4c235 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/boot/application/stm32f7/src/bin/b.rs b/examples/boot/application/stm32f7/src/bin/b.rs
index 190477204..6bc9c9ab8 100644
--- a/examples/boot/application/stm32f7/src/bin/b.rs
+++ b/examples/boot/application/stm32f7/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 995487cdd..5e7f4d5e7 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-stm32/defmt", 28 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 29 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt", 30 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index f61ac1f71..c1b1a267a 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/boot/application/stm32h7/src/bin/b.rs b/examples/boot/application/stm32h7/src/bin/b.rs
index 5f3f35207..13bdae1f1 100644
--- a/examples/boot/application/stm32h7/src/bin/b.rs
+++ b/examples/boot/application/stm32h7/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index b2abc005c..60fdcfafb 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index f066c1139..dcc10e5c6 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l0/src/bin/b.rs b/examples/boot/application/stm32l0/src/bin/b.rs
index 6bf00f41a..a59c6f540 100644
--- a/examples/boot/application/stm32l0/src/bin/b.rs
+++ b/examples/boot/application/stm32l0/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 7203e6350..fe3ab2c04 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index f066c1139..dcc10e5c6 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l1/src/bin/b.rs b/examples/boot/application/stm32l1/src/bin/b.rs
index 6bf00f41a..a59c6f540 100644
--- a/examples/boot/application/stm32l1/src/bin/b.rs
+++ b/examples/boot/application/stm32l1/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index ec134f394..169856358 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index a0079ee33..7f8015c04 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l4/src/bin/b.rs b/examples/boot/application/stm32l4/src/bin/b.rs
index 22ba82d5e..b1a505631 100644
--- a/examples/boot/application/stm32l4/src/bin/b.rs
+++ b/examples/boot/application/stm32l4/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 0bdf94331..7cef8fe0d 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -5,13 +5,13 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } 15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
16 16
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index 37c3d7d90..0ab99ff90 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
@@ -41,7 +41,6 @@ async fn main(_spawner: Spawner) {
41 config.product = Some("USB-DFU Runtime example"); 41 config.product = Some("USB-DFU Runtime example");
42 config.serial_number = Some("1235678"); 42 config.serial_number = Some("1235678");
43 43
44 let mut device_descriptor = [0; 256];
45 let mut config_descriptor = [0; 256]; 44 let mut config_descriptor = [0; 256];
46 let mut bos_descriptor = [0; 256]; 45 let mut bos_descriptor = [0; 256];
47 let mut control_buf = [0; 64]; 46 let mut control_buf = [0; 64];
@@ -49,7 +48,6 @@ async fn main(_spawner: Spawner) {
49 let mut builder = Builder::new( 48 let mut builder = Builder::new(
50 driver, 49 driver,
51 config, 50 config,
52 &mut device_descriptor,
53 &mut config_descriptor, 51 &mut config_descriptor,
54 &mut bos_descriptor, 52 &mut bos_descriptor,
55 &mut [], 53 &mut [],
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index e38e9f3af..860a835a9 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -5,12 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index e1d4e7fa8..20109e37e 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -5,7 +5,8 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08018000, LENGTH = 68K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
9 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128
9} 10}
10 11
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); 12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
@@ -13,3 +14,11 @@ __bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - O
13 14
14__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); 15__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
15__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); 16__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
17
18SECTIONS
19{
20 .shared_data :
21 {
22 *(.shared_data)
23 } > SHARED_RAM
24}
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 2fb16bdc4..127de0237 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -1,7 +1,9 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4use core::mem::MaybeUninit;
5
6#[cfg(feature = "defmt")]
5use defmt_rtt::*; 7use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 9use embassy_embedded_hal::adapter::BlockingAsync;
@@ -9,6 +11,7 @@ use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 12use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Level, Output, Pull, Speed};
14use embassy_stm32::SharedData;
12use embassy_sync::mutex::Mutex; 15use embassy_sync::mutex::Mutex;
13use panic_reset as _; 16use panic_reset as _;
14 17
@@ -17,9 +20,12 @@ static APP_B: &[u8] = &[0, 1, 2, 3];
17#[cfg(not(feature = "skip-include"))] 20#[cfg(not(feature = "skip-include"))]
18static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
19 22
23#[link_section = ".shared_data"]
24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
25
20#[embassy_executor::main] 26#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 28 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
23 let flash = Flash::new_blocking(p.FLASH); 29 let flash = Flash::new_blocking(p.FLASH);
24 let flash = Mutex::new(BlockingAsync::new(flash)); 30 let flash = Mutex::new(BlockingAsync::new(flash));
25 31
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index 8dd15d8cd..768dadf8b 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -1,16 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4use core::mem::MaybeUninit;
5
6#[cfg(feature = "defmt")]
5use defmt_rtt::*; 7use defmt_rtt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::SharedData;
8use embassy_time::Timer; 11use embassy_time::Timer;
9use panic_reset as _; 12use panic_reset as _;
10 13
14#[link_section = ".shared_data"]
15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
16
11#[embassy_executor::main] 17#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
14 let mut led = Output::new(p.PB15, Level::High, Speed::Low); 20 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
15 21
16 loop { 22 loop {
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index 3e41d1479..9d5d51a13 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -12,20 +12,20 @@ defmt-rtt = { version = "0.4", optional = true }
12embassy-nrf = { path = "../../../../embassy-nrf", features = [] } 12embassy-nrf = { path = "../../../../embassy-nrf", features = [] }
13embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } 13embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 16cortex-m-rt = { version = "0.7" }
17cfg-if = "1.0.0" 17cfg-if = "1.0.0"
18 18
19[features] 19[features]
20defmt = [ 20defmt = [
21 "dep:defmt", 21 "dep:defmt",
22 "dep:defmt-rtt",
22 "embassy-boot-nrf/defmt", 23 "embassy-boot-nrf/defmt",
23 "embassy-nrf/defmt", 24 "embassy-nrf/defmt",
24] 25]
25softdevice = [ 26softdevice = [
26 "embassy-boot-nrf/softdevice", 27 "embassy-boot-nrf/softdevice",
27] 28]
28debug = ["defmt-rtt", "defmt"]
29 29
30[profile.dev] 30[profile.dev]
31debug = 2 31debug = 2
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index 3cf61a002..9df396e5e 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-rp = { path = "../../../../embassy-rp", features = [] } 12embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] }
13embassy-boot-rp = { path = "../../../../embassy-boot-rp" } 13embassy-boot-rp = { path = "../../../../embassy-boot-rp" }
14embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 14embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
15embassy-time = { path = "../../../../embassy-time", features = [] } 15embassy-time = { path = "../../../../embassy-time", features = [] }
16 16
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
@@ -23,10 +23,10 @@ cfg-if = "1.0.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-boot-rp/defmt", 27 "embassy-boot-rp/defmt",
27 "embassy-rp/defmt", 28 "embassy-rp/defmt",
28] 29]
29debug = ["defmt-rtt", "defmt"]
30 30
31[profile.release] 31[profile.release]
32debug = true 32debug = true
diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x
index c3b54976e..88b5bbb15 100644
--- a/examples/boot/bootloader/rp/memory.x
+++ b/examples/boot/bootloader/rp/memory.x
@@ -2,7 +2,7 @@ MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K 5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100
6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K 6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K 7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
8 DFU : ORIGIN = 0x10087000, LENGTH = 516K 8 DFU : ORIGIN = 0x10087000, LENGTH = 516K
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
index 313187adc..b91b05412 100644
--- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -15,15 +15,14 @@ cortex-m = { version = "0.7.6", features = [
15 "inline-asm", 15 "inline-asm",
16 "critical-section-single-core", 16 "critical-section-single-core",
17] } 17] }
18embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 18embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
19cortex-m-rt = { version = "0.7" } 19cortex-m-rt = { version = "0.7" }
20embedded-storage = "0.3.1" 20embedded-storage = "0.3.1"
21embedded-storage-async = "0.4.0" 21embedded-storage-async = "0.4.0"
22cfg-if = "1.0.0" 22cfg-if = "1.0.0"
23 23
24[features] 24[features]
25defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] 25defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"]
26debug = ["defmt-rtt", "defmt"]
27 26
28[profile.dev] 27[profile.dev]
29debug = 2 28debug = 2
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
index 3de3171cd..cd6c0bc84 100644
--- a/examples/boot/bootloader/stm32-dual-bank/README.md
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -2,16 +2,16 @@
2 2
3## Overview 3## Overview
4 4
5This bootloader leverages `embassy-boot` to interact with the flash. 5This bootloader leverages `embassy-boot` to interact with the flash.
6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. 6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. 7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
8 8
9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. 9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
10 10
11## Memory Configuration 11## Memory Configuration
12 12
13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. 13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. 14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
15 15
16### Symbol Definitions 16### Symbol Definitions
17 17
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 74c01b0f4..541186949 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true }
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 16cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1" 17embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 18embedded-storage-async = "0.4.0"
@@ -21,10 +21,10 @@ cfg-if = "1.0.0"
21[features] 21[features]
22defmt = [ 22defmt = [
23 "dep:defmt", 23 "dep:defmt",
24 "dep:defmt-rtt",
24 "embassy-boot-stm32/defmt", 25 "embassy-boot-stm32/defmt",
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26] 27]
27debug = ["defmt-rtt", "defmt"]
28 28
29[profile.dev] 29[profile.dev]
30debug = 2 30debug = 2
diff --git a/examples/boot/bootloader/stm32/memory.x b/examples/boot/bootloader/stm32/memory.x
index b6f185ef7..198290520 100644
--- a/examples/boot/bootloader/stm32/memory.x
+++ b/examples/boot/bootloader/stm32/memory.x
@@ -2,7 +2,7 @@ MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 24K 4 FLASH : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 8K
6 ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K 6 ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08010000, LENGTH = 36K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 854f94d85..050b672ce 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -12,24 +12,24 @@ defmt-rtt = { version = "0.4", optional = true }
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 16cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1" 17embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 18embedded-storage-async = "0.4.0"
19cfg-if = "1.0.0" 19cfg-if = "1.0.0"
20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } 20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] }
21embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } 21embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb", default-features = false }
22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } 22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" }
23 23
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-stm32/defmt", 29 "embassy-stm32/defmt",
29 "embassy-usb/defmt", 30 "embassy-usb/defmt",
30 "embassy-usb-dfu/defmt" 31 "embassy-usb-dfu/defmt"
31] 32]
32debug = ["defmt-rtt", "defmt"]
33 33
34[profile.dev] 34[profile.dev]
35debug = 2 35debug = 2
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index d989fbfdf..093b39f9d 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -49,7 +49,6 @@ fn main() -> ! {
49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]); 49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); 50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
51 51
52 let mut device_descriptor = [0; 256];
53 let mut config_descriptor = [0; 256]; 52 let mut config_descriptor = [0; 256];
54 let mut bos_descriptor = [0; 256]; 53 let mut bos_descriptor = [0; 256];
55 let mut control_buf = [0; 4096]; 54 let mut control_buf = [0; 4096];
@@ -57,7 +56,6 @@ fn main() -> ! {
57 let mut builder = Builder::new( 56 let mut builder = Builder::new(
58 driver, 57 driver,
59 config, 58 config,
60 &mut device_descriptor,
61 &mut config_descriptor, 59 &mut config_descriptor,
62 &mut bos_descriptor, 60 &mut bos_descriptor,
63 &mut [], 61 &mut [],
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 17210994b..98a678815 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -15,15 +15,14 @@ log = [
15] 15]
16 16
17[dependencies] 17[dependencies]
18embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } 18embassy-sync = { version = "0.6.0", path = "../../embassy-sync" }
19embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } 19embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] }
20embassy-time = { version = "0.3.0", path = "../../embassy-time" } 20embassy-time = { version = "0.3.2", path = "../../embassy-time" }
21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 21embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
22 22
23cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 23cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
24cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
25panic-probe = { version = "0.3" } 25panic-probe = { version = "0.3" }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27rand = { version = "0.8.4", default-features = false } 26rand = { version = "0.8.4", default-features = false }
28serde = { version = "1.0.136", default-features = false } 27serde = { version = "1.0.136", default-features = false }
29rtos-trace = "0.1.3" 28rtos-trace = "0.1.3"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index 06c3d20cb..93a19bea7 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11 11
12defmt = "0.3" 12defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
diff --git a/examples/nrf52810/.cargo/config.toml b/examples/nrf52810/.cargo/config.toml
new file mode 100644
index 000000000..917a5364a
--- /dev/null
+++ b/examples/nrf52810/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82810_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF52810_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
new file mode 100644
index 000000000..0e3e81c3f
--- /dev/null
+++ b/examples/nrf52810/Cargo.toml
@@ -0,0 +1,24 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52810-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13
14defmt = "0.3"
15defmt-rtt = "0.4"
16
17fixed = "1.10.0"
18static_cell = { version = "2" }
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0"
21panic-probe = { version = "0.3", features = ["print-defmt"] }
22
23[profile.release]
24debug = 2
diff --git a/examples/nrf52810/build.rs b/examples/nrf52810/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52810/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/nrf52810/memory.x b/examples/nrf52810/memory.x
new file mode 100644
index 000000000..7cf560e44
--- /dev/null
+++ b/examples/nrf52810/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x00000000, LENGTH = 256K
5 RAM : ORIGIN = 0x20000000, LENGTH = 24K
6
7}
diff --git a/examples/nrf52810/src/bin/blinky.rs b/examples/nrf52810/src/bin/blinky.rs
new file mode 100644
index 000000000..1da039f7d
--- /dev/null
+++ b/examples/nrf52810/src/bin/blinky.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_18, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 Timer::after_millis(300).await;
17 led.set_low();
18 Timer::after_millis(300).await;
19 }
20}
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index d91f58d0e..7fae7aefc 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8rtic = { version = "2", features = ["thumbv7-backend"] } 8rtic = { version = "2", features = ["thumbv7-backend"] }
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -18,7 +18,6 @@ defmt-rtt = "0.4"
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22 21
23[profile.release] 22[profile.release]
24debug = 2 23debug = 2
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index abb995be6..17fa6234d 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embedded-io = { version = "0.6.0", features = ["defmt-03"] } 15embedded-io = { version = "0.6.0", features = ["defmt-03"] }
16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
@@ -25,10 +25,9 @@ static_cell = { version = "2" }
25cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 25cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
26cortex-m-rt = "0.7.0" 26cortex-m-rt = "0.7.0"
27panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "0.3", features = ["print-defmt"] }
28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29rand = { version = "0.8.4", default-features = false } 28rand = { version = "0.8.4", default-features = false }
30embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
31usbd-hid = "0.6.0" 30usbd-hid = "0.8.1"
32serde = { version = "1.0.136", default-features = false } 31serde = { version = "1.0.136", default-features = false }
33embedded-hal = { version = "1.0" } 32embedded-hal = { version = "1.0" }
34embedded-hal-async = { version = "1.0" } 33embedded-hal-async = { version = "1.0" }
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
index 7fcea9dbd..e06ba1c73 100644
--- a/examples/nrf52840/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -35,8 +35,8 @@ async fn main(spawner: Spawner) {
35 35
36 loop { 36 loop {
37 match CHANNEL.receive().await { 37 match CHANNEL.receive().await {
38 LedState::On => led.set_high(), 38 LedState::On => led.set_low(),
39 LedState::Off => led.set_low(), 39 LedState::Off => led.set_high(),
40 } 40 }
41 } 41 }
42} 42}
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index 3095a04ec..29f70f91c 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -33,8 +33,8 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta
33 33
34 loop { 34 loop {
35 match receiver.receive().await { 35 match receiver.receive().await {
36 LedState::On => led.set_high(), 36 LedState::On => led.set_low(),
37 LedState::Off => led.set_low(), 37 LedState::Off => led.set_high(),
38 } 38 }
39 } 39 }
40} 40}
diff --git a/examples/nrf52840/src/bin/egu.rs b/examples/nrf52840/src/bin/egu.rs
new file mode 100644
index 000000000..8bf712697
--- /dev/null
+++ b/examples/nrf52840/src/bin/egu.rs
@@ -0,0 +1,43 @@
1//! This example shows the use of the EGU peripheral combined with PPI.
2//!
3//! It chains events from button -> egu0-trigger0 -> egu0-trigger1 -> led
4#![no_std]
5#![no_main]
6
7use embassy_executor::Spawner;
8use embassy_nrf::egu::{Egu, TriggerNumber};
9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
10use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity};
11use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2};
12use embassy_nrf::ppi::Ppi;
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let led1 = Output::new(p.P0_13, Level::High, OutputDrive::Standard);
21 let btn1 = Input::new(p.P0_11, Pull::Up);
22
23 let mut egu1 = Egu::new(p.EGU0);
24 let led1 = OutputChannel::new(p.GPIOTE_CH0, led1, OutputChannelPolarity::Toggle);
25 let btn1 = InputChannel::new(p.GPIOTE_CH1, btn1, InputChannelPolarity::LoToHi);
26
27 let trigger0 = egu1.trigger(TriggerNumber::Trigger0);
28 let trigger1 = egu1.trigger(TriggerNumber::Trigger1);
29
30 let mut ppi1: Ppi<PPI_CH0, 1, 1> = Ppi::new_one_to_one(p.PPI_CH0, btn1.event_in(), trigger0.task());
31 ppi1.enable();
32
33 let mut ppi2: Ppi<PPI_CH1, 1, 1> = Ppi::new_one_to_one(p.PPI_CH1, trigger0.event(), trigger1.task());
34 ppi2.enable();
35
36 let mut ppi3: Ppi<PPI_CH2, 1, 1> = Ppi::new_one_to_one(p.PPI_CH2, trigger1.event(), led1.task_out());
37 ppi3.enable();
38
39 defmt::info!("Push the button to toggle the LED");
40 loop {
41 Timer::after(Duration::from_secs(60)).await;
42 }
43}
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 279f32edc..0946492fe 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_net_enc28j60::Enc28j60; 8use embassy_net_enc28j60::Enc28j60;
9use embassy_nrf::gpio::{Level, Output, OutputDrive}; 9use embassy_nrf::gpio::{Level, Output, OutputDrive};
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
@@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs {
23 23
24#[embassy_executor::task] 24#[embassy_executor::task]
25async fn net_task( 25async fn net_task(
26 stack: &'static Stack< 26 mut runner: embassy_net::Runner<
27 'static,
27 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, 28 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>,
28 >, 29 >,
29) -> ! { 30) -> ! {
30 stack.run().await 31 runner.run().await
31} 32}
32 33
33#[embassy_executor::main] 34#[embassy_executor::main]
@@ -66,18 +67,10 @@ async fn main(spawner: Spawner) {
66 let seed = u64::from_le_bytes(seed); 67 let seed = u64::from_le_bytes(seed);
67 68
68 // Init network stack 69 // Init network stack
69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 70 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
70 static STACK: StaticCell< 71 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>, 72
72 > = StaticCell::new(); 73 unwrap!(spawner.spawn(net_task(runner)));
73 let stack = STACK.init(Stack::new(
74 device,
75 config,
76 RESOURCES.init(StackResources::<2>::new()),
77 seed,
78 ));
79
80 unwrap!(spawner.spawn(net_task(stack)));
81 74
82 // And now we can use it! 75 // And now we can use it!
83 76
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
index e254d613d..dcfe7723a 100644
--- a/examples/nrf52840/src/bin/gpiote_channel.rs
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
@@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) {
61 } 61 }
62 }; 62 };
63 63
64 futures::join!(button1, button2, button3, button4); 64 embassy_futures::join::join4(button1, button2, button3, button4).await;
65} 65}
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index b634d8569..797be93a7 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -80,7 +80,7 @@ async fn run_med() {
80 info!(" [med] Starting long computation"); 80 info!(" [med] Starting long computation");
81 81
82 // Spin-wait to simulate a long CPU computation 82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(32_000_000); // ~1 second 83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84 84
85 let end = Instant::now(); 85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33; 86 let ms = end.duration_since(start).as_ticks() / 33;
@@ -97,7 +97,7 @@ async fn run_low() {
97 info!("[low] Starting long computation"); 97 info!("[low] Starting long computation");
98 98
99 // Spin-wait to simulate a long CPU computation 99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(64_000_000); // ~2 seconds 100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101 101
102 let end = Instant::now(); 102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33; 103 let ms = end.duration_since(start).as_ticks() / 33;
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 3469c6e5f..b07adac1f 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -6,7 +6,7 @@ use core::mem;
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_net::tcp::TcpSocket; 8use embassy_net::tcp::TcpSocket;
9use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
12use embassy_nrf::usb::Driver; 12use embassy_nrf::usb::Driver;
@@ -39,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 42async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
43 stack.run().await 43 runner.run().await
44} 44}
45 45
46#[embassy_executor::main] 46#[embassy_executor::main]
@@ -70,7 +70,6 @@ async fn main(spawner: Spawner) {
70 config.device_protocol = 0x01; 70 config.device_protocol = 0x01;
71 71
72 // Create embassy-usb DeviceBuilder using the driver and config. 72 // Create embassy-usb DeviceBuilder using the driver and config.
73 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
74 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 73 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
75 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 74 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
76 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); 75 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new();
@@ -78,7 +77,6 @@ async fn main(spawner: Spawner) {
78 let mut builder = Builder::new( 77 let mut builder = Builder::new(
79 driver, 78 driver,
80 config, 79 config,
81 &mut DEVICE_DESC.init([0; 256])[..],
82 &mut CONFIG_DESC.init([0; 256])[..], 80 &mut CONFIG_DESC.init([0; 256])[..],
83 &mut BOS_DESC.init([0; 256])[..], 81 &mut BOS_DESC.init([0; 256])[..],
84 &mut MSOS_DESC.init([0; 128])[..], 82 &mut MSOS_DESC.init([0; 128])[..],
@@ -117,11 +115,10 @@ async fn main(spawner: Spawner) {
117 let seed = u64::from_le_bytes(seed); 115 let seed = u64::from_le_bytes(seed);
118 116
119 // Init network stack 117 // Init network stack
120 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 118 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
121 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 119 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
122 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
123 120
124 unwrap!(spawner.spawn(net_task(stack))); 121 unwrap!(spawner.spawn(net_task(runner)));
125 122
126 // And now we can use it! 123 // And now we can use it!
127 124
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 3e86590c4..e33ee5866 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -50,12 +50,11 @@ async fn main(_spawner: Spawner) {
50 50
51 // Create embassy-usb DeviceBuilder using the driver and config. 51 // Create embassy-usb DeviceBuilder using the driver and config.
52 // It needs some buffers for building the descriptors. 52 // It needs some buffers for building the descriptors.
53 let mut device_descriptor = [0; 256];
54 let mut config_descriptor = [0; 256]; 53 let mut config_descriptor = [0; 256];
55 let mut bos_descriptor = [0; 256]; 54 let mut bos_descriptor = [0; 256];
56 let mut msos_descriptor = [0; 256]; 55 let mut msos_descriptor = [0; 256];
57 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
58 let request_handler = MyRequestHandler {}; 57 let mut request_handler = MyRequestHandler {};
59 let mut device_handler = MyDeviceHandler::new(); 58 let mut device_handler = MyDeviceHandler::new();
60 59
61 let mut state = State::new(); 60 let mut state = State::new();
@@ -63,7 +62,6 @@ async fn main(_spawner: Spawner) {
63 let mut builder = Builder::new( 62 let mut builder = Builder::new(
64 driver, 63 driver,
65 config, 64 config,
66 &mut device_descriptor,
67 &mut config_descriptor, 65 &mut config_descriptor,
68 &mut bos_descriptor, 66 &mut bos_descriptor,
69 &mut msos_descriptor, 67 &mut msos_descriptor,
@@ -75,7 +73,7 @@ async fn main(_spawner: Spawner) {
75 // Create classes on the builder. 73 // Create classes on the builder.
76 let config = embassy_usb::class::hid::Config { 74 let config = embassy_usb::class::hid::Config {
77 report_descriptor: KeyboardReport::desc(), 75 report_descriptor: KeyboardReport::desc(),
78 request_handler: Some(&request_handler), 76 request_handler: None,
79 poll_ms: 60, 77 poll_ms: 60,
80 max_packet_size: 64, 78 max_packet_size: 64,
81 }; 79 };
@@ -139,7 +137,7 @@ async fn main(_spawner: Spawner) {
139 }; 137 };
140 138
141 let out_fut = async { 139 let out_fut = async {
142 reader.run(false, &request_handler).await; 140 reader.run(false, &mut request_handler).await;
143 }; 141 };
144 142
145 // Run everything concurrently. 143 // Run everything concurrently.
@@ -150,21 +148,21 @@ async fn main(_spawner: Spawner) {
150struct MyRequestHandler {} 148struct MyRequestHandler {}
151 149
152impl RequestHandler for MyRequestHandler { 150impl RequestHandler for MyRequestHandler {
153 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { 151 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
154 info!("Get report for {:?}", id); 152 info!("Get report for {:?}", id);
155 None 153 None
156 } 154 }
157 155
158 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { 156 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
159 info!("Set report for {:?}: {=[u8]}", id, data); 157 info!("Set report for {:?}: {=[u8]}", id, data);
160 OutResponse::Accepted 158 OutResponse::Accepted
161 } 159 }
162 160
163 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { 161 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
164 info!("Set idle rate for {:?} to {:?}", id, dur); 162 info!("Set idle rate for {:?} to {:?}", id, dur);
165 } 163 }
166 164
167 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { 165 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
168 info!("Get idle rate for {:?}", id); 166 info!("Get idle rate for {:?}", id);
169 None 167 None
170 } 168 }
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 04ad841b7..8076ac283 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -43,19 +43,17 @@ async fn main(_spawner: Spawner) {
43 43
44 // Create embassy-usb DeviceBuilder using the driver and config. 44 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors. 45 // It needs some buffers for building the descriptors.
46 let mut device_descriptor = [0; 256];
47 let mut config_descriptor = [0; 256]; 46 let mut config_descriptor = [0; 256];
48 let mut bos_descriptor = [0; 256]; 47 let mut bos_descriptor = [0; 256];
49 let mut msos_descriptor = [0; 256]; 48 let mut msos_descriptor = [0; 256];
50 let mut control_buf = [0; 64]; 49 let mut control_buf = [0; 64];
51 let request_handler = MyRequestHandler {}; 50 let mut request_handler = MyRequestHandler {};
52 51
53 let mut state = State::new(); 52 let mut state = State::new();
54 53
55 let mut builder = Builder::new( 54 let mut builder = Builder::new(
56 driver, 55 driver,
57 config, 56 config,
58 &mut device_descriptor,
59 &mut config_descriptor, 57 &mut config_descriptor,
60 &mut bos_descriptor, 58 &mut bos_descriptor,
61 &mut msos_descriptor, 59 &mut msos_descriptor,
@@ -65,7 +63,7 @@ async fn main(_spawner: Spawner) {
65 // Create classes on the builder. 63 // Create classes on the builder.
66 let config = embassy_usb::class::hid::Config { 64 let config = embassy_usb::class::hid::Config {
67 report_descriptor: MouseReport::desc(), 65 report_descriptor: MouseReport::desc(),
68 request_handler: Some(&request_handler), 66 request_handler: Some(&mut request_handler),
69 poll_ms: 60, 67 poll_ms: 60,
70 max_packet_size: 8, 68 max_packet_size: 8,
71 }; 69 };
@@ -107,21 +105,21 @@ async fn main(_spawner: Spawner) {
107struct MyRequestHandler {} 105struct MyRequestHandler {}
108 106
109impl RequestHandler for MyRequestHandler { 107impl RequestHandler for MyRequestHandler {
110 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { 108 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
111 info!("Get report for {:?}", id); 109 info!("Get report for {:?}", id);
112 None 110 None
113 } 111 }
114 112
115 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { 113 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
116 info!("Set report for {:?}: {=[u8]}", id, data); 114 info!("Set report for {:?}: {=[u8]}", id, data);
117 OutResponse::Accepted 115 OutResponse::Accepted
118 } 116 }
119 117
120 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { 118 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
121 info!("Set idle rate for {:?} to {:?}", id, dur); 119 info!("Set idle rate for {:?} to {:?}", id, dur);
122 } 120 }
123 121
124 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { 122 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
125 info!("Get idle rate for {:?}", id); 123 info!("Get idle rate for {:?}", id);
126 None 124 None
127 } 125 }
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index aff539b1b..02048e692 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -48,7 +48,6 @@ async fn main(_spawner: Spawner) {
48 48
49 // Create embassy-usb DeviceBuilder using the driver and config. 49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 50 // It needs some buffers for building the descriptors.
51 let mut device_descriptor = [0; 256];
52 let mut config_descriptor = [0; 256]; 51 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256]; 52 let mut bos_descriptor = [0; 256];
54 let mut msos_descriptor = [0; 256]; 53 let mut msos_descriptor = [0; 256];
@@ -59,7 +58,6 @@ async fn main(_spawner: Spawner) {
59 let mut builder = Builder::new( 58 let mut builder = Builder::new(
60 driver, 59 driver,
61 config, 60 config,
62 &mut device_descriptor,
63 &mut config_descriptor, 61 &mut config_descriptor,
64 &mut bos_descriptor, 62 &mut bos_descriptor,
65 &mut msos_descriptor, 63 &mut msos_descriptor,
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 4e8118fb8..895cca8b9 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -67,7 +67,6 @@ async fn main(spawner: Spawner) {
67 let state = STATE.init(State::new()); 67 let state = STATE.init(State::new());
68 68
69 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
70 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
71 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 70 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
72 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 71 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
73 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); 72 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new();
@@ -75,7 +74,6 @@ async fn main(spawner: Spawner) {
75 let mut builder = Builder::new( 74 let mut builder = Builder::new(
76 driver, 75 driver,
77 config, 76 config,
78 &mut DEVICE_DESC.init([0; 256])[..],
79 &mut CONFIG_DESC.init([0; 256])[..], 77 &mut CONFIG_DESC.init([0; 256])[..],
80 &mut BOS_DESC.init([0; 256])[..], 78 &mut BOS_DESC.init([0; 256])[..],
81 &mut MSOS_DESC.init([0; 128])[..], 79 &mut MSOS_DESC.init([0; 128])[..],
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index 060f9ba94..c6675a3d3 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) {
53 53
54 // Create embassy-usb DeviceBuilder using the driver and config. 54 // Create embassy-usb DeviceBuilder using the driver and config.
55 // It needs some buffers for building the descriptors. 55 // It needs some buffers for building the descriptors.
56 let mut device_descriptor = [0; 256];
57 let mut config_descriptor = [0; 256]; 56 let mut config_descriptor = [0; 256];
58 let mut bos_descriptor = [0; 256]; 57 let mut bos_descriptor = [0; 256];
59 let mut msos_descriptor = [0; 256]; 58 let mut msos_descriptor = [0; 256];
@@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) {
64 let mut builder = Builder::new( 63 let mut builder = Builder::new(
65 driver, 64 driver,
66 config, 65 config,
67 &mut device_descriptor,
68 &mut config_descriptor, 66 &mut config_descriptor,
69 &mut bos_descriptor, 67 &mut bos_descriptor,
70 &mut msos_descriptor, 68 &mut msos_descriptor,
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 00bd50081..26eaf485e 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -4,7 +4,7 @@
4use defmt::{info, unwrap, warn}; 4use defmt::{info, unwrap, warn};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
9use embassy_nrf::rng::Rng; 9use embassy_nrf::rng::Rng;
10use embassy_nrf::spim::{self, Spim}; 10use embassy_nrf::spim::{self, Spim};
@@ -36,8 +36,8 @@ async fn wifi_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -89,16 +89,10 @@ async fn main(spawner: Spawner) {
89 let seed = u64::from_le_bytes(seed); 89 let seed = u64::from_le_bytes(seed);
90 90
91 // Init network stack 91 // Init network stack
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new(); 93 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 let stack = &*STACK.init(Stack::new( 94
95 device, 95 unwrap!(spawner.spawn(net_task(runner)));
96 config,
97 RESOURCES.init(StackResources::<2>::new()),
98 seed,
99 ));
100
101 unwrap!(spawner.spawn(net_task(stack)));
102 96
103 // And now we can use it! 97 // And now we can use it!
104 98
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 56b9c8018..0da85be07 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embedded-io-async = { version = "0.6.1" } 15embedded-io-async = { version = "0.6.1" }
16 16
17defmt = "0.3" 17defmt = "0.3"
@@ -21,10 +21,9 @@ static_cell = "2"
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25rand = { version = "0.8.4", default-features = false } 24rand = { version = "0.8.4", default-features = false }
26embedded-storage = "0.3.1" 25embedded-storage = "0.3.1"
27usbd-hid = "0.6.0" 26usbd-hid = "0.8.1"
28serde = { version = "1.0.136", default-features = false } 27serde = { version = "1.0.136", default-features = false }
29 28
30[profile.release] 29[profile.release]
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs
index c0a55142f..23f6fca98 100644
--- a/examples/nrf5340/src/bin/gpiote_channel.rs
+++ b/examples/nrf5340/src/bin/gpiote_channel.rs
@@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) {
61 } 61 }
62 }; 62 };
63 63
64 futures::join!(button1, button2, button3, button4); 64 embassy_futures::join::join4(button1, button2, button3, button4).await;
65} 65}
diff --git a/examples/nrf9151/ns/.cargo/config.toml b/examples/nrf9151/ns/.cargo/config.toml
new file mode 100644
index 000000000..1444b0cd1
--- /dev/null
+++ b/examples/nrf9151/ns/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF9160_xxAA"
4
5[build]
6target = "thumbv8m.main-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
new file mode 100644
index 000000000..17fe27b67
--- /dev/null
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf9151-non-secure-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf9151/ns/README.md b/examples/nrf9151/ns/README.md
new file mode 100644
index 000000000..a3f81d24e
--- /dev/null
+++ b/examples/nrf9151/ns/README.md
@@ -0,0 +1,4 @@
1You must flash the TFM before running any non-secure examples. The TFM
2configures the secure and non-secure execution environments and then loads the
3non-secure application. A reference TFM is included, and you can use the
4provided helper script to flash it.
diff --git a/examples/nrf9151/ns/build.rs b/examples/nrf9151/ns/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf9151/ns/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/nrf9151/ns/flash_tfm.sh b/examples/nrf9151/ns/flash_tfm.sh
new file mode 100644
index 000000000..29e4e0ed5
--- /dev/null
+++ b/examples/nrf9151/ns/flash_tfm.sh
@@ -0,0 +1,2 @@
1nrfjprog --family NRF91 --recover
2nrfjprog --family NRF91 --chiperase --verify --program tfm.hex
diff --git a/examples/nrf9151/ns/memory.x b/examples/nrf9151/ns/memory.x
new file mode 100644
index 000000000..8d7b66fcc
--- /dev/null
+++ b/examples/nrf9151/ns/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* Trusted Firmware-M (TF-M) is flashed at the start */
4 FLASH : ORIGIN = 0x00008000, LENGTH = 0xf8000
5 RAM (rwx) : ORIGIN = 0x2000C568, LENGTH = 0x33a98
6}
7
diff --git a/examples/nrf9151/ns/src/bin/blinky.rs b/examples/nrf9151/ns/src/bin/blinky.rs
new file mode 100644
index 000000000..7457a95a3
--- /dev/null
+++ b/examples/nrf9151/ns/src/bin/blinky.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 defmt::info!("high");
17 Timer::after_millis(500).await;
18 led.set_low();
19 defmt::info!("low");
20 Timer::after_millis(1000).await;
21 }
22}
diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs
new file mode 100644
index 000000000..2220dccfb
--- /dev/null
+++ b/examples/nrf9151/ns/src/bin/uart.rs
@@ -0,0 +1,37 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_nrf::{bind_interrupts, peripherals, uarte};
7use {defmt_rtt as _, panic_probe as _};
8
9bind_interrupts!(struct Irqs {
10 SPIM0_SPIS0_TWIM0_TWIS0_UARTE0 => uarte::InterruptHandler<peripherals::SERIAL0>;
11});
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16 let mut config = uarte::Config::default();
17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200;
19
20 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P0_26, p.P0_27, config);
21
22 info!("uarte initialized!");
23
24 // Message must be in SRAM
25 let mut buf = [0; 8];
26 buf.copy_from_slice(b"Hello!\r\n");
27
28 unwrap!(uart.write(&buf).await);
29 info!("wrote hello in uart!");
30
31 loop {
32 info!("reading...");
33 unwrap!(uart.read(&mut buf).await);
34 info!("writing...");
35 unwrap!(uart.write(&buf).await);
36 }
37}
diff --git a/examples/nrf9151/ns/tfm.hex b/examples/nrf9151/ns/tfm.hex
new file mode 100644
index 000000000..9864a1849
--- /dev/null
+++ b/examples/nrf9151/ns/tfm.hex
@@ -0,0 +1,1543 @@
1:10000000F80B0020690600000D070000255A0000CB
2:10001000455A0000655A0000A55A0000855A0000A4
3:100020000000000000000000000000001D2700008C
4:100030000D070000000000000D0700000D07000084
5:10004000000000000000000000000000F13200008D
6:10005000000000000D07000000000000000000008C
7:100060000D0700000D0700000D0700000D07000040
8:10007000000000000D0700000D0700000D07000044
9:100080000D0700000D070000000000000000000048
10:100090000D0700000D070000000000000000000038
11:1000A0000D07000000000000000000000D07000028
12:1000B0000D0700000D0700000D0700000D070000F0
13:1000C0000D0700000D0700000D0700000D070000E0
14:1000D0000D070000000000000D07000000000000F8
15:1000E0000D070000000000000D07000000000000E8
16:1000F0000D070000000000000000000000000000EC
17:10010000000000000D0700000000000000000000DB
18:1001100000000000000000000000000000000000DF
19:10012000000000000D0700000000000000000000BB
20:1001300000000000000000000000000000000000BF
21:100140000D07000000015F5F00000000FE0B0000D3
22:10015000F9270000800600000000000000000000F9
23:10016000000000000000000000000000401200201D
24:100170000000000001015F5F030100001F0100009B
25:1001800085040000000000000000000001000000E5
26:10019000010000000000000000000000000000005E
27:1001A0000000000070000000CC5E00008000000035
28:1001B000000F000001000000D102000001015F5F9C
29:1001C000040100001F010000F30500000000000012
30:1001D000000000000000000001000000000000001E
31:1001E000000000000000000000000000D75E0000DA
32:1001F000400000000507000001000000DF040000CF
33:1002000038B50025054C29462046D4F80024C4F80A
34:10021000045405F0B0FCC4F8005438BD200C002094
35:1002200013B511460022CDE9002242680346382A60
36:10023000046844D194F82820022A19D01AB900F091
37:1002400047F902B010BD21482468D0F80404013AEF
38:10025000CDE90040082A35D8DFE802F0050A0E1380
39:10026000181D22272C006A46184600F02EF9E8E7F0
40:10027000184600F018F9E4E76A46184600F016F947
41:10028000DFE76A46184600F00BF9DAE76A461846D7
42:1002900000F00FF9D5E76A46184600F00DF9D0E7EF
43:1002A0006A46184600F00BF9CBE76A46184600F09C
44:1002B00009F9C6E76A46184600F00EF9C1E76FF083
45:1002C0008000BEE76FF08500BBE700BF200C002078
46:1002D0002DE9F04F05680446A1B0002D40F0AA803A
47:1002E0002022294602A805F046FC12AF202229460A
48:1002F0000AA805F040FC38222946384605F03BFCA8
49:10030000E26904F11C039846B2B10426E26A04F1E2
50:100310002C03EAB10425EEB96FF08306304621B014
51:10032000BDE8F08F002EF1D053F8041D3246013E97
52:100330000029F7D01646E9E70326F5E7002DEAD0B5
53:1003400053F8041D2A46013D0029F7D01546E2E77F
54:100350000325F5E738233A460021606805F048FC9C
55:100360003828D9D14FF00109CDE90270334F0DF192
56:10037000080A04F1100B4E45D7F800141CD10DF1FA
57:1003800028094B46002008EB850EC64533D108B13D
58:10039000C7F80014A3683146C7F804340AAA2B46EC
59:1003A00002A8FFF73DFF00270646BD4209F10809F4
60:1003B00038D1FFF725FFB1E75BF8043FC1F5806254
61:1003C000D81C20F00300904204D9FFF719FF6FF00A
62:1003D0008C06A3E70844CA19C7F8000449466068B8
63:1003E000019205F005FC019ACAF80C0009F1010917
64:1003F0004AF8082FBFE758F804CFC1F5806A0CF11E
65:10040000030222F00302524503F1080305D87818CD
66:1004100043E9020C11440120B7E70028D5D0C7F802
67:100420000014D2E7394659E90223606805F0F5FB6C
68:100430000137BAE76FF0850670E700BF200C002097
69:1004400008B528220021024805F095FB002008BDD0
70:100450002810002010B5044C0F222046034905F057
71:1004600065FB204610BD00BF51100020F6050000BE
72:1004700008B50121024803F011FB002008BD00BFB0
73:100480005010002008B5FFF7DBFF40B9FFF7E2FF8F
74:10049000FFF7EEFF18B9BDE8084003F06DBB08BDDB
75:1004A0006FF0850070476FF0850070476FF0850032
76:1004B00070476FF0850070476FF0850070476FF0F0
77:1004C000850070476FF0850070476FF085007047BA
78:1004D000D1E9000103F030BB6FF085007047F0B543
79:1004E00003680546B3F57D7FA7B007D040F2F5322B
80:1004F000934207D06FF0850027B0F0BD01F08EFC6D
81:100500000020F9E700243C22214607A8CDE9024457
82:10051000CDE90444069405F02EFB3C22214617A8A1
83:10052000169405F028FBEA69019405F11C0302B357
84:100530000426EA6A05F12C033AB30424731E012B46
85:1005400052D8012C50D80423002168680DEB030217
86:1005500005F04EFB04281AD06FF08000CCE7002E87
87:10056000E7D053F8041D3246013E0029F7D0164665
88:10057000DFE70326F5E7002CE0D053F8041D224600
89:10058000013C0029F7D01446D8E70324F5E7022EF2
90:1005900016D16E69402E29D806AF33463A4601215E
91:1005A000686805F025FB8642D6D1CDE9027602A91E
92:1005B00044B92246019801F01AFE044620469BE702
93:1005C0000021F5E72B6A402BC6D816AACDE90423F3
94:1005D000019804AA01F00BFEDDE904230446002182
95:1005E000686805F01AFBE9E7012085E76FF08900EC
96:1005F00082E7002070474D62656420544C532033DD
97:100600002E352E3000000000000000000000000029
98:1006100000000000000000000000000000000000DA
99:100620005431000001000000407C000080100020D8
100:100630004A000000407C0000200C00200000000068
101:10064000407C0000000C002000000000A8110020E9
102:10065000C4050000200C002018010000000C002040
103:100660000800000002F07ABC08B572B61E4A1F4BA3
104:100670009A601F4B83F309881E4B83F30A8883F328
105:100680000B881D4B16A1D1E90001C3E9000100F060
106:1006900089F81A4B1A498B4212D30020194B1A4978
107:1006A0008B4218D303F06AF8186850F82240586853
108:1006B00040F82240013298688242F5D30C33EAE7D1
109:1006C0000022F8E71C6844F8220001325C68A2426C
110:1006D000F8D30833E4E70022F8E700BFAFF3008067
111:1006E000A5EDF5FEA5EDF5FE0000000000ED00E033
112:1006F000F80B002000040020F80B00202806000062
113:100700004C0600004C06000064060000EFF3088071
114:10071000EFF309812DE9F00F6B46724600F038F9CE
115:1007200008B0FFF79FFFFEE708B5EFF31083012B3A
116:100730000C4A07D1126ABFF34F8F511C4A424A41FB
117:10074000104608BD01F0BEFB00B172B6126ABFF3DD
118:100750004F8F531C5A425A4101F0B4FB0028EFD08E
119:1007600062B6EDE70080FF0008B5EFF31083012BC0
120:100770000B4A06D1D269BFF34F8F02F00102104637
121:1007800008BD01F09FFB00B172B6D269BFF34F8F75
122:1007900002F0010201F096FB0028F0D062B6EEE70D
123:1007A0000080FF006F4A10B5D2F8D03043F002034A
124:1007B000C2F8D03001F086FB30B14FF05023002258
125:1007C000C3F81421C3F8182101F08BFB28B10122D2
126:1007D000654BC3F8382AC3F878254FF47F02D2F866
127:1007E0003031D2F83421BFF34F8FC3F30B03092B01
128:1007F00005D1012A1EBF01225B4BC3F8782501F009
129:1008000070FB18B10E22594BC3F8E42E01F05AFBCD
130:1008100030B10022544BC3F80C270122C3F8102733
131:100820000022D30003F57F03D3F80013BFF34F8FEB
132:10083000013108D0D3F800130132D3F80433B2F5F4
133:10084000807F0B60EDD1EFF31084FFF78DFF002860
134:100850004DD0BFF34F8F464BD3F80024012AFBD174
135:10086000C3F80425D3F80024012AFBD1012C03D0BE
136:1008700001F028FB00B172B6FFF776FF58B13D4A90
137:10088000D36923F00103D361BFF34F8F384AD2F805
138:100890000034012BFBD1FFF747FF68B1354A136ADB
139:1008A00023F0FF0343F020031362BFF34F8F304A5E
140:1008B000D2F80034012BFBD1012C03D001F002FB54
141:1008C00000B162B600222A4BC3F80425D3F80024F5
142:1008D000012AFBD1BFF34F8F2249274BCA6802F48C
143:1008E000E0621343CB60BFF34F8F00BFFDE7FFF71C
144:1008F0001BFF0028ADD11B4AD2F88C3043F4406373
145:10090000C2F88C304FF47F03D3F83021D3F8343160
146:10091000BFF34F8FC2F30B02092A16D1013B022B02
147:1009200002D8164AD35C83B1124815490368104AAD
148:100930008B420CBF5A230023C2F8103EC36A8B427D
149:100940000CBF5A230023C2F8003E064AD2F8883072
150:1009500043F47003C2F88830BFF34F8FBFF36F8F3B
151:1009600010BD00BF00ED00E00040005000A00350AB
152:10097000009003500080FF000400FA05C43300001B
153:10098000FA50FA507C22014905F0D0B8DC1800205A
154:1009900038B51D46374B384C5B68C3F308032360FA
155:1009A000EFF30383C4E901206365C2F3801302F00F
156:1009B0000C020C2AE16038D10BB9EFF389812022B7
157:1009C0002E48216105F0B2F825B1202229462C4895
158:1009D00005F0ACF8274B9A6AA265D96AE165986B75
159:1009E000206602F400406066586BA06602F080004A
160:1009F000E0669A62D962D3F8E4202267D3F8E8105F
161:100A0000616702F04001A167C3F8E42000F06AF8D2
162:100A10000E211C4801F077FA2268D31E042B1CD843
163:100A2000DFE803F0090F1215180013B9EFF38881FE
164:100A3000C5E70146C3E70C211348BDE8384001F083
165:100A400062BA12211148F8E70B211148F5E70D2190
166:100A50001048F2E70E211048EFE70F2A98BF142143
167:100A6000BDE8384089BF25210C480D48103A01F0F7
168:100A7000F5BB00BF00ED00E0DC180020F0180020FE
169:100A800010190020C7330000D5330000E133000007
170:100A9000F3330000FE3300000B3400001934000073
171:100AA0002D3400002DE9F34106460F460C4DD5F8D4
172:100AB0002C80C04710F00104FBD1394630466B69E9
173:100AC000984740B9C047C307FCD42B6A019302B0D2
174:100AD000BDE8F0411847204602B0BDE8F08100BFF4
175:100AE0005434000010B5094C0020A36898472369CE
176:100AF00002209847A46A4FF4E1310120A047234621
177:100B0000BDE8104001211520184700BF54340000F3
178:100B100010B5044C002023699847E368BDE81040F5
179:100B2000184700BF54340000064B82B018680023F9
180:100B300082B262F30F03000C60F31F43184602B049
181:100B4000704700BF9C340000014B1869704700BF1C
182:100B500084100020014B5869704700BF84100020AA
183:100B600038B50C4D0C4695F8203013B94FF0FF30D6
184:100B700038BD0A460146284600F06CFF064B9842F5
185:100B800005D00B3B9842F1D100206C61F0E76FF08B
186:100B90000100EDE7841000200B00AD0BF0B51B4EFB
187:100BA000054696F820300C4691B01BB94FF0FF3047
188:100BB00011B0F0BD00F06043B3F1005F21D100231C
189:100BC0000A460146304600F031FC114B98421AD0DB
190:100BD0000B3B9842EAD1346111E0A71B402F28BF9C
191:100BE0004027A9193A46684604F0A0FF39466846EE
192:100BF000FFF7D4FF0028DBD14036B442EDD8002007
193:100C0000D6E70026F9E76FF00100D1E78410002055
194:100C10000B00AD0BC3B2012B10B540F096804DF622
195:100C2000C023994270D028D8B1F5615F6FD011D838
196:100C3000B1F5965F6DD008D8B1F5966F6BD0B1F570
197:100C4000166F6BD06FF007005DE0B1F5165FF9D15C
198:100C5000454B33E047F61223994262D007D8B1F5ED
199:100C6000964F61D0B1F5E14FECD1404B26E0B1F5A4
200:100C7000164FE7D14FF41D0320E03D4B994255D06C
201:100C800011D8B1F5E13F54D007D8B1F5614F53D039
202:100C9000B1F5963FD6D1374B10E0B1F5613FD1D1D8
203:100CA0004FF06C730AE0B1F5612F48D0324B994296
204:100CB00048D0B1F5E12FC5D14FF0E86310F4E06FF3
205:100CC00046D110F4404103D0B1F5804F43D11021FB
206:100CD00010F4405203D0B2F5805F3FD10E2210F4E1
207:100CE000403003D0B0F5403F3BD10120234C20766B
208:100CF0006276E361A1760A4324681043C4F8243580
209:100D0000C4F86C05002010BD4FF46503D6E71C4BFA
210:100D1000D4E71C4BD2E74FF49E23CFE74FF41D23BB
211:100D2000CCE74FF40003C9E7174BC7E74FF08063E8
212:100D3000C4E74FF0EB73C1E74FF46B03BEE74FF02E
213:100D40007063BBE74FF08053B8E76FF00300DAE75A
214:100D50006FF00800D7E76FF00A00D4E76FF00900E2
215:100D6000D1E76FF00B00CEE70050270000C0750000
216:100D700090D0030000903A0140420F008410002000
217:100D800000F03A0000B0130000A04E0010B5114C66
218:100D9000204600F0D5FD0021206884F8201000F0E6
219:100DA00047FF226842F30732002A11DB0121530971
220:100DB0009B0003F1604303F56143D3F8800202F026
221:100DC0001F0201FA02F20243C3F88022D3F88032F4
222:100DD000002010BD8410002010B5264C0021206892
223:100DE0008EB000F017FF226842F30732002A12DBB0
224:100DF000012053099B0003F1604303F56143D3F8DD
225:100E0000801202F01F0200FA02F221EA0202C3F885
226:100E10008022D3F880322422002105A804F0ABFE02
227:100E2000D4E902124FF0FF33CDE90133CDE90333AA
228:100E30004FF0EB730B93072301A88DF8363001F0C8
229:100E400080F8014600220B4800F03AFA0A4B98421B
230:100E50000DD10C9B002023831B0CA3760B9BC4E9B4
231:100E60000400E361012384F820300EB010BD6FF060
232:100E70000100FAE7841000200000AD0B7FB50025CB
233:100E80000C46C0F808511646D0F80821D0F80022C8
234:100E900022F02002C0F80022104AC0F8082301F016
235:100EA000A0F8A560256104F14C03D3E8EF1F21F4FD
236:100EB0007F0121F47041C3E8E21F002AF5D110221E
237:100EC0002946684604F057FE042368468DF8003032
238:100ED0000196D4E90013984704B070BD10020A00CF
239:100EE00000F01F03400909D1074A02EB8303D3F83E
240:100EF0000012064A0A40C3F80022704700228033DD
241:100F000052F82330FFDE00BF00258450F0F8FCFFCC
242:100F10002DE9F04F804690F804A05020664F0E4611
243:100F200000FB0A70416885B049B113F0020304D098
244:100F3000836B002B00F0B2800123009300E000914E
245:100F40004FF0500909FB0A73DB6CD90600F1A6804B
246:100F50004FF0010BB3180293029BB34200F0A7803D
247:100F600006F06043039398F80450D8F8004009FB5A
248:100F700005739A6B9AB9039BB3F1005F40F09980B7
249:100F8000019200F0A1FD09FB0572D16C204601F031
250:100F9000010100F0F4FF28B900F09EFDE3E7012312
251:100FA0000193EEE7516C33460029BCBFD4F84C15D1
252:100FB0005164019A42B109FB05713078D1E90E23E1
253:100FC000D054D1E90E3213441BB1C4F84435C4F8EF
254:100FD00048B50022C4F82021D4F82011C4F85821C3
255:100FE000D4F85811C4F85021D4F850210822C4F87C
256:100FF0000025009AE2B14FF48003C4F80433C4F82A
257:1010000008B000F069FD502303FB0A725168002903
258:101010004BD1D26C120748D503FB0A734C33D3E88B
259:10102000EF1F21F00801C3E8E21F002A36D0F6E7DF
260:10103000C4F808B0019300F04FFD09FB0572D16CB4
261:10104000019B01F001012046019300F098FF8446C6
262:10105000019BD4F84C05D4F84425BCF1000F0DD108
263:101060009342F0D005EB850507EB0515D1B100F0F3
264:101070002BFD2946204600F0F9FFC2E705EB850568
265:10108000934207EB0515F1D10028EFD100F01CFDCC
266:101090002946204600F0EAFF00F01EFD074805B093
267:1010A000BDE8F08FC4F80CB0E1E7013654E704481E
268:1010B000F5E70448F3E700BF581900200800AD0B1E
269:1010C0000000AD0B0400AD0B430904D10123034A1A
270:1010D00083409360704700239B60FFDE00258450AF
271:1010E00000F01F0340090BD1084A02EB8302D2F83B
272:1010F0000012074B0B4043F00303C2F80032704765
273:101100000022803352F82330FFDE00BF00258450D8
274:10111000F0F8FCFF2DE9F84391F8303005460C4615
275:1011200090F804800F6853BB5023DFF85091781C6F
276:1011300003FB0893DE6C46F00072DA6404D0384694
277:10114000FFF7C2FFFFF7CCFF6068411C01D0FFF73B
278:10115000C7FE94F82C30012B11D1502303FB0893C8
279:10116000E06846F02066421CDE6401D0FFF7B8FE5E
280:10117000A068431C03D0FFF7A7FFFFF7B1FF94F867
281:101180002F0038B950223D4B02FB0833DA6C42F095
282:101190008072DA6494F82CC094F82D1094F82EE044
283:1011A000A26A2B6841EA0C01E668D4E90198C3F809
284:1011B00024254EEA0102C3F86C2550B9BCF1010F99
285:1011C000C3F80C75C3F8149504BFC3F80885C3F8B9
286:1011D0001065D3F8682503F26458012A08BFDA6065
287:1011E000D3F86425012A13D1082149F64046244F3B
288:1011F000C3F8001547F001075A60D8F800309BBBD0
289:101200002B68D3F88024C3F880240022C3F800257B
290:1012100000212B6894F83220C3F81011D3F8100184
291:10122000C3F82011D3F82001C3F82411D3F8240106
292:10123000C3F84411D3F84401C3F85811D3F8581136
293:1012400043F307335201002BD2B212DB0D49C81809
294:1012500080F800230122580903F01F0302FA03F368
295:1012600041F82030BDE8F8834020B847013EC4D1A2
296:10127000C6E7054903F00F03CA54F3E758190020E5
297:10128000A034000000E100E014ED00E000F01F03D6
298:1012900040090BD1084A02EB8302D2F80012074B37
299:1012A0000B4043F00203C2F8003270470022803343
300:1012B00052F82330FFDE00BF00258450F0F8FCFF19
301:1012C0002DE9F3479046502290F80490514C02FBD0
302:1012D00009FA04EB0A070D4697F84810064600295C
303:1012E00040F0858009EB890004EB001004F043FC1A
304:1012F0002B69AA6944F80A306B69BB6302B1013AF1
305:10130000502303FB0943DA632A6A042A81BFEA698E
306:101310009A610022DA6195F83130B8F1000F37D0C8
307:1013200083F001073F0233B1502303FB0943DA6C1A
308:1013300042F00102DA64502303FB09440123C4F89C
309:10134000048084F848303468D4F84C2112BB294614
310:101350003046FFF7DFFE0822002334688DF807309F
311:10136000C4F800250DF10702C4F84425C4F8483537
312:1013700001230A25A360E360D4F85831002B38D14B
313:10138000254B402043F001039847013DF4D128E06C
314:101390004746C8E708224FF06409C4F80025636097
315:1013A0001D4B43F0010AD4F84431F3B9D4F8243189
316:1013B000DBB94FF42070D047B9F10109F3D14B46A6
317:1013C0000022C4F84C21D4F84C11C4F81021D4F8F0
318:1013D0001011C4F84421D4F84411C4F80025002B9E
319:1013E000B5D10E4802B0BDE8F0870123E8E70C480C
320:1013F000F8E70023C4F820319845D4F82021C4F838
321:101400000035084B08BF00231F4333680648C3F864
322:101410000473E7E758190020A03400000100AD0B69
323:101420000C00AD0B10020A000000AD0B2DE9F047D7
324:1014300084460F469E4616460579002A51D04FF045
325:10144000500ADFF8BC80D0F800900AFB058ADAF871
326:10145000044074B96BB9DAF82C50002D43D1CAF8A6
327:101460002C20FFF755FD0446CAF82C502046BDE855
328:10147000F0871EF0030F07D0734632463946BDE8A9
329:10148000F0476046FFF744BD07F06043B3F1005FEB
330:101490004FF0500414D104FB058400F015FBE26A00
331:1014A0001AB1134C00F018FBE0E7C4E90A7605EB2B
332:1014B0008505484608EB051100F0E3FD0D4CF1E70A
333:1014C00004FB0584A36B83B100F0FEFAE36A002BF2
334:1014D000E7D1E36C012243F00203C4E90A76E36436
335:1014E000E5E7054CC2E7024CC0E7044CBEE700BF8D
336:1014F0000B00AD0B0000AD0B0600AD0B0A00AD0BF1
337:10150000581900202DE9F84350230679284D046826
338:1015100003FB0653D4F80473DA6AC4F8087322B9DB
339:101520002448C4F80473BDE8F88306EB860005F18F
340:101530004C024FEA001802EB0012D2E8EFCF4CF059
341:10154000080CC2E8E0CF0028F7D10122E26031B3F5
342:10155000D96C01EA02094946204600F010FD002836
343:10156000FAD000F0B1FAB9F1000F1CD1D4F8203153
344:1015700053B10123E360D4F85831002BFBD020464F
345:1015800005EB080100F072FD00F0A6FA0023C4F894
346:101590002031D4F82021502202FB0655EB62064888
347:1015A000C4F80473BFE7D4F85831002BE7D1EBE758
348:1015B000581900200500AD0B0000AD0B2DE9F843D4
349:1015C00090F80480484F08EB8806360106F14C0578
350:1015D00004683D44D5E8EF3F43F48052C5E8E02F6E
351:1015E0000028F7D1DB047BD4480705D5502303FB43
352:1015F00008739B69002B75D03C4B3E44C4F80833FC
353:101600000823C4F800350023C4F81031D4F81021A1
354:10161000C4F84C31D4F84C21C4F844310A03D4F84E
355:1016200044318B0303F4804302F400524903134313
356:1016300001F400410B43D5E8EF2F1A43C5E8E12F31
357:101640000029F8D14FF0500909FB0879D9F8083082
358:10165000BBB9D9F8043063B9D5E8EF3F23F47F0371
359:1016600023F47043C5E8E23F002AF5D12048BDE8E5
360:10167000F8830321304600F08FFCD9F80830002BA6
361:10168000EAD0D4F80433590713D5502303FB087369
362:101690005A6872B1DB6C1A030BD5D5E8EF3F23F41F
363:1016A0000023C5E8E23F002AF7D10621304600F0CA
364:1016B00073FC502303FB0873DB6CDB0401D40D487F
365:1016C000D5E7D4F84C310BB901232360502303FB39
366:1016D00008735B68002BF2D0044BC4F80433EEE7C8
367:1016E0000548C4E70548C2E75819002010020A005F
368:1016F0000200AD0B0000AD0B0B00AD0B0800AD0BF5
369:101700002DE9F84F056801F06043D5F804A3B3F163
370:10171000005F90F804B089461746C5F808A37CD14D
371:101720005023404E03FB0B639A6852B15B68002B59
372:101730005ED1D5F81021002A5AD0C5F81031D5F85D
373:101740001031502404FB0B64E269C4E90297002ABB
374:101750003CD00BEB8B0897424FEA081824D24FF08D
375:10176000000B3A46A1694846C4E902BB04F0DEF921
376:10177000E269A069D21BC119E26104F0A1F96368B2
377:101780006BB1B04449463A46404600F016FCE36C63
378:10179000990404D55A4641462846FFF76FFB224874
379:1017A000C5F804A3BDE8F88F4846A16904F0BEF966
380:1017B000E36963620023E3611C4B9844D8E8EF3F80
381:1017C00043F40023C8E8E23F002AF7D1502303FB8B
382:1017D0000B63586ADA689968DB6C121A0144C5F821
383:1017E0003415C5F83825DA04D9D501232B60D6E79E
384:1017F000502303FB0B6633698BB9F36CC5F8349542
385:101800005B04C6E90497C5F83875C8D5D5F8003229
386:1018100043F02003C5F80032C1E70548C0E705489A
387:10182000BEE700BF581900200000AD0BA41900202E
388:101830000A00AD0B0B00AD0B50232DE9F0413C4DE0
389:1018400090F80480046803FB0853DB6CD4F80002B2
390:1018500003F48223B3F5805F68D1D4F80463C4F83D
391:10186000086309B9830656D4D4F8003223F0200364
392:10187000C4F800324FF4842308EB8801090101F118
393:101880004C072F44D7E8EF0F1843C7E8EC0FBCF123
394:10189000000FF7D12AB9502303FB08535B68002BD4
395:1018A00041D1244BC4F8083301236360D4F8443198
396:1018B000002BFBD00023C4F84C31D4F84C21C4F8E1
397:1018C0001031D4F81021C4F84431D4F844315023F5
398:1018D00003FB0853DA6C12F400421FD1DA61204690
399:1018E00000F07FFB502303FB08550023AB602B6106
400:1018F000D7E8EF3F23F47F0323F47043C7E8E23FC8
401:10190000002AF5D126F4202626F404760A48C4F8E5
402:101910000463BDE8F0814FF48033ADE720462944ED
403:1019200000F071FBDBE701236360EFE70348F0E7BA
404:101930005819002010020A000000AD0B0500AD0B85
405:101940002DE9F8432F4A03680679C3F8082343F3C7
406:101950000733002B04460DDB01215A0903F01F0356
407:10196000994002F12003284A42F82310BFF34F8F19
408:10197000BFF36F8F012220461146FFF75DFF012163
409:101980002046FFF7BFFD50212279204D236801FB3F
410:101990000252D46CD3F80C05E201D3F81495D3F8B5
411:1019A0000875D3F8108509D54FF0FF32C3F80C2520
412:1019B000C3F81425C3F80825C3F81025A30116D5CC
413:1019C000411C01D0FFF762FCB9F1FF3F02D048464D
414:1019D000FFF75CFC22010AD5B8F1FF3F02D0404678
415:1019E000FFF754FC7B1C02D03846FFF74FFC502316
416:1019F000002203FB0653DA6483F848205A60BDE8EE
417:101A0000F88300BF10034A0000E100E058190020ED
418:101A100010B5502402790B4B04FB02335B686BB9A1
419:101A20000368D3F810211AB9D3F80025082A07D083
420:101A300011B1D3F83C350B60034810BD0348FCE7F7
421:101A40000348FAE7581900200000AD0B0800AD0B61
422:101A50000B00AD0BF7B505461646FFF751FE164BCA
423:101A60000446984222D1032128462F79FFF7A6FD8C
424:101A7000124B984201D0A0421BD15022104B02FBC6
425:101A800007335B6893B90C4C284601A9FFF7C0FFE8
426:101A9000A042F9D1019BB34207D301222846114647
427:101AA00003B0BDE8F040FFF7C7BE064C204603B0C8
428:101AB000F0BD0446FAE700BF0000AD0B0B00AD0B14
429:101AC000581900200800AD0B72B6024A13680133A2
430:101AD00013607047A8190020034A1368013B136084
431:101AE00003B962B6704700BFA81900200722024B55
432:101AF000C3F80423704700BF00300050084BD3F8F0
433:101B00000801D3F80021003818BF012080000AB175
434:101B100040F00100D3F804310BB140F002007047EF
435:101B2000003000500022074BC3F80021D3F8001109
436:101B3000C3F80421D3F80411C3F80821D3F80831FD
437:101B4000704700BF0030005000231720094A03F5FA
438:101B5000C0710133202B42F82100F8D10023172057
439:101B6000044A03F5E0710133202B42F82100F8D13B
440:101B7000704700BF0030005010B59DF80840C00B02
441:101B800043EA0423064CC90B43EA0213884200D9F6
442:101B900010BDC2B202F5C07244F822300130F5E740
443:101BA0000030005010B59DF8084000F1604043EA55
444:101BB000042301F16041074C400B490B43EA021337
445:101BC000884200D910BDC2B202F5E07244F822305A
446:101BD0000130F5E700300050C0F30E03C3F50043B9
447:101BE000B3FA83F3C3F11B03064AC0F3C730DBB279
448:101BF00040F4807043F48073C2F80005C2F80435E5
449:101C0000704700BF0030005043030148184470473C
450:101C1000FF1FF81F054BC0F30730090241F03001E8
451:101C200000F5007043F82010704700BF00300050EE
452:101C3000044BC0F30730090200F5007043F8201090
453:101C4000704700BF00300050003A18BF0122003931
454:101C500018BF012103688900074841EA420118635F
455:101C600059605A6842F001025A60BFF34F8FBFF3C8
456:101C70006F8F0020704700BF04AAFF0008B5FFF770
457:101C80003DFF044B162118600348BDE8084000F0F2
458:101C90003AB900BFEC1F0020A63400000C22014915
459:101CA00003F044BFEC1F002010B501F006FB044612
460:101CB00090B901F097FF044680B90A4A2E21D368F3
461:101CC000094823F008031B041B0C43F0BF6343F4D3
462:101CD0000033D36000F017F9204610BD45F22354BD
463:101CE000FAE700BF00ED00E0BC340000024B1860D2
464:101CF000024B002019607047FC1F0020F81F0020D5
465:101D00001FB5374C426923685A6282699A62C26978
466:101D1000DA62026A1A63426A5A63826A9A63C26A20
467:101D2000DA63026B1A64426B5A60826B9A60C26B10
468:101D3000DA60026C1A61426C5A61826C9A61C26C00
469:101D4000DA61026D1A62826D5A65C26D9A65026F20
470:101D5000DA65026E1A66826E5A66426F9A66EFF311
471:101D600088825A64EFF389829A644268DA64EFF3F6
472:101D700094821A65026801A81A67FFF78FFF23682B
473:101D8000019ADA6601221A70164B1C686408640016
474:101D90002046214622462346B7EE000AF7EE000A07
475:101DA000B7EE001AF7EE001AB7EE002AF7EE002A97
476:101DB000B7EE003AF7EE003AB7EE004AF7EE004A07
477:101DC000B7EE005AF7EE005AB7EE006AF7EE006A77
478:101DD000B7EE007AF7EE007A03F081FF04B010BD91
479:101DE000FC1F0020F81F002000B5A1B001A8FEF7DD
480:101DF000C9FD029B63B15B060AD4019B23F0020379
481:101E0000052B05D1044B1B6813B101A8FFF778FF20
482:101E100021B05DF804FB00BFF81F0020BFF34F8F17
483:101E20000549064BCA6802F4E0621343CB60BFF376
484:101E30004F8F00BFFDE700BF00ED00E00400FA0592
485:101E400038B543680C2B30D14B68042B2DD14FF0A3
486:101E5000FF3304680D6821682B6031B3A26822B398
487:101E60000623012001F081F9F8B96168104B99420D
488:101E70000DD9A2680F485318834202D9F43883421F
489:101E800010D8206803F052FE0020286038BD0A4BAD
490:101E900099420AD9A26809488B188342F1D90730C0
491:101EA000814202D906488342EBD90220EEE700BF07
492:101EB000FF01FF002C02FF002F01FF003801FF008F
493:101EC0004C01FF004FF47F03D3F83001D3F83431D5
494:101ED000BFF34F8FC0F30B00A0F1090358425841E4
495:101EE00070474FF47F02D2F83031D2F83401BFF39B
496:101EF0004F8FC3F30B03092B03D1431E58425841A4
497:101F0000704700207047FEF7CDBD012070476FF08D
498:101F100003007047002382B00193019802B070471C
499:101F20006FF003007047002382B00193019802B064
500:101F30007047022814BF6FF0030000207047FEF7BF
501:101F40002DBE30B501EB8202914200D130BD51F877
502:101F5000044B04F07F037F2B4FEA144408BF4FF07B
503:101F6000FF33032CF0D8DFE804F002040608036016
504:101F7000EAE74360E8E78360E6E7C360E4E7034637
505:101F8000D0F8580130B931B9D3F82001003818BF62
506:101F9000012070470120704730B504460D4685B0DA
507:101FA00010220021684603F0E6FDD4E900136846DC
508:101FB0008DF80050984705B030BD7FB504460E46F9
509:101FC000154600211022684603F0D5FD012368461E
510:101FD0008DF80030CDE90165D4E90013984704B0CD
511:101FE00070BD10B50446FFF76FFDD4F8583133B11A
512:101FF000D4F8043313F4800308BFC4F80035BDE8F7
513:102000001040FFF769BD70B50D4604460522AA21B0
514:10201000D0F83C65A86903F0AEFD0522AB69C4F8B1
515:102020003435C4F838250022C4F81021D4F8101132
516:102030000121E162D4F810110029FBD0C4F84C2131
517:10204000D4F84C11C4F81021D4F81021D4F83C2550
518:102050009642EA6109D15A1E043312F8011FAA29D7
519:1020600003D19A42F9D10023EB6170BDD0F8583109
520:1020700033B1CB6CC3F30032DB0458BFC0F800258A
521:10208000704770B5CE6C0D4606F001010446FFF7AF
522:1020900076FF38B94FF4800346F00406EE64C4F8C6
523:1020A000043370BDD5E90A365AB1296CEA6B761A49
524:1020B000964228BF164619443246A86B03F036FDF7
525:1020C000AB6B4FF0FF326A641BB1C4F84435C4F8FF
526:1020D00048650023C4F82031D4F82021C4F85831D1
527:1020E000D4F85821C4F85031D4F850310823C4F83A
528:1020F00000354FF48003C4F804330123A360D0E714
529:10210000C0037047C00300F5FF407F3070470020D8
530:1021100070471F2070474FF40040704700F57F4024
531:10212000C03040037047402070475F2070474FF435
532:10213000005070474B6830B513F01F052DD1026871
533:102140000C681068C0F30720844226D2506855609E
534:1021500094600C7C23F01F0304F001041C438B7C6F
535:10216000DB0003F018031C434B7C5B0003F0060309
536:102170002343D3608B68013B23F01F04CB685B00D3
537:1021800003F00E03234343F0010313615060BFF3D8
538:102190004F8FBFF36F8F284630BD0120FCE70368E7
539:1021A00000205A68C9B258609960D86018615A60B6
540:1021B000704770B50546002403681E68C6F30726FD
541:1021C000B44201D1002070BD21462846FFF7E7FF49
542:1021D0000134F5E70020704708B5FFF705FE72B639
543:1021E00020BFFDE7002070470020704770470B4676
544:1021F00070B5114618B1032806D0032070BD1846EB
545:10220000BDE87040FFF71CBE5A68082A01D00220C2
546:10221000F4E74C68042CFAD11D684FF0FF330E68C8
547:10222000296833600029F2D06B68002BEFD0262399
548:102230007422012000F099FF0028E8D122462323D0
549:102240000120696800F091FF04460028DFD1D5E93C
550:102250000001FFF74BFD30602046CFE730B50C465C
551:10226000154685B038B139B1FFF74DFE041E03DACB
552:10227000204605B030BD044640F60D23ADF80E30C3
553:1022800009230B4901A805F00F028A5C2D091A5495
554:10229000013B012BF7D147F630030C21ADF8043098
555:1022A000FFF731FE0028B4BF04462418E0E700BF62
556:1022B000EA34000008B5194B83F30A88184800F087
557:1022C000E7FF40BBFFF7F0FC28BBFFF783FF10BB25
558:1022D000FFF788FFD8B9FFF789FF00F067FA3521CB
559:1022E0001048FFF710FE17210F48FFF70CFE1821CA
560:1022F0000E48FFF708FE00F03FFC21210C48FFF7D5
561:1023000002FE00F03FFA00F0CDFE002008BDFFF70E
562:102310006BFF0028DFD000F021FEEEE70004002074
563:10232000AC190020FA3400002F35000046350000BB
564:102330005E3500002DE9F04F93B00093574B814676
565:10234000D3F800B00BB2002B0D461646C1F302685D
566:10235000C1F3024A04DA6FF0800013B0BDE8F08FD9
567:102360008B42C36001D10020F7E708EB0A03042B7E
568:10237000F1D8CC0F64014FEAC80731463A46DBF882
569:10238000080044F0020300F0F0FE01460028E2D10C
570:10239000202202A803F0EFFB3A46314602A84FEA9A
571:1023A000CA0603F0C3FB32460099DBF8080044F08C
572:1023B000060300F0DAFE07460028CCD101462022B1
573:1023C0000AA803F0D8FB324600990AA802AE03F02F
574:1023D000ADFB33460137B84514D91A46BC460DE06B
575:1023E000D2F808E0D16818687144884203D259686D
576:1023F00008448645AFD30CF1010C0832C445EFD137
577:102400000833E7E715F0006F18BF202409F118071B
578:1024100007EB880844F00203474513D1202C26D14E
579:10242000002D02DBC5F3C0456C0109F128050AAE99
580:1024300005EB8A0A44F0060455451AD1009BC9F8F9
581:102440007C3090E77268DBF8080056F8081B0193AF
582:1024500000F08BFE00287FF47EAF56F8042C019B21
583:1024600047F8042F56F8082C38633A62D4E7002462
584:10247000DBE77268234656F8081BDBF8080000F01B
585:1024800074FE00287FF467AF56F8043C45F8043F1B
586:1024900056F8083C28642B63CEE700BFB019002033
587:1024A0002DE9F0411F461A4B0D461646D3F8008021
588:1024B00000F051FF044608B900F050FDE368002B1E
589:1024C00001DA00F04BFD032D01D900F047FD04EBCC
590:1024D0008504E569E36CED1A16D006233A463146C9
591:1024E000D8F8080000F041FE08B100F037FDBD4209
592:1024F00028BF3D46E36CE16B2A461944304603F0A1
593:1025000015FBE36C2B44E3642846BDE8F08100BF73
594:10251000B01900202DE9F0411D461A4B0F46164612
595:10252000D3F8008000F017FF044608B900F016FD4C
596:10253000E368002B01DA00F011FD032F01D900F050
597:102540000DFD04EB8704E36AE26E9B1AAB4201D2F5
598:1025500000F004FD02232A463146D8F8080000F0B6
599:1025600004FE08B100F0FAFCE36EE06D2A46314645
600:10257000184403F0DBFAE36E00202B44E366BDE869
601:10258000F08100BFB01900202DE9F04105464FF061
602:1025900001080E4E0E4B37685C681CB92846376040
603:1025A000BDE8F0812268936813F400700CD1A36930
604:1025B000012B09D0D368346023B19847002801DA91
605:1025C00000F0CCFCC4F81880246AE6E7B0190020BB
606:1025D000B419002038B5044610B96FF0800038BD3A
607:1025E0008368002BF9D01A68002AF6D05D68002DA8
608:1025F000F3D00B4BE861A8691D6020B92B68DB683C
609:1026000053B90123AB61A36804F10C001B681B697B
610:10261000984701232360E2E798470028F1DADCE7D6
611:10262000B01900204268024B08461A60704700BF8C
612:10263000B0190020002330B505680446AA68C0E937
613:10264000063312F4406F85B01CD012F4006202D041
614:1026500000F0C2F90246A96A2B6968460B440731AB
615:1026600023F0070321F00701CDE9021300930023B3
616:1026700005490193EB6800F09FFA684600F04EFEB2
617:10268000024B1C6005B030BD89250000B019002048
618:1026900001F00C0370B50C2B0CBF154605464A061D
619:1026A0000C461ED58B0658BF2835AB6913F8026C53
620:1026B00084F00803C3F3C003C6F38012934201D031
621:1026C00000F04CFC16F0A00F1ED176B1032E17D0EF
622:1026D00032461C210E48FFF7C1FD6FF083032B60CB
623:1026E0000CE000F03BFC2026E2E700F03BFB044658
624:1026F000FEF70EFA2146074800F00AFE204670BD9C
625:10270000284600F03FFAF9E732461F210248E2E787
626:102710007F350000F80B00209B350000EFF30880A8
627:102720007146EFF30982EFF30B830CB406B4FFF7A5
628:10273000AFFF8646009900F0080001F00801401A3A
629:1027400002DC12DB04B070471EF020031CBF2DE931
630:10275000F00FBDF1080D0A4C254626462746A04637
631:10276000A146A246A34630B4704704B030BC1EF068
632:1027700020031CBF1DF1080DBDE8F00F04B0704729
633:10278000A5EDF5FE084BDA6882F07F4282F47F0205
634:1027900042F48042DA6000221A765A76DA76DA77E4
635:1027A000602283F82220704700ED00E0114BD3F83F
636:1027B000882042F47002C3F88820BFF34F8FBFF324
637:1027C0006F8FD3F88C2042F44062C3F88C20D3F88A
638:1027D000342242F08042C3F83422D3F8342242F04B
639:1027E0003C42C3F834224FF0E022D36843F4200384
640:1027F000D360704700ED00E0009A164B9A4227D153
641:1028000001229043014641EC100B41EC110B41ECCD
642:10281000120B41EC130B41EC140B41EC150B41EC8A
643:10282000160B41EC170BEFF3148222F0040282F333
644:102830001488BFF36F8F02460346044605460646DA
645:10284000074680468146824683468446864604473C
646:10285000FEE70000A5EDF5FE2DE9F041044618B9AC
647:1028600043F6DA30BDE8F0810029F9D0836800250D
648:1028700013F4406F14BF01230023134F43F00203EE
649:10288000DFF848800B6000F13006236AAB4201D8C4
650:102890000020E7E71421A369E26906EB830301FB4B
651:1028A00002330C226A4399188968090709D59B5895
652:1028B000BB4201D04345D3D1186810B10121FFF7C5
653:1028C000A9F90135E1E700BFB4100020AC100020E9
654:1028D00070B5324C86B03248FFF76BFC2368012597
655:1028E0005A1C01932F4B2260DA681B694FF4407623
656:1028F000039300232A4801A902920495ADF81460BD
657:102900008DF81630FFF716FC18B143F6DA3006B032
658:1029100070BD23688DF816005A1C0193224B204885
659:102920000293224B01A9CDE903352260ADF8146072
660:10293000FFF700FC0028E8D123688DF816005A1C28
661:1029400001931B4B164802931A4B01A9CDE903359D
662:102950002260ADF81460FFF7EDFB0028D5D12368A5
663:102960008DF816005A1C0193134B0D480293134B1C
664:1029700001A903930223049340F201132260ADF8EE
665:102980001430FFF7D7FB04460028BED12A4629465B
666:102990000348FFF759F92046B9E700BFBC190020EA
667:1029A000A81000202C36000060360000005F0000F8
668:1029B0002006000020060000000C0020200C002053
669:1029C000014B1868704700BF2C360000014B1B6894
670:1029D000186870472C360000014B1B685868704718
671:1029E0002C36000008B5FFF749F9FFF79BF80A4BB2
672:1029F0005A68103AD3B2120609D401215A0903F0D9
673:102A00001F03994002F16003044A42F82310BDE815
674:102A1000084000F0A3BA00BF00ED00E000E100E0D4
675:102A20000020034BD8765A6A42F470225A627047EB
676:102A300000ED00E00349044BCA68002092B2134342
677:102A4000CB60704700ED00E00800FA0500224FF06F
678:102A5000FF300D4B02F1A0010132102A43F8210092
679:102A6000F8D1D3F88022002022F00802C3F8802297
680:102A7000D3F88022D3F8802222F40072C3F8802297
681:102A8000D3F88032704700BF00E100E008B5FFF7DF
682:102A90002DF80822024BC3F880211A60002008BDDF
683:102AA00000E100E0064BD3F8D02022F00102C3F889
684:102AB000D020D3F8D02042F00202C3F8D0207047D3
685:102AC00000ED00E037B50124FFF73EF8134D224634
686:102AD000052347F6FF7100200094FFF74DF82246CA
687:102AE00007234FF000500E490094FFF75BF8D5E93B
688:102AF0000101072300220094FFF73EF8072300227C
689:102B0000084909480094FFF74DF82969E868013938
690:102B1000FFF762F8002003B030BD00BF2C36000084
691:102B2000FF7F0020FFFF03200080002038B5002435
692:102B30000E4D002155F8040B0134FFF779F81C2CD9
693:102B4000F7D10020012240F20111094BC3F88004A3
694:102B5000C3F88424C3F8C004C3F8C424054AC2F8E7
695:102B600040154FF48072C3F8402438BDBC350000D6
696:102B700000300050009003500122014B1A60704752
697:102B8000C019002010B50446094B228918686168F5
698:102B90000623806800F0E9FA28B9064B1B68012B70
699:102BA00001D100F087F86FF08603236010BD00BFED
700:102BB000B0190020C01900202DE9F84305461E4633
701:102BC0000068134B9046AA68A0F1080440E902335C
702:102BD000503890420F4601D200F0C0F9A4F14809E4
703:102BE00048220021484602F0C6FF002344E907338B
704:102BF00044F8143C4FF0807344F8043C6FF0020337
705:102C000044E9036744F8208CC5E90093BDE8F883E4
706:102C1000A5EDF5FE30B5094C024661680023084673
707:102C200040B105686D68954205D11BB1826860604E
708:102C30009A60816030BD03468068F1E7441A002045
709:102C400038B504462AB10B689B68DB0512D5002015
710:102C500038BD0B4B1D680DB900F080F900222B68C0
711:102C600099692C338A4203D053F8040FA04204D14F
712:102C70009142ECD16FF0FC00EAE70132F2E700BFCD
713:102C8000B019002070B504460E46154600213022CA
714:102C90000C3002F070FF064B20461B68A660636094
715:102CA000656100F001FA00232061236070BD00BF60
716:102CB000B0190020044B1B681BB11B680BB158688E
717:102CC00070474FF0FF307047B0190020064B10B529
718:102CD0001C680CB900F042F923689B6813F4406F3C
719:102CE00014BF0120002010BDB01900202DE9F843C9
720:102CF000904607460C46FFF7E9FF024624B96FF0FD
721:102D000080042046BDE8F8836300F8D5144B04F036
722:102D10001F0153F82150002DF1D02B682946586827
723:102D2000FFF78EFFB0B9C4F30721284600F001FB7E
724:102D300004460028E3D1EFF3108972B600F0C1F920
725:102D4000064689F3108840B142462946FFF79AFFAC
726:102D50003E60D6E76FF08104D3E76FF08204D0E7DE
727:102D6000C41900202DE9F04100F0AAF90023134E08
728:102D7000134F73607B6000F0E5F8DFF84880304661
729:102D800000F022F80446A8B139468023424600F0FC
730:102D90007FF80546204600F011FB206804F1080189
731:102DA000FFF75AFD08B100F0D9F829462046FFF791
732:102DB00041FCE4E7BDE8F04100F071B9B41900202E
733:102DC000441A0020C4190020F8B5054608B900F0DF
734:102DD000C5F82A4E346814F1290F4CD8284B1968CD
735:102DE00004F128038B4246D2236AA26903EB430312
736:102DF0000C321344606AE269024402EB820213441B
737:102E00009B00E31801D2994201D200F0A7F8236891
738:102E10001C4A1B0C1B04934201D000F09FF823882E
739:102E2000B3F5817F01D300F099F86368002B01DAD4
740:102E300000F094F8144A176807F124031360134A4A
741:102E40001268934201D900F089F8236AA26903EB62
742:102E500043030C32616A1344E2693C600A4402EBAA
743:102E600082021344326802EB83026B6832603B6279
744:102E70006F603846F8BD0027FBE700BFC410002094
745:102E80004836000000005F5FC0100020443600009C
746:102E90002DE9F74F0F4690460646009300B109B959
747:102EA00000F05CF8D6F800A0DAF818200AF1300338
748:102EB00003EB820BDAF81C40204B1D6854B10C2246
749:102EC00002FB04541C601E4B1B689C4201D900F09D
750:102ED00045F82C4625464FF00009DAF81C204A45F3
751:102EE00000D91CB9002003B0BDE8F08F142303FB08
752:102EF00009B20023C5E900269268AB60930516D598
753:102F0000B8F1000F02D0009B802B03D0019200F09B
754:102F100025F8019A12F0E00FD0B202D158F8202023
755:102F20001AB1019000F01AF8019848F820507A6818
756:102F300009F10109AA607D600C35CEE7BC100020C4
757:102F40004036000008B5FFF73BFD034B9860FFF7E4
758:102F50003DFD80F3888808BD00ED02E0FFF73CB935
759:102F60008230012808B506D8FFF7B0FE18B9BDE8D1
760:102F70000840FFF7F3BF08BDF8B506460D4600F060
761:102F8000EAF9044608B9FFF7E9FFA7680FB9FFF7A8
762:102F9000E5FFE368991C20D05A1C21D1A5B315F197
763:102FA000820F13D102232360EFF3108672B62946F5
764:102FB0002046FFF737FB054686F310882368022B6F
765:102FC00024D1204600F086F82846F8BD15F1830F7D
766:102FD000EAD0FFF7C3FF0025E6E702232360FAE704
767:102FE000002BF6DB204600F0DAF93B689B689B0576
768:102FF00001D50223236015F1810FD5D16369002B20
769:10300000D2DBFFF7ABFFCFE73546F4E700232360C1
770:10301000DAE708B5FFF7E0F86FF0830008BD2DE9A7
771:10302000F3410E46174698460546FFF74FFE00F05F
772:10303000A6F92946024601A8FFF758FE044660B9E2
773:1030400043463A4631460198FFF774F9044640B1C9
774:103050006B0002D5019800F03DF8204602B0BDE8B3
775:10306000F0810198FFF7B6FA0446F6E740F2011046
776:10307000704770B50546FFF729FE06462846FFF75C
777:10308000C9FD044608B9002070BD014632462846F5
778:10309000FFF7D6FD0028F6D12368D868F4E76FF073
779:1030A0000200704700DF70474FF480507047B0F562
780:1030B000805F03D1EFF30B808038704700207047AA
781:1030C0007047EFF30B8000F1800383F30B887047A8
782:1030D00000207047EFF30B83803B83F30B8870472E
783:1030E00080EA0000E1EE100A00EE100A00EE900AFD
784:1030F00001EE100A01EE900A02EE100A02EE900AAA
785:1031000003EE100A03EE900A04EE100A04EE900A91
786:1031100005EE100A05EE900A06EE100A06EE900A79
787:1031200007EE100A07EE900A08EE100A08EE900A61
788:1031300009EE100A09EE900A0AEE100A0AEE900A49
789:103140000BEE100A0BEE900A0CEE100A0CEE900A31
790:103150000DEE100A0DEE900A0EEE100A0EEE900A19
791:103160000FEE100A0FEE900A70472DE9F0410E465F
792:103170001546002A4AD0C4074BD480F00204C4F399
793:103180004004A40003F00602062A4AD144F00104D8
794:1031900022462946304602F077FBB8BB46E800F2EB
795:1031A00005EB0608100E120208F1FF3747E800F39E
796:1031B0004FEA136166D51B0264D5884262D046E8A7
797:1031C00000F547E800F7FEF7A2FF2D0E85424FEA13
798:1031D000176734D3FEF79DFF874230D82846FEF7A5
799:1031E00091FF2246C6F101010144304602F04CFB3A
800:1031F000002847D00135AF4218D83846FEF780FF87
801:103200002246A8EB000102F03FFBD8B30020BDE846
802:10321000F081EFF39484A40004F0040444F0120459
803:10322000B0E7990731D544F00804B1E72846FEF726
804:1032300067FF0646FEF76FFF22460146D5E7FEF719
805:1032400072FF85421ED3FEF770FF87421AD82846C8
806:10325000FEF7DAFC2246C6F101010144304602F0D5
807:1032600013FB78B10135AF4203D83846FEF756FF5D
808:10327000C6E72846FEF752FF0646FEF758FF2246ED
809:103280000146EBE76FF07F00C1E74CF2DA20BEE7C2
810:1032900010B50446FFF706FCFFF714FC10B143F627
811:1032A000DA3010BDFFF742FC0028F8D1FFF710FB21
812:1032B0000028F4D102232360F3E708B5FFF7B0FB41
813:1032C00010B143F6DA3008BDFFF7B4FB0028F8D19F
814:1032D00000F01CF80028F4D162B6FDF703FCFFF7FC
815:1032E000B5FB0028EDD1FFF7D1FB0028EBD0E8E7D4
816:1032F000EFF30880EFF309812DE9F00F6B4672467A
817:10330000FDF746FB08B0FFF76DFBFEE700207047B6
818:1033100004460D46FFF7E4FEA54628470368283318
819:1033200083F30988836883F30B88BFF36F8F40684A
820:10333000704703689A68DB6812F4806F05D18B428E
821:103340002CBF00206FF0FA0070478B420CBF0020AA
822:103350006FF0FA00704710B5FFF7A9FE0446FFF7BB
823:10336000B7FE50B9FFF7A6FCA3685B681B685B68F3
824:10337000834218BF0024204610BD0024FBE738B567
825:10338000054648B100F01BF8B5EBD07F044601D0EC
826:10339000FFF7E4FD204638BDFFF78CFCF4E700237F
827:1033A00010B500F1280252F8041F19B1C16F146C56
828:1033B00019444C600833202BF5D110BD70474FF0F5
829:1033C000FF307047000001464154414C20455252A5
830:1033D0004F523A2000486172644661756C740D0A60
831:1033E000004D656D4D616E616765206661756C7439
832:1033F0000D0A004275734661756C740D0A005573B1
833:103400006167654661756C740D0A0053656375727A
834:10341000654661756C740D0A005265736572766558
835:103420006420457863657074696F6E2000506C612C
836:1034300074666F726D2065787465726E616C206958
837:103440006E7465727275707420284952516E293AF3
838:1034500020000000290B00000B1F0000D90D000008
839:103460008D0D0000331F00003F1F0000610B0000A6
840:103470000F1F0000490B0000550B0000150C000049
841:10348000151F0000211F0000271F00001D00000065
842:10349000100004001C0002001100060003020202DA
843:1034A0000338FDD87047506C6174666F726D2045AB
844:1034B0007863657074696F6E3A0D0A00416C6C2018
845:1034C00070696E732068617665206265656E206341
846:1034D0006F6E66696775726564206173206E6F6ECA
847:1034E0002D7365637572650D0A00303132333435E2
848:1034F000363738394142434445461B5B313B333410
849:103500006D5B536563205468726561645D2053652B
850:103510006375726520696D61676520696E6974699C
851:10352000616C697A696E67211B5B306D0D0A00540E
852:10353000462D4D20466C6F6174204142493A204827
853:103540006172640D0A004C617A7920737461636B57
854:10355000696E6720656E61626C65640D0A001B5BB5
855:10356000313B33346D426F6F74696E672054462D62
856:103570004D2076322E302E301B5B306D0D0A0055FB
857:103580006E6B6E6F776E2053504D205356432072F2
858:1035900065717565737465643A2000556E6B6E6F66
859:1035A000776E20535643206E756D6265722072658A
860:1035B000717565737465643A200000000040005026
861:1035C000005000500080005000A0005000B000509B
862:1035D00000E0005000F000500000015000100150C9
863:1035E0000040015000500150007001500080015017
864:1035F00000B0015000C0015000D0015000E0015067
865:1036000000F0015000000250001002500020025053
866:103610000030025000400250006002500080025012
867:1036200000A002500090035000258450008000004C
868:1036300000800000FFFF0F00007C00000080000001
869:0C3640002C1200201412002000020000D8
870:10366000009A204B9A4208D110B502F0A7FA02F056
871:10367000A9F906BC96460C46744702F0E3FA009A94
872:10368000184B9A4208D110B502F0A4FA02F09AF948
873:1036900006BC96460C46744702F0D4FA0CB4029A63
874:1036A000104B9A420CD14FF0004319430CBC10B59B
875:1036B00000F09EF802F086F906BC96460C46744768
876:1036C00002F0C0FA009A074B9A4202D106490868F4
877:1036D000744702F0B7FA009A024B9A4200D174473D
878:1036E00002F0B0FAA5EDF5FE801000200348044B6F
879:1036F000834202D0034B03B118477047A811002042
880:10370000A8110020000000000548064B1B1AD90F25
881:1037100001EBA301491002D0034B03B118477047D6
882:10372000A8110020A81100200000000010B5064CD0
883:10373000237843B9FFF7DAFF044B13B10448AFF322
884:1037400000800123237010BDC0180020000000007D
885:10375000EC5E000008B5044B1BB104490448AFF30C
886:103760000080BDE80840CFE700000000C41800203A
887:10377000EC5E0000A3F5803A704700BF174B002BAA
888:1037800008BF134B9D46FFF7F5FF00218B460F4600
889:103790001348144A121A02F0EEF90E4B002B00D017
890:1037A00098470D4B002B00D09847002000210400C3
891:1037B0000D000D48002802D00C48AFF3008002F045
892:1037C000DBF820002900FEF775FD02F0C1F800BF0C
893:1037D000000008000000000000000000F80B0020BE
894:1037E000A8110020B8280020000000000000000000
895:1037F0002DE9F84304460D4616461F46EFF30583B0
896:10380000C3F308030BB1FFF7A9FBDFF834903B4685
897:10381000204632462946D9F80080FFF700FCD9F847
898:1038200000300446984506D0DB6901461869BDE8BA
899:10383000F843FFF7A1BBFFF793FB2046BDE8F883F1
900:10384000B019002001680E4A0346914215D1C169A2
901:10385000A2F11022A2F1EF1291420ED18268012A48
902:103860000BD8C26812B101698A4206D0586928B1E2
903:103870009B691B1A5842584170470120704700BF8E
904:1038800055AA00FF0D4B70B59E68A6B13046FFF7F4
905:10389000D9FF044678B9F3686BB935690DB920468C
906:1038A00070BD2846FFF7CEFF28B9EB68B34202D1BE
907:1038B0002E462D69F2E70124F1E700BF4C1A0020E3
908:1038C0002DE9F041394E3468F368D4B1B468C4B11D
909:1038D000002861D000295FD001FB00F5B5FBF0F0B6
910:1038E000884259D1291D57D8AA070DD025F00302C7
911:1038F00004321C4603E0616891424FD2A469002C57
912:10390000F9D12046BDE8F0812A46F2E7891A232939
913:1039100004F12007D4E9050C1AD80123A360A0B153
914:10392000C0F818C0A36903B158610023C4E9053386
915:103930003369DB0702D5FFF7A5FFA0BB2A460021AC
916:1039400038463C4602F017F9DBE7C6F80CC0E9E759
917:1039500002F1200804EB08032039C3E9011E2169A4
918:10396000DFF84CE0DC60196144F808E0AEF1102E9D
919:10397000AEF1EF1EC3F81CE001B1CB60C3E9050C4A
920:1039800040B18361996901B14B6101212361C4E9AF
921:103990000121CAE7F360F5E70024B2E7D4F808E0B4
922:1039A000BEF1000FB2D0012001F0D2FF4C1A00206E
923:1039B00055AA00FFF8B5054600283AD0364E3368C0
924:1039C000002B36D0B268002A33D0834203D8726805
925:1039D0001344984202D3012001F0BAFFA0F1200461
926:1039E0002046FFF72FFF0028F5D155F8183C012B92
927:1039F000F1D145F8180C55E90570DFB1BB68CBB9BA
928:103A000055F81C2C7B68203213447B60386100B170
929:103A1000C76020220021204602F0ADF8386908B1C5
930:103A200083682BB333699B0703D5FFF72BFF00286F
931:103A3000D1D1F8BD40B3836833BB42686368134497
932:103A4000203363600369D4E90521236192B9B9B9D0
933:103A5000426981696261A161A2B19461A26902B106
934:103A6000546103B1DC602022002102F084F8D9E720
935:103A70003C46E2E79161A1690029E9D04A61E7E7A4
936:103A8000F160F8E7F460E9E7F36845F8083C03B152
937:103A90005C61F460C6E700BF4C1A002038B50D46E3
938:103AA000142200210446124802F065F81149124818
939:103AB00000F02CF8232D1AD914F003031FBF043D86
940:103AC000ED18C3F10403E4182A460021204602F051
941:103AD00052F8074B094AC3E900459C602260A2F1F5
942:103AE0001022203DA2F1EF126560E261DC6038BD7A
943:103AF0004C1A0020B5390000C138000055AA00FF5B
944:103B0000014B1B68184700BFC8100020024B18600B
945:103B1000024B002019607047CC100020C810002014
946:103B200010B50A46044619B1024B00211B6898479C
947:103B300010BD00BFD0100020054B0A46197819B1FE
948:103B40000146181D02F0B8B86FF08800704700BF3A
949:103B5000601A002010B5074C00F032F8204602F041
950:103B6000BCF8201F0821FFF7DBFFBDE8104002F082
951:103B7000A0B800BF641A002070B50C4D2B787BB93B
952:103B800002F095F8044670B90126281D6E7002F007
953:103B900091F8044638B900F00BF8044618B92E70B5
954:103BA0000024204670BDFFF7D5FFFAE7601A002019
955:103BB0000122024B002083F880257047681A0020FC
956:103BC000F8B5074C2025264601272046276202F03B
957:103BD0005DF8013D04F12C04F7D186F88055F8BD5D
958:103BE000681A002010B50C4C236813B10B4B1B68EE
959:103BF0002BB900F089FC30B90122084B1A6001236F
960:103C00002360002010BD0138062801D9044810BDEA
961:103C1000044B53F8200010BD042000200020002099
962:103C2000FE8FFFFF545D0000144B2DE9F043002888
963:103C300014BF04461C46124F236883B0BB4219D000
964:103C400016460D4620464FF4147104F1040900F0A5
965:103C500047F804F58E78484600F0CEF8404600F06C
966:103C600019FA2B464A4640460649009600F034FBB6
967:103C700008B92760002003B0BDE8F08308200020C9
968:103C8000A5BCC95A7D3E000070B50D4C1D460028EC
969:103C900014BF064626460B4B306882B098420DD1C1
970:103CA00006F58E70002633460096144600F03EFB63
971:103CB000002818BF34462C6002B070BD0248FBE7F4
972:103CC00008200020A5BCC95AE88FFFFF38B131B1E8
973:103CD000002201440346013081421A70FAD1704734
974:103CE00038B131B1002201440346013088421A70D4
975:103CF000FAD170472DE9F043202B1D460646884631
976:103D000091468BB026D8DBB202AF8DF80480B04666
977:103D100058F8041B8DF8053021B9404601F038F9F8
978:103D2000044640B9012302224046336001A901F054
979:103D300043F9044638B138462021FFF7D1FF204629
980:103D40000BB0BDE8F0832A464946404601F034F9FD
981:103D50000446F0E702AF1946104600233A4601F048
982:103D6000B1FA04460028E6D12023B9461D46CCE727
983:103D70002DE9F041D0F8F830A6B0002BD8BF02AE44
984:103D800031DD05460027D0F80C4102AEA4F1010850
985:103D90009022D5F8FC403146D0F8000101AB0197E4
986:103DA000B8FA88F8A0474FEA5818044620B9019B92
987:103DB00053B9B8F1000F16D030469021FFF790FFAD
988:103DC000204626B0BDE8F081014632462846FFF77E
989:103DD00091FF58B9D5F80431019A1344C5F804315C
990:103DE000B8F1000FE8D16FF03C04E5E70446204647
991:103DF00026B0BDE8F08100BF70B50025044614224E
992:103E000004F588762946C0F8F850FC3001F0B3FE7E
993:103E100008222946304601F0AEFE144B30461B689E
994:103E20009847204640F8045B01F098F8104B304664
995:103E30001B689847C8B9D4F8F830AB420FDC03EBE5
996:103E4000830204EB82022021C2F800010120C2E9B2
997:103E5000421008490133C2F8FC10C4F8F830064B90
998:103E60003046BDE870401B68184770BDF010002058
999:103E7000EC100020614E0000E81000202DE9F04712
1000:103E8000202A88B07AD83F4B00F5887904461B6811
1001:103E900048461746884698470546F8B940F2011645
1002:103EA000D4F8F830002B65D02046FFF761FF0546B7
1003:103EB00038B9D4F8F830002B14DC013EF2D16FF0A1
1004:103EC0003B056E4620213046FFF70AFF2E4B484641
1005:103ED0001B689847002818BF6FF01D05284608B0DA
1006:103EE000BDE8F087D4E94132934203D3D4F80C21E2
1007:103EF000012A02D0013ED7D1E1E71F2BFAD96E4645
1008:103F000001462022304604F1040A01F034FE314615
1009:103F1000504601F07BF805460028D3D1504601F009
1010:103F200031F8504601F01AF82946504601F030F8B1
1011:103F300005460028C6D150462022314601F03CF803
1012:103F400005460028BED1034632462021304601F006
1013:103F5000B9F905460028B5D1D4F8F8303A46002B17
1014:103F6000C8BF002340463146C8BFC4F8043101F041
1015:103F7000DDFDA7E76FF03F056E46A3E76FF03B0559
1016:103F8000ACE700BFEC100020E810002070B590B046
1017:103F900000287AD03E4C0D46402236210646204667
1018:103FA00001F0E9FD40225C21A01801F0E4FD2B1D89
1019:103FB000A34203D904F144039D4252D32B682268E3
1020:103FC000534023602B68226C534023646B68626803
1021:103FD000534063606B68626C53406364AB68A26873
1022:103FE0005340A360AB68A26C5340A364EB68E268E3
1023:103FF0005340E360EB68E26C5340E3642B69226951
1024:1040000053402361226D2B695340236562696B69BC
1025:10401000534063616B69626D53406365AB69A2692C
1026:104020005340A361AB69A26D5340A365EB69E2699C
1027:104030005340E361EB69E26D5340E3650021304694
1028:1040400000F0A6FF044628B940223046104900F08F
1029:10405000B3FF044640216846FFF742FE204610B0F9
1030:1040600070BD631E04F13F01013D1F3415F8010FBF
1031:1040700013F8012F42401A7011F8012F2878A3423B
1032:1040800082EA00020A70F1D1D8E76FF07304E5E725
1033:104090005822002010B54FF49A720021044601F016
1034:1040A0006AFD42F21072044BC4F8202104F59670A8
1035:1040B0001B68BDE810401847F01000202DE9F04FB4
1036:1040C00004468846914695B0002900F0A780002A52
1037:1040D0000CBF0126022600238DF80C30002C00F0C6
1038:1040E0009F80DFF844A104AF0AF1400B0021204675
1039:1040F00000F04EFF034648B1384620210193FFF7F8
1040:10410000EFFD019B184615B0BDE8F08F40225146E7
1041:10411000204600F051FF03460028EDD104F1F405DC
1042:1041200020222946204600F047FF03460028E3D11D
1043:104130000122204603A900F03FFF03460028DBD1FF
1044:10414000022E62D020460CA900F060FF0346002832
1045:10415000D2D10146204600F01BFF03460028CBD1F8
1046:1041600040225946204600F027FF03460028C3D1CD
1047:10417000202220460CA900F01FFF03460028BBD1D7
1048:104180003946204600F042FF03460028B4D13946A4
1049:104190002046FFF7FBFE03460028ADD1202229462A
1050:1041A000204600F009FF03460028A5D120460CA9AF
1051:1041B00000F02CFF034600289ED10146204600F067
1052:1041C000E7FE0346002897D140225946204600F0DA
1053:1041D000F3FE034600288FD1202220460CA900F0D0
1054:1041E000EBFE0346002887D12946204600F00EFF4B
1055:1041F0000346002880D19DF80C200132D2B2B24291
1056:104200008DF80C20FFF472AF76E74A46414620460F
1057:1042100000F0D2FE0346002894D06DE701265AE74D
1058:104220006FF0730304AF67E7582200202DE9F041D7
1059:104230000446884615461F46D0F81801E0B013B171
1060:1042400000EB40004008B5F5807F3ED82844B0F52B
1061:10425000C07F3AD84FF4C0720021684601F08BFC51
1062:104260006946D4F82431D4F81821D4F828019847A5
1063:1042700070BBD4F8186157B1D4E9493072080DEB1E
1064:104280000601984720BBD4F8183106EB5306B8F165
1065:10429000000F00D08DB9324669462046FFF70EFF69
1066:1042A000054610B90123C4F8143131466846FFF7BA
1067:1042B00017FD284660B0BDE8F0810DEB06004146D1
1068:1042C0002A462E4401F032FCE5E76FF00405F0E7E2
1069:1042D0006FF00805EDE700BF2DE9F047044604F153
1070:1042E000F4050F4691461E46DDF8208000F036FEAC
1071:1042F00029462046FFF74AFE08B1BDE8F087284668
1072:104300002022012101F037FCD4F81831C4F82471BF
1073:10431000C4F8289113B92023C4F818314246314615
1074:104320002046BDE8F0470123FFF780BFB2F5806F5C
1075:1043300000F295802DE9F04F89B09A46129BB3F5B3
1076:10434000807F00F29080D0F82431164604460F4654
1077:104350004BB3D0F81C31012B05D0D0F81421D0F884
1078:1043600020319A421FDD514600232046129AFFF762
1079:104370005DFF014698B900231293002E5ED0DFF84E
1080:10438000EC9009F1400B0021204600F001FE202EA8
1081:104390003546014628BF202504F1F40890B10846AF
1082:1043A00009B0BDE8F08FBAF1000FE6D0129B002BE8
1083:1043B000E1D051461A462046FFF780FE014600280C
1084:1043C000DBD0ECE749464022204600F0F5FD0146EF
1085:1043D0000028E4D141462022204600F0EDFD0146B0
1086:1043E0000028DCD16946204600F010FE0146002876
1087:1043F000D5D1204600F0CCFD01460028CFD159464A
1088:104400004022204600F0D8FD01460028C7D1694669
1089:104410002022204600F0D0FD01460028BFD14146B1
1090:10442000204600F0F3FD01460028B8D138462A4660
1091:10443000414601F07BFB761B2F44A4D15146204618
1092:10444000129AFFF73BFE01460028A8D10846D4F88F
1093:1044500014310133C4F8143109B0BDE8F08F6FF0A6
1094:104460000201084670476FF0040198E758220020C7
1095:10447000002130B58DB0282202A8019101F07BFB0C
1096:1044800002A800F047FF044610B120460DB030BD31
1097:10449000174D4FF0FF31286800F042F9044620B173
1098:1044A000144800F0D3F9012C18D0002000F068F96E
1099:1044B000D0B9114A02A901A800F0C4FC04460120A9
1100:1044C00000F05EF960B9286800F032F90028DCD00D
1101:1044D0000A4800F0BBF920460DB030BD0524F2E7D4
1102:1044E000074800F0B3F9EEE7064800F0AFF9E0E75F
1103:1044F000D4100020705D0000D8220020C85D0000AC
1104:10450000A85D0000885D000030B583B000F05CF865
1105:1045100028B100F0ABF80324204603B030BD00F012
1106:1045200077F8D8B900F02CF9E0B9224CD4F8283942
1107:104530001B0EF02B0AD1D4F8242A1F4B9A4231D0FB
1108:1045400000F044F8072400F091F8E5E7062400F0B5
1109:104550003DF800F08BF8204603B030BD042420461F
1110:1045600003B030BD00F032F800F080F8FFF780FFB4
1111:10457000044698B9114D2B68002BCDD10246014657
1112:10458000FFF752FB50B968220D4901ABFFF77CFBE6
1113:1045900020B920460B4B2B6003B030BD05242046CC
1114:1045A00003B030BD012000F0EBF80028DAD1C4F8E8
1115:1045B0000C0ADBE7001084500000E020F824002003
1116:1045C000FC2400205AEA5A5A002070470020704705
1117:1045D000430504D54FF0FF32034BC3F80821024BCB
1118:1045E000C3F8080A704700BF00108450014BC3F89D
1119:1045F000040A70470010845008B100F06BB84FF403
1120:104600007500704708B100F04FB84FF4750070475F
1121:1046100010B5114800F070F800B110BD0F4800F05F
1122:104620006BF80028F9D10E4C204600F065F8002800
1123:10463000F3D10C4B0C481C6000F05EF801460028DA
1124:10464000EBD100F02DF8044608B1204610BD00F073
1125:1046500079F82046FAE700BFE4100020E0100020BF
1126:10466000DC100020D4100020D810002008B5084825
1127:1046700000F04CF8074800F049F8074800F046F809
1128:10468000064800F043F8BDE8084000F00BB800BF52
1129:10469000E4100020E0100020DC100020D8100020E2
1130:1046A00000207047704700BF024610B4084CD4F891
1131:1046B000003A1342FBD021B1D4F804310B60C4F8A6
1132:1046C0000831034B0020C3F8082A5DF8044B7047FB
1133:1046D00000108450044AD2F8003A1842FBD0C2F8C5
1134:1046E000080A0020704700BF0010845001F0E8B9AC
1135:1046F0000A46002101F03FBA08B5034B02681B6867
1136:1047000010689847002008BD1011002008B5034B21
1137:1047100002685B6810689847002008BD10110020EF
1138:10472000024B02689B681068184700BF10110020F8
1139:1047300008B5034B0268DB6810689847002008BD85
1140:104740001011002070B5094C094D2069AB689847DD
1141:1047500018B1084B08485B6898470021074AEB6886
1142:1047600011602069BDE87040184700BFFC100020B0
1143:1047700010110020F4100020E05D000064250020EE
1144:10478000F8B51A4D1A4E0446B26828699047E8B940
1145:10479000184F3B684CB1A3B1012B19D0013B3B60D2
1146:1047A0002869F36898470020F8BD43B90121124AEF
1147:1047B000C2F800151149D1F81029002AFBD10133A4
1148:1047C0003B60F368286998470020F8BD0C48F8BDA5
1149:1047D0000A4AD2F81039002BFBD1074A6FF07E400D
1150:1047E000C2F80035FFF702FF3B68D7E7FC10002056
1151:1047F0001011002064250020000084500010845017
1152:10480000E98FFFFF014B1B68184700BF1011002004
1153:10481000014B9B68184700BF10110020014BDB685B
1154:10482000184700BF10110020BFF34F8F0549064BFA
1155:10483000CA6802F4E0621343CB60BFF34F8F00BF3E
1156:10484000FDE700BF00ED00E00400FA0530B44FF0D2
1157:10485000FE320025074B084C08494968C3F800247C
1158:10486000C3F80424C3F80824C3F80C24C4F8005582
1159:1048700030BC08470010845000008450F410002021
1160:1048800010B5044650B1636813F0685F05D0064A5E
1161:10489000934202D000236260236010BD034B0448A2
1162:1048A0005B689847EFE700BF2C5F5CA9F41000201D
1163:1048B000005E0000C8B143680D4A934213D013F064
1164:1048C000685F0ED0012350E8002F194640E8001C15
1165:1048D0009CF0000FF7D1012AF5D0BFF35F8F0020C5
1166:1048E000704704487047044870476FF4E0407047D1
1167:1048F0002C5F5CA9E98FFFFFEA8FFFFF034680B1C1
1168:10490000426809498A420AD012F0685F05D0BFF3B5
1169:104910005F8F002210461A607047044870470448B1
1170:1049200070476FF4E04070472C5F5CA9E98FFFFF90
1171:10493000EA8FFFFF10B5044620B10023034A23602D
1172:10494000626010BD0248FFF781FFF6E73A00003AC7
1173:10495000285E00002DE9F047002878D00C46002999
1174:1049600075D01D46002B72D007461AB101220023D4
1175:104970002A6003602B68002B64D02946204600F093
1176:10498000B7FD804600285FD12146286800F096FDDB
1177:104990008046002858D12B68082B6CD0042B6DD092
1178:1049A000A3F10209B9FA89F94FEA59190121354EE3
1179:1049B000C6F8C411C6F84011C6F8C411636AC6F837
1180:1049C0003031D6F830219342F6D14FF0000A4FF043
1181:1049D000FF30C6F82CA1FFF7FBFD6FF01B0350461C
1182:1049E000C6F80031FFF702FEC6F80C91D6F8040AAB
1183:1049F00040F48060FFF7FAFD0A23C6F83831089BBF
1184:104A0000012B29D02369204AA2FB03231B09626AD8
1185:104A1000404602FB03F303EB43031A4ADB039B0903
1186:104A2000C2F8D8310123C2F82C313B682A6823F040
1187:104A30007F4343EA02633B602A6843EA02233B6008
1188:104A4000BDE8F087DFF844804046BDE8F087DFF836
1189:104A500040804046BDE8F0874FF47F03D3F80C2C2C
1190:104A6000013206D0D3F80C3C074AA2FB03231B09F2
1191:104A7000CDE71623CBE74FF0030997E74FF0020984
1192:104A800094E700BF00108450ABAAAAAA310CF10031
1193:104A9000350CF10058B34B1EB3F5047F27D230B567
1194:104AA0004FF0000ECD00744671464B0901F01F0C0B
1195:104AB00050F82330BCF11F0F23FA0CF306D003F09B
1196:104AC000010319B901211C468E46EEE79C4201F113
1197:104AD000010106D01C464FF0010EA942E5D100208D
1198:104AE00030BD0EF1010E9645F7D1024830BD0148A8
1199:104AF000704700BF360CF100C0B32DE9F0434C1EE7
1200:104B0000B4F5047F1DD2E3B1DAB100252E46A846E4
1201:104B10002C46CF0003F1FF394FEA541C04F01F0E5E
1202:104B200050F82C10BEF11F0F21FA0EFC0CD00CF027
1203:104B3000010C4CB90126E04634463546ECE7964276
1204:104B400016D90C48BDE8F083AB420BD0C44508BF72
1205:104B50000136A945F3D001350134BC42DCD1002037
1206:104B6000BDE8F0830125E0462E46F5E70148704791
1207:104B70001D46F1E7370CF1002DE9F04F91B0834667
1208:104B8000DDE91B460D46002E6ED10F691C60002327
1209:104B90001A990B60002A00F02F819D4B6A6AD3F8A6
1210:104BA0003811D3F830319A4269D10A2967D19BF87C
1211:104BB0000330089304F10803079304230593954BEE
1212:104BC000934CA3FB07239B0803EB4303A7EB43038F
1213:104BD000039306971A9B069E1E60002E00F0EA8043
1214:104BE00000F096FC00230993BBF1000F00F0D58084
1215:104BF00098464FF0010ADDF81C90002D00F0CD80A2
1216:104C0000089B002B3DD0284608A900F071FC002825
1217:104C100039D0814B984220D0089B082B00F0E480CB
1218:104C200000225B000893294608AB58460092FFF724
1219:104C300091FE7A4B984200F0D38070B9DBF80020E7
1220:104C4000130A03F47F03134323F07F43CBF80030B0
1221:104C5000059B013B0593BDD10020039000F058FC5B
1222:104C6000039811B0BDE8F08F4FF47F01D1F80C0C20
1223:104C700001300CBF4FF40477D1F80C7C86E768480C
1224:104C8000EBE76648C5E72946089800F017FC0028BE
1225:104C9000BFD1089B082B00F0A980042B00F0A9804D
1226:104CA000A3F10203B3FA83F35B090493C4F8C4A12C
1227:104CB000C4F840A1C4F8C4A16B6AC4F83031D4F878
1228:104CC00030219342F6D100234FF0FF30C4F82C314D
1229:104CD000FFF77EFC002318466FF01B03C4F8003179
1230:104CE000FFF784FC049B4B4FC4F80C31D4F8040A42
1231:104CF00040F48060FFF77AFC0A23C4F838312B694E
1232:104D000009A8A7FB03236A6A1B0902FB03F303EB51
1233:104D10004303DB039B09C4F8D831C4F82CA1DBF8AA
1234:104D20000030089923F07F420B0243EA01631343EA
1235:104D3000CBF8003000F0B2FB099B03F01A030343E9
1236:104D40007FF46AAFA7FB0637D4F81431B8EB970F9E
1237:104D50000A93D4F818310B93D4F81C310C93D4F87F
1238:104D600020310D93D4F824310E93D4F828310F93C9
1239:104D700001D1039B9BB9484618220AA9183EFFF7A8
1240:104D8000B5FC09F1180908F101089EB100F0C0FB5B
1241:104D900000230993002D7FF433AF224839E74846BA
1242:104DA0001A46F61A0AA9994408F10108FFF79EFC71
1243:104DB000002EEBD1069F079E6A6939463046FFF701
1244:104DC00069FEAA6940B94FF4806339463046FFF75F
1245:104DD00093FE00283FF440AF00231A9A136018E7AF
1246:104DE0002B6A002B3FF439AF0F4836E703230493B7
1247:104DF0005CE70223049359E70122294658460096AE
1248:104E000008ABFFF7A7FD00283FF4D4AE25E700BFAD
1249:104E100000108450ABAAAAAA020CF100310CF100D8
1250:104E2000300CF100350CF100320CF10030B4DDE94A
1251:104E3000023402940024049DCDE9035430BCFFF7F2
1252:104E40009BBE00BF30B51546012487B005AB00936B
1253:104E50000022CDE9015404ABFFF78EFE07B030BD50
1254:104E6000F0B587B0002966D01E46002B63D01446EB
1255:104E7000002A60D0314F0D4638684FF0FF31FFF700
1256:104E80004FFC00284DD10020FFF77AFC002844D1C8
1257:104E90002B4800F03FFAD8B101204FF0FF35FFF763
1258:104EA0006FFC002835D14FF408712648FEF70EFF3D
1259:104EB00004212548FEF70AFF21482821FEF706FFB6
1260:104EC0003868FFF735FC00282FD1284607B0F0BD21
1261:104ED0001C4A0346029205AA019204AA039000927A
1262:104EE000174902461848FFF7A1FF03460028D3D10F
1263:104EF00028461D46059B22469C4228BF1A46049917
1264:104F000032600831FFF7F2FB0120FFF739FC00287F
1265:104F1000C9D00E48FFF79AFCC5E70D48FFF796FC8D
1266:104F2000B6E70C48FFF792FCADE70B48FFF78EFCA5
1267:104F3000284607B0F0BD4FF0FF35C6E7D41000207B
1268:104F40007C250020A425002078250020A85D0000F5
1269:104F5000885D0000705D00004C5E000010B50446E6
1270:104F600028B12046BDE81040F421FFF7C1BB04483A
1271:104F7000FFF76CFC2046BDE81040F421FFF7B8BBFA
1272:104F8000645E000010B1F421FEF7A0BE704700BFC0
1273:104F900008B521B1012908D06FF0360008BD012104
1274:104FA00000F058F80028F7D108BD022100F052F8AF
1275:104FB0000028F9D0F0E700BF30B505468818B0F5F5
1276:104FC000801F0B461446A1B001D8802A0CD9B3F536
1277:104FD000801F17D922461946284600F07DF804465E
1278:104FE00084B9204621B030BD6846FFF77FFB2246DA
1279:104FF0006946284600F070F8802104466846FFF7AD
1280:1050000077FBEDE76FF03604EBE700BF70B5E8B172
1281:105010000E46D9B1044600F031F80546B0B9236810
1282:10502000012B0BD0022B01D0284670BD1C2230462C
1283:1050300004F10801FFF75AFB284670BD20223046D4
1284:1050400004F10801FFF752FB284670BD6FF03605EA
1285:10505000EAE700BF78B138B50D46F0210446FFF706
1286:1050600047FB402320462560E36500F091FA0038B5
1287:1050700018BF012038BD0120704700BFF0B5056E94
1288:10508000A5B0044604AEE5B90023012701933046DC
1289:105090006760294602AA009300F046FA10B1012089
1290:1050A00025B0F0BD2A46204602A900F099FA002852
1291:1050B000F5D1204600F0AAFB0028F0D1206625B0EB
1292:1050C000F0BD802D2A46304628BF802204F16401BD
1293:1050D000FFF70CFB256ED7E7002800F0AE802DE926
1294:1050E000F04F1446A5B0002A3DD00F46002949D004
1295:1050F000B2F5803F0546006E20D34FF6FF7805F1EC
1296:10510000640AEB6D1A1AB2FBF3F103FB1122002AB9
1297:1051100065D18342B9464FF6FF7672D0B6FBF3FBFA
1298:1051200003FB0BFBBBF1000F30D1002E45D1A4F5E2
1299:105130007F44FF3CB4F5803F4744E2D2EA6D161A43
1300:10514000B6FBF2F302FB1366A64228BF2646002EEA
1301:1051500075D1824200F08D80B4FBF2F602FB06F6B8
1302:105160002EB9002C79D1002025B0BDE8F08F0023A6
1303:1051700031463846CDE9003302AA00F0D5F90028BF
1304:1051800000F09580012025B0BDE8F08F002359463E
1305:105190004846CDE9003302AA00F0C6F90028F1D153
1306:1051A0005A46284602A900F01BFA0028EAD1A6EBCD
1307:1051B0000B06286ED944002EB9D019304946324624
1308:1051C00005EB8000FFF792FAA4F57F44286EFF3CC0
1309:1051D0003044B4F5803F4744286692D2AEE742455A
1310:1051E00028BF4246164639465044FFF77FFA286EDC
1311:1051F000EB6D3044834207EB06092866A8EB0606F0
1312:105200008CD1802B28BF802351461A4604A8FFF773
1313:105210006DFA0023E96D02AACDE9003304A800F07D
1314:1052200083F90028AED12846EA6D02A900F0D8F92A
1315:105230000028A7D1EB6D286670E70120704705F1C3
1316:105240006403394632461844FFF750FA286EEA6D77
1317:105250003044A41B374428667BE72B6E2246193363
1318:1052600005EB83003946FFF741FA2B6E23442B668A
1319:1052700079E7802A28BF802205F1640104A8FFF79E
1320:1052800035FA0023E96D04A8CDE9003302AA00F045
1321:105290004BF900287FF476AF2846EA6D02A900F0AA
1322:1052A0009FF900287FF46EAFEA6D286654E7324616
1323:1052B000284602A900F094F900287FF463AF374430
1324:1052C000A41B4EE7F8B51C460546114816460F4686
1325:1052D000FFF744FE21460E48FFF75AFE044620B170
1326:1052E0000B48FFF74FFE2046F8BD3A4629460848CE
1327:1052F000FFF762FE04460028F2D131460448FFF76A
1328:1053000085FE04460248FFF73DFE2046F8BD00BF7B
1329:10531000C42700201C2370B582B001A90546019363
1330:1053200000F032F8044638B9019B1C2B07D0144C0E
1331:105330001C212846FFF7DCF9204602B070BDD5E9F4
1332:105340000112131E18BF0123003918BF01210126C5
1333:1053500028689B00EA6843EA4103002818BF43F02D
1334:105360000103EE612AB9C5E90834002BE4D1054CEC
1335:10537000DEE7204643F00803C5E9083402B070BDFB
1336:10538000370CF0000E0CF0000346002866D0002910
1337:1053900064D00A681C2A61D14FF47F023B49D2F8DD
1338:1053A000100C88425CD0D2F8101C013158D0D2F8D1
1339:1053B000101C4FF47F021960D2F8140C3449884253
1340:1053C00060D0D2F8141C01315CD0D2F8141C4FF418
1341:1053D0007F025960D2F8181C11F5947F4FD0D2F893
1342:1053E000181C01314BD0D2F8181C4FF47F02996081
1343:1053F000D2F81C0C274988423ED0D2F81C1C01313F
1344:105400003AD0D2F81C1C4FF47F02D960D2F8001CAD
1345:1054100070312FD0D2F8001C01312BD0D2F8001CF3
1346:105420004FF47F021961D2F8041CAF3120D0D2F8BA
1347:10543000041C01311CD0D2F8041C4FF47F025961C6
1348:10544000D2F8080C144988420DD0D2F8081C01315A
1349:1054500009D0D2F8082C00209A61704701207047CB
1350:1054600040F6FC01A5E740F2373200209A61704710
1351:105470005121E2E79021D3E742F60411C3E740F659
1352:10548000D861B2E742F2D001A1E700BFFCF8FFFF0C
1353:10549000D020FFFF0429FFFF37F3FFFF014608B5C7
1354:1054A0004FF48060FFF7AEF80022034BC3F8C82129
1355:1054B000C3F82C2108BD00BF001084500138072814
1356:1054C00005D8DFE800F0100E040A040404060748BB
1357:1054D0007047CB6800204B6270478B6800204B629E
1358:1054E00070474B68F6E70B68F4E700BF310CF1003A
1359:1054F0000B6802E0082B0B6006D8026A13424FEAE1
1360:105500004303F7D00020704700487047310CF1008A
1361:105510000022044B4FF48060C3F82C21C3F8C4214F
1362:10552000FFF756B800108450F0B5002483B0B0F1F6
1363:10553000005F8DF8074025D38C468444BCF1804F32
1364:1055400004461FD817461D4601220DF1070300F03F
1365:1055500097F90646B0B99DF80730099A3C603B714F
1366:1055600092B14DB10246089928460DF1070300F0AB
1367:1055700087F938B99DF807303046099A15601371DC
1368:1055800003B0F0BD4FF47506304603B0F0BD00BF68
1369:10559000D8B108B50368012B04D0022B0FD043B15A
1370:1055A0000B4808BD20220B490830FFF79FF8002068
1371:1055B00008BD142208490830FFF798F8F7E72022C1
1372:1055C00006490830FFF792F8F1E74FF4730070478F
1373:1055D0000100F300745E0000B45E0000945E000001
1374:1055E0002DE9F843002900F0F9800446002800F076
1375:1055F000F98003680F469046002B00F0C380013B02
1376:10560000012B00F2D7804FF0FF3178484FF00209AC
1377:10561000FFF786F8002840F0BF800020FFF7B0F8C1
1378:105620000646002840F0C280714AD2F81C39002B8F
1379:10563000FBD16F4DD5F8203C002BFBD14FF0FF3054
1380:10564000FEF7C6FFD5F8040A20F04000FEF7CEFFB3
1381:1056500001230722C5F81838C5F80029C5F8C43752
1382:10566000A36CC5F8CC37E36CC5F8D037C5F8C09744
1383:1056700023685BB1013B012B18D8636AC5F85C361F
1384:10568000236AC5F85836E369C5F85436A269584B01
1385:10569000C3F850266269C3F84C262269C3F848262D
1386:1056A000E268C3F84426A268C3F84026504AD2F8FC
1387:1056B0001039002BFBD1B8F1000F5FD06368402098
1388:1056C000012B08BFC2F884363A68494BC3F8282C2E
1389:1056D000C3F82C8CFEF790FF0646454AD2F81039E5
1390:1056E000002BFBD1424AD2F8203C002BFBD123688F
1391:1056F0005BB1013B012B18D8D2F85C366362D2F85B
1392:1057000058362362D2F85436E361394BD3F8502629
1393:10571000A261D3F84C266261D3F848262261D3F8FF
1394:105720004426E260D3F84036A36000230121304ACA
1395:10573000D2F8CC07A064D2F8D007E064C2F8C4174E
1396:10574000C2F88436C2F8C837D2F81039002BFBD122
1397:10575000C2F81838002E3BD1254BD3F8040A40F08C
1398:105760004000FEF743FF0120FFF70AF860BB1F4827
1399:10577000FEF7DEFF10BB3046BDE8F8830423C2F815
1400:10578000C837AAE74FF0FF3118484FF00109FEF77C
1401:10579000C7FF00283FF441AF1648FFF757F8002035
1402:1057A000FEF7EEFF064600283FF43EAF1248FFF733
1403:1057B0004DF839E7114E3046BDE8F8831048FFF741
1404:1057C00045F83046BDE8F8830E48FFF73FF8CEE7CE
1405:1057D000102104F10800FEF78BFFBDE70A4E3046AA
1406:1057E000BDE8F8834FF47306C5E700BFE41000205E
1407:1057F00000108450705D0000885D00000100F3001F
1408:10580000C85D0000A85D00000300F300A0B30346DC
1409:1058100070B4D0E90240D3E9041226BA05BA0CBA32
1410:1058200010BAC3E90440D3E90612986A09BAC3E979
1411:10583000026512BA996100BAD3E9084125BA0CBAD7
1412:10584000C3E90725D3E90B12C3E9094009BAD86BAC
1413:1058500012BAD962D3E90D4125BAC3E90C250CBAB5
1414:1058600000BAD3E9101209BA12BAC3E90E4019649A
1415:1058700000205A6470BC70474FF47300704700BF3B
1416:1058800000201870704700BF431810B501D21F2ABE
1417:1058900001D9002010BD013902F014030144102B7E
1418:1058A00080EA01043CD009DC8BB1042BF1D11F2C20
1419:1058B00040E840F315D941E840F10EE0142BE8D15F
1420:1058C0001F2C40E8C0F30CD941E8C0F105E01F2CC3
1421:1058D00040E800F305D941E800F11C460B468C4234
1422:1058E000D7D122F01402013A0A2AD2D801A151F8E4
1423:1058F00022F000BF435900003D5900002F5900001D
1424:1059000093580000935800009358000093580000EB
1425:105910004959000043590000375900002F59000031
1426:105920001F2C40E880F3DCD941E880F1D5E713F47F
1427:10593000001FAFD1ADE713F4801FFAE75B02A9D5D2
1428:10594000A7E713F4002FF4E713F4802FF1E700BF6B
1429:1059500008B5074B044613B10021AFF30080054B97
1430:105960001868836A03B19847204600F029F800BF01
1431:1059700000000000C85E000070B50D4D00260D4C03
1432:10598000641BA410A64209D10B4D00260B4C00F05D
1433:10599000D5F9641BA410A64205D170BD55F8043B8F
1434:1059A00001369847EEE755F8043B01369847F2E791
1435:1059B000A0110020A0110020A0110020A41100209F
1436:1059C000FEE700BFB7EE000AF7EE000AB7EE001AD6
1437:1059D000F7EE001AB7EE002AF7EE002AB7EE003A0B
1438:1059E000F7EE003AB7EE004AF7EE004AB7EE005A7B
1439:1059F000F7EE005AB7EE006AF7EE006AB7EE007AEB
1440:105A0000F7EE007AF1EE10CA40F29F01CFF20001EA
1441:105A10003CEA010CE1EE10CA002383F300887047D2
1442:105A2000FDF79CBAEFF30880EFF309812DE9F00F41
1443:105A30006B467246FAF7ACFF08B0FFF7F1FFFEE7DE
1444:105A4000FDF78CBAEFF30880EFF309812DE9F00F31
1445:105A50006B467246FAF79CFF08B0FFF7F1FFFEE7CE
1446:105A6000FDF77CBAEFF30880EFF309812DE9F00F21
1447:105A70006B467246FAF78CFF08B0FFF7F1FFFEE7BE
1448:105A8000FDF76CBAEFF30880EFF309812DE9F00F11
1449:105A90006B467246FAF77CFF08B0FFF7F1FFFEE7AE
1450:105AA000FDF75CBAEFF30880EFF309812DE9F00F01
1451:105AB0006B467246FAF76CFF08B0FFF7F1FFFEE79E
1452:105AC000814270B40546144602D370BC00F02EB873
1453:105AD000821821443CB141EA020313F003030FD1C1
1454:105AE000E018032812D86FF00300A30843430020F6
1455:105AF00019441A442344984210D1284670BC704778
1456:105B000011F8013D013C02F8013DE3E7581850F857
1457:105B1000046C981840F8046C043BE1E70C1A14F884
1458:105B2000016C141A04F8016C0130E4E770B5044606
1459:105B30003AB141EA040313F003030CD1D518032D45
1460:105B40000FD822F003031C441944002302F003027F
1461:105B500093420CD170BD11F8013B013A04F8013BAE
1462:105B6000E6E7CD1A2E68E51A2E60043BE6E75D5C99
1463:105B7000E5540133ECE7F0B5044662B922F00303C3
1464:105B8000234402F003021A44934214D1F0BD04F8F6
1465:105B9000011B013AF1E7A307F9D115460B0443EACB
1466:105BA00001630B4343EA01231619032DE6D9771B42
1467:105BB0003B60043DF9E703F8011BE5E708B5EFF3A7
1468:105BC0000583C3F308030BB1FDF7C8F9BDE808402E
1469:105BD000FDF74CBA10B50446EFF30583C3F3080391
1470:105BE0000BB1FDF7BBF92046BDE81040FDF741BA07
1471:105BF0002DE9F04104460D4616461F46EFF3058396
1472:105C0000C3F308030BB1FDF7A9F93B463246294619
1473:105C10002046BDE8F041FCF743BC2DE9F0410446C5
1474:105C20000D4616461F46EFF30583C3F308030BB179
1475:105C3000FDF794F93B46324629462046BDE8F0413F
1476:105C4000FCF768BC08B5EFF30583C3F308030BB199
1477:105C5000FDF784F9BDE80840FDF7DBB90020704787
1478:105C6000704710B5044608B1FDF75AFF2046BDE85D
1479:105C70001040FDF745BF10B50446406A10B1A16A57
1480:105C8000FFF7EFFF0020C4E9090010BD38B5044656
1481:105C9000FFF7F1FF236A2C22012B0CBF05466FF0A2
1482:105CA000960500212046FFF766FF284638BD0020F4
1483:105CB000704770470020704713B5002001AB1446B1
1484:105CC000FDF7E2FF30B9019BA34218BF6FF09300CC
1485:105CD00002B010BD6FF09200FAE7002070472DE986
1486:105CE000E04F2746A046A146A246A346A4462DED76
1487:105CF000108B4FF0000545EC185B45EC195A45EC4C
1488:105D00001A5A45EC1B5A45EC1C5A45EC1D5A45ECF9
1489:105D10001E5A45EC1F5AF1EE105A4FF66076C0F647
1490:105D2000FF763540E1EE105A84F30088254626467A
1491:105D3000A447BDEC108BBDE8E08F0000F8B500BFB4
1492:105D4000F8BC08BC9E467047F8B500BFF8BC08BC5C
1493:105D50009E467047FF8FFFFFFF8FFFFFFE8FFFFF05
1494:105D6000FE8FFFFFFD8FFFFFFC8FFFFFFC8FFFFF0C
1495:105D70004661696C20746F2061637175697265207A
1496:105D80006D757465780A00004661696C20746F2037
1497:105D9000696E63726561736520504D20636F756E27
1498:105DA0007465720A000000004661696C20746F20FF
1499:105DB000646563726561736520504D20636F756E15
1500:105DC0007465720A000000004661696C20746F20DF
1501:105DD00072656C65617365206D757465780A000085
1502:105DE000436F756C64206E6F74206C6F636B2070F2
1503:105DF0006F7765722073617665206D7574657800C4
1504:105E00006D757465785F667265652063616C6C653D
1505:105E1000642077697468204E554C4C207061726123
1506:105E20006D6574657200000043616E277420696EB1
1507:105E3000697469616C697A65206D757465782C2068
1508:105E4000776173204E554C4C0D0A00004661696C19
1509:105E500020746F20756E6C6F636B206D7574657840
1510:105E60000A0000000A637478206973204E554C4C78
1511:105E70000A00000067E6096A85AE67BB72F36E3CF4
1512:105E80003AF54FA57F520E518C68059BABD9831F05
1513:105E900019CDE05BD89E05C107D57C3617DD703083
1514:105EA00039590EF7310BC0FF11155868A78FF964E7
1515:105EB000A44FFABE0123456789ABCDEFFEDCBA984B
1516:105EC00076543210F0E1D2C34011002054464D5FA9
1517:105ED00043525950544F0054464D5F504C41544624
1518:105EE0004F524D5F53455256494345000000000054
1519:105EF00000000000000000000000000000000000A2
1520:107C00007FE97FE9FBF72CBD7FE97FE9FBF737BD13
1521:107C10007FE97FE9FBF75FBD7FE97FE9FBF752BDB5
1522:107C20007FE97FE9FBF73ABD00000000000000009B
1523:107C30000000000000000000000000000000000044
1524:107C40007AFFFFFF00900050000000008C3400001D
1525:107C50000400000000000000000000000000000020
1526:107C6000000000000000000090ED00E000A00350C4
1527:107C70007FA60350009000506F9500501412002012
1528:107C8000A811002044010000615C00005D5C000060
1529:107C9000775B0000DC1000200C1100200411002094
1530:107CA00000110020FC1000201D48000011480000B9
1531:107CB000054800000000000029480000381100209D
1532:107CC00030110020281100200000000020110020A9
1533:107CD0003549000081480000B5480000FD4800001B
1534:107CE000682500203A00003A6C2500203A00003A4E
1535:107CF000702500203A00003A742500203A00003A2E
1536:107D00000000000000000000000000000000000073
1537:107D10000000000000000000000000000000000063
1538:107D20000000000000000000000000000000000053
1539:107D30000000000000000000000000000000000043
1540:107D40000000000000000000000000000000000033
1541:107D50000000000000000000000000000000000023
1542:087D6000553700002D3700002B
1543:00000001FF
diff --git a/examples/nrf9151/s/.cargo/config.toml b/examples/nrf9151/s/.cargo/config.toml
new file mode 100644
index 000000000..f64c63966
--- /dev/null
+++ b/examples/nrf9151/s/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip nRF9160_xxAA"
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
new file mode 100644
index 000000000..7253fc4be
--- /dev/null
+++ b/examples/nrf9151/s/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf9151-secure-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf9151/s/build.rs b/examples/nrf9151/s/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf9151/s/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/nrf9151/s/memory.x b/examples/nrf9151/s/memory.x
new file mode 100644
index 000000000..4c7d4ebf0
--- /dev/null
+++ b/examples/nrf9151/s/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20018000, LENGTH = 160K
5}
diff --git a/examples/nrf9151/s/src/bin/blinky.rs b/examples/nrf9151/s/src/bin/blinky.rs
new file mode 100644
index 000000000..7457a95a3
--- /dev/null
+++ b/examples/nrf9151/s/src/bin/blinky.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 defmt::info!("high");
17 Timer::after_millis(500).await;
18 led.set_low();
19 defmt::info!("low");
20 Timer::after_millis(1000).await;
21 }
22}
diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml
index 1444b0cd1..6072b8595 100644
--- a/examples/nrf9160/.cargo/config.toml
+++ b/examples/nrf9160/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` 2# runner = "probe-rs run --chip nRF9160_xxAA"
3runner = "probe-rs run --chip nRF9160_xxAA" 3runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ]
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index af2385960..9aeb99317 100644
--- a/examples/nrf9160/Cargo.toml
+++ b/examples/nrf9160/Cargo.toml
@@ -5,16 +5,22 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] }
12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
11 13
12defmt = "0.3" 14defmt = "0.3"
13defmt-rtt = "0.4" 15defmt-rtt = "0.4"
14 16
17heapless = "0.8"
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21static_cell = { version = "2" }
22embedded-io = "0.6.1"
23embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
18 24
19[profile.release] 25[profile.release]
20debug = 2 26debug = 2
diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x
index 4c7d4ebf0..e33498773 100644
--- a/examples/nrf9160/memory.x
+++ b/examples/nrf9160/memory.x
@@ -1,5 +1,9 @@
1MEMORY 1MEMORY
2{ 2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K 3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20018000, LENGTH = 160K 4 RAM : ORIGIN = 0x20010000, LENGTH = 192K
5 IPC : ORIGIN = 0x20000000, LENGTH = 64K
5} 6}
7
8PROVIDE(__start_ipc = ORIGIN(IPC));
9PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC));
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs
new file mode 100644
index 000000000..929883884
--- /dev/null
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -0,0 +1,198 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5use core::net::IpAddr;
6use core::ptr::addr_of_mut;
7use core::slice;
8use core::str::FromStr;
9
10use defmt::{info, unwrap, warn};
11use embassy_executor::Spawner;
12use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources};
13use embassy_net_nrf91::context::Status;
14use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader};
15use embassy_nrf::buffered_uarte::{self, BufferedUarteTx};
16use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
17use embassy_nrf::uarte::Baudrate;
18use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte};
19use embassy_time::{Duration, Timer};
20use embedded_io_async::Write;
21use heapless::Vec;
22use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _};
24
25#[interrupt]
26fn IPC() {
27 embassy_net_nrf91::on_ipc_irq();
28}
29
30bind_interrupts!(struct Irqs {
31 UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;
32});
33
34#[embassy_executor::task]
35async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! {
36 let mut rx = [0u8; 1024];
37 loop {
38 let n = reader.read(&mut rx[..]).await;
39 unwrap!(uart.write_all(&rx[..n]).await);
40 }
41}
42
43#[embassy_executor::task]
44async fn modem_task(runner: Runner<'static>) -> ! {
45 runner.run().await
46}
47
48#[embassy_executor::task]
49async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_nrf91::NetDriver<'static>>) -> ! {
50 runner.run().await
51}
52
53#[embassy_executor::task]
54async fn control_task(
55 control: &'static context::Control<'static>,
56 config: context::Config<'static>,
57 stack: Stack<'static>,
58) {
59 unwrap!(control.configure(&config).await);
60 unwrap!(
61 control
62 .run(|status| {
63 stack.set_config_v4(status_to_config(status));
64 })
65 .await
66 );
67}
68
69fn status_to_config(status: &Status) -> embassy_net::ConfigV4 {
70 let Some(IpAddr::V4(addr)) = status.ip else {
71 panic!("Unexpected IP address");
72 };
73 let addr = Ipv4Address(addr.octets());
74
75 let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
76 Some(Ipv4Address(addr.octets()))
77 } else {
78 None
79 };
80
81 let mut dns_servers = Vec::new();
82 for dns in status.dns.iter() {
83 if let IpAddr::V4(ip) = dns {
84 unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
85 }
86 }
87
88 embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
89 address: Ipv4Cidr::new(addr, 32),
90 gateway,
91 dns_servers,
92 })
93}
94
95#[embassy_executor::task]
96async fn blink_task(pin: AnyPin) {
97 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
98 loop {
99 led.set_high();
100 Timer::after_millis(1000).await;
101 led.set_low();
102 Timer::after_millis(1000).await;
103 }
104}
105
106extern "C" {
107 static __start_ipc: u8;
108 static __end_ipc: u8;
109}
110
111#[embassy_executor::main]
112async fn main(spawner: Spawner) {
113 let p = embassy_nrf::init(Default::default());
114
115 info!("Hello World!");
116
117 unwrap!(spawner.spawn(blink_task(p.P0_02.degrade())));
118
119 let ipc_mem = unsafe {
120 let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit<u8>;
121 let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit<u8>;
122 let ipc_len = ipc_end.offset_from(ipc_start) as usize;
123 slice::from_raw_parts_mut(ipc_start, ipc_len)
124 };
125
126 static mut TRACE_BUF: [u8; 4096] = [0u8; 4096];
127 let mut config = uarte::Config::default();
128 config.baudrate = Baudrate::BAUD1M;
129 let uart = BufferedUarteTx::new(
130 //let trace_uart = BufferedUarteTx::new(
131 unsafe { peripherals::SERIAL0::steal() },
132 Irqs,
133 unsafe { peripherals::P0_01::steal() },
134 //unsafe { peripherals::P0_14::steal() },
135 config,
136 unsafe { &mut *addr_of_mut!(TRACE_BUF) },
137 );
138
139 static STATE: StaticCell<State> = StaticCell::new();
140 static TRACE: StaticCell<TraceBuffer> = StaticCell::new();
141 let (device, control, runner, tracer) =
142 embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await;
143 unwrap!(spawner.spawn(modem_task(runner)));
144 unwrap!(spawner.spawn(trace_task(uart, tracer)));
145
146 let config = embassy_net::Config::default();
147
148 // Generate "random" seed. nRF91 has no RNG, TODO figure out something...
149 let seed = 123456;
150
151 // Init network stack
152 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
153 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed);
154
155 unwrap!(spawner.spawn(net_task(runner)));
156
157 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
158 let control = CONTROL.init(context::Control::new(control, 0).await);
159
160 unwrap!(spawner.spawn(control_task(
161 control,
162 context::Config {
163 apn: b"iot.nat.es",
164 auth_prot: context::AuthProt::Pap,
165 auth: Some((b"orange", b"orange")),
166 },
167 stack
168 )));
169
170 stack.wait_config_up().await;
171
172 let mut rx_buffer = [0; 4096];
173 let mut tx_buffer = [0; 4096];
174 loop {
175 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
176 socket.set_timeout(Some(Duration::from_secs(10)));
177
178 info!("Connecting...");
179 let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
180 if let Err(e) = socket.connect((host_addr, 4242)).await {
181 warn!("connect error: {:?}", e);
182 Timer::after_secs(10).await;
183 continue;
184 }
185 info!("Connected to {:?}", socket.remote_endpoint());
186
187 let msg = b"Hello world!\n";
188 for _ in 0..10 {
189 if let Err(e) = socket.write_all(msg).await {
190 warn!("write error: {:?}", e);
191 break;
192 }
193 info!("txd: {}", core::str::from_utf8(msg).unwrap());
194 Timer::after_secs(1).await;
195 }
196 Timer::after_secs(4).await;
197 }
198}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e1092dba4..04b4c6317 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -6,29 +6,37 @@ license = "MIT OR Apache-2.0"
6 6
7 7
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] }
20cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } 20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] }
21 21
22defmt = "0.3" 22defmt = "0.3"
23defmt-rtt = "0.4" 23defmt-rtt = "0.4"
24fixed = "1.23.1" 24fixed = "1.23.1"
25fixed-macro = "1.2" 25fixed-macro = "1.2"
26 26
27# for web request example
28reqwless = { version = "0.12.0", features = ["defmt",]}
29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1"
31
32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
34
27#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
28cortex-m = { version = "0.7.6", features = ["inline-asm"] } 36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
29cortex-m-rt = "0.7.0" 37cortex-m-rt = "0.7.0"
38critical-section = "1.1"
30panic-probe = { version = "0.3", features = ["print-defmt"] } 39panic-probe = { version = "0.3", features = ["print-defmt"] }
31futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
32display-interface-spi = "0.4.1" 40display-interface-spi = "0.4.1"
33embedded-graphics = "0.7.1" 41embedded-graphics = "0.7.1"
34st7789 = "0.6.1" 42st7789 = "0.6.1"
@@ -36,19 +44,39 @@ display-interface = "0.4.1"
36byte-slice-cast = { version = "1.2.0", default-features = false } 44byte-slice-cast = { version = "1.2.0", default-features = false }
37smart-leds = "0.3.0" 45smart-leds = "0.3.0"
38heapless = "0.8" 46heapless = "0.8"
39usbd-hid = "0.6.1" 47usbd-hid = "0.8.1"
40 48
41embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 49embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
42embedded-hal-async = "1.0" 50embedded-hal-async = "1.0"
43embedded-hal-bus = { version = "0.1", features = ["async"] } 51embedded-hal-bus = { version = "0.1", features = ["async"] }
44embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 52embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
45embedded-storage = { version = "0.3" } 53embedded-storage = { version = "0.3" }
46static_cell = "2" 54static_cell = "2.1"
47portable-atomic = { version = "1.5", features = ["critical-section"] } 55portable-atomic = { version = "1.5", features = ["critical-section"] }
48log = "0.4" 56log = "0.4"
49pio-proc = "0.2" 57pio-proc = "0.2"
50pio = "0.2.1" 58pio = "0.2.1"
51rand = { version = "0.8.5", default-features = false } 59rand = { version = "0.8.5", default-features = false }
60embedded-sdmmc = "0.7.0"
61
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
52 64
53[profile.release] 65[profile.release]
54debug = 2 66debug = 2
67lto = true
68opt-level = 'z'
69
70[profile.dev]
71debug = 2
72lto = true
73opt-level = "z"
74
75[patch.crates-io]
76trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
77embassy-executor = { path = "../../embassy-executor" }
78embassy-sync = { path = "../../embassy-sync" }
79embassy-futures = { path = "../../embassy-futures" }
80embassy-time = { path = "../../embassy-time" }
81embassy-time-driver = { path = "../../embassy-time-driver" }
82embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp/src/bin/adc_dma.rs b/examples/rp/src/bin/adc_dma.rs
new file mode 100644
index 000000000..f755cf5bf
--- /dev/null
+++ b/examples/rp/src/bin/adc_dma.rs
@@ -0,0 +1,54 @@
1//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads.
2//! For multichannel, the samples are interleaved in the buffer:
3//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]`
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::Pull;
12use embassy_time::{Duration, Ticker};
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 ADC_IRQ_FIFO => InterruptHandler;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_rp::init(Default::default());
22 info!("Here we go!");
23
24 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
25 let mut dma = p.DMA_CH0;
26 let mut pin = Channel::new_pin(p.PIN_26, Pull::Up);
27 let mut pins = [
28 Channel::new_pin(p.PIN_27, Pull::Down),
29 Channel::new_pin(p.PIN_28, Pull::None),
30 Channel::new_pin(p.PIN_29, Pull::Up),
31 Channel::new_temp_sensor(p.ADC_TEMP_SENSOR),
32 ];
33
34 const BLOCK_SIZE: usize = 100;
35 const NUM_CHANNELS: usize = 4;
36 let mut ticker = Ticker::every(Duration::from_secs(1));
37 loop {
38 // Read 100 samples from a single channel
39 let mut buf = [0_u16; BLOCK_SIZE];
40 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1)
41 adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap();
42 info!("single: {:?} ...etc", buf[..8]);
43
44 // Read 100 samples from 4 channels interleaved
45 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }];
46 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1)
47 adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma)
48 .await
49 .unwrap();
50 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]);
51
52 ticker.next().await;
53 }
54}
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/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs
new file mode 100644
index 000000000..7524e7929
--- /dev/null
+++ b/examples/rp/src/bin/bluetooth.rs
@@ -0,0 +1,150 @@
1//! This example test the RP Pico W on board LED.
2//!
3//! It does not work with the RP Pico board. See blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use bt_hci::controller::ExternalController;
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_futures::join::join3;
13use embassy_rp::bind_interrupts;
14use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIO0};
16use embassy_rp::pio::{InterruptHandler, Pio};
17use embassy_sync::blocking_mutex::raw::NoopRawMutex;
18use embassy_time::{Duration, Timer};
19use static_cell::StaticCell;
20use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE};
21use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid};
22use trouble_host::gatt::GattEvent;
23use trouble_host::{Address, BleHost, BleHostResources, PacketQos};
24use {defmt_rtt as _, embassy_time as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30#[embassy_executor::task]
31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
32 runner.run().await
33}
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default());
38 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
39 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
40 let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin");
41
42 // To make flashing faster for development, you may want to flash the firmwares independently
43 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
44 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
45 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
46 // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) };
50
51 let pwr = Output::new(p.PIN_23, Level::Low);
52 let cs = Output::new(p.PIN_25, Level::High);
53 let mut pio = Pio::new(p.PIO0, Irqs);
54 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
55
56 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new());
58 let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
59 unwrap!(spawner.spawn(cyw43_task(runner)));
60 control.init(clm).await;
61
62 let controller: ExternalController<_, 10> = ExternalController::new(bt_device);
63 static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new();
64 let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None));
65
66 let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources);
67
68 ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff]));
69 let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();
70
71 // Generic Access Service (mandatory)
72 let id = b"Pico W Bluetooth";
73 let appearance = [0x80, 0x07];
74 let mut bat_level = [0; 1];
75 let handle = {
76 let mut svc = table.add_service(Service::new(0x1800));
77 let _ = svc.add_characteristic_ro(0x2a00, id);
78 let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
79 svc.build();
80
81 // Generic attribute service (mandatory)
82 table.add_service(Service::new(0x1801));
83
84 // Battery service
85 let mut svc = table.add_service(Service::new(0x180f));
86
87 svc.add_characteristic(
88 0x2a19,
89 &[CharacteristicProp::Read, CharacteristicProp::Notify],
90 &mut bat_level,
91 )
92 .build()
93 };
94
95 let mut adv_data = [0; 31];
96 AdStructure::encode_slice(
97 &[
98 AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
99 AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]),
100 AdStructure::CompleteLocalName(b"Pico W Bluetooth"),
101 ],
102 &mut adv_data[..],
103 )
104 .unwrap();
105
106 let server = ble.gatt_server(&table);
107
108 info!("Starting advertising and GATT service");
109 let _ = join3(
110 ble.run(),
111 async {
112 loop {
113 match server.next().await {
114 Ok(GattEvent::Write { handle, connection: _ }) => {
115 let _ = table.get(handle, |value| {
116 info!("Write event. Value written: {:?}", value);
117 });
118 }
119 Ok(GattEvent::Read { .. }) => {
120 info!("Read event");
121 }
122 Err(e) => {
123 error!("Error processing GATT events: {:?}", e);
124 }
125 }
126 }
127 },
128 async {
129 let mut advertiser = ble
130 .advertise(
131 &Default::default(),
132 Advertisement::ConnectableScannableUndirected {
133 adv_data: &adv_data[..],
134 scan_data: &[],
135 },
136 )
137 .await
138 .unwrap();
139 let conn = advertiser.accept().await.unwrap();
140 // Keep connection alive
141 let mut tick: u8 = 0;
142 loop {
143 Timer::after(Duration::from_secs(10)).await;
144 tick += 1;
145 server.notify(handle, &conn, &[tick]).await.unwrap();
146 }
147 },
148 )
149 .await;
150}
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index bd52cadca..12003adbe 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -36,8 +36,8 @@ async fn ethernet_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -63,24 +63,24 @@ 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
70 let seed = rng.next_u64(); 71 let seed = rng.next_u64();
71 72
72 // Init network stack 73 // Init network stack
73 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
75 let stack = &*STACK.init(Stack::new( 75 let (stack, runner) = embassy_net::new(
76 device, 76 device,
77 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
78 RESOURCES.init(StackResources::<3>::new()), 78 RESOURCES.init(StackResources::new()),
79 seed, 79 seed,
80 )); 80 );
81 81
82 // Launch network task 82 // Launch network task
83 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(runner)));
84 84
85 info!("Waiting for DHCP..."); 85 info!("Waiting for DHCP...");
86 let cfg = wait_for_config(stack).await; 86 let cfg = wait_for_config(stack).await;
@@ -88,12 +88,12 @@ async fn main(spawner: Spawner) {
88 info!("IP address: {:?}", local_addr); 88 info!("IP address: {:?}", local_addr);
89 89
90 // Create two sockets listening to the same port, to handle simultaneous connections 90 // Create two sockets listening to the same port, to handle simultaneous connections
91 unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); 91 unwrap!(spawner.spawn(listen_task(stack, 0, 1234)));
92 unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); 92 unwrap!(spawner.spawn(listen_task(stack, 1, 1234)));
93} 93}
94 94
95#[embassy_executor::task(pool_size = 2)] 95#[embassy_executor::task(pool_size = 2)]
96async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) { 96async fn listen_task(stack: Stack<'static>, id: u8, port: u16) {
97 let mut rx_buffer = [0; 4096]; 97 let mut rx_buffer = [0; 4096];
98 let mut tx_buffer = [0; 4096]; 98 let mut tx_buffer = [0; 4096];
99 let mut buf = [0; 4096]; 99 let mut buf = [0; 4096];
@@ -130,7 +130,7 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16)
130 } 130 }
131} 131}
132 132
133async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 133async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
134 loop { 134 loop {
135 if let Some(config) = stack.config_v4() { 135 if let Some(config) = stack.config_v4() {
136 return config.clone(); 136 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 3e4fbd2e6..d66a43a88 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -38,8 +38,8 @@ async fn ethernet_task(
38} 38}
39 39
40#[embassy_executor::task] 40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 41async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
42 stack.run().await 42 runner.run().await
43} 43}
44 44
45#[embassy_executor::main] 45#[embassy_executor::main]
@@ -66,24 +66,24 @@ 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
73 let seed = rng.next_u64(); 74 let seed = rng.next_u64();
74 75
75 // Init network stack 76 // Init network stack
76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 77 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
77 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 78 let (stack, runner) = embassy_net::new(
78 let stack = &*STACK.init(Stack::new(
79 device, 79 device,
80 embassy_net::Config::dhcpv4(Default::default()), 80 embassy_net::Config::dhcpv4(Default::default()),
81 RESOURCES.init(StackResources::<2>::new()), 81 RESOURCES.init(StackResources::new()),
82 seed, 82 seed,
83 )); 83 );
84 84
85 // Launch network task 85 // Launch network task
86 unwrap!(spawner.spawn(net_task(&stack))); 86 unwrap!(spawner.spawn(net_task(runner)));
87 87
88 info!("Waiting for DHCP..."); 88 info!("Waiting for DHCP...");
89 let cfg = wait_for_config(stack).await; 89 let cfg = wait_for_config(stack).await;
@@ -118,7 +118,7 @@ async fn main(spawner: Spawner) {
118 } 118 }
119} 119}
120 120
121async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 121async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
122 loop { 122 loop {
123 if let Some(config) = stack.config_v4() { 123 if let Some(config) = stack.config_v4() {
124 return config.clone(); 124 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 5532851f3..97d9bd4c9 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -37,8 +37,8 @@ async fn ethernet_task(
37} 37}
38 38
39#[embassy_executor::task] 39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
41 stack.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::main] 44#[embassy_executor::main]
@@ -65,24 +65,24 @@ 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
72 let seed = rng.next_u64(); 73 let seed = rng.next_u64();
73 74
74 // Init network stack 75 // Init network stack
75 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 76 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 77 let (stack, runner) = embassy_net::new(
77 let stack = &*STACK.init(Stack::new(
78 device, 78 device,
79 embassy_net::Config::dhcpv4(Default::default()), 79 embassy_net::Config::dhcpv4(Default::default()),
80 RESOURCES.init(StackResources::<2>::new()), 80 RESOURCES.init(StackResources::new()),
81 seed, 81 seed,
82 )); 82 );
83 83
84 // Launch network task 84 // Launch network task
85 unwrap!(spawner.spawn(net_task(&stack))); 85 unwrap!(spawner.spawn(net_task(runner)));
86 86
87 info!("Waiting for DHCP..."); 87 info!("Waiting for DHCP...");
88 let cfg = wait_for_config(stack).await; 88 let cfg = wait_for_config(stack).await;
@@ -127,7 +127,7 @@ async fn main(spawner: Spawner) {
127 } 127 }
128} 128}
129 129
130async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 130async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
131 loop { 131 loop {
132 if let Some(config) = stack.config_v4() { 132 if let Some(config) = stack.config_v4() {
133 return config.clone(); 133 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index adb1d8941..b1b5f9758 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -36,8 +36,8 @@ async fn ethernet_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -63,24 +63,24 @@ 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
70 let seed = rng.next_u64(); 71 let seed = rng.next_u64();
71 72
72 // Init network stack 73 // Init network stack
73 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
74 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 75 let (stack, runner) = embassy_net::new(
75 let stack = &*STACK.init(Stack::new(
76 device, 76 device,
77 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
78 RESOURCES.init(StackResources::<2>::new()), 78 RESOURCES.init(StackResources::new()),
79 seed, 79 seed,
80 )); 80 );
81 81
82 // Launch network task 82 // Launch network task
83 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(runner)));
84 84
85 info!("Waiting for DHCP..."); 85 info!("Waiting for DHCP...");
86 let cfg = wait_for_config(stack).await; 86 let cfg = wait_for_config(stack).await;
@@ -107,7 +107,7 @@ async fn main(spawner: Spawner) {
107 } 107 }
108} 108}
109 109
110async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 110async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
111 loop { 111 loop {
112 if let Some(config) = stack.config_v4() { 112 if let Some(config) = stack.config_v4() {
113 return config.clone(); 113 return config.clone();
diff --git a/examples/rp/src/bin/i2c_async_embassy.rs b/examples/rp/src/bin/i2c_async_embassy.rs
new file mode 100644
index 000000000..a65b71b9f
--- /dev/null
+++ b/examples/rp/src/bin/i2c_async_embassy.rs
@@ -0,0 +1,85 @@
1//! This example shows how to communicate asynchronous using i2c with external chip.
2//!
3//! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c.
4//! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_rp::i2c::InterruptHandler;
11use {defmt_rtt as _, panic_probe as _};
12
13// Our anonymous hypotetical temperature sensor could be:
14// a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C
15// It requires no configuration or calibration, works with all i2c bus speeds,
16// never stretches clock or does anything complicated. Replies with one u16.
17// It requires only one write to take it out of suspend mode, and stays on.
18// Often result would be just on 12 bits, but here we'll simplify it to 16.
19
20enum UncomplicatedSensorId {
21 A(UncomplicatedSensorU8),
22 B(UncomplicatedSensorU16),
23}
24enum UncomplicatedSensorU8 {
25 First = 0x48,
26}
27enum UncomplicatedSensorU16 {
28 Other = 0x0049,
29}
30
31impl Into<u16> for UncomplicatedSensorU16 {
32 fn into(self) -> u16 {
33 self as u16
34 }
35}
36impl Into<u16> for UncomplicatedSensorU8 {
37 fn into(self) -> u16 {
38 0x48
39 }
40}
41impl From<UncomplicatedSensorId> for u16 {
42 fn from(t: UncomplicatedSensorId) -> Self {
43 match t {
44 UncomplicatedSensorId::A(x) => x.into(),
45 UncomplicatedSensorId::B(x) => x.into(),
46 }
47 }
48}
49
50embassy_rp::bind_interrupts!(struct Irqs {
51 I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>;
52});
53
54#[embassy_executor::main]
55async fn main(_task_spawner: embassy_executor::Spawner) {
56 let p = embassy_rp::init(Default::default());
57 let sda = p.PIN_14;
58 let scl = p.PIN_15;
59 let config = embassy_rp::i2c::Config::default();
60 let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config);
61
62 const WAKEYWAKEY: u16 = 0xBABE;
63 let mut result: [u8; 2] = [0, 0];
64 // wait for sensors to initialize
65 embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
66
67 let _res_1 = bus
68 .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes())
69 .await;
70 let _res_2 = bus
71 .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes())
72 .await;
73
74 loop {
75 let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First);
76 let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other);
77 let sensors = [s1, s2];
78 for sensor in sensors {
79 if bus.read_async(sensor, &mut result).await.is_ok() {
80 info!("Result {}", u16::from_be_bytes(result.into()));
81 }
82 }
83 embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await;
84 }
85}
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
index ac470d2be..9fffb4646 100644
--- a/examples/rp/src/bin/i2c_slave.rs
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -110,7 +110,7 @@ async fn main(spawner: Spawner) {
110 let c_sda = p.PIN_1; 110 let c_sda = p.PIN_1;
111 let c_scl = p.PIN_0; 111 let c_scl = p.PIN_0;
112 let mut config = i2c::Config::default(); 112 let mut config = i2c::Config::default();
113 config.frequency = 5_000; 113 config.frequency = 1_000_000;
114 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); 114 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
115 115
116 unwrap!(spawner.spawn(controller_task(controller))); 116 unwrap!(spawner.spawn(controller_task(controller)));
diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs
new file mode 100644
index 000000000..5b9d7027e
--- /dev/null
+++ b/examples/rp/src/bin/interrupt.rs
@@ -0,0 +1,94 @@
1//! This example shows how you can use raw interrupt handlers alongside embassy.
2//! The example also showcases some of the options available for sharing resources/data.
3//!
4//! In the example, an ADC reading is triggered every time the PWM wraps around.
5//! The sample data is sent down a channel, to be processed inside a low priority task.
6//! The processed data is then used to adjust the PWM duty cycle, once every second.
7
8#![no_std]
9#![no_main]
10
11use core::cell::{Cell, RefCell};
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::gpio::Pull;
17use embassy_rp::interrupt;
18use embassy_rp::pwm::{Config, Pwm};
19use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
20use embassy_sync::blocking_mutex::Mutex;
21use embassy_sync::channel::Channel;
22use embassy_time::{Duration, Ticker};
23use portable_atomic::{AtomicU32, Ordering};
24use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _};
26
27static COUNTER: AtomicU32 = AtomicU32::new(0);
28static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
29static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
30 Mutex::new(RefCell::new(None));
31static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 embassy_rp::pac::SIO.spinlock(31).write_value(1);
36 let p = embassy_rp::init(Default::default());
37
38 let adc = Adc::new_blocking(p.ADC, Default::default());
39 let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
40 ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
41
42 let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
43 PWM.lock(|p| p.borrow_mut().replace(pwm));
44
45 // Enable the interrupt for pwm slice 4
46 embassy_rp::pac::PWM.inte().modify(|w| w.set_ch4(true));
47 unsafe {
48 cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP);
49 }
50
51 // Tasks require their resources to have 'static lifetime
52 // No Mutex needed when sharing within the same executor/prio level
53 static AVG: StaticCell<Cell<u32>> = StaticCell::new();
54 let avg = AVG.init(Default::default());
55 spawner.must_spawn(processing(avg));
56
57 let mut ticker = Ticker::every(Duration::from_secs(1));
58 loop {
59 ticker.next().await;
60 let freq = COUNTER.swap(0, Ordering::Relaxed);
61 info!("pwm freq: {:?} Hz", freq);
62 info!("adc average: {:?}", avg.get());
63
64 // Update the pwm duty cycle, based on the averaged adc reading
65 let mut config = Config::default();
66 config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
67 PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
68 }
69}
70
71#[embassy_executor::task]
72async fn processing(avg: &'static Cell<u32>) {
73 let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
74 loop {
75 let val = ADC_VALUES.receive().await;
76 buffer.write(val);
77 let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
78 avg.set(sum / buffer.len() as u32);
79 }
80}
81
82#[interrupt]
83fn PWM_IRQ_WRAP() {
84 critical_section::with(|cs| {
85 let mut adc = ADC.borrow(cs).borrow_mut();
86 let (adc, p26) = adc.as_mut().unwrap();
87 let val = adc.blocking_read(p26).unwrap();
88 ADC_VALUES.try_send(val).ok();
89
90 // Clear the interrupt, so we don't immediately re-enter this irq handler
91 PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped();
92 });
93 COUNTER.fetch_add(1, Ordering::Relaxed);
94}
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index c7b087476..7cb546c91 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -30,10 +30,14 @@ fn main() -> ! {
30 let p = embassy_rp::init(Default::default()); 30 let p = embassy_rp::init(Default::default());
31 let led = Output::new(p.PIN_25, Level::Low); 31 let led = Output::new(p.PIN_25, Level::Low);
32 32
33 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { 33 spawn_core1(
34 let executor1 = EXECUTOR1.init(Executor::new()); 34 p.CORE1,
35 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); 35 unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) },
36 }); 36 move || {
37 let executor1 = EXECUTOR1.init(Executor::new());
38 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
39 },
40 );
37 41
38 let executor0 = EXECUTOR0.init(Executor::new()); 42 let executor0 = EXECUTOR0.init(Executor::new());
39 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); 43 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
index 26b80c11d..2b397f97d 100644
--- a/examples/rp/src/bin/multiprio.rs
+++ b/examples/rp/src/bin/multiprio.rs
@@ -80,7 +80,7 @@ async fn run_med() {
80 info!(" [med] Starting long computation"); 80 info!(" [med] Starting long computation");
81 81
82 // Spin-wait to simulate a long CPU computation 82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(125_000_000); // ~1 second 83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84 84
85 let end = Instant::now(); 85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; 86 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
@@ -97,7 +97,7 @@ async fn run_low() {
97 info!("[low] Starting long computation"); 97 info!("[low] Starting long computation");
98 98
99 // Spin-wait to simulate a long CPU computation 99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(250_000_000); // ~2 seconds 100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101 101
102 let end = Instant::now(); 102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; 103 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs
new file mode 100644
index 000000000..0e21d5833
--- /dev/null
+++ b/examples/rp/src/bin/orchestrate_tasks.rs
@@ -0,0 +1,318 @@
1//! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system.
2//!
3//! We demonstrate how to:
4//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system.
5//! - use a signal to terminate a task.
6//! - use command channels to send commands to another task.
7//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures.
8//!
9//! There are more patterns to orchestrate tasks, this is just one example.
10//!
11//! We will use these tasks to generate example "state information":
12//! - a task that generates random numbers in intervals of 60s
13//! - a task that generates random numbers in intervals of 30s
14//! - a task that generates random numbers in intervals of 90s
15//! - a task that notifies about being attached/disattached from usb power
16//! - a task that measures vsys voltage in intervals of 30s
17//! - a task that consumes the state information and reacts to it
18
19#![no_std]
20#![no_main]
21
22use assign_resources::assign_resources;
23use defmt::*;
24use embassy_executor::Spawner;
25use embassy_futures::select::{select, Either};
26use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
27use embassy_rp::clocks::RoscRng;
28use embassy_rp::gpio::{Input, Pull};
29use embassy_rp::{bind_interrupts, peripherals};
30use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
31use embassy_sync::{channel, signal};
32use embassy_time::{Duration, Timer};
33use rand::RngCore;
34use {defmt_rtt as _, panic_probe as _};
35
36// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks.
37// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software
38// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins.
39// For this example it will not matter much, the concept of what we are showing remains valid.
40assign_resources! {
41 vsys: Vsys {
42 adc: ADC,
43 pin_29: PIN_29,
44 },
45 vbus: Vbus {
46 pin_24: PIN_24,
47 },
48}
49
50bind_interrupts!(struct Irqs {
51 ADC_IRQ_FIFO => InterruptHandler;
52});
53
54/// This is the type of Events that we will send from the worker tasks to the orchestrating task.
55enum Events {
56 UsbPowered(bool),
57 VsysVoltage(f32),
58 FirstRandomSeed(u32),
59 SecondRandomSeed(u32),
60 ThirdRandomSeed(u32),
61 ResetFirstRandomSeed,
62}
63
64/// This is the type of Commands that we will send from the orchestrating task to the worker tasks.
65/// Note that we are lazy here and only have one command, you might want to have more.
66enum Commands {
67 /// This command will stop the appropriate worker task
68 Stop,
69}
70
71/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex.
72#[derive(Default, Debug, Clone, Format)]
73struct State {
74 usb_powered: bool,
75 vsys_voltage: f32,
76 first_random_seed: u32,
77 second_random_seed: u32,
78 third_random_seed: u32,
79 times_we_got_first_random_seed: u8,
80 maximum_times_we_want_first_random_seed: u8,
81}
82
83impl State {
84 fn new() -> Self {
85 Self {
86 usb_powered: false,
87 vsys_voltage: 0.0,
88 first_random_seed: 0,
89 second_random_seed: 0,
90 third_random_seed: 0,
91 times_we_got_first_random_seed: 0,
92 maximum_times_we_want_first_random_seed: 3,
93 }
94 }
95}
96
97/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events.
98/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we
99/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for
100/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots
101/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting.
102/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options.
103static EVENT_CHANNEL: channel::Channel<CriticalSectionRawMutex, Events, 10> = channel::Channel::new();
104
105/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active.
106static STOP_FIRST_RANDOM_SIGNAL: signal::Signal<CriticalSectionRawMutex, Commands> = signal::Signal::new();
107
108/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although
109/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice
110/// and depends on your use case.
111static CONSUMER_CHANNEL: channel::Channel<CriticalSectionRawMutex, State, 1> = channel::Channel::new();
112
113// And now we can put all this into use
114
115/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the
116/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running.
117#[embassy_executor::main]
118async fn main(spawner: Spawner) {
119 // initialize the peripherals
120 let p = embassy_rp::init(Default::default());
121 // split the resources, for convenience - see above
122 let r = split_resources! {p};
123
124 // spawn the tasks
125 spawner.spawn(orchestrate(spawner)).unwrap();
126 spawner.spawn(random_60s(spawner)).unwrap();
127 spawner.spawn(random_90s(spawner)).unwrap();
128 spawner.spawn(usb_power(spawner, r.vbus)).unwrap();
129 spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap();
130 spawner.spawn(consumer(spawner)).unwrap();
131}
132
133/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system.
134#[embassy_executor::task]
135async fn orchestrate(_spawner: Spawner) {
136 let mut state = State::new();
137
138 // we need to have a receiver for the events
139 let receiver = EVENT_CHANNEL.receiver();
140
141 // and we need a sender for the consumer task
142 let state_sender = CONSUMER_CHANNEL.sender();
143
144 loop {
145 // we await on the receiver, this will block until a new event is available
146 // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event
147 // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html
148 // The task random_30s does a select, if you want to have a look at that.
149 // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame.
150 // We keep it simple here.
151 let event = receiver.receive().await;
152
153 // react to the events
154 match event {
155 Events::UsbPowered(usb_powered) => {
156 // update the state and/or react to the event here
157 state.usb_powered = usb_powered;
158 info!("Usb powered: {}", usb_powered);
159 }
160 Events::VsysVoltage(voltage) => {
161 // update the state and/or react to the event here
162 state.vsys_voltage = voltage;
163 info!("Vsys voltage: {}", voltage);
164 }
165 Events::FirstRandomSeed(seed) => {
166 // update the state and/or react to the event here
167 state.first_random_seed = seed;
168 // here we change some meta state, we count how many times we got the first random seed
169 state.times_we_got_first_random_seed += 1;
170 info!(
171 "First random seed: {}, and that was iteration {} of receiving this.",
172 seed, &state.times_we_got_first_random_seed
173 );
174 }
175 Events::SecondRandomSeed(seed) => {
176 // update the state and/or react to the event here
177 state.second_random_seed = seed;
178 info!("Second random seed: {}", seed);
179 }
180 Events::ThirdRandomSeed(seed) => {
181 // update the state and/or react to the event here
182 state.third_random_seed = seed;
183 info!("Third random seed: {}", seed);
184 }
185 Events::ResetFirstRandomSeed => {
186 // update the state and/or react to the event here
187 state.times_we_got_first_random_seed = 0;
188 state.first_random_seed = 0;
189 info!("Resetting the first random seed counter");
190 }
191 }
192 // we now have an altered state
193 // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here
194 // for now we just keep it simple
195
196 // we send the state to the consumer task
197 // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example
198 // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the
199 // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed.
200 // We keep it simple here.
201 state_sender.send(state.clone()).await;
202 }
203}
204
205/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex
206/// and we could have multiple consumer tasks, each reacting to different parts of the state.
207#[embassy_executor::task]
208async fn consumer(spawner: Spawner) {
209 // we need to have a receiver for the state
210 let receiver = CONSUMER_CHANNEL.receiver();
211 let sender = EVENT_CHANNEL.sender();
212 loop {
213 // we await on the receiver, this will block until a new state is available
214 let state = receiver.receive().await;
215 // react to the state, in this case here we just log it
216 info!("The consumer has reveived this state: {:?}", &state);
217
218 // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system
219 match state.times_we_got_first_random_seed {
220 max if max == state.maximum_times_we_want_first_random_seed => {
221 info!("Stopping the first random signal task");
222 // we send a command to the task
223 STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop);
224 // we notify the orchestrator that we have sent the command
225 sender.send(Events::ResetFirstRandomSeed).await;
226 }
227 0 => {
228 // we start the task, which presents us with an interesting problem, because we may return here before the task has started
229 // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully
230 info!("Starting the first random signal task");
231 match spawner.spawn(random_30s(spawner)) {
232 Ok(_) => info!("Successfully spawned random_30s task"),
233 Err(e) => info!("Failed to spawn random_30s task: {:?}", e),
234 }
235 }
236 _ => {}
237 }
238 }
239}
240
241/// This task will generate random numbers in intervals of 30s
242/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that.
243/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically.
244#[embassy_executor::task]
245async fn random_30s(_spawner: Spawner) {
246 let mut rng = RoscRng;
247 let sender = EVENT_CHANNEL.sender();
248 loop {
249 // we either await on the timer or the signal, whichever comes first.
250 let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await;
251 match futures {
252 Either::First(_) => {
253 // we received are operating on the timer
254 info!("30s are up, generating random number");
255 let random_number = rng.next_u32();
256 sender.send(Events::FirstRandomSeed(random_number)).await;
257 }
258 Either::Second(_) => {
259 // we received the signal to stop
260 info!("Received signal to stop, goodbye!");
261 break;
262 }
263 }
264 }
265}
266
267/// This task will generate random numbers in intervals of 60s
268#[embassy_executor::task]
269async fn random_60s(_spawner: Spawner) {
270 let mut rng = RoscRng;
271 let sender = EVENT_CHANNEL.sender();
272 loop {
273 Timer::after(Duration::from_secs(60)).await;
274 let random_number = rng.next_u32();
275 sender.send(Events::SecondRandomSeed(random_number)).await;
276 }
277}
278
279/// This task will generate random numbers in intervals of 90s
280#[embassy_executor::task]
281async fn random_90s(_spawner: Spawner) {
282 let mut rng = RoscRng;
283 let sender = EVENT_CHANNEL.sender();
284 loop {
285 Timer::after(Duration::from_secs(90)).await;
286 let random_number = rng.next_u32();
287 sender.send(Events::ThirdRandomSeed(random_number)).await;
288 }
289}
290
291/// This task will notify if we are connected to usb power
292#[embassy_executor::task]
293pub async fn usb_power(_spawner: Spawner, r: Vbus) {
294 let mut vbus_in = Input::new(r.pin_24, Pull::None);
295 let sender = EVENT_CHANNEL.sender();
296 loop {
297 sender.send(Events::UsbPowered(vbus_in.is_high())).await;
298 vbus_in.wait_for_any_edge().await;
299 }
300}
301
302/// This task will measure the vsys voltage in intervals of 30s
303#[embassy_executor::task]
304pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) {
305 let mut adc = Adc::new(r.adc, Irqs, Config::default());
306 let vsys_in = r.pin_29;
307 let mut channel = Channel::new_pin(vsys_in, Pull::None);
308 let sender = EVENT_CHANNEL.sender();
309 loop {
310 // read the adc value
311 let adc_value = adc.read(&mut channel).await.unwrap();
312 // convert the adc value to voltage.
313 // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc
314 let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0;
315 sender.send(Events::VsysVoltage(voltage)).await;
316 Timer::after(Duration::from_secs(30)).await;
317 }
318}
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index 3fab7b5f2..6c02630e0 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) {
35 // allowing direct connection of the display to the RP2040 without level shifters. 35 // allowing direct connection of the display to the RP2040 without level shifters.
36 let p = embassy_rp::init(Default::default()); 36 let p = embassy_rp::init(Default::default());
37 37
38 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { 38 let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, {
39 let mut c = pwm::Config::default(); 39 let mut c = pwm::Config::default();
40 c.divider = 125.into(); 40 c.divider = 125.into();
41 c.top = 100; 41 c.top = 100;
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
new file mode 100644
index 000000000..5076101ec
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -0,0 +1,155 @@
1//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor.
2
3#![no_std]
4#![no_main]
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 PIO0_IRQ_0 => InterruptHandler<PIO0>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let mut pio = Pio::new(p.PIO0, Irqs);
21 let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2);
22
23 loop {
24 sensor.start().await; // Start a new measurement
25 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
26 match sensor.temperature().await {
27 Ok(temp) => info!("temp = {:?} deg C", temp),
28 _ => error!("sensor error"),
29 }
30 Timer::after_secs(1).await;
31 }
32}
33
34/// DS18B20 temperature sensor driver
35pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
36 sm: StateMachine<'d, PIO, SM>,
37}
38
39impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> {
40 /// Create a new instance the driver
41 pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self {
42 let prg = pio_proc::pio_asm!(
43 r#"
44 .wrap_target
45 again:
46 pull block
47 mov x, osr
48 jmp !x, read
49 write:
50 set pindirs, 1
51 set pins, 0
52 loop1:
53 jmp x--,loop1
54 set pindirs, 0 [31]
55 wait 1 pin 0 [31]
56 pull block
57 mov x, osr
58 bytes1:
59 pull block
60 set y, 7
61 set pindirs, 1
62 bit1:
63 set pins, 0 [1]
64 out pins,1 [31]
65 set pins, 1 [20]
66 jmp y--,bit1
67 jmp x--,bytes1
68 set pindirs, 0 [31]
69 jmp again
70 read:
71 pull block
72 mov x, osr
73 bytes2:
74 set y, 7
75 bit2:
76 set pindirs, 1
77 set pins, 0 [1]
78 set pindirs, 0 [5]
79 in pins,1 [10]
80 jmp y--,bit2
81 jmp x--,bytes2
82 .wrap
83 "#,
84 );
85
86 let pin = common.make_pio_pin(pin);
87 let mut cfg = Config::default();
88 cfg.use_program(&common.load_program(&prg.program), &[]);
89 cfg.set_out_pins(&[&pin]);
90 cfg.set_in_pins(&[&pin]);
91 cfg.set_set_pins(&[&pin]);
92 cfg.shift_in = ShiftConfig {
93 auto_fill: true,
94 direction: ShiftDirection::Right,
95 threshold: 8,
96 };
97 cfg.clock_divider = 255_u8.into();
98 sm.set_config(&cfg);
99 sm.set_enable(true);
100 Self { sm }
101 }
102
103 /// Write bytes over the wire
104 async fn write_bytes(&mut self, bytes: &[u8]) {
105 self.sm.tx().wait_push(250).await;
106 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
107 for b in bytes {
108 self.sm.tx().wait_push(*b as u32).await;
109 }
110 }
111
112 /// Read bytes from the wire
113 async fn read_bytes(&mut self, bytes: &mut [u8]) {
114 self.sm.tx().wait_push(0).await;
115 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
116 for b in bytes.iter_mut() {
117 *b = (self.sm.rx().wait_pull().await >> 24) as u8;
118 }
119 }
120
121 /// Calculate CRC8 of the data
122 fn crc8(data: &[u8]) -> u8 {
123 let mut temp;
124 let mut data_byte;
125 let mut crc = 0;
126 for b in data {
127 data_byte = *b;
128 for _ in 0..8 {
129 temp = (crc ^ data_byte) & 0x01;
130 crc >>= 1;
131 if temp != 0 {
132 crc ^= 0x8C;
133 }
134 data_byte >>= 1;
135 }
136 }
137 crc
138 }
139
140 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
141 pub async fn start(&mut self) {
142 self.write_bytes(&[0xCC, 0x44]).await;
143 }
144
145 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
146 pub async fn temperature(&mut self) -> Result<f32, ()> {
147 self.write_bytes(&[0xCC, 0xBE]).await;
148 let mut data = [0; 9];
149 self.read_bytes(&mut data).await;
150 match Self::crc8(&data) == 0 {
151 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.),
152 false => Err(()),
153 }
154 }
155}
diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs
new file mode 100644
index 000000000..23d63d435
--- /dev/null
+++ b/examples/rp/src/bin/pio_pwm.rs
@@ -0,0 +1,118 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::gpio::Level;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
11use embassy_rp::{bind_interrupts, clocks};
12use embassy_time::Timer;
13use pio::InstructionOperands;
14use {defmt_rtt as _, panic_probe as _};
15
16const REFRESH_INTERVAL: u64 = 20000;
17
18bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22pub fn to_pio_cycles(duration: Duration) -> u32 {
23 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
24}
25
26pub struct PwmPio<'d, T: Instance, const SM: usize> {
27 sm: StateMachine<'d, T, SM>,
28}
29
30impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
31 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
32 let prg = pio_proc::pio_asm!(
33 ".side_set 1 opt"
34 "pull noblock side 0"
35 "mov x, osr"
36 "mov y, isr"
37 "countloop:"
38 "jmp x!=y noset"
39 "jmp skip side 1"
40 "noset:"
41 "nop"
42 "skip:"
43 "jmp y-- countloop"
44 );
45
46 pio.load_program(&prg.program);
47 let pin = pio.make_pio_pin(pin);
48 sm.set_pins(Level::High, &[&pin]);
49 sm.set_pin_dirs(Direction::Out, &[&pin]);
50
51 let mut cfg = Config::default();
52 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
53
54 sm.set_config(&cfg);
55
56 Self { sm }
57 }
58
59 pub fn start(&mut self) {
60 self.sm.set_enable(true);
61 }
62
63 pub fn stop(&mut self) {
64 self.sm.set_enable(false);
65 }
66
67 pub fn set_period(&mut self, duration: Duration) {
68 let is_enabled = self.sm.is_enabled();
69 while !self.sm.tx().empty() {} // Make sure that the queue is empty
70 self.sm.set_enable(false);
71 self.sm.tx().push(to_pio_cycles(duration));
72 unsafe {
73 self.sm.exec_instr(
74 InstructionOperands::PULL {
75 if_empty: false,
76 block: false,
77 }
78 .encode(),
79 );
80 self.sm.exec_instr(
81 InstructionOperands::OUT {
82 destination: ::pio::OutDestination::ISR,
83 bit_count: 32,
84 }
85 .encode(),
86 );
87 };
88 if is_enabled {
89 self.sm.set_enable(true) // Enable if previously enabled
90 }
91 }
92
93 pub fn set_level(&mut self, level: u32) {
94 self.sm.tx().push(level);
95 }
96
97 pub fn write(&mut self, duration: Duration) {
98 self.set_level(to_pio_cycles(duration));
99 }
100}
101
102#[embassy_executor::main]
103async fn main(_spawner: Spawner) {
104 let p = embassy_rp::init(Default::default());
105 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
106
107 // Note that PIN_25 is the led pin on the Pico
108 let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25);
109 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL));
110 pwm_pio.start();
111
112 let mut duration = 0;
113 loop {
114 duration = (duration + 1) % 1000;
115 pwm_pio.write(Duration::from_micros(duration));
116 Timer::after_millis(1).await;
117 }
118}
diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs
new file mode 100644
index 000000000..a79540479
--- /dev/null
+++ b/examples/rp/src/bin/pio_servo.rs
@@ -0,0 +1,208 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::gpio::Level;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
11use embassy_rp::{bind_interrupts, clocks};
12use embassy_time::Timer;
13use pio::InstructionOperands;
14use {defmt_rtt as _, panic_probe as _};
15
16const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo
17const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo
18const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical
19const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle
20
21bind_interrupts!(struct Irqs {
22 PIO0_IRQ_0 => InterruptHandler<PIO0>;
23});
24
25pub fn to_pio_cycles(duration: Duration) -> u32 {
26 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
27}
28
29pub struct PwmPio<'d, T: Instance, const SM: usize> {
30 sm: StateMachine<'d, T, SM>,
31}
32
33impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
34 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
35 let prg = pio_proc::pio_asm!(
36 ".side_set 1 opt"
37 "pull noblock side 0"
38 "mov x, osr"
39 "mov y, isr"
40 "countloop:"
41 "jmp x!=y noset"
42 "jmp skip side 1"
43 "noset:"
44 "nop"
45 "skip:"
46 "jmp y-- countloop"
47 );
48
49 pio.load_program(&prg.program);
50 let pin = pio.make_pio_pin(pin);
51 sm.set_pins(Level::High, &[&pin]);
52 sm.set_pin_dirs(Direction::Out, &[&pin]);
53
54 let mut cfg = Config::default();
55 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
56
57 sm.set_config(&cfg);
58
59 Self { sm }
60 }
61
62 pub fn start(&mut self) {
63 self.sm.set_enable(true);
64 }
65
66 pub fn stop(&mut self) {
67 self.sm.set_enable(false);
68 }
69
70 pub fn set_period(&mut self, duration: Duration) {
71 let is_enabled = self.sm.is_enabled();
72 while !self.sm.tx().empty() {} // Make sure that the queue is empty
73 self.sm.set_enable(false);
74 self.sm.tx().push(to_pio_cycles(duration));
75 unsafe {
76 self.sm.exec_instr(
77 InstructionOperands::PULL {
78 if_empty: false,
79 block: false,
80 }
81 .encode(),
82 );
83 self.sm.exec_instr(
84 InstructionOperands::OUT {
85 destination: ::pio::OutDestination::ISR,
86 bit_count: 32,
87 }
88 .encode(),
89 );
90 };
91 if is_enabled {
92 self.sm.set_enable(true) // Enable if previously enabled
93 }
94 }
95
96 pub fn set_level(&mut self, level: u32) {
97 self.sm.tx().push(level);
98 }
99
100 pub fn write(&mut self, duration: Duration) {
101 self.set_level(to_pio_cycles(duration));
102 }
103}
104
105pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
106 pwm: PwmPio<'d, T, SM>,
107 period: Duration,
108 min_pulse_width: Duration,
109 max_pulse_width: Duration,
110 max_degree_rotation: u64,
111}
112
113impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
114 pub fn new(pwm: PwmPio<'d, T, SM>) -> Self {
115 Self {
116 pwm,
117 period: Duration::from_micros(REFRESH_INTERVAL),
118 min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH),
119 max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH),
120 max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION,
121 }
122 }
123
124 pub fn set_period(mut self, duration: Duration) -> Self {
125 self.period = duration;
126 self
127 }
128
129 pub fn set_min_pulse_width(mut self, duration: Duration) -> Self {
130 self.min_pulse_width = duration;
131 self
132 }
133
134 pub fn set_max_pulse_width(mut self, duration: Duration) -> Self {
135 self.max_pulse_width = duration;
136 self
137 }
138
139 pub fn set_max_degree_rotation(mut self, degree: u64) -> Self {
140 self.max_degree_rotation = degree;
141 self
142 }
143
144 pub fn build(mut self) -> Servo<'d, T, SM> {
145 self.pwm.set_period(self.period);
146 Servo {
147 pwm: self.pwm,
148 min_pulse_width: self.min_pulse_width,
149 max_pulse_width: self.max_pulse_width,
150 max_degree_rotation: self.max_degree_rotation,
151 }
152 }
153}
154
155pub struct Servo<'d, T: Instance, const SM: usize> {
156 pwm: PwmPio<'d, T, SM>,
157 min_pulse_width: Duration,
158 max_pulse_width: Duration,
159 max_degree_rotation: u64,
160}
161
162impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> {
163 pub fn start(&mut self) {
164 self.pwm.start();
165 }
166
167 pub fn stop(&mut self) {
168 self.pwm.stop();
169 }
170
171 pub fn write_time(&mut self, duration: Duration) {
172 self.pwm.write(duration);
173 }
174
175 pub fn rotate(&mut self, degree: u64) {
176 let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64)
177 / self.max_degree_rotation;
178 let mut duration =
179 Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64);
180 if self.max_pulse_width < duration {
181 duration = self.max_pulse_width;
182 }
183
184 self.pwm.write(duration);
185 }
186}
187
188#[embassy_executor::main]
189async fn main(_spawner: Spawner) {
190 let p = embassy_rp::init(Default::default());
191 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
192
193 let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1);
194 let mut servo = ServoBuilder::new(pwm_pio)
195 .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo
196 .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment.
197 .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value.
198 .build();
199
200 servo.start();
201
202 let mut degree = 0;
203 loop {
204 degree = (degree + 1) % 120;
205 servo.rotate(degree);
206 Timer::after_millis(50).await;
207 }
208}
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs
index ab9ecf623..4952f4fbd 100644
--- a/examples/rp/src/bin/pio_stepper.rs
+++ b/examples/rp/src/bin/pio_stepper.rs
@@ -69,7 +69,7 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); 69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); 70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
71 assert!(clock_divider >= 1, "clkdiv must be >= 1"); 71 assert!(clock_divider >= 1, "clkdiv must be >= 1");
72 T::PIO.sm(SM).clkdiv().write(|w| w.0 = clock_divider.to_bits() << 8); 72 self.sm.set_clock_divider(clock_divider);
73 self.sm.clkdiv_restart(); 73 self.sm.clkdiv_restart();
74 } 74 }
75 75
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index a07f1c180..53b696309 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) {
60 60
61 // Create embassy-usb DeviceBuilder using the driver and config. 61 // Create embassy-usb DeviceBuilder using the driver and config.
62 // It needs some buffers for building the descriptors. 62 // It needs some buffers for building the descriptors.
63 let mut device_descriptor = [0; 256];
64 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
65 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
66 let mut control_buf = [0; 64]; 65 let mut control_buf = [0; 64];
@@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) {
70 let mut builder = Builder::new( 69 let mut builder = Builder::new(
71 driver, 70 driver,
72 config, 71 config,
73 &mut device_descriptor,
74 &mut config_descriptor, 72 &mut config_descriptor,
75 &mut bos_descriptor, 73 &mut bos_descriptor,
76 &mut [], // no msos descriptors 74 &mut [], // no msos descriptors
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index 9a97cb8a7..ac145933c 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -12,7 +12,7 @@ use embassy_rp::pio::{
12 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 12 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
13}; 13};
14use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; 14use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
15use embassy_time::Timer; 15use embassy_time::{Duration, Ticker, Timer};
16use fixed::types::U24F8; 16use fixed::types::U24F8;
17use fixed_macro::fixed; 17use fixed_macro::fixed;
18use smart_leds::RGB8; 18use smart_leds::RGB8;
@@ -107,6 +107,8 @@ impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
107 107
108 // DMA transfer 108 // DMA transfer
109 self.sm.tx().dma_push(self.dma.reborrow(), &words).await; 109 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
110
111 Timer::after_micros(55).await;
110 } 112 }
111} 113}
112 114
@@ -143,6 +145,7 @@ async fn main(_spawner: Spawner) {
143 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); 145 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
144 146
145 // Loop forever making RGB values and pushing them out to the WS2812. 147 // Loop forever making RGB values and pushing them out to the WS2812.
148 let mut ticker = Ticker::every(Duration::from_millis(10));
146 loop { 149 loop {
147 for j in 0..(256 * 5) { 150 for j in 0..(256 * 5) {
148 debug!("New Colors:"); 151 debug!("New Colors:");
@@ -152,7 +155,7 @@ async fn main(_spawner: Spawner) {
152 } 155 }
153 ws2812.write(&data).await; 156 ws2812.write(&data).await;
154 157
155 Timer::after_millis(10).await; 158 ticker.next().await;
156 } 159 }
157 } 160 }
158} 161}
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
index 4fb62546d..26e233260 100644
--- a/examples/rp/src/bin/pwm.rs
+++ b/examples/rp/src/bin/pwm.rs
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
18 let mut c: Config = Default::default(); 18 let mut c: Config = Default::default();
19 c.top = 0x8000; 19 c.top = 0x8000;
20 c.compare_b = 8; 20 c.compare_b = 8;
21 let mut pwm = Pwm::new_output_b(p.PWM_CH4, p.PIN_25, c.clone()); 21 let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone());
22 22
23 loop { 23 loop {
24 info!("current LED duty cycle: {}/32768", c.compare_b); 24 info!("current LED duty cycle: {}/32768", c.compare_b);
diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs
index e7bcbfbd4..bf454a936 100644
--- a/examples/rp/src/bin/pwm_input.rs
+++ b/examples/rp/src/bin/pwm_input.rs
@@ -5,6 +5,7 @@
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::gpio::Pull;
8use embassy_rp::pwm::{Config, InputMode, Pwm}; 9use embassy_rp::pwm::{Config, InputMode, Pwm};
9use embassy_time::{Duration, Ticker}; 10use embassy_time::{Duration, Ticker};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -14,7 +15,7 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
15 16
16 let cfg: Config = Default::default(); 17 let cfg: Config = Default::default();
17 let pwm = Pwm::new_input(p.PWM_CH2, p.PIN_5, InputMode::RisingEdge, cfg); 18 let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg);
18 19
19 let mut ticker = Ticker::every(Duration::from_secs(1)); 20 let mut ticker = Ticker::every(Duration::from_secs(1));
20 loop { 21 loop {
diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs
new file mode 100644
index 000000000..c6cb5d64c
--- /dev/null
+++ b/examples/rp/src/bin/shared_bus.rs
@@ -0,0 +1,115 @@
1//! This example shows how to share (async) I2C and SPI buses between multiple devices.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{AnyPin, Level, Output};
12use embassy_rp::i2c::{self, I2c, InterruptHandler};
13use embassy_rp::peripherals::{I2C1, SPI1};
14use embassy_rp::spi::{self, Spi};
15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::mutex::Mutex;
17use embassy_time::Timer;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>;
22type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>;
23
24bind_interrupts!(struct Irqs {
25 I2C1_IRQ => InterruptHandler<I2C1>;
26});
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31 info!("Here we go!");
32
33 // Shared I2C bus
34 let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default());
35 static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new();
36 let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
37
38 spawner.must_spawn(i2c_task_a(i2c_bus));
39 spawner.must_spawn(i2c_task_b(i2c_bus));
40
41 // Shared SPI bus
42 let spi_cfg = spi::Config::default();
43 let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg);
44 static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new();
45 let spi_bus = SPI_BUS.init(Mutex::new(spi));
46
47 // Chip select pins for the SPI devices
48 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High);
49 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High);
50
51 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
52 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
53}
54
55#[embassy_executor::task]
56async fn i2c_task_a(i2c_bus: &'static I2c1Bus) {
57 let i2c_dev = I2cDevice::new(i2c_bus);
58 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0);
59 loop {
60 info!("i2c task A");
61 Timer::after_secs(1).await;
62 }
63}
64
65#[embassy_executor::task]
66async fn i2c_task_b(i2c_bus: &'static I2c1Bus) {
67 let i2c_dev = I2cDevice::new(i2c_bus);
68 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE);
69 loop {
70 info!("i2c task B");
71 Timer::after_secs(1).await;
72 }
73}
74
75#[embassy_executor::task]
76async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
77 let spi_dev = SpiDevice::new(spi_bus, cs);
78 let _sensor = DummySpiDeviceDriver::new(spi_dev);
79 loop {
80 info!("spi task A");
81 Timer::after_secs(1).await;
82 }
83}
84
85#[embassy_executor::task]
86async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
87 let spi_dev = SpiDevice::new(spi_bus, cs);
88 let _sensor = DummySpiDeviceDriver::new(spi_dev);
89 loop {
90 info!("spi task B");
91 Timer::after_secs(1).await;
92 }
93}
94
95// Dummy I2C device driver, using `embedded-hal-async`
96struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> {
97 _i2c: I2C,
98}
99
100impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> {
101 fn new(i2c_dev: I2C, _address: u8) -> Self {
102 Self { _i2c: i2c_dev }
103 }
104}
105
106// Dummy SPI device driver, using `embedded-hal-async`
107struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> {
108 _spi: SPI,
109}
110
111impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> {
112 fn new(spi_dev: SPI) -> Self {
113 Self { _spi: spi_dev }
114 }
115}
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/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs
new file mode 100644
index 000000000..4cbc82f7b
--- /dev/null
+++ b/examples/rp/src/bin/spi_sdmmc.rs
@@ -0,0 +1,83 @@
1//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI.
2//!
3//! The example will attempt to read a file `MY_FILE.TXT` from the root directory
4//! of the SD card and print its contents.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_embedded_hal::SetConfig;
11use embassy_executor::Spawner;
12use embassy_rp::spi::Spi;
13use embassy_rp::{gpio, spi};
14use embedded_hal_bus::spi::ExclusiveDevice;
15use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
16use gpio::{Level, Output};
17use {defmt_rtt as _, panic_probe as _};
18
19struct DummyTimesource();
20
21impl embedded_sdmmc::TimeSource for DummyTimesource {
22 fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
23 embedded_sdmmc::Timestamp {
24 year_since_1970: 0,
25 zero_indexed_month: 0,
26 zero_indexed_day: 0,
27 hours: 0,
28 minutes: 0,
29 seconds: 0,
30 }
31 }
32}
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 embassy_rp::pac::SIO.spinlock(31).write_value(1);
37 let p = embassy_rp::init(Default::default());
38
39 // SPI clock needs to be running at <= 400kHz during initialization
40 let mut config = spi::Config::default();
41 config.frequency = 400_000;
42 let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config);
43 // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons
44 let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin);
45 // Real cs pin
46 let cs = Output::new(p.PIN_16, Level::High);
47
48 let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay);
49 info!("Card size is {} bytes", sdcard.num_bytes().unwrap());
50
51 // Now that the card is initialized, the SPI clock can go faster
52 let mut config = spi::Config::default();
53 config.frequency = 16_000_000;
54 sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
55
56 // Now let's look for volumes (also known as partitions) on our block device.
57 // To do this we need a Volume Manager. It will take ownership of the block device.
58 let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource());
59
60 // Try and access Volume 0 (i.e. the first partition).
61 // The volume object holds information about the filesystem on that volume.
62 let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap();
63 info!("Volume 0: {:?}", defmt::Debug2Format(&volume0));
64
65 // Open the root directory (mutably borrows from the volume).
66 let mut root_dir = volume0.open_root_dir().unwrap();
67
68 // Open a file called "MY_FILE.TXT" in the root directory
69 // This mutably borrows the directory.
70 let mut my_file = root_dir
71 .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
72 .unwrap();
73
74 // Print the contents of the file
75 while !my_file.is_eof() {
76 let mut buf = [0u8; 32];
77 if let Ok(n) = my_file.read(&mut buf) {
78 info!("{:a}", buf[..n]);
79 }
80 }
81
82 loop {}
83}
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index fac61aa04..468d2b61a 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -31,7 +31,7 @@ async fn main(spawner: Spawner) {
31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); 31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
32 let rx_buf = &mut RX_BUF.init([0; 16])[..]; 32 let rx_buf = &mut RX_BUF.init([0; 16])[..];
33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
34 let (rx, mut tx) = uart.split(); 34 let (mut tx, rx) = uart.split();
35 35
36 unwrap!(spawner.spawn(reader(rx))); 36 unwrap!(spawner.spawn(reader(rx)));
37 37
diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs
new file mode 100644
index 000000000..085be280b
--- /dev/null
+++ b/examples/rp/src/bin/uart_r503.rs
@@ -0,0 +1,158 @@
1#![no_std]
2#![no_main]
3
4use defmt::{debug, error, info};
5use embassy_executor::Spawner;
6use embassy_rp::bind_interrupts;
7use embassy_rp::peripherals::UART0;
8use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart};
9use embassy_time::{with_timeout, Duration, Timer};
10use heapless::Vec;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(pub struct Irqs {
14 UART0_IRQ => UARTInterruptHandler<UART0>;
15});
16
17const START: u16 = 0xEF01;
18const ADDRESS: u32 = 0xFFFFFFFF;
19
20// ================================================================================
21
22// Data package format
23// Name Length Description
24// ==========================================================================================================
25// Start 2 bytes Fixed value of 0xEF01; High byte transferred first.
26// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command.
27// High byte transferred first and at wrong adder value, module
28// will reject to transfer.
29// PID 1 byte 01H Command packet;
30// 02H Data packet; Data packet shall not appear alone in executing
31// processs, must follow command packet or acknowledge packet.
32// 07H Acknowledge packet;
33// 08H End of Data packet.
34// LENGTH 2 bytes Refers to the length of package content (command packets and data packets)
35// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes.
36// And high byte is transferred first.
37// DATA - It can be commands, data, command’s parameters, acknowledge result, etc.
38// (fingerprint character value, template are all deemed as data);
39// SUM 2 bytes The arithmetic sum of package identifier, package length and all package
40// contens. Overflowing bits are omitted. high byte is transferred first.
41
42// ================================================================================
43
44// Checksum is calculated on 'length (2 bytes) + data (??)'.
45fn compute_checksum(buf: Vec<u8, 32>) -> u16 {
46 let mut checksum = 0u16;
47
48 let check_end = buf.len();
49 let checked_bytes = &buf[6..check_end];
50 for byte in checked_bytes {
51 checksum += (*byte) as u16;
52 }
53 return checksum;
54}
55
56#[embassy_executor::main]
57async fn main(_spawner: Spawner) {
58 info!("Start");
59
60 let p = embassy_rp::init(Default::default());
61
62 // Initialize the fingerprint scanner.
63 let mut config = Config::default();
64 config.baudrate = 57600;
65 config.stop_bits = StopBits::STOP1;
66 config.data_bits = DataBits::DataBits8;
67 config.parity = Parity::ParityNone;
68
69 let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1);
70 let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config);
71 let (mut tx, mut rx) = uart.split();
72
73 let mut vec_buf: Vec<u8, 32> = heapless::Vec::new();
74 let mut data: Vec<u8, 32> = heapless::Vec::new();
75
76 let mut speeds: Vec<u8, 3> = heapless::Vec::new();
77 let _ = speeds.push(0xC8); // Slow
78 let _ = speeds.push(0x20); // Medium
79 let _ = speeds.push(0x02); // Fast
80
81 // Cycle through the three colours Red, Blue and Purple forever.
82 loop {
83 for colour in 1..=3 {
84 for speed in &speeds {
85 // Set the data first, because the length is dependent on that.
86 // However, we write the length bits before we do the data.
87 data.clear();
88 let _ = data.push(0x01); // ctrl=Breathing light
89 let _ = data.push(*speed);
90 let _ = data.push(colour as u8); // colour=Red, Blue, Purple
91 let _ = data.push(0x00); // times=Infinite
92
93 // Clear buffers
94 vec_buf.clear();
95
96 // START
97 let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]);
98
99 // ADDRESS
100 let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]);
101
102 // PID
103 let _ = vec_buf.extend_from_slice(&[0x01]);
104
105 // LENGTH
106 let len: u16 = (1 + data.len() + 2).try_into().unwrap();
107 let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]);
108
109 // COMMAND
110 let _ = vec_buf.push(0x35); // Command: AuraLedConfig
111
112 // DATA
113 let _ = vec_buf.extend_from_slice(&data);
114
115 // SUM
116 let chk = compute_checksum(vec_buf.clone());
117 let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]);
118
119 // =====
120
121 // Send command buffer.
122 let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap();
123 debug!(" write='{:?}'", data_write[..]);
124 match tx.write(&data_write).await {
125 Ok(..) => info!("Write successful."),
126 Err(e) => error!("Write error: {:?}", e),
127 }
128
129 // =====
130
131 // Read command buffer.
132 let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time!
133 let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer.
134
135 info!("Attempting read.");
136 loop {
137 // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms
138 // for this command.
139 match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await {
140 Ok(..) => {
141 // Extract and save read byte.
142 debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]);
143 let _ = data_read.push(read_buf[0]).unwrap();
144 }
145 Err(..) => break, // TimeoutError -> Ignore.
146 }
147 }
148 info!("Read successful");
149 debug!(" read='{:?}'", data_read[..]);
150
151 Timer::after_secs(3).await;
152 info!("Changing speed.");
153 }
154
155 info!("Changing colour.");
156 }
157 }
158}
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 01f0d5967..9a15125d4 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -8,7 +8,8 @@
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_net::tcp::TcpSocket; 10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Stack, StackResources}; 11use embassy_net::StackResources;
12use embassy_rp::clocks::RoscRng;
12use embassy_rp::peripherals::USB; 13use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler}; 14use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_rp::{bind_interrupts, peripherals}; 15use embassy_rp::{bind_interrupts, peripherals};
@@ -16,6 +17,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
17use embassy_usb::{Builder, Config, UsbDevice}; 18use embassy_usb::{Builder, Config, UsbDevice};
18use embedded_io_async::Write; 19use embedded_io_async::Write;
20use rand::RngCore;
19use static_cell::StaticCell; 21use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
21 23
@@ -38,13 +40,14 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
38} 40}
39 41
40#[embassy_executor::task] 42#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 43async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
42 stack.run().await 44 runner.run().await
43} 45}
44 46
45#[embassy_executor::main] 47#[embassy_executor::main]
46async fn main(spawner: Spawner) { 48async fn main(spawner: Spawner) {
47 let p = embassy_rp::init(Default::default()); 49 let p = embassy_rp::init(Default::default());
50 let mut rng = RoscRng;
48 51
49 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
50 let driver = Driver::new(p.USB, Irqs); 53 let driver = Driver::new(p.USB, Irqs);
@@ -64,14 +67,12 @@ async fn main(spawner: Spawner) {
64 config.device_protocol = 0x01; 67 config.device_protocol = 0x01;
65 68
66 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
67 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
68 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 70 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
69 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 71 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
70 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); 72 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
71 let mut builder = Builder::new( 73 let mut builder = Builder::new(
72 driver, 74 driver,
73 config, 75 config,
74 &mut DEVICE_DESC.init([0; 256])[..],
75 &mut CONFIG_DESC.init([0; 256])[..], 76 &mut CONFIG_DESC.init([0; 256])[..],
76 &mut BOS_DESC.init([0; 256])[..], 77 &mut BOS_DESC.init([0; 256])[..],
77 &mut [], // no msos descriptors 78 &mut [], // no msos descriptors
@@ -104,19 +105,13 @@ async fn main(spawner: Spawner) {
104 //}); 105 //});
105 106
106 // Generate random seed 107 // Generate random seed
107 let seed = 1234; // guaranteed random, chosen by a fair dice roll 108 let seed = rng.next_u64();
108 109
109 // Init network stack 110 // Init network stack
110 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 111 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
111 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 112 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
112 let stack = &*STACK.init(Stack::new(
113 device,
114 config,
115 RESOURCES.init(StackResources::<2>::new()),
116 seed,
117 ));
118 113
119 unwrap!(spawner.spawn(net_task(stack))); 114 unwrap!(spawner.spawn(net_task(runner)));
120 115
121 // And now we can use it! 116 // And now we can use it!
122 117
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
index b5ac16245..a7cb322d8 100644
--- a/examples/rp/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -36,13 +36,12 @@ async fn main(_spawner: Spawner) {
36 36
37 // Create embassy-usb DeviceBuilder using the driver and config. 37 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 38 // It needs some buffers for building the descriptors.
39 let mut device_descriptor = [0; 256];
40 let mut config_descriptor = [0; 256]; 39 let mut config_descriptor = [0; 256];
41 let mut bos_descriptor = [0; 256]; 40 let mut bos_descriptor = [0; 256];
42 // You can also add a Microsoft OS descriptor. 41 // You can also add a Microsoft OS descriptor.
43 let mut msos_descriptor = [0; 256]; 42 let mut msos_descriptor = [0; 256];
44 let mut control_buf = [0; 64]; 43 let mut control_buf = [0; 64];
45 let request_handler = MyRequestHandler {}; 44 let mut request_handler = MyRequestHandler {};
46 let mut device_handler = MyDeviceHandler::new(); 45 let mut device_handler = MyDeviceHandler::new();
47 46
48 let mut state = State::new(); 47 let mut state = State::new();
@@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) {
50 let mut builder = Builder::new( 49 let mut builder = Builder::new(
51 driver, 50 driver,
52 config, 51 config,
53 &mut device_descriptor,
54 &mut config_descriptor, 52 &mut config_descriptor,
55 &mut bos_descriptor, 53 &mut bos_descriptor,
56 &mut msos_descriptor, 54 &mut msos_descriptor,
@@ -62,7 +60,7 @@ async fn main(_spawner: Spawner) {
62 // Create classes on the builder. 60 // Create classes on the builder.
63 let config = embassy_usb::class::hid::Config { 61 let config = embassy_usb::class::hid::Config {
64 report_descriptor: KeyboardReport::desc(), 62 report_descriptor: KeyboardReport::desc(),
65 request_handler: Some(&request_handler), 63 request_handler: None,
66 poll_ms: 60, 64 poll_ms: 60,
67 max_packet_size: 64, 65 max_packet_size: 64,
68 }; 66 };
@@ -116,7 +114,7 @@ async fn main(_spawner: Spawner) {
116 }; 114 };
117 115
118 let out_fut = async { 116 let out_fut = async {
119 reader.run(false, &request_handler).await; 117 reader.run(false, &mut request_handler).await;
120 }; 118 };
121 119
122 // Run everything concurrently. 120 // Run everything concurrently.
@@ -127,21 +125,21 @@ async fn main(_spawner: Spawner) {
127struct MyRequestHandler {} 125struct MyRequestHandler {}
128 126
129impl RequestHandler for MyRequestHandler { 127impl RequestHandler for MyRequestHandler {
130 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { 128 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
131 info!("Get report for {:?}", id); 129 info!("Get report for {:?}", id);
132 None 130 None
133 } 131 }
134 132
135 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { 133 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
136 info!("Set report for {:?}: {=[u8]}", id, data); 134 info!("Set report for {:?}: {=[u8]}", id, data);
137 OutResponse::Accepted 135 OutResponse::Accepted
138 } 136 }
139 137
140 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { 138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
141 info!("Set idle rate for {:?} to {:?}", id, dur); 139 info!("Set idle rate for {:?} to {:?}", id, dur);
142 } 140 }
143 141
144 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { 142 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
145 info!("Get idle rate for {:?}", id); 143 info!("Get idle rate for {:?}", id);
146 None 144 None
147 } 145 }
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..5ee650910
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,173 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_rp::bind_interrupts;
10use embassy_rp::clocks::RoscRng;
11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_time::Timer;
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
15use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler};
17use rand::Rng;
18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
19use {defmt_rtt as _, panic_probe as _};
20
21bind_interrupts!(struct Irqs {
22 USBCTRL_IRQ => InterruptHandler<USB>;
23});
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let p = embassy_rp::init(Default::default());
28 // Create the driver, from the HAL.
29 let driver = Driver::new(p.USB, Irqs);
30
31 // Create embassy-usb Config
32 let mut config = Config::new(0xc0de, 0xcafe);
33 config.manufacturer = Some("Embassy");
34 config.product = Some("HID keyboard example");
35 config.serial_number = Some("12345678");
36 config.max_power = 100;
37 config.max_packet_size_0 = 64;
38
39 // Create embassy-usb DeviceBuilder using the driver and config.
40 // It needs some buffers for building the descriptors.
41 let mut config_descriptor = [0; 256];
42 let mut bos_descriptor = [0; 256];
43 // You can also add a Microsoft OS descriptor.
44 let mut msos_descriptor = [0; 256];
45 let mut control_buf = [0; 64];
46 let mut request_handler = MyRequestHandler {};
47 let mut device_handler = MyDeviceHandler::new();
48
49 let mut state = State::new();
50
51 let mut builder = Builder::new(
52 driver,
53 config,
54 &mut config_descriptor,
55 &mut bos_descriptor,
56 &mut msos_descriptor,
57 &mut control_buf,
58 );
59
60 builder.handler(&mut device_handler);
61
62 // Create classes on the builder.
63 let config = embassy_usb::class::hid::Config {
64 report_descriptor: MouseReport::desc(),
65 request_handler: None,
66 poll_ms: 60,
67 max_packet_size: 64,
68 };
69 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
70
71 // Build the builder.
72 let mut usb = builder.build();
73
74 // Run the USB device.
75 let usb_fut = usb.run();
76
77 let (reader, mut writer) = hid.split();
78
79 // Do stuff with the class!
80 let in_fut = async {
81 let mut rng = RoscRng;
82
83 loop {
84 // every 1 second
85 _ = Timer::after_secs(1).await;
86 let report = MouseReport {
87 buttons: 0,
88 x: rng.gen_range(-100..100), // random small x movement
89 y: rng.gen_range(-100..100), // random small y movement
90 wheel: 0,
91 pan: 0,
92 };
93 // Send the report.
94 match writer.write_serialize(&report).await {
95 Ok(()) => {}
96 Err(e) => warn!("Failed to send report: {:?}", e),
97 }
98 }
99 };
100
101 let out_fut = async {
102 reader.run(false, &mut request_handler).await;
103 };
104
105 // Run everything concurrently.
106 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
107 join(usb_fut, join(in_fut, out_fut)).await;
108}
109
110struct MyRequestHandler {}
111
112impl RequestHandler for MyRequestHandler {
113 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
114 info!("Get report for {:?}", id);
115 None
116 }
117
118 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
119 info!("Set report for {:?}: {=[u8]}", id, data);
120 OutResponse::Accepted
121 }
122
123 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
124 info!("Set idle rate for {:?} to {:?}", id, dur);
125 }
126
127 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
128 info!("Get idle rate for {:?}", id);
129 None
130 }
131}
132
133struct MyDeviceHandler {
134 configured: AtomicBool,
135}
136
137impl MyDeviceHandler {
138 fn new() -> Self {
139 MyDeviceHandler {
140 configured: AtomicBool::new(false),
141 }
142 }
143}
144
145impl Handler for MyDeviceHandler {
146 fn enabled(&mut self, enabled: bool) {
147 self.configured.store(false, Ordering::Relaxed);
148 if enabled {
149 info!("Device enabled");
150 } else {
151 info!("Device disabled");
152 }
153 }
154
155 fn reset(&mut self) {
156 self.configured.store(false, Ordering::Relaxed);
157 info!("Bus reset, the Vbus current limit is 100mA");
158 }
159
160 fn addressed(&mut self, addr: u8) {
161 self.configured.store(false, Ordering::Relaxed);
162 info!("USB address set to: {}", addr);
163 }
164
165 fn configured(&mut self, configured: bool) {
166 self.configured.store(configured, Ordering::Relaxed);
167 if configured {
168 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
169 } else {
170 info!("Device is no longer configured, the Vbus current limit is 100mA.");
171 }
172 }
173}
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs
index 95306a35c..11db1b2e1 100644
--- a/examples/rp/src/bin/usb_midi.rs
+++ b/examples/rp/src/bin/usb_midi.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 46
47 // Create embassy-usb DeviceBuilder using the driver and config. 47 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 48 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 49 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 50 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
@@ -54,7 +53,6 @@ async fn main(_spawner: Spawner) {
54 let mut builder = Builder::new( 53 let mut builder = Builder::new(
55 driver, 54 driver,
56 config, 55 config,
57 &mut device_descriptor,
58 &mut config_descriptor, 56 &mut config_descriptor,
59 &mut bos_descriptor, 57 &mut bos_descriptor,
60 &mut [], // no msos descriptors 58 &mut [], // no msos descriptors
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs
index a6c8a5b2e..97e7e0244 100644
--- a/examples/rp/src/bin/usb_raw.rs
+++ b/examples/rp/src/bin/usb_raw.rs
@@ -93,7 +93,6 @@ async fn main(_spawner: Spawner) {
93 93
94 // Create embassy-usb DeviceBuilder using the driver and config. 94 // Create embassy-usb DeviceBuilder using the driver and config.
95 // It needs some buffers for building the descriptors. 95 // It needs some buffers for building the descriptors.
96 let mut device_descriptor = [0; 256];
97 let mut config_descriptor = [0; 256]; 96 let mut config_descriptor = [0; 256];
98 let mut bos_descriptor = [0; 256]; 97 let mut bos_descriptor = [0; 256];
99 let mut msos_descriptor = [0; 256]; 98 let mut msos_descriptor = [0; 256];
@@ -106,7 +105,6 @@ async fn main(_spawner: Spawner) {
106 let mut builder = Builder::new( 105 let mut builder = Builder::new(
107 driver, 106 driver,
108 config, 107 config,
109 &mut device_descriptor,
110 &mut config_descriptor, 108 &mut config_descriptor,
111 &mut bos_descriptor, 109 &mut bos_descriptor,
112 &mut msos_descriptor, 110 &mut msos_descriptor,
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs
index 0dc8e9f72..331c3da4c 100644
--- a/examples/rp/src/bin/usb_raw_bulk.rs
+++ b/examples/rp/src/bin/usb_raw_bulk.rs
@@ -71,7 +71,6 @@ async fn main(_spawner: Spawner) {
71 71
72 // Create embassy-usb DeviceBuilder using the driver and config. 72 // Create embassy-usb DeviceBuilder using the driver and config.
73 // It needs some buffers for building the descriptors. 73 // It needs some buffers for building the descriptors.
74 let mut device_descriptor = [0; 256];
75 let mut config_descriptor = [0; 256]; 74 let mut config_descriptor = [0; 256];
76 let mut bos_descriptor = [0; 256]; 75 let mut bos_descriptor = [0; 256];
77 let mut msos_descriptor = [0; 256]; 76 let mut msos_descriptor = [0; 256];
@@ -80,7 +79,6 @@ async fn main(_spawner: Spawner) {
80 let mut builder = Builder::new( 79 let mut builder = Builder::new(
81 driver, 80 driver,
82 config, 81 config,
83 &mut device_descriptor,
84 &mut config_descriptor, 82 &mut config_descriptor,
85 &mut bos_descriptor, 83 &mut bos_descriptor,
86 &mut msos_descriptor, 84 &mut msos_descriptor,
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index ab24a994c..4a802994a 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -5,15 +5,15 @@
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7 7
8use defmt::{info, panic}; 8use defmt::{info, panic, unwrap};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
12use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, Instance, InterruptHandler}; 12use embassy_rp::usb::{Driver, Instance, InterruptHandler};
14use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
15use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
16use embassy_usb::{Builder, Config}; 15use embassy_usb::UsbDevice;
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::main] 23#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 24async fn main(spawner: Spawner) {
25 info!("Hello there!"); 25 info!("Hello there!");
26 26
27 let p = embassy_rp::init(Default::default()); 27 let p = embassy_rp::init(Default::default());
@@ -30,61 +30,69 @@ async fn main(_spawner: Spawner) {
30 let driver = Driver::new(p.USB, Irqs); 30 let driver = Driver::new(p.USB, Irqs);
31 31
32 // Create embassy-usb Config 32 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe); 33 let config = {
34 config.manufacturer = Some("Embassy"); 34 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
35 config.product = Some("USB-serial example"); 35 config.manufacturer = Some("Embassy");
36 config.serial_number = Some("12345678"); 36 config.product = Some("USB-serial example");
37 config.max_power = 100; 37 config.serial_number = Some("12345678");
38 config.max_packet_size_0 = 64; 38 config.max_power = 100;
39 39 config.max_packet_size_0 = 64;
40 // Required for windows compatibility. 40
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help 41 // Required for windows compatibility.
42 config.device_class = 0xEF; 42 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
43 config.device_sub_class = 0x02; 43 config.device_class = 0xEF;
44 config.device_protocol = 0x01; 44 config.device_sub_class = 0x02;
45 config.composite_with_iads = true; 45 config.device_protocol = 0x01;
46 config.composite_with_iads = true;
47 config
48 };
46 49
47 // Create embassy-usb DeviceBuilder using the driver and config. 50 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 51 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256]; 52 let mut builder = {
50 let mut config_descriptor = [0; 256]; 53 static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
51 let mut bos_descriptor = [0; 256]; 54 static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
52 let mut control_buf = [0; 64]; 55 static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new();
53 56
54 let mut state = State::new(); 57 let builder = embassy_usb::Builder::new(
55 58 driver,
56 let mut builder = Builder::new( 59 config,
57 driver, 60 CONFIG_DESCRIPTOR.init([0; 256]),
58 config, 61 BOS_DESCRIPTOR.init([0; 256]),
59 &mut device_descriptor, 62 &mut [], // no msos descriptors
60 &mut config_descriptor, 63 CONTROL_BUF.init([0; 64]),
61 &mut bos_descriptor, 64 );
62 &mut [], // no msos descriptors 65 builder
63 &mut control_buf, 66 };
64 );
65 67
66 // Create classes on the builder. 68 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); 69 let mut class = {
70 static STATE: StaticCell<State> = StaticCell::new();
71 let state = STATE.init(State::new());
72 CdcAcmClass::new(&mut builder, state, 64)
73 };
68 74
69 // Build the builder. 75 // Build the builder.
70 let mut usb = builder.build(); 76 let usb = builder.build();
71 77
72 // Run the USB device. 78 // Run the USB device.
73 let usb_fut = usb.run(); 79 unwrap!(spawner.spawn(usb_task(usb)));
74 80
75 // Do stuff with the class! 81 // Do stuff with the class!
76 let echo_fut = async { 82 loop {
77 loop { 83 class.wait_connection().await;
78 class.wait_connection().await; 84 info!("Connected");
79 info!("Connected"); 85 let _ = echo(&mut class).await;
80 let _ = echo(&mut class).await; 86 info!("Disconnected");
81 info!("Disconnected"); 87 }
82 } 88}
83 }; 89
90type MyUsbDriver = Driver<'static, USB>;
91type MyUsbDevice = UsbDevice<'static, MyUsbDriver>;
84 92
85 // Run everything concurrently. 93#[embassy_executor::task]
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead. 94async fn usb_task(mut usb: MyUsbDevice) -> ! {
87 join(usb_fut, echo_fut).await; 95 usb.run().await
88} 96}
89 97
90struct Disconnected {} 98struct Disconnected {}
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs
index 4ba4fc25c..f9cfdef94 100644
--- a/examples/rp/src/bin/usb_serial_with_logger.rs
+++ b/examples/rp/src/bin/usb_serial_with_logger.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 46
47 // Create embassy-usb DeviceBuilder using the driver and config. 47 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 48 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 49 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 50 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
@@ -57,7 +56,6 @@ async fn main(_spawner: Spawner) {
57 let mut builder = Builder::new( 56 let mut builder = Builder::new(
58 driver, 57 driver,
59 config, 58 config,
60 &mut device_descriptor,
61 &mut config_descriptor, 59 &mut config_descriptor,
62 &mut bos_descriptor, 60 &mut bos_descriptor,
63 &mut [], // no msos descriptors 61 &mut [], // no msos descriptors
diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs
new file mode 100644
index 000000000..e73938ac9
--- /dev/null
+++ b/examples/rp/src/bin/usb_webusb.rs
@@ -0,0 +1,155 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a WebUSB capable device that echoes data back to the host.
4//!
5//! To test this in the browser (ideally host this on localhost:8080, to test the landing page
6//! feature):
7//! ```js
8//! (async () => {
9//! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] });
10//! await device.open();
11//! await device.claimInterface(1);
12//! device.transferIn(1, 64).then(data => console.log(data));
13//! await device.transferOut(1, new Uint8Array([1,2,3]));
14//! })();
15//! ```
16
17#![no_std]
18#![no_main]
19
20use defmt::info;
21use embassy_executor::Spawner;
22use embassy_futures::join::join;
23use embassy_rp::bind_interrupts;
24use embassy_rp::peripherals::USB;
25use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
26use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb};
27use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut};
28use embassy_usb::msos::{self, windows_version};
29use embassy_usb::{Builder, Config};
30use {defmt_rtt as _, panic_probe as _};
31
32bind_interrupts!(struct Irqs {
33 USBCTRL_IRQ => InterruptHandler<USB>;
34});
35
36// This is a randomly generated GUID to allow clients on Windows to find our device
37const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42
43 // Create the driver, from the HAL.
44 let driver = UsbDriver::new(p.USB, Irqs);
45
46 // Create embassy-usb Config
47 let mut config = Config::new(0xf569, 0x0001);
48 config.manufacturer = Some("Embassy");
49 config.product = Some("WebUSB example");
50 config.serial_number = Some("12345678");
51 config.max_power = 100;
52 config.max_packet_size_0 = 64;
53
54 // Required for windows compatibility.
55 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
56 config.device_class = 0xff;
57 config.device_sub_class = 0x00;
58 config.device_protocol = 0x00;
59
60 // Create embassy-usb DeviceBuilder using the driver and config.
61 // It needs some buffers for building the descriptors.
62 let mut config_descriptor = [0; 256];
63 let mut bos_descriptor = [0; 256];
64 let mut control_buf = [0; 64];
65 let mut msos_descriptor = [0; 256];
66
67 let webusb_config = WebUsbConfig {
68 max_packet_size: 64,
69 vendor_code: 1,
70 // If defined, shows a landing page which the device manufacturer would like the user to visit in order to control their device. Suggest the user to navigate to this URL when the device is connected.
71 landing_url: Some(Url::new("http://localhost:8080")),
72 };
73
74 let mut state = State::new();
75
76 let mut builder = Builder::new(
77 driver,
78 config,
79 &mut config_descriptor,
80 &mut bos_descriptor,
81 &mut msos_descriptor,
82 &mut control_buf,
83 );
84
85 // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor.
86 // We tell Windows that this entire device is compatible with the "WINUSB" feature,
87 // which causes it to use the built-in WinUSB driver automatically, which in turn
88 // can be used by libusb/rusb software without needing a custom driver or INF file.
89 // In principle you might want to call msos_feature() just on a specific function,
90 // if your device also has other functions that still use standard class drivers.
91 builder.msos_descriptor(windows_version::WIN8_1, 0);
92 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
93 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
94 "DeviceInterfaceGUIDs",
95 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
96 ));
97
98 // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything)
99 WebUsb::configure(&mut builder, &mut state, &webusb_config);
100 // Create some USB bulk endpoints for testing.
101 let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config);
102
103 // Build the builder.
104 let mut usb = builder.build();
105
106 // Run the USB device.
107 let usb_fut = usb.run();
108
109 // Do some WebUSB transfers.
110 let webusb_fut = async {
111 loop {
112 endpoints.wait_connected().await;
113 info!("Connected");
114 endpoints.echo().await;
115 }
116 };
117
118 // Run everything concurrently.
119 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
120 join(usb_fut, webusb_fut).await;
121}
122
123struct WebEndpoints<'d, D: Driver<'d>> {
124 write_ep: D::EndpointIn,
125 read_ep: D::EndpointOut,
126}
127
128impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
129 fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self {
130 let mut func = builder.function(0xff, 0x00, 0x00);
131 let mut iface = func.interface();
132 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
133
134 let write_ep = alt.endpoint_bulk_in(config.max_packet_size);
135 let read_ep = alt.endpoint_bulk_out(config.max_packet_size);
136
137 WebEndpoints { write_ep, read_ep }
138 }
139
140 // Wait until the device's endpoints are enabled.
141 async fn wait_connected(&mut self) {
142 self.read_ep.wait_enabled().await
143 }
144
145 // Echo data back to the host.
146 async fn echo(&mut self) {
147 let mut buf = [0; 64];
148 loop {
149 let n = self.read_ep.read(&mut buf).await.unwrap();
150 let data = &buf[..n];
151 info!("Data read: {:x}", data);
152 self.write_ep.write(data).await.unwrap();
153 }
154 }
155}
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index b60852359..4c9651433 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -11,13 +11,15 @@ use cyw43_pio::PioSpi;
11use defmt::*; 11use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_net::tcp::TcpSocket; 13use embassy_net::tcp::TcpSocket;
14use embassy_net::{Config, Stack, StackResources}; 14use embassy_net::{Config, StackResources};
15use embassy_rp::bind_interrupts; 15use embassy_rp::bind_interrupts;
16use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
17use embassy_rp::peripherals::{DMA_CH0, PIO0}; 18use embassy_rp::peripherals::{DMA_CH0, PIO0};
18use embassy_rp::pio::{InterruptHandler, Pio}; 19use embassy_rp::pio::{InterruptHandler, Pio};
19use embassy_time::Duration; 20use embassy_time::Duration;
20use embedded_io_async::Write; 21use embedded_io_async::Write;
22use rand::RngCore;
21use static_cell::StaticCell; 23use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
23 25
@@ -26,13 +28,13 @@ bind_interrupts!(struct Irqs {
26}); 28});
27 29
28#[embassy_executor::task] 30#[embassy_executor::task]
29async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
30 runner.run().await 32 runner.run().await
31} 33}
32 34
33#[embassy_executor::task] 35#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 36async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
35 stack.run().await 37 runner.run().await
36} 38}
37 39
38#[embassy_executor::main] 40#[embassy_executor::main]
@@ -40,14 +42,15 @@ async fn main(spawner: Spawner) {
40 info!("Hello World!"); 42 info!("Hello World!");
41 43
42 let p = embassy_rp::init(Default::default()); 44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
43 46
44 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); 47 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
45 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); 48 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
46 49
47 // To make flashing faster for development, you may want to flash the firmwares independently 50 // To make flashing faster for development, you may want to flash the firmwares independently
48 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 51 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
49 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 52 // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
50 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 53 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
51 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; 54 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
52 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 55 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
53 56
@@ -59,7 +62,7 @@ async fn main(spawner: Spawner) {
59 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 62 static STATE: StaticCell<cyw43::State> = StaticCell::new();
60 let state = STATE.init(cyw43::State::new()); 63 let state = STATE.init(cyw43::State::new());
61 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
62 unwrap!(spawner.spawn(wifi_task(runner))); 65 unwrap!(spawner.spawn(cyw43_task(runner)));
63 66
64 control.init(clm).await; 67 control.init(clm).await;
65 control 68 control
@@ -74,19 +77,13 @@ async fn main(spawner: Spawner) {
74 }); 77 });
75 78
76 // Generate random seed 79 // Generate random seed
77 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 80 let seed = rng.next_u64();
78 81
79 // Init network stack 82 // Init network stack
80 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); 83 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
81 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 84 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
82 let stack = &*STACK.init(Stack::new( 85
83 net_device, 86 unwrap!(spawner.spawn(net_task(runner)));
84 config,
85 RESOURCES.init(StackResources::<2>::new()),
86 seed,
87 ));
88
89 unwrap!(spawner.spawn(net_task(stack)));
90 87
91 //control.start_ap_open("cyw43", 5).await; 88 //control.start_ap_open("cyw43", 5).await;
92 control.start_ap_wpa2("cyw43", "password", 5).await; 89 control.start_ap_wpa2("cyw43", "password", 5).await;
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index 18eefe41f..04a61bbd5 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::task] 23#[embassy_executor::task]
24async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 24async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
25 runner.run().await 25 runner.run().await
26} 26}
27 27
@@ -33,8 +33,8 @@ async fn main(spawner: Spawner) {
33 33
34 // To make flashing faster for development, you may want to flash the firmwares independently 34 // To make flashing faster for development, you may want to flash the firmwares independently
35 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 35 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
36 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 36 // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
37 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 37 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
38 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; 38 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
39 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 39 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
40 40
@@ -46,7 +46,7 @@ async fn main(spawner: Spawner) {
46 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 46 static STATE: StaticCell<cyw43::State> = StaticCell::new();
47 let state = STATE.init(cyw43::State::new()); 47 let state = STATE.init(cyw43::State::new());
48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
49 unwrap!(spawner.spawn(wifi_task(runner))); 49 unwrap!(spawner.spawn(cyw43_task(runner)));
50 50
51 control.init(clm).await; 51 control.init(clm).await;
52 control 52 control
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index e0f85a6b0..434f0074c 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -10,7 +10,6 @@ use core::str;
10use cyw43_pio::PioSpi; 10use cyw43_pio::PioSpi;
11use defmt::*; 11use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_net::Stack;
14use embassy_rp::bind_interrupts; 13use embassy_rp::bind_interrupts;
15use embassy_rp::gpio::{Level, Output}; 14use embassy_rp::gpio::{Level, Output};
16use embassy_rp::peripherals::{DMA_CH0, PIO0}; 15use embassy_rp::peripherals::{DMA_CH0, PIO0};
@@ -23,13 +22,13 @@ bind_interrupts!(struct Irqs {
23}); 22});
24 23
25#[embassy_executor::task] 24#[embassy_executor::task]
26async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 25async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
27 runner.run().await 26 runner.run().await
28} 27}
29 28
30#[embassy_executor::task] 29#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 30async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
32 stack.run().await 31 runner.run().await
33} 32}
34 33
35#[embassy_executor::main] 34#[embassy_executor::main]
@@ -43,8 +42,8 @@ async fn main(spawner: Spawner) {
43 42
44 // To make flashing faster for development, you may want to flash the firmwares independently 43 // To make flashing faster for development, you may want to flash the firmwares independently
45 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
46 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 45 // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
47 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 46 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
48 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; 47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
49 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
50 49
@@ -56,7 +55,7 @@ async fn main(spawner: Spawner) {
56 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 55 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new()); 56 let state = STATE.init(cyw43::State::new());
58 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 57 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
59 unwrap!(spawner.spawn(wifi_task(runner))); 58 unwrap!(spawner.spawn(cyw43_task(runner)));
60 59
61 control.init(clm).await; 60 control.init(clm).await;
62 control 61 control
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index f1afc4a00..7bf546e01 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -7,17 +7,20 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43::JoinOptions;
10use cyw43_pio::PioSpi; 11use cyw43_pio::PioSpi;
11use defmt::*; 12use defmt::*;
12use embassy_executor::Spawner; 13use embassy_executor::Spawner;
13use embassy_net::tcp::TcpSocket; 14use embassy_net::tcp::TcpSocket;
14use embassy_net::{Config, Stack, StackResources}; 15use embassy_net::{Config, StackResources};
15use embassy_rp::bind_interrupts; 16use embassy_rp::bind_interrupts;
17use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Level, Output}; 18use embassy_rp::gpio::{Level, Output};
17use embassy_rp::peripherals::{DMA_CH0, PIO0}; 19use embassy_rp::peripherals::{DMA_CH0, PIO0};
18use embassy_rp::pio::{InterruptHandler, Pio}; 20use embassy_rp::pio::{InterruptHandler, Pio};
19use embassy_time::{Duration, Timer}; 21use embassy_time::{Duration, Timer};
20use embedded_io_async::Write; 22use embedded_io_async::Write;
23use rand::RngCore;
21use static_cell::StaticCell; 24use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
23 26
@@ -25,17 +28,17 @@ bind_interrupts!(struct Irqs {
25 PIO0_IRQ_0 => InterruptHandler<PIO0>; 28 PIO0_IRQ_0 => InterruptHandler<PIO0>;
26}); 29});
27 30
28const WIFI_NETWORK: &str = "EmbassyTest"; 31const WIFI_NETWORK: &str = "LadronDeWifi";
29const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; 32const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8";
30 33
31#[embassy_executor::task] 34#[embassy_executor::task]
32async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 35async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
33 runner.run().await 36 runner.run().await
34} 37}
35 38
36#[embassy_executor::task] 39#[embassy_executor::task]
37async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
38 stack.run().await 41 runner.run().await
39} 42}
40 43
41#[embassy_executor::main] 44#[embassy_executor::main]
@@ -43,14 +46,15 @@ async fn main(spawner: Spawner) {
43 info!("Hello World!"); 46 info!("Hello World!");
44 47
45 let p = embassy_rp::init(Default::default()); 48 let p = embassy_rp::init(Default::default());
49 let mut rng = RoscRng;
46 50
47 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); 51 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
48 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); 52 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
49 53
50 // To make flashing faster for development, you may want to flash the firmwares independently 54 // To make flashing faster for development, you may want to flash the firmwares independently
51 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 55 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
52 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 56 // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
53 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 57 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
54 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; 58 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
55 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 59 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
56 60
@@ -62,7 +66,7 @@ async fn main(spawner: Spawner) {
62 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 66 static STATE: StaticCell<cyw43::State> = StaticCell::new();
63 let state = STATE.init(cyw43::State::new()); 67 let state = STATE.init(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 68 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner))); 69 unwrap!(spawner.spawn(cyw43_task(runner)));
66 70
67 control.init(clm).await; 71 control.init(clm).await;
68 control 72 control
@@ -77,23 +81,19 @@ async fn main(spawner: Spawner) {
77 //}); 81 //});
78 82
79 // Generate random seed 83 // Generate random seed
80 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 84 let seed = rng.next_u64();
81 85
82 // Init network stack 86 // Init network stack
83 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); 87 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
84 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 88 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
85 let stack = &*STACK.init(Stack::new(
86 net_device,
87 config,
88 RESOURCES.init(StackResources::<2>::new()),
89 seed,
90 ));
91 89
92 unwrap!(spawner.spawn(net_task(stack))); 90 unwrap!(spawner.spawn(net_task(runner)));
93 91
94 loop { 92 loop {
95 //control.join_open(WIFI_NETWORK).await; 93 match control
96 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 94 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
95 .await
96 {
97 Ok(_) => break, 97 Ok(_) => break,
98 Err(err) => { 98 Err(err) => {
99 info!("join failed with status={}", err.status); 99 info!("join failed with status={}", err.status);
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs
new file mode 100644
index 000000000..1ae909917
--- /dev/null
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -0,0 +1,190 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Connects to Wifi network and makes a web request to get the current time.
3
4#![no_std]
5#![no_main]
6#![allow(async_fn_in_trait)]
7
8use core::str::from_utf8;
9
10use cyw43::JoinOptions;
11use cyw43_pio::PioSpi;
12use defmt::*;
13use embassy_executor::Spawner;
14use embassy_net::dns::DnsSocket;
15use embassy_net::tcp::client::{TcpClient, TcpClientState};
16use embassy_net::{Config, StackResources};
17use embassy_rp::bind_interrupts;
18use embassy_rp::clocks::RoscRng;
19use embassy_rp::gpio::{Level, Output};
20use embassy_rp::peripherals::{DMA_CH0, PIO0};
21use embassy_rp::pio::{InterruptHandler, Pio};
22use embassy_time::{Duration, Timer};
23use rand::RngCore;
24use reqwless::client::{HttpClient, TlsConfig, TlsVerify};
25use reqwless::request::Method;
26use serde::Deserialize;
27use static_cell::StaticCell;
28use {defmt_rtt as _, panic_probe as _, serde_json_core};
29
30bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32});
33
34const WIFI_NETWORK: &str = "ssid"; // change to your network SSID
35const WIFI_PASSWORD: &str = "pwd"; // change to your network password
36
37#[embassy_executor::task]
38async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
39 runner.run().await
40}
41
42#[embassy_executor::task]
43async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
44 runner.run().await
45}
46
47#[embassy_executor::main]
48async fn main(spawner: Spawner) {
49 info!("Hello World!");
50
51 let p = embassy_rp::init(Default::default());
52 let mut rng = RoscRng;
53
54 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
55 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
56 // To make flashing faster for development, you may want to flash the firmwares independently
57 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
58 // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
59 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
60 // let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
61 // let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
62
63 let pwr = Output::new(p.PIN_23, Level::Low);
64 let cs = Output::new(p.PIN_25, Level::High);
65 let mut pio = Pio::new(p.PIO0, Irqs);
66 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
67
68 static STATE: StaticCell<cyw43::State> = StaticCell::new();
69 let state = STATE.init(cyw43::State::new());
70 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
71 unwrap!(spawner.spawn(cyw43_task(runner)));
72
73 control.init(clm).await;
74 control
75 .set_power_management(cyw43::PowerManagementMode::PowerSave)
76 .await;
77
78 let config = Config::dhcpv4(Default::default());
79 // Use static IP configuration instead of DHCP
80 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
81 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
82 // dns_servers: Vec::new(),
83 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
84 //});
85
86 // Generate random seed
87 let seed = rng.next_u64();
88
89 // Init network stack
90 static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new();
91 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
92
93 unwrap!(spawner.spawn(net_task(runner)));
94
95 loop {
96 match control
97 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
98 .await
99 {
100 Ok(_) => break,
101 Err(err) => {
102 info!("join failed with status={}", err.status);
103 }
104 }
105 }
106
107 // Wait for DHCP, not necessary when using static IP
108 info!("waiting for DHCP...");
109 while !stack.is_config_up() {
110 Timer::after_millis(100).await;
111 }
112 info!("DHCP is now up!");
113
114 info!("waiting for link up...");
115 while !stack.is_link_up() {
116 Timer::after_millis(500).await;
117 }
118 info!("Link is up!");
119
120 info!("waiting for stack to be up...");
121 stack.wait_config_up().await;
122 info!("Stack is up!");
123
124 // And now we can use it!
125
126 loop {
127 let mut rx_buffer = [0; 8192];
128 let mut tls_read_buffer = [0; 16640];
129 let mut tls_write_buffer = [0; 16640];
130
131 let client_state = TcpClientState::<1, 1024, 1024>::new();
132 let tcp_client = TcpClient::new(stack, &client_state);
133 let dns_client = DnsSocket::new(stack);
134 let tls_config = TlsConfig::new(seed, &mut tls_read_buffer, &mut tls_write_buffer, TlsVerify::None);
135
136 let mut http_client = HttpClient::new_with_tls(&tcp_client, &dns_client, tls_config);
137 let url = "https://worldtimeapi.org/api/timezone/Europe/Berlin";
138 // for non-TLS requests, use this instead:
139 // let mut http_client = HttpClient::new(&tcp_client, &dns_client);
140 // let url = "http://worldtimeapi.org/api/timezone/Europe/Berlin";
141
142 info!("connecting to {}", &url);
143
144 let mut request = match http_client.request(Method::GET, &url).await {
145 Ok(req) => req,
146 Err(e) => {
147 error!("Failed to make HTTP request: {:?}", e);
148 return; // handle the error
149 }
150 };
151
152 let response = match request.send(&mut rx_buffer).await {
153 Ok(resp) => resp,
154 Err(_e) => {
155 error!("Failed to send HTTP request");
156 return; // handle the error;
157 }
158 };
159
160 let body = match from_utf8(response.body().read_to_end().await.unwrap()) {
161 Ok(b) => b,
162 Err(_e) => {
163 error!("Failed to read response body");
164 return; // handle the error
165 }
166 };
167 info!("Response body: {:?}", &body);
168
169 // parse the response body and update the RTC
170
171 #[derive(Deserialize)]
172 struct ApiResponse<'a> {
173 datetime: &'a str,
174 // other fields as needed
175 }
176
177 let bytes = body.as_bytes();
178 match serde_json_core::de::from_slice::<ApiResponse>(bytes) {
179 Ok((output, _used)) => {
180 info!("Datetime: {:?}", output.datetime);
181 }
182 Err(_e) => {
183 error!("Failed to parse response body");
184 return; // handle the error
185 }
186 }
187
188 Timer::after(Duration::from_secs(5)).await;
189 }
190}
diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
new file mode 100644
index 000000000..39f03c8e4
--- /dev/null
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -0,0 +1,94 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA.
4#![no_std]
5#![no_main]
6
7use core::sync::atomic::{AtomicU16, Ordering};
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::Pull;
14use embassy_rp::peripherals::DMA_CH0;
15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
17use embassy_time::{Duration, Ticker, Timer};
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type SampleBuffer = [u16; 512];
22
23bind_interrupts!(struct Irqs {
24 ADC_IRQ_FIFO => InterruptHandler;
25});
26
27const BLOCK_SIZE: usize = 512;
28const NUM_BLOCKS: usize = 2;
29static MAX: AtomicU16 = AtomicU16::new(0);
30
31struct AdcParts {
32 adc: Adc<'static, Async>,
33 pin: adc::Channel<'static>,
34 dma: DMA_CH0,
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 info!("Here we go!");
41
42 let adc_parts = AdcParts {
43 adc: Adc::new(p.ADC, Irqs, Config::default()),
44 pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
45 dma: p.DMA_CH0,
46 };
47
48 static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
49 let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
50
51 static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
52 let channel = CHANNEL.init(Channel::new(buf));
53 let (sender, receiver) = channel.split();
54
55 spawner.must_spawn(consumer(receiver));
56 spawner.must_spawn(producer(sender, adc_parts));
57
58 let mut ticker = Ticker::every(Duration::from_secs(1));
59 loop {
60 ticker.next().await;
61 let max = MAX.load(Ordering::Relaxed);
62 info!("latest block's max value: {:?}", max);
63 }
64}
65
66#[embassy_executor::task]
67async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
68 loop {
69 // Obtain a free buffer from the channel
70 let buf = sender.send().await;
71
72 // Fill it with data
73 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
74
75 // Notify the channel that the buffer is now ready to be received
76 sender.send_done();
77 }
78}
79
80#[embassy_executor::task]
81async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
82 loop {
83 // Receive a buffer from the channel
84 let buf = receiver.receive().await;
85
86 // Simulate using the data, while the producer is filling up the next buffer
87 Timer::after_micros(1000).await;
88 let max = buf.iter().max().unwrap();
89 MAX.store(*max, Ordering::Relaxed);
90
91 // Notify the channel that the buffer is now ready to be reused
92 receiver.receive_done();
93 }
94}
diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml
new file mode 100644
index 000000000..9a92b1ce2
--- /dev/null
+++ b/examples/rp23/.cargo/config.toml
@@ -0,0 +1,10 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "probe-rs run --chip RP2040"
3#runner = "elf2uf2-rs -d"
4runner = "picotool load -u -v -x -t elf"
5
6[build]
7target = "thumbv8m.main-none-eabihf"
8
9[env]
10DEFMT_LOG = "debug"
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
new file mode 100644
index 000000000..087f6fd69
--- /dev/null
+++ b/examples/rp23/Cargo.toml
@@ -0,0 +1,79 @@
1[package]
2edition = "2021"
3name = "embassy-rp2350-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7
8[dependencies]
9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] }
20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] }
21
22defmt = "0.3"
23defmt-rtt = "0.4"
24fixed = "1.23.1"
25fixed-macro = "1.2"
26
27# for web request example
28reqwless = { version = "0.12.0", features = ["defmt",]}
29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1"
31
32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
34
35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
37cortex-m-rt = "0.7.0"
38critical-section = "1.1"
39panic-probe = { version = "0.3", features = ["print-defmt"] }
40display-interface-spi = "0.4.1"
41embedded-graphics = "0.7.1"
42st7789 = "0.6.1"
43display-interface = "0.4.1"
44byte-slice-cast = { version = "1.2.0", default-features = false }
45smart-leds = "0.3.0"
46heapless = "0.8"
47usbd-hid = "0.8.1"
48
49embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
50embedded-hal-async = "1.0"
51embedded-hal-bus = { version = "0.1", features = ["async"] }
52embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
53embedded-storage = { version = "0.3" }
54static_cell = "2.1"
55portable-atomic = { version = "1.5", features = ["critical-section"] }
56log = "0.4"
57pio-proc = "0.2"
58pio = "0.2.1"
59rand = { version = "0.8.5", default-features = false }
60embedded-sdmmc = "0.7.0"
61
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
64
65[profile.release]
66debug = 2
67
68[profile.dev]
69lto = true
70opt-level = "z"
71
72[patch.crates-io]
73trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
74embassy-executor = { path = "../../embassy-executor" }
75embassy-sync = { path = "../../embassy-sync" }
76embassy-futures = { path = "../../embassy-futures" }
77embassy-time = { path = "../../embassy-time" }
78embassy-time-driver = { path = "../../embassy-time-driver" }
79embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp23/assets/ferris.raw b/examples/rp23/assets/ferris.raw
new file mode 100644
index 000000000..9733889c5
--- /dev/null
+++ b/examples/rp23/assets/ferris.raw
Binary files differ
diff --git a/examples/rp23/build.rs b/examples/rp23/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/rp23/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/rp23/memory.x b/examples/rp23/memory.x
new file mode 100644
index 000000000..777492062
--- /dev/null
+++ b/examples/rp23/memory.x
@@ -0,0 +1,74 @@
1MEMORY {
2 /*
3 * The RP2350 has either external or internal flash.
4 *
5 * 2 MiB is a safe default here, although a Pico 2 has 4 MiB.
6 */
7 FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
8 /*
9 * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping.
10 * This is usually good for performance, as it distributes load on
11 * those banks evenly.
12 */
13 RAM : ORIGIN = 0x20000000, LENGTH = 512K
14 /*
15 * RAM banks 8 and 9 use a direct mapping. They can be used to have
16 * memory areas dedicated for some specific job, improving predictability
17 * of access times.
18 * Example: Separate stacks for core0 and core1.
19 */
20 SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K
21 SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K
22}
23
24SECTIONS {
25 /* ### Boot ROM info
26 *
27 * Goes after .vector_table, to keep it in the first 4K of flash
28 * where the Boot ROM (and picotool) can find it
29 */
30 .start_block : ALIGN(4)
31 {
32 __start_block_addr = .;
33 KEEP(*(.start_block));
34 } > FLASH
35
36} INSERT AFTER .vector_table;
37
38/* move .text to start /after/ the boot info */
39_stext = ADDR(.start_block) + SIZEOF(.start_block);
40
41SECTIONS {
42 /* ### Picotool 'Binary Info' Entries
43 *
44 * Picotool looks through this block (as we have pointers to it in our
45 * header) to find interesting information.
46 */
47 .bi_entries : ALIGN(4)
48 {
49 /* We put this in the header */
50 __bi_entries_start = .;
51 /* Here are the entries */
52 KEEP(*(.bi_entries));
53 /* Keep this block a nice round size */
54 . = ALIGN(4);
55 /* We put this in the header */
56 __bi_entries_end = .;
57 } > FLASH
58} INSERT AFTER .text;
59
60SECTIONS {
61 /* ### Boot ROM extra info
62 *
63 * Goes after everything in our program, so it can contain a signature.
64 */
65 .end_block : ALIGN(4)
66 {
67 __end_block_addr = .;
68 KEEP(*(.end_block));
69 } > FLASH
70
71} INSERT AFTER .uninit;
72
73PROVIDE(start_to_end = __end_block_addr - __start_block_addr);
74PROVIDE(end_to_start = __start_block_addr - __end_block_addr);
diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs
new file mode 100644
index 000000000..d1f053d39
--- /dev/null
+++ b/examples/rp23/src/bin/adc.rs
@@ -0,0 +1,63 @@
1//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28.
2//! It also reads the temperature sensor in the chip.
3
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler;
32});
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 let p = embassy_rp::init(Default::default());
37 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
38
39 let mut p26 = Channel::new_pin(p.PIN_26, Pull::None);
40 let mut p27 = Channel::new_pin(p.PIN_27, Pull::None);
41 let mut p28 = Channel::new_pin(p.PIN_28, Pull::None);
42 let mut ts = Channel::new_temp_sensor(p.ADC_TEMP_SENSOR);
43
44 loop {
45 let level = adc.read(&mut p26).await.unwrap();
46 info!("Pin 26 ADC: {}", level);
47 let level = adc.read(&mut p27).await.unwrap();
48 info!("Pin 27 ADC: {}", level);
49 let level = adc.read(&mut p28).await.unwrap();
50 info!("Pin 28 ADC: {}", level);
51 let temp = adc.read(&mut ts).await.unwrap();
52 info!("Temp: {} degrees", convert_to_celsius(temp));
53 Timer::after_secs(1).await;
54 }
55}
56
57fn convert_to_celsius(raw_temp: u16) -> f32 {
58 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
59 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721;
60 let sign = if temp < 0.0 { -1.0 } else { 1.0 };
61 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
62 (rounded_temp_x10 as f32) / 10.0
63}
diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs
new file mode 100644
index 000000000..5046e5530
--- /dev/null
+++ b/examples/rp23/src/bin/adc_dma.rs
@@ -0,0 +1,69 @@
1//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads.
2//! For multichannel, the samples are interleaved in the buffer:
3//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]`
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Ticker};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler;
32});
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 let p = embassy_rp::init(Default::default());
37 info!("Here we go!");
38
39 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
40 let mut dma = p.DMA_CH0;
41 let mut pin = Channel::new_pin(p.PIN_26, Pull::Up);
42 let mut pins = [
43 Channel::new_pin(p.PIN_27, Pull::Down),
44 Channel::new_pin(p.PIN_28, Pull::None),
45 Channel::new_pin(p.PIN_29, Pull::Up),
46 Channel::new_temp_sensor(p.ADC_TEMP_SENSOR),
47 ];
48
49 const BLOCK_SIZE: usize = 100;
50 const NUM_CHANNELS: usize = 4;
51 let mut ticker = Ticker::every(Duration::from_secs(1));
52 loop {
53 // Read 100 samples from a single channel
54 let mut buf = [0_u16; BLOCK_SIZE];
55 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1)
56 adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap();
57 info!("single: {:?} ...etc", buf[..8]);
58
59 // Read 100 samples from 4 channels interleaved
60 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }];
61 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1)
62 adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma)
63 .await
64 .unwrap();
65 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]);
66
67 ticker.next().await;
68 }
69}
diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs
new file mode 100644
index 000000000..2f9783917
--- /dev/null
+++ b/examples/rp23/src/bin/assign_resources.rs
@@ -0,0 +1,94 @@
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::block::ImageDef;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{self, PIN_20, PIN_21};
20use embassy_time::Timer;
21use {defmt_rtt as _, panic_probe as _};
22
23#[link_section = ".start_block"]
24#[used]
25pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
26
27// Program metadata for `picotool info`
28#[link_section = ".bi_entries"]
29#[used]
30pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
31 embassy_rp::binary_info::rp_program_name!(c"example"),
32 embassy_rp::binary_info::rp_cargo_version!(),
33 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
34 embassy_rp::binary_info::rp_program_build_attribute!(),
35];
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 // initialize the peripherals
40 let p = embassy_rp::init(Default::default());
41
42 // 1) Assigning a resource to a task by passing parts of the peripherals.
43 spawner
44 .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21))
45 .unwrap();
46
47 // 2) Using the assign-resources macro to assign resources to a task.
48 // we perform the split, see further below for the definition of the resources struct
49 let r = split_resources!(p);
50 // and then we can use them
51 spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap();
52}
53
54// 1) Assigning a resource to a task by passing parts of the peripherals.
55#[embassy_executor::task]
56async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) {
57 let mut led_20 = Output::new(pin_20, Level::Low);
58 let mut led_21 = Output::new(pin_21, Level::High);
59
60 loop {
61 info!("toggling leds");
62 led_20.toggle();
63 led_21.toggle();
64 Timer::after_secs(1).await;
65 }
66}
67
68// 2) Using the assign-resources macro to assign resources to a task.
69// first we define the resources we want to assign to the task using the assign_resources! macro
70// basically this will split up the peripherals struct into smaller structs, that we define here
71// naming is up to you, make sure your future self understands what you did here
72assign_resources! {
73 leds: Leds{
74 led_10: PIN_10,
75 led_11: PIN_11,
76 }
77 // add more resources to more structs if needed, for example defining one struct for each task
78}
79// this could be done in another file and imported here, but for the sake of simplicity we do it here
80// see https://github.com/adamgreig/assign-resources for more information
81
82// 2) Using the split resources in a task
83#[embassy_executor::task]
84async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) {
85 let mut led_10 = Output::new(r.led_10, Level::Low);
86 let mut led_11 = Output::new(r.led_11, Level::High);
87
88 loop {
89 info!("toggling leds");
90 led_10.toggle();
91 led_11.toggle();
92 Timer::after_secs(1).await;
93 }
94}
diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs
new file mode 100644
index 000000000..9e45679c8
--- /dev/null
+++ b/examples/rp23/src/bin/blinky.rs
@@ -0,0 +1,44 @@
1//! This example test the RP Pico on board LED.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_time::Timer;
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default());
33 let mut led = Output::new(p.PIN_2, Level::Low);
34
35 loop {
36 info!("led on!");
37 led.set_high();
38 Timer::after_millis(250).await;
39
40 info!("led off!");
41 led.set_low();
42 Timer::after_millis(250).await;
43 }
44}
diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs
new file mode 100644
index 000000000..87fc58bbc
--- /dev/null
+++ b/examples/rp23/src/bin/blinky_two_channels.rs
@@ -0,0 +1,65 @@
1#![no_std]
2#![no_main]
3/// This example demonstrates how to access a given pin from more than one embassy task
4/// The on-board LED is toggled by two tasks with slightly different periods, leading to the
5/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar
6/// to interference and the 'beats' you can hear if you play two frequencies close to one another
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::channel::{Channel, Sender};
14use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output};
16use {defmt_rtt as _, panic_probe as _};
17
18#[link_section = ".start_block"]
19#[used]
20pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
21
22// Program metadata for `picotool info`
23#[link_section = ".bi_entries"]
24#[used]
25pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
26 embassy_rp::binary_info::rp_program_name!(c"example"),
27 embassy_rp::binary_info::rp_cargo_version!(),
28 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
29 embassy_rp::binary_info::rp_program_build_attribute!(),
30];
31
32enum LedState {
33 Toggle,
34}
35static CHANNEL: Channel<ThreadModeRawMutex, LedState, 64> = Channel::new();
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High);
41
42 let dt = 100 * 1_000_000;
43 let k = 1.003;
44
45 unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt))));
46 unwrap!(spawner.spawn(toggle_led(
47 CHANNEL.sender(),
48 Duration::from_nanos((dt as f64 * k) as u64)
49 )));
50
51 loop {
52 match CHANNEL.receive().await {
53 LedState::Toggle => led.toggle(),
54 }
55 }
56}
57
58#[embassy_executor::task(pool_size = 2)]
59async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) {
60 let mut ticker = Ticker::every(delay);
61 loop {
62 control.send(LedState::Toggle).await;
63 ticker.next().await;
64 }
65}
diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs
new file mode 100644
index 000000000..40236c53b
--- /dev/null
+++ b/examples/rp23/src/bin/blinky_two_tasks.rs
@@ -0,0 +1,64 @@
1#![no_std]
2#![no_main]
3/// This example demonstrates how to access a given pin from more than one embassy task
4/// The on-board LED is toggled by two tasks with slightly different periods, leading to the
5/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar
6/// to interference and the 'beats' you can hear if you play two frequencies close to one another
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::mutex::Mutex;
14use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output};
16use {defmt_rtt as _, panic_probe as _};
17
18#[link_section = ".start_block"]
19#[used]
20pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
21
22// Program metadata for `picotool info`
23#[link_section = ".bi_entries"]
24#[used]
25pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
26 embassy_rp::binary_info::rp_program_name!(c"example"),
27 embassy_rp::binary_info::rp_cargo_version!(),
28 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
29 embassy_rp::binary_info::rp_program_build_attribute!(),
30];
31
32type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>;
33static LED: LedType = Mutex::new(None);
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default());
38 // set the content of the global LED reference to the real LED pin
39 let led = Output::new(AnyPin::from(p.PIN_25), Level::High);
40 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the
41 // Mutex is released
42 {
43 *(LED.lock().await) = Some(led);
44 }
45 let dt = 100 * 1_000_000;
46 let k = 1.003;
47
48 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt))));
49 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64))));
50}
51
52#[embassy_executor::task(pool_size = 2)]
53async fn toggle_led(led: &'static LedType, delay: Duration) {
54 let mut ticker = Ticker::every(delay);
55 loop {
56 {
57 let mut led_unlocked = led.lock().await;
58 if let Some(pin_ref) = led_unlocked.as_mut() {
59 pin_ref.toggle();
60 }
61 }
62 ticker.next().await;
63 }
64}
diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs
new file mode 100644
index 000000000..fb067a370
--- /dev/null
+++ b/examples/rp23/src/bin/button.rs
@@ -0,0 +1,43 @@
1//! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board.
2//!
3//! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin.
4
5#![no_std]
6#![no_main]
7
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Output, Pull};
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".start_block"]
14#[used]
15pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
16
17// Program metadata for `picotool info`
18#[link_section = ".bi_entries"]
19#[used]
20pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
21 embassy_rp::binary_info::rp_program_name!(c"example"),
22 embassy_rp::binary_info::rp_cargo_version!(),
23 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
24 embassy_rp::binary_info::rp_program_build_attribute!(),
25];
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default());
30 let mut led = Output::new(p.PIN_25, Level::Low);
31
32 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
33 // You need to add your own button.
34 let button = Input::new(p.PIN_28, Pull::Up);
35
36 loop {
37 if button.is_high() {
38 led.set_high();
39 } else {
40 led.set_low();
41 }
42 }
43}
diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs
new file mode 100644
index 000000000..e672521ec
--- /dev/null
+++ b/examples/rp23/src/bin/debounce.rs
@@ -0,0 +1,95 @@
1//! This example shows the ease of debouncing a button with async rust.
2//! Hook up a button or switch between pin 9 and ground.
3
4#![no_std]
5#![no_main]
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Pull};
11use embassy_time::{with_deadline, Duration, Instant, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28pub struct Debouncer<'a> {
29 input: Input<'a>,
30 debounce: Duration,
31}
32
33impl<'a> Debouncer<'a> {
34 pub fn new(input: Input<'a>, debounce: Duration) -> Self {
35 Self { input, debounce }
36 }
37
38 pub async fn debounce(&mut self) -> Level {
39 loop {
40 let l1 = self.input.get_level();
41
42 self.input.wait_for_any_edge().await;
43
44 Timer::after(self.debounce).await;
45
46 let l2 = self.input.get_level();
47 if l1 != l2 {
48 break l2;
49 }
50 }
51 }
52}
53
54#[embassy_executor::main]
55async fn main(_spawner: Spawner) {
56 let p = embassy_rp::init(Default::default());
57 let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
58
59 info!("Debounce Demo");
60
61 loop {
62 // button pressed
63 btn.debounce().await;
64 let start = Instant::now();
65 info!("Button Press");
66
67 match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
68 // Button Released < 1s
69 Ok(_) => {
70 info!("Button pressed for: {}ms", start.elapsed().as_millis());
71 continue;
72 }
73 // button held for > 1s
74 Err(_) => {
75 info!("Button Held");
76 }
77 }
78
79 match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
80 // Button released <5s
81 Ok(_) => {
82 info!("Button pressed for: {}ms", start.elapsed().as_millis());
83 continue;
84 }
85 // button held for > >5s
86 Err(_) => {
87 info!("Button Long Held");
88 }
89 }
90
91 // wait for button release before handling another press
92 btn.debounce().await;
93 info!("Button pressed for: {}ms", start.elapsed().as_millis());
94 }
95}
diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs
new file mode 100644
index 000000000..84011e394
--- /dev/null
+++ b/examples/rp23/src/bin/flash.rs
@@ -0,0 +1,140 @@
1//! This example test the flash connected to the RP2040 chip.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH;
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Flash"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28const ADDR_OFFSET: u32 = 0x100000;
29const FLASH_SIZE: usize = 2 * 1024 * 1024;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 info!("Hello World!");
35
36 // add some delay to give an attached debug probe time to parse the
37 // defmt RTT header. Reading that header might touch flash memory, which
38 // interferes with flash write operations.
39 // https://github.com/knurling-rs/defmt/pull/683
40 Timer::after_millis(10).await;
41
42 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
43
44 erase_write_sector(&mut flash, 0x00);
45
46 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
47
48 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await;
49
50 info!("Flash Works!");
51}
52
53fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
54 info!(">>>> [multiwrite_bytes]");
55 let mut read_buf = [0u8; ERASE_SIZE];
56 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
57
58 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
59 info!("Contents start with {=[u8]}", read_buf[0..4]);
60
61 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
62
63 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
64 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
65 if read_buf.iter().any(|x| *x != 0xFF) {
66 defmt::panic!("unexpected");
67 }
68
69 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01]));
70 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02]));
71 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03]));
72 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04]));
73
74 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
75 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
76 if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] {
77 defmt::panic!("unexpected");
78 }
79}
80
81fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
82 info!(">>>> [erase_write_sector]");
83 let mut buf = [0u8; ERASE_SIZE];
84 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
85
86 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
87 info!("Contents start with {=[u8]}", buf[0..4]);
88
89 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
90
91 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
92 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
93 if buf.iter().any(|x| *x != 0xFF) {
94 defmt::panic!("unexpected");
95 }
96
97 for b in buf.iter_mut() {
98 *b = 0xDA;
99 }
100
101 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf));
102
103 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
104 info!("Contents after write starts with {=[u8]}", buf[0..4]);
105 if buf.iter().any(|x| *x != 0xDA) {
106 defmt::panic!("unexpected");
107 }
108}
109
110async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
111 info!(">>>> [background_read]");
112
113 let mut buf = [0u32; 8];
114 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
115
116 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
117 info!("Contents start with {=u32:x}", buf[0]);
118
119 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
120
121 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
122 info!("Contents after erase starts with {=u32:x}", buf[0]);
123 if buf.iter().any(|x| *x != 0xFFFFFFFF) {
124 defmt::panic!("unexpected");
125 }
126
127 for b in buf.iter_mut() {
128 *b = 0xDABA1234;
129 }
130
131 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe {
132 core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4)
133 }));
134
135 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
136 info!("Contents after write starts with {=u32:x}", buf[0]);
137 if buf.iter().any(|x| *x != 0xDABA1234) {
138 defmt::panic!("unexpected");
139 }
140}
diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs
new file mode 100644
index 000000000..ff12367bf
--- /dev/null
+++ b/examples/rp23/src/bin/gpio_async.rs
@@ -0,0 +1,55 @@
1//! This example shows how async gpio can be used with a RP2040.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_time::Timer;
13use gpio::{Input, Level, Output, Pull};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30/// It requires an external signal to be manually triggered on PIN 16. For
31/// example, this could be accomplished using an external power source with a
32/// button so that it is possible to toggle the signal from low to high.
33///
34/// This example will begin with turning on the LED on the board and wait for a
35/// high signal on PIN 16. Once the high event/signal occurs the program will
36/// continue and turn off the LED, and then wait for 2 seconds before completing
37/// the loop and starting over again.
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) {
40 let p = embassy_rp::init(Default::default());
41 let mut led = Output::new(p.PIN_25, Level::Low);
42 let mut async_input = Input::new(p.PIN_16, Pull::None);
43
44 loop {
45 info!("wait_for_high. Turn on LED");
46 led.set_high();
47
48 async_input.wait_for_high().await;
49
50 info!("done wait_for_high. Turn off LED");
51 led.set_low();
52
53 Timer::after_secs(2).await;
54 }
55}
diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs
new file mode 100644
index 000000000..d2ee55197
--- /dev/null
+++ b/examples/rp23/src/bin/gpout.rs
@@ -0,0 +1,52 @@
1//! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::clocks;
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32
33 let gpout3 = clocks::Gpout::new(p.PIN_25);
34 gpout3.set_div(1000, 0);
35 gpout3.enable();
36
37 loop {
38 gpout3.set_src(clocks::GpoutSrc::Sys);
39 info!(
40 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
41 gpout3.get_freq()
42 );
43 Timer::after_secs(2).await;
44
45 gpout3.set_src(clocks::GpoutSrc::Ref);
46 info!(
47 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
48 gpout3.get_freq()
49 );
50 Timer::after_secs(2).await;
51 }
52}
diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs
new file mode 100644
index 000000000..c8d918b56
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_async.rs
@@ -0,0 +1,125 @@
1//! This example shows how to communicate asynchronous using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts;
12use embassy_rp::block::ImageDef;
13use embassy_rp::i2c::{self, Config, InterruptHandler};
14use embassy_rp::peripherals::I2C1;
15use embassy_time::Timer;
16use embedded_hal_async::i2c::I2c;
17use {defmt_rtt as _, panic_probe as _};
18
19#[link_section = ".start_block"]
20#[used]
21pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
22
23// Program metadata for `picotool info`
24#[link_section = ".bi_entries"]
25#[used]
26pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
27 embassy_rp::binary_info::rp_program_name!(c"example"),
28 embassy_rp::binary_info::rp_cargo_version!(),
29 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
30 embassy_rp::binary_info::rp_program_build_attribute!(),
31];
32
33bind_interrupts!(struct Irqs {
34 I2C1_IRQ => InterruptHandler<I2C1>;
35});
36
37#[allow(dead_code)]
38mod mcp23017 {
39 pub const ADDR: u8 = 0x20; // default addr
40
41 macro_rules! mcpregs {
42 ($($name:ident : $val:expr),* $(,)?) => {
43 $(
44 pub const $name: u8 = $val;
45 )*
46
47 pub fn regname(reg: u8) -> &'static str {
48 match reg {
49 $(
50 $val => stringify!($name),
51 )*
52 _ => panic!("bad reg"),
53 }
54 }
55 }
56 }
57
58 // These are correct for IOCON.BANK=0
59 mcpregs! {
60 IODIRA: 0x00,
61 IPOLA: 0x02,
62 GPINTENA: 0x04,
63 DEFVALA: 0x06,
64 INTCONA: 0x08,
65 IOCONA: 0x0A,
66 GPPUA: 0x0C,
67 INTFA: 0x0E,
68 INTCAPA: 0x10,
69 GPIOA: 0x12,
70 OLATA: 0x14,
71 IODIRB: 0x01,
72 IPOLB: 0x03,
73 GPINTENB: 0x05,
74 DEFVALB: 0x07,
75 INTCONB: 0x09,
76 IOCONB: 0x0B,
77 GPPUB: 0x0D,
78 INTFB: 0x0F,
79 INTCAPB: 0x11,
80 GPIOB: 0x13,
81 OLATB: 0x15,
82 }
83}
84
85#[embassy_executor::main]
86async fn main(_spawner: Spawner) {
87 let p = embassy_rp::init(Default::default());
88
89 let sda = p.PIN_14;
90 let scl = p.PIN_15;
91
92 info!("set up i2c ");
93 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default());
94
95 use mcp23017::*;
96
97 info!("init mcp23017 config for IxpandO");
98 // init - a outputs, b inputs
99 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
100 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
101 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
102
103 let mut val = 1;
104 loop {
105 let mut portb = [0];
106
107 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
108 info!("portb = {:02x}", portb[0]);
109 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
110 val = val.rotate_left(1);
111
112 // get a register dump
113 info!("getting register dump");
114 let mut regs = [0; 22];
115 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
116 // always get the regdump but only display it if portb'0 is set
117 if portb[0] & 1 != 0 {
118 for (idx, reg) in regs.into_iter().enumerate() {
119 info!("{} => {:02x}", regname(idx as u8), reg);
120 }
121 }
122
123 Timer::after_millis(100).await;
124 }
125}
diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs
new file mode 100644
index 000000000..cce0abcde
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_async_embassy.rs
@@ -0,0 +1,100 @@
1//! This example shows how to communicate asynchronous using i2c with external chip.
2//!
3//! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c.
4//! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_rp::block::ImageDef;
11use embassy_rp::i2c::InterruptHandler;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28// Our anonymous hypotetical temperature sensor could be:
29// a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C
30// It requires no configuration or calibration, works with all i2c bus speeds,
31// never stretches clock or does anything complicated. Replies with one u16.
32// It requires only one write to take it out of suspend mode, and stays on.
33// Often result would be just on 12 bits, but here we'll simplify it to 16.
34
35enum UncomplicatedSensorId {
36 A(UncomplicatedSensorU8),
37 B(UncomplicatedSensorU16),
38}
39enum UncomplicatedSensorU8 {
40 First = 0x48,
41}
42enum UncomplicatedSensorU16 {
43 Other = 0x0049,
44}
45
46impl Into<u16> for UncomplicatedSensorU16 {
47 fn into(self) -> u16 {
48 self as u16
49 }
50}
51impl Into<u16> for UncomplicatedSensorU8 {
52 fn into(self) -> u16 {
53 0x48
54 }
55}
56impl From<UncomplicatedSensorId> for u16 {
57 fn from(t: UncomplicatedSensorId) -> Self {
58 match t {
59 UncomplicatedSensorId::A(x) => x.into(),
60 UncomplicatedSensorId::B(x) => x.into(),
61 }
62 }
63}
64
65embassy_rp::bind_interrupts!(struct Irqs {
66 I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>;
67});
68
69#[embassy_executor::main]
70async fn main(_task_spawner: embassy_executor::Spawner) {
71 let p = embassy_rp::init(Default::default());
72 let sda = p.PIN_14;
73 let scl = p.PIN_15;
74 let config = embassy_rp::i2c::Config::default();
75 let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config);
76
77 const WAKEYWAKEY: u16 = 0xBABE;
78 let mut result: [u8; 2] = [0, 0];
79 // wait for sensors to initialize
80 embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
81
82 let _res_1 = bus
83 .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes())
84 .await;
85 let _res_2 = bus
86 .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes())
87 .await;
88
89 loop {
90 let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First);
91 let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other);
92 let sensors = [s1, s2];
93 for sensor in sensors {
94 if bus.read_async(sensor, &mut result).await.is_ok() {
95 info!("Result {}", u16::from_be_bytes(result.into()));
96 }
97 }
98 embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await;
99 }
100}
diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs
new file mode 100644
index 000000000..85c33bf0d
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_blocking.rs
@@ -0,0 +1,89 @@
1//! This example shows how to communicate using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::i2c::{self, Config};
13use embassy_time::Timer;
14use embedded_hal_1::i2c::I2c;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31#[allow(dead_code)]
32mod mcp23017 {
33 pub const ADDR: u8 = 0x20; // default addr
34
35 pub const IODIRA: u8 = 0x00;
36 pub const IPOLA: u8 = 0x02;
37 pub const GPINTENA: u8 = 0x04;
38 pub const DEFVALA: u8 = 0x06;
39 pub const INTCONA: u8 = 0x08;
40 pub const IOCONA: u8 = 0x0A;
41 pub const GPPUA: u8 = 0x0C;
42 pub const INTFA: u8 = 0x0E;
43 pub const INTCAPA: u8 = 0x10;
44 pub const GPIOA: u8 = 0x12;
45 pub const OLATA: u8 = 0x14;
46 pub const IODIRB: u8 = 0x01;
47 pub const IPOLB: u8 = 0x03;
48 pub const GPINTENB: u8 = 0x05;
49 pub const DEFVALB: u8 = 0x07;
50 pub const INTCONB: u8 = 0x09;
51 pub const IOCONB: u8 = 0x0B;
52 pub const GPPUB: u8 = 0x0D;
53 pub const INTFB: u8 = 0x0F;
54 pub const INTCAPB: u8 = 0x11;
55 pub const GPIOB: u8 = 0x13;
56 pub const OLATB: u8 = 0x15;
57}
58
59#[embassy_executor::main]
60async fn main(_spawner: Spawner) {
61 let p = embassy_rp::init(Default::default());
62
63 let sda = p.PIN_14;
64 let scl = p.PIN_15;
65
66 info!("set up i2c ");
67 let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default());
68
69 use mcp23017::*;
70
71 info!("init mcp23017 config for IxpandO");
72 // init - a outputs, b inputs
73 i2c.write(ADDR, &[IODIRA, 0x00]).unwrap();
74 i2c.write(ADDR, &[IODIRB, 0xff]).unwrap();
75 i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups
76
77 let mut val = 0xaa;
78 loop {
79 let mut portb = [0];
80
81 i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap();
82 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap();
83
84 info!("portb = {:02x}", portb[0]);
85 val = !val;
86
87 Timer::after_secs(1).await;
88 }
89}
diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs
new file mode 100644
index 000000000..fb5f3cda1
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_slave.rs
@@ -0,0 +1,132 @@
1//! This example shows how to use the 2040 as an i2c slave.
2#![no_std]
3#![no_main]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave};
10use embassy_time::Timer;
11use embedded_hal_async::i2c::I2c;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28bind_interrupts!(struct Irqs {
29 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
30 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
31});
32
33const DEV_ADDR: u8 = 0x42;
34
35#[embassy_executor::task]
36async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
37 info!("Device start");
38
39 let mut state = 0;
40
41 loop {
42 let mut buf = [0u8; 128];
43 match dev.listen(&mut buf).await {
44 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]),
45 Ok(i2c_slave::Command::Read) => loop {
46 match dev.respond_to_read(&[state]).await {
47 Ok(x) => match x {
48 i2c_slave::ReadStatus::Done => break,
49 i2c_slave::ReadStatus::NeedMoreBytes => (),
50 i2c_slave::ReadStatus::LeftoverBytes(x) => {
51 info!("tried to write {} extra bytes", x);
52 break;
53 }
54 },
55 Err(e) => error!("error while responding {}", e),
56 }
57 },
58 Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]),
59 Ok(i2c_slave::Command::WriteRead(len)) => {
60 info!("device received write read: {:x}", buf[..len]);
61 match buf[0] {
62 // Set the state
63 0xC2 => {
64 state = buf[1];
65 match dev.respond_and_fill(&[state], 0x00).await {
66 Ok(read_status) => info!("response read status {}", read_status),
67 Err(e) => error!("error while responding {}", e),
68 }
69 }
70 // Reset State
71 0xC8 => {
72 state = 0;
73 match dev.respond_and_fill(&[state], 0x00).await {
74 Ok(read_status) => info!("response read status {}", read_status),
75 Err(e) => error!("error while responding {}", e),
76 }
77 }
78 x => error!("Invalid Write Read {:x}", x),
79 }
80 }
81 Err(e) => error!("{}", e),
82 }
83 }
84}
85
86#[embassy_executor::task]
87async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
88 info!("Controller start");
89
90 loop {
91 let mut resp_buff = [0u8; 2];
92 for i in 0..10 {
93 match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await {
94 Ok(_) => info!("write_read response: {}", resp_buff),
95 Err(e) => error!("Error writing {}", e),
96 }
97
98 Timer::after_millis(100).await;
99 }
100 match con.read(DEV_ADDR, &mut resp_buff).await {
101 Ok(_) => info!("read response: {}", resp_buff),
102 Err(e) => error!("Error writing {}", e),
103 }
104 match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await {
105 Ok(_) => info!("write_read response: {}", resp_buff),
106 Err(e) => error!("Error writing {}", e),
107 }
108 Timer::after_millis(100).await;
109 }
110}
111
112#[embassy_executor::main]
113async fn main(spawner: Spawner) {
114 let p = embassy_rp::init(Default::default());
115 info!("Hello World!");
116
117 let d_sda = p.PIN_3;
118 let d_scl = p.PIN_2;
119 let mut config = i2c_slave::Config::default();
120 config.addr = DEV_ADDR as u16;
121 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
122
123 unwrap!(spawner.spawn(device_task(device)));
124
125 let c_sda = p.PIN_1;
126 let c_scl = p.PIN_0;
127 let mut config = i2c::Config::default();
128 config.frequency = 1_000_000;
129 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
130
131 unwrap!(spawner.spawn(controller_task(controller)));
132}
diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs
new file mode 100644
index 000000000..ee3d9bfe7
--- /dev/null
+++ b/examples/rp23/src/bin/interrupt.rs
@@ -0,0 +1,109 @@
1//! This example shows how you can use raw interrupt handlers alongside embassy.
2//! The example also showcases some of the options available for sharing resources/data.
3//!
4//! In the example, an ADC reading is triggered every time the PWM wraps around.
5//! The sample data is sent down a channel, to be processed inside a low priority task.
6//! The processed data is then used to adjust the PWM duty cycle, once every second.
7
8#![no_std]
9#![no_main]
10
11use core::cell::{Cell, RefCell};
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::block::ImageDef;
17use embassy_rp::gpio::Pull;
18use embassy_rp::interrupt;
19use embassy_rp::pwm::{Config, Pwm};
20use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
21use embassy_sync::blocking_mutex::Mutex;
22use embassy_sync::channel::Channel;
23use embassy_time::{Duration, Ticker};
24use portable_atomic::{AtomicU32, Ordering};
25use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _};
27
28#[link_section = ".start_block"]
29#[used]
30pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
31
32// Program metadata for `picotool info`
33#[link_section = ".bi_entries"]
34#[used]
35pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
36 embassy_rp::binary_info::rp_program_name!(c"example"),
37 embassy_rp::binary_info::rp_cargo_version!(),
38 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
39 embassy_rp::binary_info::rp_program_build_attribute!(),
40];
41
42static COUNTER: AtomicU32 = AtomicU32::new(0);
43static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
44static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
45 Mutex::new(RefCell::new(None));
46static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
47
48#[embassy_executor::main]
49async fn main(spawner: Spawner) {
50 embassy_rp::pac::SIO.spinlock(31).write_value(1);
51 let p = embassy_rp::init(Default::default());
52
53 let adc = Adc::new_blocking(p.ADC, Default::default());
54 let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
55 ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
56
57 let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
58 PWM.lock(|p| p.borrow_mut().replace(pwm));
59
60 // Enable the interrupt for pwm slice 4
61 embassy_rp::pac::PWM.irq0_inte().modify(|w| w.set_ch4(true));
62 unsafe {
63 cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP_0);
64 }
65
66 // Tasks require their resources to have 'static lifetime
67 // No Mutex needed when sharing within the same executor/prio level
68 static AVG: StaticCell<Cell<u32>> = StaticCell::new();
69 let avg = AVG.init(Default::default());
70 spawner.must_spawn(processing(avg));
71
72 let mut ticker = Ticker::every(Duration::from_secs(1));
73 loop {
74 ticker.next().await;
75 let freq = COUNTER.swap(0, Ordering::Relaxed);
76 info!("pwm freq: {:?} Hz", freq);
77 info!("adc average: {:?}", avg.get());
78
79 // Update the pwm duty cycle, based on the averaged adc reading
80 let mut config = Config::default();
81 config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
82 PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
83 }
84}
85
86#[embassy_executor::task]
87async fn processing(avg: &'static Cell<u32>) {
88 let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
89 loop {
90 let val = ADC_VALUES.receive().await;
91 buffer.write(val);
92 let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
93 avg.set(sum / buffer.len() as u32);
94 }
95}
96
97#[interrupt]
98fn PWM_IRQ_WRAP_0() {
99 critical_section::with(|cs| {
100 let mut adc = ADC.borrow(cs).borrow_mut();
101 let (adc, p26) = adc.as_mut().unwrap();
102 let val = adc.blocking_read(p26).unwrap();
103 ADC_VALUES.try_send(val).ok();
104
105 // Clear the interrupt, so we don't immediately re-enter this irq handler
106 PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped();
107 });
108 COUNTER.fetch_add(1, Ordering::Relaxed);
109}
diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs
new file mode 100644
index 000000000..9ab43d7a5
--- /dev/null
+++ b/examples/rp23/src/bin/multicore.rs
@@ -0,0 +1,81 @@
1//! This example shows how to send messages between the two cores in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::multicore::{spawn_core1, Stack};
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14use embassy_sync::channel::Channel;
15use embassy_time::Timer;
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _};
18
19#[link_section = ".start_block"]
20#[used]
21pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
22
23// Program metadata for `picotool info`
24#[link_section = ".bi_entries"]
25#[used]
26pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
27 embassy_rp::binary_info::rp_program_name!(c"example"),
28 embassy_rp::binary_info::rp_cargo_version!(),
29 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
30 embassy_rp::binary_info::rp_program_build_attribute!(),
31];
32
33static mut CORE1_STACK: Stack<4096> = Stack::new();
34static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
35static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
36static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new();
37
38enum LedState {
39 On,
40 Off,
41}
42
43#[cortex_m_rt::entry]
44fn main() -> ! {
45 let p = embassy_rp::init(Default::default());
46 let led = Output::new(p.PIN_25, Level::Low);
47
48 spawn_core1(
49 p.CORE1,
50 unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) },
51 move || {
52 let executor1 = EXECUTOR1.init(Executor::new());
53 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
54 },
55 );
56
57 let executor0 = EXECUTOR0.init(Executor::new());
58 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
59}
60
61#[embassy_executor::task]
62async fn core0_task() {
63 info!("Hello from core 0");
64 loop {
65 CHANNEL.send(LedState::On).await;
66 Timer::after_millis(100).await;
67 CHANNEL.send(LedState::Off).await;
68 Timer::after_millis(400).await;
69 }
70}
71
72#[embassy_executor::task]
73async fn core1_task(mut led: Output<'static>) {
74 info!("Hello from core 1");
75 loop {
76 match CHANNEL.receive().await {
77 LedState::On => led.set_high(),
78 LedState::Off => led.set_low(),
79 }
80 }
81}
diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs
new file mode 100644
index 000000000..27cd3656e
--- /dev/null
+++ b/examples/rp23/src/bin/multiprio.rs
@@ -0,0 +1,160 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58
59use cortex_m_rt::entry;
60use defmt::{info, unwrap};
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_rp::block::ImageDef;
63use embassy_rp::interrupt;
64use embassy_rp::interrupt::{InterruptExt, Priority};
65use embassy_time::{Instant, Timer, TICK_HZ};
66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _};
68
69#[link_section = ".start_block"]
70#[used]
71pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
72
73// Program metadata for `picotool info`
74#[link_section = ".bi_entries"]
75#[used]
76pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
77 embassy_rp::binary_info::rp_program_name!(c"example"),
78 embassy_rp::binary_info::rp_cargo_version!(),
79 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
80 embassy_rp::binary_info::rp_program_build_attribute!(),
81];
82
83#[embassy_executor::task]
84async fn run_high() {
85 loop {
86 info!(" [high] tick!");
87 Timer::after_ticks(673740).await;
88 }
89}
90
91#[embassy_executor::task]
92async fn run_med() {
93 loop {
94 let start = Instant::now();
95 info!(" [med] Starting long computation");
96
97 // Spin-wait to simulate a long CPU computation
98 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
99
100 let end = Instant::now();
101 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
102 info!(" [med] done in {} ms", ms);
103
104 Timer::after_ticks(53421).await;
105 }
106}
107
108#[embassy_executor::task]
109async fn run_low() {
110 loop {
111 let start = Instant::now();
112 info!("[low] Starting long computation");
113
114 // Spin-wait to simulate a long CPU computation
115 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
116
117 let end = Instant::now();
118 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
119 info!("[low] done in {} ms", ms);
120
121 Timer::after_ticks(82983).await;
122 }
123}
124
125static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
126static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
127static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
128
129#[interrupt]
130unsafe fn SWI_IRQ_1() {
131 EXECUTOR_HIGH.on_interrupt()
132}
133
134#[interrupt]
135unsafe fn SWI_IRQ_0() {
136 EXECUTOR_MED.on_interrupt()
137}
138
139#[entry]
140fn main() -> ! {
141 info!("Hello World!");
142
143 let _p = embassy_rp::init(Default::default());
144
145 // High-priority executor: SWI_IRQ_1, priority level 2
146 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
147 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
148 unwrap!(spawner.spawn(run_high()));
149
150 // Medium-priority executor: SWI_IRQ_0, priority level 3
151 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
152 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
153 unwrap!(spawner.spawn(run_med()));
154
155 // Low priority executor: runs in thread mode, using WFE/SEV
156 let executor = EXECUTOR_LOW.init(Executor::new());
157 executor.run(|spawner| {
158 unwrap!(spawner.spawn(run_low()));
159 });
160}
diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs
new file mode 100644
index 000000000..106e514ca
--- /dev/null
+++ b/examples/rp23/src/bin/otp.rs
@@ -0,0 +1,46 @@
1//! This example shows reading the OTP constants on the RP235x.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::otp;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".start_block"]
14#[used]
15pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
16
17// Program metadata for `picotool info`
18#[link_section = ".bi_entries"]
19#[used]
20pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
21 embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"),
22 embassy_rp::binary_info::rp_cargo_version!(),
23 embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"),
24 embassy_rp::binary_info::rp_program_build_attribute!(),
25];
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let _ = embassy_rp::init(Default::default());
30 //
31 // add some delay to give an attached debug probe time to parse the
32 // defmt RTT header. Reading that header might touch flash memory, which
33 // interferes with flash write operations.
34 // https://github.com/knurling-rs/defmt/pull/683
35 Timer::after_millis(10).await;
36
37 let chip_id = unwrap!(otp::get_chipid());
38 info!("Unique id:{:X}", chip_id);
39
40 let private_rand = unwrap!(otp::get_private_random_number());
41 info!("Private Rand:{:X}", private_rand);
42
43 loop {
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs
new file mode 100644
index 000000000..231afc80e
--- /dev/null
+++ b/examples/rp23/src/bin/pio_async.rs
@@ -0,0 +1,145 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::block::ImageDef;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
11use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => InterruptHandler<PIO0>;
31});
32
33fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
34 // Setup sm0
35
36 // Send data serially to pin
37 let prg = pio_proc::pio_asm!(
38 ".origin 16",
39 "set pindirs, 1",
40 ".wrap_target",
41 "out pins,1 [19]",
42 ".wrap",
43 );
44
45 let mut cfg = Config::default();
46 cfg.use_program(&pio.load_program(&prg.program), &[]);
47 let out_pin = pio.make_pio_pin(pin);
48 cfg.set_out_pins(&[&out_pin]);
49 cfg.set_set_pins(&[&out_pin]);
50 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
51 cfg.shift_out.auto_fill = true;
52 sm.set_config(&cfg);
53}
54
55#[embassy_executor::task]
56async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
57 sm.set_enable(true);
58
59 let mut v = 0x0f0caffa;
60 loop {
61 sm.tx().wait_push(v).await;
62 v ^= 0xffff;
63 info!("Pushed {:032b} to FIFO", v);
64 }
65}
66
67fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
68 // Setupm sm1
69
70 // Read 0b10101 repeatedly until ISR is full
71 let prg = pio_proc::pio_asm!(
72 //
73 ".origin 8",
74 "set x, 0x15",
75 ".wrap_target",
76 "in x, 5 [31]",
77 ".wrap",
78 );
79
80 let mut cfg = Config::default();
81 cfg.use_program(&pio.load_program(&prg.program), &[]);
82 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
83 cfg.shift_in.auto_fill = true;
84 cfg.shift_in.direction = ShiftDirection::Right;
85 sm.set_config(&cfg);
86}
87
88#[embassy_executor::task]
89async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
90 sm.set_enable(true);
91 loop {
92 let rx = sm.rx().wait_pull().await;
93 info!("Pulled {:032b} from FIFO", rx);
94 }
95}
96
97fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
98 // Setup sm2
99
100 // Repeatedly trigger IRQ 3
101 let prg = pio_proc::pio_asm!(
102 ".origin 0",
103 ".wrap_target",
104 "set x,10",
105 "delay:",
106 "jmp x-- delay [15]",
107 "irq 3 [15]",
108 ".wrap",
109 );
110 let mut cfg = Config::default();
111 cfg.use_program(&pio.load_program(&prg.program), &[]);
112 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
113 sm.set_config(&cfg);
114}
115
116#[embassy_executor::task]
117async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
118 sm.set_enable(true);
119 loop {
120 irq.wait().await;
121 info!("IRQ trigged");
122 }
123}
124
125#[embassy_executor::main]
126async fn main(spawner: Spawner) {
127 let p = embassy_rp::init(Default::default());
128 let pio = p.PIO0;
129
130 let Pio {
131 mut common,
132 irq3,
133 mut sm0,
134 mut sm1,
135 mut sm2,
136 ..
137 } = Pio::new(pio, Irqs);
138
139 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
140 setup_pio_task_sm1(&mut common, &mut sm1);
141 setup_pio_task_sm2(&mut common, &mut sm2);
142 spawner.spawn(pio_task_sm0(sm0)).unwrap();
143 spawner.spawn(pio_task_sm1(sm1)).unwrap();
144 spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap();
145}
diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs
new file mode 100644
index 000000000..60fbcb83a
--- /dev/null
+++ b/examples/rp23/src/bin/pio_dma.rs
@@ -0,0 +1,98 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_rp::block::ImageDef;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::{bind_interrupts, Peripheral};
12use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32});
33
34fn swap_nibbles(v: u32) -> u32 {
35 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
36 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
37 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
38}
39
40#[embassy_executor::main]
41async fn main(_spawner: Spawner) {
42 let p = embassy_rp::init(Default::default());
43 let pio = p.PIO0;
44 let Pio {
45 mut common,
46 sm0: mut sm,
47 ..
48 } = Pio::new(pio, Irqs);
49
50 let prg = pio_proc::pio_asm!(
51 ".origin 0",
52 "set pindirs,1",
53 ".wrap_target",
54 "set y,7",
55 "loop:",
56 "out x,4",
57 "in x,4",
58 "jmp y--, loop",
59 ".wrap",
60 );
61
62 let mut cfg = Config::default();
63 cfg.use_program(&common.load_program(&prg.program), &[]);
64 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
65 cfg.shift_in = ShiftConfig {
66 auto_fill: true,
67 threshold: 32,
68 direction: ShiftDirection::Left,
69 };
70 cfg.shift_out = ShiftConfig {
71 auto_fill: true,
72 threshold: 32,
73 direction: ShiftDirection::Right,
74 };
75
76 sm.set_config(&cfg);
77 sm.set_enable(true);
78
79 let mut dma_out_ref = p.DMA_CH0.into_ref();
80 let mut dma_in_ref = p.DMA_CH1.into_ref();
81 let mut dout = [0x12345678u32; 29];
82 for i in 1..dout.len() {
83 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
84 }
85 let mut din = [0u32; 29];
86 loop {
87 let (rx, tx) = sm.rx_tx();
88 join(
89 tx.dma_push(dma_out_ref.reborrow(), &dout),
90 rx.dma_pull(dma_in_ref.reborrow(), &mut din),
91 )
92 .await;
93 for i in 0..din.len() {
94 assert_eq!(din[i], swap_nibbles(dout[i]));
95 }
96 info!("Swapped {} words", dout.len());
97 }
98}
diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs
new file mode 100644
index 000000000..92aa858f9
--- /dev/null
+++ b/examples/rp23/src/bin/pio_hd44780.rs
@@ -0,0 +1,255 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display.
2//! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
3
4#![no_std]
5#![no_main]
6
7use core::fmt::Write;
8
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::dma::{AnyChannel, Channel};
12use embassy_rp::peripherals::PIO0;
13use embassy_rp::pio::{
14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
15};
16use embassy_rp::pwm::{self, Pwm};
17use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
18use embassy_time::{Instant, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21#[link_section = ".start_block"]
22#[used]
23pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
24
25// Program metadata for `picotool info`
26#[link_section = ".bi_entries"]
27#[used]
28pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
29 embassy_rp::binary_info::rp_program_name!(c"example"),
30 embassy_rp::binary_info::rp_cargo_version!(),
31 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
32 embassy_rp::binary_info::rp_program_build_attribute!(),
33];
34
35bind_interrupts!(pub struct Irqs {
36 PIO0_IRQ_0 => InterruptHandler<PIO0>;
37});
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 // this test assumes a 2x16 HD44780 display attached as follow:
42 // rs = PIN0
43 // rw = PIN1
44 // e = PIN2
45 // db4 = PIN3
46 // db5 = PIN4
47 // db6 = PIN5
48 // db7 = PIN6
49 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
50 // allowing direct connection of the display to the RP2040 without level shifters.
51 let p = embassy_rp::init(Default::default());
52
53 let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, {
54 let mut c = pwm::Config::default();
55 c.divider = 125.into();
56 c.top = 100;
57 c.compare_b = 50;
58 c
59 });
60
61 let mut hd = HD44780::new(
62 p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6,
63 )
64 .await;
65
66 loop {
67 struct Buf<const N: usize>([u8; N], usize);
68 impl<const N: usize> Write for Buf<N> {
69 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
70 for b in s.as_bytes() {
71 if self.1 >= N {
72 return Err(core::fmt::Error);
73 }
74 self.0[self.1] = *b;
75 self.1 += 1;
76 }
77 Ok(())
78 }
79 }
80 let mut buf = Buf([0; 16], 0);
81 write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
82 hd.add_line(&buf.0[0..buf.1]).await;
83 Timer::after_secs(1).await;
84 }
85}
86
87pub struct HD44780<'l> {
88 dma: PeripheralRef<'l, AnyChannel>,
89 sm: StateMachine<'l, PIO0, 0>,
90
91 buf: [u8; 40],
92}
93
94impl<'l> HD44780<'l> {
95 pub async fn new(
96 pio: impl Peripheral<P = PIO0> + 'l,
97 irq: Irqs,
98 dma: impl Peripheral<P = impl Channel> + 'l,
99 rs: impl PioPin,
100 rw: impl PioPin,
101 e: impl PioPin,
102 db4: impl PioPin,
103 db5: impl PioPin,
104 db6: impl PioPin,
105 db7: impl PioPin,
106 ) -> HD44780<'l> {
107 into_ref!(dma);
108
109 let Pio {
110 mut common,
111 mut irq0,
112 mut sm0,
113 ..
114 } = Pio::new(pio, irq);
115
116 // takes command words (<wait:24> <command:4> <0:4>)
117 let prg = pio_proc::pio_asm!(
118 r#"
119 .side_set 1 opt
120 .origin 20
121
122 loop:
123 out x, 24
124 delay:
125 jmp x--, delay
126 out pins, 4 side 1
127 out null, 4 side 0
128 jmp !osre, loop
129 irq 0
130 "#,
131 );
132
133 let rs = common.make_pio_pin(rs);
134 let rw = common.make_pio_pin(rw);
135 let e = common.make_pio_pin(e);
136 let db4 = common.make_pio_pin(db4);
137 let db5 = common.make_pio_pin(db5);
138 let db6 = common.make_pio_pin(db6);
139 let db7 = common.make_pio_pin(db7);
140
141 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
142
143 let mut cfg = Config::default();
144 cfg.use_program(&common.load_program(&prg.program), &[&e]);
145 cfg.clock_divider = 125u8.into();
146 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
147 cfg.shift_out = ShiftConfig {
148 auto_fill: true,
149 direction: ShiftDirection::Left,
150 threshold: 32,
151 };
152 cfg.fifo_join = FifoJoin::TxOnly;
153 sm0.set_config(&cfg);
154
155 sm0.set_enable(true);
156 // init to 8 bit thrice
157 sm0.tx().push((50000 << 8) | 0x30);
158 sm0.tx().push((5000 << 8) | 0x30);
159 sm0.tx().push((200 << 8) | 0x30);
160 // init 4 bit
161 sm0.tx().push((200 << 8) | 0x20);
162 // set font and lines
163 sm0.tx().push((50 << 8) | 0x20);
164 sm0.tx().push(0b1100_0000);
165
166 irq0.wait().await;
167 sm0.set_enable(false);
168
169 // takes command sequences (<rs:1> <count:7>, data...)
170 // many side sets are only there to free up a delay bit!
171 let prg = pio_proc::pio_asm!(
172 r#"
173 .origin 27
174 .side_set 1
175
176 .wrap_target
177 pull side 0
178 out x 1 side 0 ; !rs
179 out y 7 side 0 ; #data - 1
180
181 ; rs/rw to e: >= 60ns
182 ; e high time: >= 500ns
183 ; e low time: >= 500ns
184 ; read data valid after e falling: ~5ns
185 ; write data hold after e falling: ~10ns
186
187 loop:
188 pull side 0
189 jmp !x data side 0
190 command:
191 set pins 0b00 side 0
192 jmp shift side 0
193 data:
194 set pins 0b01 side 0
195 shift:
196 out pins 4 side 1 [9]
197 nop side 0 [9]
198 out pins 4 side 1 [9]
199 mov osr null side 0 [7]
200 out pindirs 4 side 0
201 set pins 0b10 side 0
202 busy:
203 nop side 1 [9]
204 jmp pin more side 0 [9]
205 mov osr ~osr side 1 [9]
206 nop side 0 [4]
207 out pindirs 4 side 0
208 jmp y-- loop side 0
209 .wrap
210 more:
211 nop side 1 [9]
212 jmp busy side 0 [9]
213 "#
214 );
215
216 let mut cfg = Config::default();
217 cfg.use_program(&common.load_program(&prg.program), &[&e]);
218 cfg.clock_divider = 8u8.into(); // ~64ns/insn
219 cfg.set_jmp_pin(&db7);
220 cfg.set_set_pins(&[&rs, &rw]);
221 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
222 cfg.shift_out.direction = ShiftDirection::Left;
223 cfg.fifo_join = FifoJoin::TxOnly;
224 sm0.set_config(&cfg);
225
226 sm0.set_enable(true);
227
228 // display on and cursor on and blinking, reset display
229 sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
230
231 Self {
232 dma: dma.map_into(),
233 sm: sm0,
234 buf: [0x20; 40],
235 }
236 }
237
238 pub async fn add_line(&mut self, s: &[u8]) {
239 // move cursor to 0:0, prepare 16 characters
240 self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
241 // move line 2 up
242 self.buf.copy_within(22..38, 3);
243 // move cursor to 1:0, prepare 16 characters
244 self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
245 // file line 2 with spaces
246 self.buf[22..38].fill(0x20);
247 // copy input line
248 let len = s.len().min(16);
249 self.buf[22..22 + len].copy_from_slice(&s[0..len]);
250 // set cursor to 1:15
251 self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
252
253 self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
254 }
255}
diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs
new file mode 100644
index 000000000..d6d2d0ade
--- /dev/null
+++ b/examples/rp23/src/bin/pio_i2s.rs
@@ -0,0 +1,140 @@
1//! This example shows generating audio and sending it to a connected i2s DAC using the PIO
2//! module of the RP2040.
3//!
4//! Connect the i2s DAC as follows:
5//! bclk : GPIO 18
6//! lrc : GPIO 19
7//! din : GPIO 20
8//! Then hold down the boot select button to trigger a rising triangle waveform.
9
10#![no_std]
11#![no_main]
12
13use core::mem;
14
15use embassy_executor::Spawner;
16use embassy_rp::block::ImageDef;
17use embassy_rp::peripherals::PIO0;
18use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
19use embassy_rp::{bind_interrupts, Peripheral};
20use fixed::traits::ToFixed;
21use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _};
23
24#[link_section = ".start_block"]
25#[used]
26pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
27
28// Program metadata for `picotool info`
29#[link_section = ".bi_entries"]
30#[used]
31pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
32 embassy_rp::binary_info::rp_program_name!(c"example"),
33 embassy_rp::binary_info::rp_cargo_version!(),
34 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
35 embassy_rp::binary_info::rp_program_build_attribute!(),
36];
37
38bind_interrupts!(struct Irqs {
39 PIO0_IRQ_0 => InterruptHandler<PIO0>;
40});
41
42const SAMPLE_RATE: u32 = 48_000;
43
44#[embassy_executor::main]
45async fn main(_spawner: Spawner) {
46 let p = embassy_rp::init(Default::default());
47
48 // Setup pio state machine for i2s output
49 let mut pio = Pio::new(p.PIO0, Irqs);
50
51 #[rustfmt::skip]
52 let pio_program = pio_proc::pio_asm!(
53 ".side_set 2",
54 " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock
55 "left_data:",
56 " out pins, 1 side 0b00",
57 " jmp x-- left_data side 0b01",
58 " out pins 1 side 0b10",
59 " set x, 14 side 0b11",
60 "right_data:",
61 " out pins 1 side 0b10",
62 " jmp x-- right_data side 0b11",
63 " out pins 1 side 0b00",
64 );
65
66 let bit_clock_pin = p.PIN_18;
67 let left_right_clock_pin = p.PIN_19;
68 let data_pin = p.PIN_20;
69
70 let data_pin = pio.common.make_pio_pin(data_pin);
71 let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin);
72 let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin);
73
74 let cfg = {
75 let mut cfg = Config::default();
76 cfg.use_program(
77 &pio.common.load_program(&pio_program.program),
78 &[&bit_clock_pin, &left_right_clock_pin],
79 );
80 cfg.set_out_pins(&[&data_pin]);
81 const BIT_DEPTH: u32 = 16;
82 const CHANNELS: u32 = 2;
83 let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS;
84 cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed();
85 cfg.shift_out = ShiftConfig {
86 threshold: 32,
87 direction: ShiftDirection::Left,
88 auto_fill: true,
89 };
90 // join fifos to have twice the time to start the next dma transfer
91 cfg.fifo_join = FifoJoin::TxOnly;
92 cfg
93 };
94 pio.sm0.set_config(&cfg);
95 pio.sm0.set_pin_dirs(
96 embassy_rp::pio::Direction::Out,
97 &[&data_pin, &left_right_clock_pin, &bit_clock_pin],
98 );
99
100 // create two audio buffers (back and front) which will take turns being
101 // filled with new audio data and being sent to the pio fifo using dma
102 const BUFFER_SIZE: usize = 960;
103 static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new();
104 let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]);
105 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE);
106
107 // start pio state machine
108 pio.sm0.set_enable(true);
109 let tx = pio.sm0.tx();
110 let mut dma_ref = p.DMA_CH0.into_ref();
111
112 let mut fade_value: i32 = 0;
113 let mut phase: i32 = 0;
114
115 loop {
116 // trigger transfer of front buffer data to the pio fifo
117 // but don't await the returned future, yet
118 let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer);
119
120 // fade in audio
121 let fade_target = i32::MAX;
122
123 // fill back buffer with fresh audio samples before awaiting the dma future
124 for s in back_buffer.iter_mut() {
125 // exponential approach of fade_value => fade_target
126 fade_value += (fade_target - fade_value) >> 14;
127 // generate triangle wave with amplitude and frequency based on fade value
128 phase = (phase + (fade_value >> 22)) & 0xffff;
129 let triangle_sample = (phase as i16 as i32).abs() - 16384;
130 let sample = (triangle_sample * (fade_value >> 15)) >> 16;
131 // duplicate mono sample into lower and upper half of dma word
132 *s = (sample as u16 as u32) * 0x10001;
133 }
134
135 // now await the dma future. once the dma finishes, the next buffer needs to be queued
136 // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us
137 dma_future.await;
138 mem::swap(&mut back_buffer, &mut front_buffer);
139 }
140}
diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs
new file mode 100644
index 000000000..587f91ac3
--- /dev/null
+++ b/examples/rp23/src/bin/pio_pwm.rs
@@ -0,0 +1,133 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Level;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
12use embassy_rp::{bind_interrupts, clocks};
13use embassy_time::Timer;
14use pio::InstructionOperands;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31const REFRESH_INTERVAL: u64 = 20000;
32
33bind_interrupts!(struct Irqs {
34 PIO0_IRQ_0 => InterruptHandler<PIO0>;
35});
36
37pub fn to_pio_cycles(duration: Duration) -> u32 {
38 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
39}
40
41pub struct PwmPio<'d, T: Instance, const SM: usize> {
42 sm: StateMachine<'d, T, SM>,
43}
44
45impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
46 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
47 let prg = pio_proc::pio_asm!(
48 ".side_set 1 opt"
49 "pull noblock side 0"
50 "mov x, osr"
51 "mov y, isr"
52 "countloop:"
53 "jmp x!=y noset"
54 "jmp skip side 1"
55 "noset:"
56 "nop"
57 "skip:"
58 "jmp y-- countloop"
59 );
60
61 pio.load_program(&prg.program);
62 let pin = pio.make_pio_pin(pin);
63 sm.set_pins(Level::High, &[&pin]);
64 sm.set_pin_dirs(Direction::Out, &[&pin]);
65
66 let mut cfg = Config::default();
67 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
68
69 sm.set_config(&cfg);
70
71 Self { sm }
72 }
73
74 pub fn start(&mut self) {
75 self.sm.set_enable(true);
76 }
77
78 pub fn stop(&mut self) {
79 self.sm.set_enable(false);
80 }
81
82 pub fn set_period(&mut self, duration: Duration) {
83 let is_enabled = self.sm.is_enabled();
84 while !self.sm.tx().empty() {} // Make sure that the queue is empty
85 self.sm.set_enable(false);
86 self.sm.tx().push(to_pio_cycles(duration));
87 unsafe {
88 self.sm.exec_instr(
89 InstructionOperands::PULL {
90 if_empty: false,
91 block: false,
92 }
93 .encode(),
94 );
95 self.sm.exec_instr(
96 InstructionOperands::OUT {
97 destination: ::pio::OutDestination::ISR,
98 bit_count: 32,
99 }
100 .encode(),
101 );
102 };
103 if is_enabled {
104 self.sm.set_enable(true) // Enable if previously enabled
105 }
106 }
107
108 pub fn set_level(&mut self, level: u32) {
109 self.sm.tx().push(level);
110 }
111
112 pub fn write(&mut self, duration: Duration) {
113 self.set_level(to_pio_cycles(duration));
114 }
115}
116
117#[embassy_executor::main]
118async fn main(_spawner: Spawner) {
119 let p = embassy_rp::init(Default::default());
120 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
121
122 // Note that PIN_25 is the led pin on the Pico
123 let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25);
124 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL));
125 pwm_pio.start();
126
127 let mut duration = 0;
128 loop {
129 duration = (duration + 1) % 1000;
130 pwm_pio.write(Duration::from_micros(duration));
131 Timer::after_millis(1).await;
132 }
133}
diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs
new file mode 100644
index 000000000..c147351e8
--- /dev/null
+++ b/examples/rp23/src/bin/pio_rotary_encoder.rs
@@ -0,0 +1,95 @@
1//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder.
2
3#![no_std]
4#![no_main]
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::{bind_interrupts, pio};
12use fixed::traits::ToFixed;
13use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32});
33
34pub struct PioEncoder<'d, T: Instance, const SM: usize> {
35 sm: StateMachine<'d, T, SM>,
36}
37
38impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
39 pub fn new(
40 pio: &mut Common<'d, T>,
41 mut sm: StateMachine<'d, T, SM>,
42 pin_a: impl PioPin,
43 pin_b: impl PioPin,
44 ) -> Self {
45 let mut pin_a = pio.make_pio_pin(pin_a);
46 let mut pin_b = pio.make_pio_pin(pin_b);
47 pin_a.set_pull(Pull::Up);
48 pin_b.set_pull(Pull::Up);
49 sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]);
50
51 let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",);
52
53 let mut cfg = Config::default();
54 cfg.set_in_pins(&[&pin_a, &pin_b]);
55 cfg.fifo_join = FifoJoin::RxOnly;
56 cfg.shift_in.direction = ShiftDirection::Left;
57 cfg.clock_divider = 10_000.to_fixed();
58 cfg.use_program(&pio.load_program(&prg.program), &[]);
59 sm.set_config(&cfg);
60 sm.set_enable(true);
61 Self { sm }
62 }
63
64 pub async fn read(&mut self) -> Direction {
65 loop {
66 match self.sm.rx().wait_pull().await {
67 0 => return Direction::CounterClockwise,
68 1 => return Direction::Clockwise,
69 _ => {}
70 }
71 }
72 }
73}
74
75pub enum Direction {
76 Clockwise,
77 CounterClockwise,
78}
79
80#[embassy_executor::main]
81async fn main(_spawner: Spawner) {
82 let p = embassy_rp::init(Default::default());
83 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
84
85 let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5);
86
87 let mut count = 0;
88 loop {
89 info!("Count: {}", count);
90 count += match encoder.read().await {
91 Direction::Clockwise => 1,
92 Direction::CounterClockwise => -1,
93 };
94 }
95}
diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs
new file mode 100644
index 000000000..5e8714178
--- /dev/null
+++ b/examples/rp23/src/bin/pio_servo.rs
@@ -0,0 +1,223 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Level;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
12use embassy_rp::{bind_interrupts, clocks};
13use embassy_time::Timer;
14use pio::InstructionOperands;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo
32const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo
33const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical
34const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle
35
36bind_interrupts!(struct Irqs {
37 PIO0_IRQ_0 => InterruptHandler<PIO0>;
38});
39
40pub fn to_pio_cycles(duration: Duration) -> u32 {
41 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
42}
43
44pub struct PwmPio<'d, T: Instance, const SM: usize> {
45 sm: StateMachine<'d, T, SM>,
46}
47
48impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
49 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
50 let prg = pio_proc::pio_asm!(
51 ".side_set 1 opt"
52 "pull noblock side 0"
53 "mov x, osr"
54 "mov y, isr"
55 "countloop:"
56 "jmp x!=y noset"
57 "jmp skip side 1"
58 "noset:"
59 "nop"
60 "skip:"
61 "jmp y-- countloop"
62 );
63
64 pio.load_program(&prg.program);
65 let pin = pio.make_pio_pin(pin);
66 sm.set_pins(Level::High, &[&pin]);
67 sm.set_pin_dirs(Direction::Out, &[&pin]);
68
69 let mut cfg = Config::default();
70 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
71
72 sm.set_config(&cfg);
73
74 Self { sm }
75 }
76
77 pub fn start(&mut self) {
78 self.sm.set_enable(true);
79 }
80
81 pub fn stop(&mut self) {
82 self.sm.set_enable(false);
83 }
84
85 pub fn set_period(&mut self, duration: Duration) {
86 let is_enabled = self.sm.is_enabled();
87 while !self.sm.tx().empty() {} // Make sure that the queue is empty
88 self.sm.set_enable(false);
89 self.sm.tx().push(to_pio_cycles(duration));
90 unsafe {
91 self.sm.exec_instr(
92 InstructionOperands::PULL {
93 if_empty: false,
94 block: false,
95 }
96 .encode(),
97 );
98 self.sm.exec_instr(
99 InstructionOperands::OUT {
100 destination: ::pio::OutDestination::ISR,
101 bit_count: 32,
102 }
103 .encode(),
104 );
105 };
106 if is_enabled {
107 self.sm.set_enable(true) // Enable if previously enabled
108 }
109 }
110
111 pub fn set_level(&mut self, level: u32) {
112 self.sm.tx().push(level);
113 }
114
115 pub fn write(&mut self, duration: Duration) {
116 self.set_level(to_pio_cycles(duration));
117 }
118}
119
120pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
121 pwm: PwmPio<'d, T, SM>,
122 period: Duration,
123 min_pulse_width: Duration,
124 max_pulse_width: Duration,
125 max_degree_rotation: u64,
126}
127
128impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
129 pub fn new(pwm: PwmPio<'d, T, SM>) -> Self {
130 Self {
131 pwm,
132 period: Duration::from_micros(REFRESH_INTERVAL),
133 min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH),
134 max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH),
135 max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION,
136 }
137 }
138
139 pub fn set_period(mut self, duration: Duration) -> Self {
140 self.period = duration;
141 self
142 }
143
144 pub fn set_min_pulse_width(mut self, duration: Duration) -> Self {
145 self.min_pulse_width = duration;
146 self
147 }
148
149 pub fn set_max_pulse_width(mut self, duration: Duration) -> Self {
150 self.max_pulse_width = duration;
151 self
152 }
153
154 pub fn set_max_degree_rotation(mut self, degree: u64) -> Self {
155 self.max_degree_rotation = degree;
156 self
157 }
158
159 pub fn build(mut self) -> Servo<'d, T, SM> {
160 self.pwm.set_period(self.period);
161 Servo {
162 pwm: self.pwm,
163 min_pulse_width: self.min_pulse_width,
164 max_pulse_width: self.max_pulse_width,
165 max_degree_rotation: self.max_degree_rotation,
166 }
167 }
168}
169
170pub struct Servo<'d, T: Instance, const SM: usize> {
171 pwm: PwmPio<'d, T, SM>,
172 min_pulse_width: Duration,
173 max_pulse_width: Duration,
174 max_degree_rotation: u64,
175}
176
177impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> {
178 pub fn start(&mut self) {
179 self.pwm.start();
180 }
181
182 pub fn stop(&mut self) {
183 self.pwm.stop();
184 }
185
186 pub fn write_time(&mut self, duration: Duration) {
187 self.pwm.write(duration);
188 }
189
190 pub fn rotate(&mut self, degree: u64) {
191 let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64)
192 / self.max_degree_rotation;
193 let mut duration =
194 Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64);
195 if self.max_pulse_width < duration {
196 duration = self.max_pulse_width;
197 }
198
199 self.pwm.write(duration);
200 }
201}
202
203#[embassy_executor::main]
204async fn main(_spawner: Spawner) {
205 let p = embassy_rp::init(Default::default());
206 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
207
208 let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1);
209 let mut servo = ServoBuilder::new(pwm_pio)
210 .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo
211 .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment.
212 .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value.
213 .build();
214
215 servo.start();
216
217 let mut degree = 0;
218 loop {
219 degree = (degree + 1) % 120;
220 servo.rotate(degree);
221 Timer::after_millis(50).await;
222 }
223}
diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs
new file mode 100644
index 000000000..24785443b
--- /dev/null
+++ b/examples/rp23/src/bin/pio_stepper.rs
@@ -0,0 +1,183 @@
1//! This example shows how to use the PIO module in the RP2040 to implement a stepper motor driver
2//! for a 5-wire stepper such as the 28BYJ-48. You can halt an ongoing rotation by dropping the future.
3
4#![no_std]
5#![no_main]
6use core::mem::{self, MaybeUninit};
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::peripherals::PIO0;
13use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine};
14use embassy_time::{with_timeout, Duration, Timer};
15use fixed::traits::ToFixed;
16use fixed::types::extra::U8;
17use fixed::FixedU32;
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34bind_interrupts!(struct Irqs {
35 PIO0_IRQ_0 => InterruptHandler<PIO0>;
36});
37
38pub struct PioStepper<'d, T: Instance, const SM: usize> {
39 irq: Irq<'d, T, SM>,
40 sm: StateMachine<'d, T, SM>,
41}
42
43impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
44 pub fn new(
45 pio: &mut Common<'d, T>,
46 mut sm: StateMachine<'d, T, SM>,
47 irq: Irq<'d, T, SM>,
48 pin0: impl PioPin,
49 pin1: impl PioPin,
50 pin2: impl PioPin,
51 pin3: impl PioPin,
52 ) -> Self {
53 let prg = pio_proc::pio_asm!(
54 "pull block",
55 "mov x, osr",
56 "pull block",
57 "mov y, osr",
58 "jmp !x end",
59 "loop:",
60 "jmp !osre step",
61 "mov osr, y",
62 "step:",
63 "out pins, 4 [31]"
64 "jmp x-- loop",
65 "end:",
66 "irq 0 rel"
67 );
68 let pin0 = pio.make_pio_pin(pin0);
69 let pin1 = pio.make_pio_pin(pin1);
70 let pin2 = pio.make_pio_pin(pin2);
71 let pin3 = pio.make_pio_pin(pin3);
72 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
73 let mut cfg = Config::default();
74 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
75 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
76 cfg.use_program(&pio.load_program(&prg.program), &[]);
77 sm.set_config(&cfg);
78 sm.set_enable(true);
79 Self { irq, sm }
80 }
81
82 // Set pulse frequency
83 pub fn set_frequency(&mut self, freq: u32) {
84 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
85 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
86 assert!(clock_divider >= 1, "clkdiv must be >= 1");
87 self.sm.set_clock_divider(clock_divider);
88 self.sm.clkdiv_restart();
89 }
90
91 // Full step, one phase
92 pub async fn step(&mut self, steps: i32) {
93 if steps > 0 {
94 self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await
95 } else {
96 self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await
97 }
98 }
99
100 // Full step, two phase
101 pub async fn step2(&mut self, steps: i32) {
102 if steps > 0 {
103 self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await
104 } else {
105 self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await
106 }
107 }
108
109 // Half step
110 pub async fn step_half(&mut self, steps: i32) {
111 if steps > 0 {
112 self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await
113 } else {
114 self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await
115 }
116 }
117
118 async fn run(&mut self, steps: i32, pattern: u32) {
119 self.sm.tx().wait_push(steps as u32).await;
120 self.sm.tx().wait_push(pattern).await;
121 let drop = OnDrop::new(|| {
122 self.sm.clear_fifos();
123 unsafe {
124 self.sm.exec_instr(
125 pio::InstructionOperands::JMP {
126 address: 0,
127 condition: pio::JmpCondition::Always,
128 }
129 .encode(),
130 );
131 }
132 });
133 self.irq.wait().await;
134 drop.defuse();
135 }
136}
137
138struct OnDrop<F: FnOnce()> {
139 f: MaybeUninit<F>,
140}
141
142impl<F: FnOnce()> OnDrop<F> {
143 pub fn new(f: F) -> Self {
144 Self { f: MaybeUninit::new(f) }
145 }
146
147 pub fn defuse(self) {
148 mem::forget(self)
149 }
150}
151
152impl<F: FnOnce()> Drop for OnDrop<F> {
153 fn drop(&mut self) {
154 unsafe { self.f.as_ptr().read()() }
155 }
156}
157
158#[embassy_executor::main]
159async fn main(_spawner: Spawner) {
160 let p = embassy_rp::init(Default::default());
161 let Pio {
162 mut common, irq0, sm0, ..
163 } = Pio::new(p.PIO0, Irqs);
164
165 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7);
166 stepper.set_frequency(120);
167 loop {
168 info!("CW full steps");
169 stepper.step(1000).await;
170
171 info!("CCW full steps, drop after 1 sec");
172 if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await {
173 info!("Time's up!");
174 Timer::after(Duration::from_secs(1)).await;
175 }
176
177 info!("CW half steps");
178 stepper.step_half(1000).await;
179
180 info!("CCW half steps");
181 stepper.step_half(-1000).await;
182 }
183}
diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs
new file mode 100644
index 000000000..00fe5e396
--- /dev/null
+++ b/examples/rp23/src/bin/pio_ws2812.rs
@@ -0,0 +1,176 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules.
2//! See (https://www.sparkfun.com/categories/tags/ws2812)
3
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::dma::{AnyChannel, Channel};
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{
13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
14};
15use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
16use embassy_time::{Duration, Ticker, Timer};
17use fixed::types::U24F8;
18use fixed_macro::fixed;
19use smart_leds::RGB8;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36bind_interrupts!(struct Irqs {
37 PIO0_IRQ_0 => InterruptHandler<PIO0>;
38});
39
40pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
41 dma: PeripheralRef<'d, AnyChannel>,
42 sm: StateMachine<'d, P, S>,
43}
44
45impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
46 pub fn new(
47 pio: &mut Common<'d, P>,
48 mut sm: StateMachine<'d, P, S>,
49 dma: impl Peripheral<P = impl Channel> + 'd,
50 pin: impl PioPin,
51 ) -> Self {
52 into_ref!(dma);
53
54 // Setup sm0
55
56 // prepare the PIO program
57 let side_set = pio::SideSet::new(false, 1, false);
58 let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
59
60 const T1: u8 = 2; // start bit
61 const T2: u8 = 5; // data bit
62 const T3: u8 = 3; // stop bit
63 const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
64
65 let mut wrap_target = a.label();
66 let mut wrap_source = a.label();
67 let mut do_zero = a.label();
68 a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
69 a.bind(&mut wrap_target);
70 // Do stop bit
71 a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
72 // Do start bit
73 a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
74 // Do data bit = 1
75 a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
76 a.bind(&mut do_zero);
77 // Do data bit = 0
78 a.nop_with_delay_and_side_set(T2 - 1, 0);
79 a.bind(&mut wrap_source);
80
81 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
82 let mut cfg = Config::default();
83
84 // Pin config
85 let out_pin = pio.make_pio_pin(pin);
86 cfg.set_out_pins(&[&out_pin]);
87 cfg.set_set_pins(&[&out_pin]);
88
89 cfg.use_program(&pio.load_program(&prg), &[&out_pin]);
90
91 // Clock config, measured in kHz to avoid overflows
92 // TODO CLOCK_FREQ should come from embassy_rp
93 let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
94 let ws2812_freq = fixed!(800: U24F8);
95 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
96 cfg.clock_divider = clock_freq / bit_freq;
97
98 // FIFO config
99 cfg.fifo_join = FifoJoin::TxOnly;
100 cfg.shift_out = ShiftConfig {
101 auto_fill: true,
102 threshold: 24,
103 direction: ShiftDirection::Left,
104 };
105
106 sm.set_config(&cfg);
107 sm.set_enable(true);
108
109 Self {
110 dma: dma.map_into(),
111 sm,
112 }
113 }
114
115 pub async fn write(&mut self, colors: &[RGB8; N]) {
116 // Precompute the word bytes from the colors
117 let mut words = [0u32; N];
118 for i in 0..N {
119 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
120 words[i] = word;
121 }
122
123 // DMA transfer
124 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
125
126 Timer::after_micros(55).await;
127 }
128}
129
130/// Input a value 0 to 255 to get a color value
131/// The colours are a transition r - g - b - back to r.
132fn wheel(mut wheel_pos: u8) -> RGB8 {
133 wheel_pos = 255 - wheel_pos;
134 if wheel_pos < 85 {
135 return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
136 }
137 if wheel_pos < 170 {
138 wheel_pos -= 85;
139 return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
140 }
141 wheel_pos -= 170;
142 (wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
143}
144
145#[embassy_executor::main]
146async fn main(_spawner: Spawner) {
147 info!("Start");
148 let p = embassy_rp::init(Default::default());
149
150 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
151
152 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
153 // feather boards for the 2040 both have one built in.
154 const NUM_LEDS: usize = 1;
155 let mut data = [RGB8::default(); NUM_LEDS];
156
157 // Common neopixel pins:
158 // Thing plus: 8
159 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4
160 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
161
162 // Loop forever making RGB values and pushing them out to the WS2812.
163 let mut ticker = Ticker::every(Duration::from_millis(10));
164 loop {
165 for j in 0..(256 * 5) {
166 debug!("New Colors:");
167 for i in 0..NUM_LEDS {
168 data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
169 debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
170 }
171 ws2812.write(&data).await;
172
173 ticker.next().await;
174 }
175 }
176}
diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs
new file mode 100644
index 000000000..bfc2c6f67
--- /dev/null
+++ b/examples/rp23/src/bin/pwm.rs
@@ -0,0 +1,44 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::pwm::{Config, Pwm};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32
33 let mut c: Config = Default::default();
34 c.top = 0x8000;
35 c.compare_b = 8;
36 let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone());
37
38 loop {
39 info!("current LED duty cycle: {}/32768", c.compare_b);
40 Timer::after_secs(1).await;
41 c.compare_b = c.compare_b.rotate_left(4);
42 pwm.set_config(&c);
43 }
44}
diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs
new file mode 100644
index 000000000..b65f2778b
--- /dev/null
+++ b/examples/rp23/src/bin/pwm_input.rs
@@ -0,0 +1,41 @@
1//! This example shows how to use the PWM module to measure the frequency of an input signal.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull;
10use embassy_rp::pwm::{Config, InputMode, Pwm};
11use embassy_time::{Duration, Ticker};
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31
32 let cfg: Config = Default::default();
33 let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg);
34
35 let mut ticker = Ticker::every(Duration::from_secs(1));
36 loop {
37 info!("Input frequency: {} Hz", pwm.counter());
38 pwm.set_counter(0);
39 ticker.next().await;
40 }
41}
diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs
new file mode 100644
index 000000000..f65b236b1
--- /dev/null
+++ b/examples/rp23/src/bin/rosc.rs
@@ -0,0 +1,46 @@
1//! This example test the RP Pico on board LED.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::{clocks, gpio};
12use embassy_time::Timer;
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let mut config = embassy_rp::config::Config::default();
33 config.clocks = clocks::ClockConfig::rosc();
34 let p = embassy_rp::init(config);
35 let mut led = Output::new(p.PIN_25, Level::Low);
36
37 loop {
38 info!("led on!");
39 led.set_high();
40 Timer::after_secs(1).await;
41
42 info!("led off!");
43 led.set_low();
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs
new file mode 100644
index 000000000..b3fde13e3
--- /dev/null
+++ b/examples/rp23/src/bin/shared_bus.rs
@@ -0,0 +1,130 @@
1//! This example shows how to share (async) I2C and SPI buses between multiple devices.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::{AnyPin, Level, Output};
13use embassy_rp::i2c::{self, I2c, InterruptHandler};
14use embassy_rp::peripherals::{I2C1, SPI1};
15use embassy_rp::spi::{self, Spi};
16use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::mutex::Mutex;
18use embassy_time::Timer;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>;
37type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>;
38
39bind_interrupts!(struct Irqs {
40 I2C1_IRQ => InterruptHandler<I2C1>;
41});
42
43#[embassy_executor::main]
44async fn main(spawner: Spawner) {
45 let p = embassy_rp::init(Default::default());
46 info!("Here we go!");
47
48 // Shared I2C bus
49 let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default());
50 static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new();
51 let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
52
53 spawner.must_spawn(i2c_task_a(i2c_bus));
54 spawner.must_spawn(i2c_task_b(i2c_bus));
55
56 // Shared SPI bus
57 let spi_cfg = spi::Config::default();
58 let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg);
59 static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new();
60 let spi_bus = SPI_BUS.init(Mutex::new(spi));
61
62 // Chip select pins for the SPI devices
63 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High);
64 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High);
65
66 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
67 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
68}
69
70#[embassy_executor::task]
71async fn i2c_task_a(i2c_bus: &'static I2c1Bus) {
72 let i2c_dev = I2cDevice::new(i2c_bus);
73 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0);
74 loop {
75 info!("i2c task A");
76 Timer::after_secs(1).await;
77 }
78}
79
80#[embassy_executor::task]
81async fn i2c_task_b(i2c_bus: &'static I2c1Bus) {
82 let i2c_dev = I2cDevice::new(i2c_bus);
83 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE);
84 loop {
85 info!("i2c task B");
86 Timer::after_secs(1).await;
87 }
88}
89
90#[embassy_executor::task]
91async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
92 let spi_dev = SpiDevice::new(spi_bus, cs);
93 let _sensor = DummySpiDeviceDriver::new(spi_dev);
94 loop {
95 info!("spi task A");
96 Timer::after_secs(1).await;
97 }
98}
99
100#[embassy_executor::task]
101async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
102 let spi_dev = SpiDevice::new(spi_bus, cs);
103 let _sensor = DummySpiDeviceDriver::new(spi_dev);
104 loop {
105 info!("spi task B");
106 Timer::after_secs(1).await;
107 }
108}
109
110// Dummy I2C device driver, using `embedded-hal-async`
111struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> {
112 _i2c: I2C,
113}
114
115impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> {
116 fn new(i2c_dev: I2C, _address: u8) -> Self {
117 Self { _i2c: i2c_dev }
118 }
119}
120
121// Dummy SPI device driver, using `embedded-hal-async`
122struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> {
123 _spi: SPI,
124}
125
126impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> {
127 fn new(spi_dev: SPI) -> Self {
128 Self { _spi: spi_dev }
129 }
130}
diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs
new file mode 100644
index 000000000..4a3301cfd
--- /dev/null
+++ b/examples/rp23/src/bin/sharing.rs
@@ -0,0 +1,165 @@
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::block::ImageDef;
23use embassy_rp::clocks::RoscRng;
24use embassy_rp::interrupt::{InterruptExt, Priority};
25use embassy_rp::peripherals::UART0;
26use embassy_rp::uart::{self, InterruptHandler, UartTx};
27use embassy_rp::{bind_interrupts, interrupt};
28use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
29use embassy_sync::{blocking_mutex, mutex};
30use embassy_time::{Duration, Ticker};
31use rand::RngCore;
32use static_cell::{ConstStaticCell, StaticCell};
33use {defmt_rtt as _, panic_probe as _};
34
35#[link_section = ".start_block"]
36#[used]
37pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
38
39// Program metadata for `picotool info`
40#[link_section = ".bi_entries"]
41#[used]
42pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
43 embassy_rp::binary_info::rp_program_name!(c"example"),
44 embassy_rp::binary_info::rp_cargo_version!(),
45 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
46 embassy_rp::binary_info::rp_program_build_attribute!(),
47];
48
49type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
50
51struct MyType {
52 inner: u32,
53}
54
55static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new();
56static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
57
58// Use Atomics for simple values
59static ATOMIC: AtomicU32 = AtomicU32::new(0);
60
61// Use blocking Mutex with Cell/RefCell for sharing non-async things
62static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> =
63 blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 }));
64
65bind_interrupts!(struct Irqs {
66 UART0_IRQ => InterruptHandler<UART0>;
67});
68
69#[interrupt]
70unsafe fn SWI_IRQ_0() {
71 EXECUTOR_HI.on_interrupt()
72}
73
74#[entry]
75fn main() -> ! {
76 let p = embassy_rp::init(Default::default());
77 info!("Here we go!");
78
79 let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default());
80 // Use the async Mutex for sharing async things (built-in interior mutability)
81 static UART: StaticCell<UartAsyncMutex> = StaticCell::new();
82 let uart = UART.init(mutex::Mutex::new(uart));
83
84 // High-priority executor: runs in interrupt mode
85 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
86 let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0);
87 spawner.must_spawn(task_a(uart));
88
89 // Low priority executor: runs in thread mode
90 let executor = EXECUTOR_LOW.init(Executor::new());
91 executor.run(|spawner| {
92 // No Mutex needed when sharing between tasks running on the same executor
93
94 // Use Cell for Copy-types
95 static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4]));
96 let cell = CELL.take();
97
98 // Use RefCell for &mut access
99 static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 }));
100 let ref_cell = REF_CELL.take();
101
102 spawner.must_spawn(task_b(uart, cell, ref_cell));
103 spawner.must_spawn(task_c(cell, ref_cell));
104 });
105}
106
107#[embassy_executor::task]
108async fn task_a(uart: &'static UartAsyncMutex) {
109 let mut ticker = Ticker::every(Duration::from_secs(1));
110 loop {
111 let random = RoscRng.next_u32();
112
113 {
114 let mut uart = uart.lock().await;
115 uart.write(b"task a").await.unwrap();
116 // The uart lock is released when it goes out of scope
117 }
118
119 ATOMIC.store(random, Ordering::Relaxed);
120
121 MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random);
122
123 ticker.next().await;
124 }
125}
126
127#[embassy_executor::task]
128async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
129 let mut ticker = Ticker::every(Duration::from_secs(1));
130 loop {
131 let random = RoscRng.next_u32();
132
133 uart.lock().await.write(b"task b").await.unwrap();
134
135 cell.set(random.to_be_bytes());
136
137 ref_cell.borrow_mut().inner = random;
138
139 ticker.next().await;
140 }
141}
142
143#[embassy_executor::task]
144async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
145 let mut ticker = Ticker::every(Duration::from_secs(1));
146 loop {
147 info!("=======================");
148
149 let atomic_val = ATOMIC.load(Ordering::Relaxed);
150 info!("atomic: {}", atomic_val);
151
152 MUTEX_BLOCKING.lock(|x| {
153 let val = x.borrow().inner;
154 info!("blocking mutex: {}", val);
155 });
156
157 let cell_val = cell.get();
158 info!("cell: {:?}", cell_val);
159
160 let ref_cell_val = ref_cell.borrow().inner;
161 info!("ref_cell: {:?}", ref_cell_val);
162
163 ticker.next().await;
164 }
165}
diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs
new file mode 100644
index 000000000..924873e60
--- /dev/null
+++ b/examples/rp23/src/bin/spi.rs
@@ -0,0 +1,61 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example for resistive touch sensor in Waveshare Pico-ResTouch
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::spi::Spi;
12use embassy_rp::{gpio, spi};
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default());
33 info!("Hello World!");
34
35 // Example for resistive touch sensor in Waveshare Pico-ResTouch
36
37 let miso = p.PIN_12;
38 let mosi = p.PIN_11;
39 let clk = p.PIN_10;
40 let touch_cs = p.PIN_16;
41
42 // create SPI
43 let mut config = spi::Config::default();
44 config.frequency = 2_000_000;
45 let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config);
46
47 // Configure CS
48 let mut cs = Output::new(touch_cs, Level::Low);
49
50 loop {
51 cs.set_low();
52 let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00];
53 spi.blocking_transfer_in_place(&mut buf).unwrap();
54 cs.set_high();
55
56 let x = (buf[1] as u32) << 5 | (buf[2] as u32) >> 3;
57 let y = (buf[4] as u32) << 5 | (buf[5] as u32) >> 3;
58
59 info!("touch: {=u32} {=u32}", x, y);
60 }
61}
diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs
new file mode 100644
index 000000000..4a74f991c
--- /dev/null
+++ b/examples/rp23/src/bin/spi_async.rs
@@ -0,0 +1,46 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back.
3
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::spi::{Config, Spi};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31 info!("Hello World!");
32
33 let miso = p.PIN_12;
34 let mosi = p.PIN_11;
35 let clk = p.PIN_10;
36
37 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
38
39 loop {
40 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
41 let mut rx_buf = [0_u8; 6];
42 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
43 info!("{:?}", rx_buf);
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs
new file mode 100644
index 000000000..71dd84658
--- /dev/null
+++ b/examples/rp23/src/bin/spi_display.rs
@@ -0,0 +1,327 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
5
6#![no_std]
7#![no_main]
8
9use core::cell::RefCell;
10
11use defmt::*;
12use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
13use embassy_executor::Spawner;
14use embassy_rp::block::ImageDef;
15use embassy_rp::gpio::{Level, Output};
16use embassy_rp::spi;
17use embassy_rp::spi::{Blocking, Spi};
18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
19use embassy_sync::blocking_mutex::Mutex;
20use embassy_time::Delay;
21use embedded_graphics::image::{Image, ImageRawLE};
22use embedded_graphics::mono_font::ascii::FONT_10X20;
23use embedded_graphics::mono_font::MonoTextStyle;
24use embedded_graphics::pixelcolor::Rgb565;
25use embedded_graphics::prelude::*;
26use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
27use embedded_graphics::text::Text;
28use st7789::{Orientation, ST7789};
29use {defmt_rtt as _, panic_probe as _};
30
31#[link_section = ".start_block"]
32#[used]
33pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
34
35// Program metadata for `picotool info`
36#[link_section = ".bi_entries"]
37#[used]
38pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
39 embassy_rp::binary_info::rp_program_name!(c"example"),
40 embassy_rp::binary_info::rp_cargo_version!(),
41 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
42 embassy_rp::binary_info::rp_program_build_attribute!(),
43];
44
45use crate::my_display_interface::SPIDeviceInterface;
46use crate::touch::Touch;
47
48const DISPLAY_FREQ: u32 = 64_000_000;
49const TOUCH_FREQ: u32 = 200_000;
50
51#[embassy_executor::main]
52async fn main(_spawner: Spawner) {
53 let p = embassy_rp::init(Default::default());
54 info!("Hello World!");
55
56 let bl = p.PIN_13;
57 let rst = p.PIN_15;
58 let display_cs = p.PIN_9;
59 let dcx = p.PIN_8;
60 let miso = p.PIN_12;
61 let mosi = p.PIN_11;
62 let clk = p.PIN_10;
63 let touch_cs = p.PIN_16;
64 //let touch_irq = p.PIN_17;
65
66 // create SPI
67 let mut display_config = spi::Config::default();
68 display_config.frequency = DISPLAY_FREQ;
69 display_config.phase = spi::Phase::CaptureOnSecondTransition;
70 display_config.polarity = spi::Polarity::IdleHigh;
71 let mut touch_config = spi::Config::default();
72 touch_config.frequency = TOUCH_FREQ;
73 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
74 touch_config.polarity = spi::Polarity::IdleHigh;
75
76 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
77 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
78
79 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
80 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
81
82 let mut touch = Touch::new(touch_spi);
83
84 let dcx = Output::new(dcx, Level::Low);
85 let rst = Output::new(rst, Level::Low);
86 // dcx: 0 = command, 1 = data
87
88 // Enable LCD backlight
89 let _bl = Output::new(bl, Level::High);
90
91 // display interface abstraction from SPI and DC
92 let di = SPIDeviceInterface::new(display_spi, dcx);
93
94 // create driver
95 let mut display = ST7789::new(di, rst, 240, 320);
96
97 // initialize
98 display.init(&mut Delay).unwrap();
99
100 // set default orientation
101 display.set_orientation(Orientation::Landscape).unwrap();
102
103 display.clear(Rgb565::BLACK).unwrap();
104
105 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
106 let ferris = Image::new(&raw_image_data, Point::new(34, 68));
107
108 // Display the image
109 ferris.draw(&mut display).unwrap();
110
111 let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
112 Text::new(
113 "Hello embedded_graphics \n + embassy + RP2040!",
114 Point::new(20, 200),
115 style,
116 )
117 .draw(&mut display)
118 .unwrap();
119
120 loop {
121 if let Some((x, y)) = touch.read() {
122 let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build();
123
124 Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
125 .into_styled(style)
126 .draw(&mut display)
127 .unwrap();
128 }
129 }
130}
131
132/// Driver for the XPT2046 resistive touchscreen sensor
133mod touch {
134 use embedded_hal_1::spi::{Operation, SpiDevice};
135
136 struct Calibration {
137 x1: i32,
138 x2: i32,
139 y1: i32,
140 y2: i32,
141 sx: i32,
142 sy: i32,
143 }
144
145 const CALIBRATION: Calibration = Calibration {
146 x1: 3880,
147 x2: 340,
148 y1: 262,
149 y2: 3850,
150 sx: 320,
151 sy: 240,
152 };
153
154 pub struct Touch<SPI: SpiDevice> {
155 spi: SPI,
156 }
157
158 impl<SPI> Touch<SPI>
159 where
160 SPI: SpiDevice,
161 {
162 pub fn new(spi: SPI) -> Self {
163 Self { spi }
164 }
165
166 pub fn read(&mut self) -> Option<(i32, i32)> {
167 let mut x = [0; 2];
168 let mut y = [0; 2];
169 self.spi
170 .transaction(&mut [
171 Operation::Write(&[0x90]),
172 Operation::Read(&mut x),
173 Operation::Write(&[0xd0]),
174 Operation::Read(&mut y),
175 ])
176 .unwrap();
177
178 let x = (u16::from_be_bytes(x) >> 3) as i32;
179 let y = (u16::from_be_bytes(y) >> 3) as i32;
180
181 let cal = &CALIBRATION;
182
183 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
184 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
185 if x == 0 && y == 0 {
186 None
187 } else {
188 Some((x, y))
189 }
190 }
191 }
192}
193
194mod my_display_interface {
195 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
196 use embedded_hal_1::digital::OutputPin;
197 use embedded_hal_1::spi::SpiDevice;
198
199 /// SPI display interface.
200 ///
201 /// This combines the SPI peripheral and a data/command pin
202 pub struct SPIDeviceInterface<SPI, DC> {
203 spi: SPI,
204 dc: DC,
205 }
206
207 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
208 where
209 SPI: SpiDevice,
210 DC: OutputPin,
211 {
212 /// Create new SPI interface for communciation with a display driver
213 pub fn new(spi: SPI, dc: DC) -> Self {
214 Self { spi, dc }
215 }
216 }
217
218 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
219 where
220 SPI: SpiDevice,
221 DC: OutputPin,
222 {
223 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
224 // 1 = data, 0 = command
225 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
226
227 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
228 Ok(())
229 }
230
231 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
232 // 1 = data, 0 = command
233 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
234
235 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
236 Ok(())
237 }
238 }
239
240 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
241 match words {
242 DataFormat::U8(slice) => spi.write(slice),
243 DataFormat::U16(slice) => {
244 use byte_slice_cast::*;
245 spi.write(slice.as_byte_slice())
246 }
247 DataFormat::U16LE(slice) => {
248 use byte_slice_cast::*;
249 for v in slice.as_mut() {
250 *v = v.to_le();
251 }
252 spi.write(slice.as_byte_slice())
253 }
254 DataFormat::U16BE(slice) => {
255 use byte_slice_cast::*;
256 for v in slice.as_mut() {
257 *v = v.to_be();
258 }
259 spi.write(slice.as_byte_slice())
260 }
261 DataFormat::U8Iter(iter) => {
262 let mut buf = [0; 32];
263 let mut i = 0;
264
265 for v in iter.into_iter() {
266 buf[i] = v;
267 i += 1;
268
269 if i == buf.len() {
270 spi.write(&buf)?;
271 i = 0;
272 }
273 }
274
275 if i > 0 {
276 spi.write(&buf[..i])?;
277 }
278
279 Ok(())
280 }
281 DataFormat::U16LEIter(iter) => {
282 use byte_slice_cast::*;
283 let mut buf = [0; 32];
284 let mut i = 0;
285
286 for v in iter.map(u16::to_le) {
287 buf[i] = v;
288 i += 1;
289
290 if i == buf.len() {
291 spi.write(&buf.as_byte_slice())?;
292 i = 0;
293 }
294 }
295
296 if i > 0 {
297 spi.write(&buf[..i].as_byte_slice())?;
298 }
299
300 Ok(())
301 }
302 DataFormat::U16BEIter(iter) => {
303 use byte_slice_cast::*;
304 let mut buf = [0; 64];
305 let mut i = 0;
306 let len = buf.len();
307
308 for v in iter.map(u16::to_be) {
309 buf[i] = v;
310 i += 1;
311
312 if i == len {
313 spi.write(&buf.as_byte_slice())?;
314 i = 0;
315 }
316 }
317
318 if i > 0 {
319 spi.write(&buf[..i].as_byte_slice())?;
320 }
321
322 Ok(())
323 }
324 _ => unimplemented!(),
325 }
326 }
327}
diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs
new file mode 100644
index 000000000..dabf41ab8
--- /dev/null
+++ b/examples/rp23/src/bin/spi_sdmmc.rs
@@ -0,0 +1,98 @@
1//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI.
2//!
3//! The example will attempt to read a file `MY_FILE.TXT` from the root directory
4//! of the SD card and print its contents.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_embedded_hal::SetConfig;
11use embassy_executor::Spawner;
12use embassy_rp::block::ImageDef;
13use embassy_rp::spi::Spi;
14use embassy_rp::{gpio, spi};
15use embedded_hal_bus::spi::ExclusiveDevice;
16use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
17use gpio::{Level, Output};
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34struct DummyTimesource();
35
36impl embedded_sdmmc::TimeSource for DummyTimesource {
37 fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
38 embedded_sdmmc::Timestamp {
39 year_since_1970: 0,
40 zero_indexed_month: 0,
41 zero_indexed_day: 0,
42 hours: 0,
43 minutes: 0,
44 seconds: 0,
45 }
46 }
47}
48
49#[embassy_executor::main]
50async fn main(_spawner: Spawner) {
51 embassy_rp::pac::SIO.spinlock(31).write_value(1);
52 let p = embassy_rp::init(Default::default());
53
54 // SPI clock needs to be running at <= 400kHz during initialization
55 let mut config = spi::Config::default();
56 config.frequency = 400_000;
57 let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config);
58 // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons
59 let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin);
60 // Real cs pin
61 let cs = Output::new(p.PIN_16, Level::High);
62
63 let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay);
64 info!("Card size is {} bytes", sdcard.num_bytes().unwrap());
65
66 // Now that the card is initialized, the SPI clock can go faster
67 let mut config = spi::Config::default();
68 config.frequency = 16_000_000;
69 sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
70
71 // Now let's look for volumes (also known as partitions) on our block device.
72 // To do this we need a Volume Manager. It will take ownership of the block device.
73 let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource());
74
75 // Try and access Volume 0 (i.e. the first partition).
76 // The volume object holds information about the filesystem on that volume.
77 let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap();
78 info!("Volume 0: {:?}", defmt::Debug2Format(&volume0));
79
80 // Open the root directory (mutably borrows from the volume).
81 let mut root_dir = volume0.open_root_dir().unwrap();
82
83 // Open a file called "MY_FILE.TXT" in the root directory
84 // This mutably borrows the directory.
85 let mut my_file = root_dir
86 .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
87 .unwrap();
88
89 // Print the contents of the file
90 while !my_file.is_eof() {
91 let mut buf = [0u8; 32];
92 if let Ok(n) = my_file.read(&mut buf) {
93 info!("{:a}", buf[..n]);
94 }
95 }
96
97 loop {}
98}
diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs
new file mode 100644
index 000000000..e146baa2e
--- /dev/null
+++ b/examples/rp23/src/bin/trng.rs
@@ -0,0 +1,64 @@
1//! This example shows TRNG usage
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::TRNG;
12use embassy_rp::trng::Trng;
13use embassy_time::Timer;
14use rand::RngCore;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31bind_interrupts!(struct Irqs {
32 TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>;
33});
34
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let peripherals = embassy_rp::init(Default::default());
38
39 // Initialize the TRNG with default configuration
40 let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default());
41 // A buffer to collect random bytes in.
42 let mut randomness = [0u8; 58];
43
44 let mut led = Output::new(peripherals.PIN_25, Level::Low);
45
46 loop {
47 trng.fill_bytes(&mut randomness).await;
48 info!("Random bytes async {}", &randomness);
49 trng.blocking_fill_bytes(&mut randomness);
50 info!("Random bytes blocking {}", &randomness);
51 let random_u32 = trng.next_u32();
52 let random_u64 = trng.next_u64();
53 info!("Random u32 {} u64 {}", random_u32, random_u64);
54 // Random number of blinks between 0 and 31
55 let blinks = random_u32 % 32;
56 for _ in 0..blinks {
57 led.set_high();
58 Timer::after_millis(20).await;
59 led.set_low();
60 Timer::after_millis(20).await;
61 }
62 Timer::after_millis(1000).await;
63 }
64}
diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs
new file mode 100644
index 000000000..0ffe0b293
--- /dev/null
+++ b/examples/rp23/src/bin/uart.rs
@@ -0,0 +1,40 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. Only output on pin 0 is tested.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
7#![no_std]
8#![no_main]
9
10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::uart;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32 let config = uart::Config::default();
33 let mut uart = uart::Uart::new_blocking(p.UART1, p.PIN_4, p.PIN_5, config);
34 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap();
35
36 loop {
37 uart.blocking_write("hello there!\r\n".as_bytes()).unwrap();
38 cortex_m::asm::delay(1_000_000);
39 }
40}
diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs
new file mode 100644
index 000000000..4e69a20c4
--- /dev/null
+++ b/examples/rp23/src/bin/uart_buffered_split.rs
@@ -0,0 +1,73 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
7#![no_std]
8#![no_main]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::Timer;
17use embedded_io_async::{Read, Write};
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21#[link_section = ".start_block"]
22#[used]
23pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
24
25// Program metadata for `picotool info`
26#[link_section = ".bi_entries"]
27#[used]
28pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
29 embassy_rp::binary_info::rp_program_name!(c"example"),
30 embassy_rp::binary_info::rp_cargo_version!(),
31 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
32 embassy_rp::binary_info::rp_program_build_attribute!(),
33];
34
35bind_interrupts!(struct Irqs {
36 UART0_IRQ => BufferedInterruptHandler<UART0>;
37});
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
43
44 static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
45 let tx_buf = &mut TX_BUF.init([0; 16])[..];
46 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
47 let rx_buf = &mut RX_BUF.init([0; 16])[..];
48 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
49 let (mut tx, rx) = uart.split();
50
51 unwrap!(spawner.spawn(reader(rx)));
52
53 info!("Writing...");
54 loop {
55 let data = [
56 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
57 29, 30, 31,
58 ];
59 info!("TX {:?}", data);
60 tx.write_all(&data).await.unwrap();
61 Timer::after_secs(1).await;
62 }
63}
64
65#[embassy_executor::task]
66async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
67 info!("Reading...");
68 loop {
69 let mut buf = [0; 31];
70 rx.read_exact(&mut buf).await.unwrap();
71 info!("RX {:?}", buf);
72 }
73}
diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs
new file mode 100644
index 000000000..5ac8839e3
--- /dev/null
+++ b/examples/rp23/src/bin/uart_r503.rs
@@ -0,0 +1,173 @@
1#![no_std]
2#![no_main]
3
4use defmt::{debug, error, info};
5use embassy_executor::Spawner;
6use embassy_rp::bind_interrupts;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::UART0;
9use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart};
10use embassy_time::{with_timeout, Duration, Timer};
11use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28bind_interrupts!(pub struct Irqs {
29 UART0_IRQ => UARTInterruptHandler<UART0>;
30});
31
32const START: u16 = 0xEF01;
33const ADDRESS: u32 = 0xFFFFFFFF;
34
35// ================================================================================
36
37// Data package format
38// Name Length Description
39// ==========================================================================================================
40// Start 2 bytes Fixed value of 0xEF01; High byte transferred first.
41// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command.
42// High byte transferred first and at wrong adder value, module
43// will reject to transfer.
44// PID 1 byte 01H Command packet;
45// 02H Data packet; Data packet shall not appear alone in executing
46// processs, must follow command packet or acknowledge packet.
47// 07H Acknowledge packet;
48// 08H End of Data packet.
49// LENGTH 2 bytes Refers to the length of package content (command packets and data packets)
50// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes.
51// And high byte is transferred first.
52// DATA - It can be commands, data, command’s parameters, acknowledge result, etc.
53// (fingerprint character value, template are all deemed as data);
54// SUM 2 bytes The arithmetic sum of package identifier, package length and all package
55// contens. Overflowing bits are omitted. high byte is transferred first.
56
57// ================================================================================
58
59// Checksum is calculated on 'length (2 bytes) + data (??)'.
60fn compute_checksum(buf: Vec<u8, 32>) -> u16 {
61 let mut checksum = 0u16;
62
63 let check_end = buf.len();
64 let checked_bytes = &buf[6..check_end];
65 for byte in checked_bytes {
66 checksum += (*byte) as u16;
67 }
68 return checksum;
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 info!("Start");
74
75 let p = embassy_rp::init(Default::default());
76
77 // Initialize the fingerprint scanner.
78 let mut config = Config::default();
79 config.baudrate = 57600;
80 config.stop_bits = StopBits::STOP1;
81 config.data_bits = DataBits::DataBits8;
82 config.parity = Parity::ParityNone;
83
84 let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1);
85 let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config);
86 let (mut tx, mut rx) = uart.split();
87
88 let mut vec_buf: Vec<u8, 32> = heapless::Vec::new();
89 let mut data: Vec<u8, 32> = heapless::Vec::new();
90
91 let mut speeds: Vec<u8, 3> = heapless::Vec::new();
92 let _ = speeds.push(0xC8); // Slow
93 let _ = speeds.push(0x20); // Medium
94 let _ = speeds.push(0x02); // Fast
95
96 // Cycle through the three colours Red, Blue and Purple forever.
97 loop {
98 for colour in 1..=3 {
99 for speed in &speeds {
100 // Set the data first, because the length is dependent on that.
101 // However, we write the length bits before we do the data.
102 data.clear();
103 let _ = data.push(0x01); // ctrl=Breathing light
104 let _ = data.push(*speed);
105 let _ = data.push(colour as u8); // colour=Red, Blue, Purple
106 let _ = data.push(0x00); // times=Infinite
107
108 // Clear buffers
109 vec_buf.clear();
110
111 // START
112 let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]);
113
114 // ADDRESS
115 let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]);
116
117 // PID
118 let _ = vec_buf.extend_from_slice(&[0x01]);
119
120 // LENGTH
121 let len: u16 = (1 + data.len() + 2).try_into().unwrap();
122 let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]);
123
124 // COMMAND
125 let _ = vec_buf.push(0x35); // Command: AuraLedConfig
126
127 // DATA
128 let _ = vec_buf.extend_from_slice(&data);
129
130 // SUM
131 let chk = compute_checksum(vec_buf.clone());
132 let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]);
133
134 // =====
135
136 // Send command buffer.
137 let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap();
138 debug!(" write='{:?}'", data_write[..]);
139 match tx.write(&data_write).await {
140 Ok(..) => info!("Write successful."),
141 Err(e) => error!("Write error: {:?}", e),
142 }
143
144 // =====
145
146 // Read command buffer.
147 let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time!
148 let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer.
149
150 info!("Attempting read.");
151 loop {
152 // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms
153 // for this command.
154 match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await {
155 Ok(..) => {
156 // Extract and save read byte.
157 debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]);
158 let _ = data_read.push(read_buf[0]).unwrap();
159 }
160 Err(..) => break, // TimeoutError -> Ignore.
161 }
162 }
163 info!("Read successful");
164 debug!(" read='{:?}'", data_read[..]);
165
166 Timer::after_secs(3).await;
167 info!("Changing speed.");
168 }
169
170 info!("Changing colour.");
171 }
172 }
173}
diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs
new file mode 100644
index 000000000..988e44a79
--- /dev/null
+++ b/examples/rp23/src/bin/uart_unidir.rs
@@ -0,0 +1,65 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for
4//! this to work
5//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
6//! with its UART port.
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_rp::bind_interrupts;
14use embassy_rp::block::ImageDef;
15use embassy_rp::peripherals::UART1;
16use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
17use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34bind_interrupts!(struct Irqs {
35 UART1_IRQ => InterruptHandler<UART1>;
36});
37
38#[embassy_executor::main]
39async fn main(spawner: Spawner) {
40 let p = embassy_rp::init(Default::default());
41
42 let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
43 let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
44
45 unwrap!(spawner.spawn(reader(uart_rx)));
46
47 info!("Writing...");
48 loop {
49 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
50 info!("TX {:?}", data);
51 uart_tx.write(&data).await.unwrap();
52 Timer::after_secs(1).await;
53 }
54}
55
56#[embassy_executor::task]
57async fn reader(mut rx: UartRx<'static, UART1, Async>) {
58 info!("Reading...");
59 loop {
60 // read a total of 4 transmissions (32 / 8) and then print the result
61 let mut buf = [0; 32];
62 rx.read(&mut buf).await.unwrap();
63 info!("RX {:?}", buf);
64 }
65}
diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs
new file mode 100644
index 000000000..3ade2226b
--- /dev/null
+++ b/examples/rp23/src/bin/usb_webusb.rs
@@ -0,0 +1,170 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a WebUSB capable device that echoes data back to the host.
4//!
5//! To test this in the browser (ideally host this on localhost:8080, to test the landing page
6//! feature):
7//! ```js
8//! (async () => {
9//! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] });
10//! await device.open();
11//! await device.claimInterface(1);
12//! device.transferIn(1, 64).then(data => console.log(data));
13//! await device.transferOut(1, new Uint8Array([1,2,3]));
14//! })();
15//! ```
16
17#![no_std]
18#![no_main]
19
20use defmt::info;
21use embassy_executor::Spawner;
22use embassy_futures::join::join;
23use embassy_rp::bind_interrupts;
24use embassy_rp::block::ImageDef;
25use embassy_rp::peripherals::USB;
26use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
27use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb};
28use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut};
29use embassy_usb::msos::{self, windows_version};
30use embassy_usb::{Builder, Config};
31use {defmt_rtt as _, panic_probe as _};
32
33#[link_section = ".start_block"]
34#[used]
35pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
36
37// Program metadata for `picotool info`
38#[link_section = ".bi_entries"]
39#[used]
40pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
41 embassy_rp::binary_info::rp_program_name!(c"example"),
42 embassy_rp::binary_info::rp_cargo_version!(),
43 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
44 embassy_rp::binary_info::rp_program_build_attribute!(),
45];
46
47bind_interrupts!(struct Irqs {
48 USBCTRL_IRQ => InterruptHandler<USB>;
49});
50
51// This is a randomly generated GUID to allow clients on Windows to find our device
52const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];
53
54#[embassy_executor::main]
55async fn main(_spawner: Spawner) {
56 let p = embassy_rp::init(Default::default());
57
58 // Create the driver, from the HAL.
59 let driver = UsbDriver::new(p.USB, Irqs);
60
61 // Create embassy-usb Config
62 let mut config = Config::new(0xf569, 0x0001);
63 config.manufacturer = Some("Embassy");
64 config.product = Some("WebUSB example");
65 config.serial_number = Some("12345678");
66 config.max_power = 100;
67 config.max_packet_size_0 = 64;
68
69 // Required for windows compatibility.
70 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
71 config.device_class = 0xff;
72 config.device_sub_class = 0x00;
73 config.device_protocol = 0x00;
74
75 // Create embassy-usb DeviceBuilder using the driver and config.
76 // It needs some buffers for building the descriptors.
77 let mut config_descriptor = [0; 256];
78 let mut bos_descriptor = [0; 256];
79 let mut control_buf = [0; 64];
80 let mut msos_descriptor = [0; 256];
81
82 let webusb_config = WebUsbConfig {
83 max_packet_size: 64,
84 vendor_code: 1,
85 // If defined, shows a landing page which the device manufacturer would like the user to visit in order to control their device. Suggest the user to navigate to this URL when the device is connected.
86 landing_url: Some(Url::new("http://localhost:8080")),
87 };
88
89 let mut state = State::new();
90
91 let mut builder = Builder::new(
92 driver,
93 config,
94 &mut config_descriptor,
95 &mut bos_descriptor,
96 &mut msos_descriptor,
97 &mut control_buf,
98 );
99
100 // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor.
101 // We tell Windows that this entire device is compatible with the "WINUSB" feature,
102 // which causes it to use the built-in WinUSB driver automatically, which in turn
103 // can be used by libusb/rusb software without needing a custom driver or INF file.
104 // In principle you might want to call msos_feature() just on a specific function,
105 // if your device also has other functions that still use standard class drivers.
106 builder.msos_descriptor(windows_version::WIN8_1, 0);
107 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
108 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
109 "DeviceInterfaceGUIDs",
110 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
111 ));
112
113 // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything)
114 WebUsb::configure(&mut builder, &mut state, &webusb_config);
115 // Create some USB bulk endpoints for testing.
116 let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config);
117
118 // Build the builder.
119 let mut usb = builder.build();
120
121 // Run the USB device.
122 let usb_fut = usb.run();
123
124 // Do some WebUSB transfers.
125 let webusb_fut = async {
126 loop {
127 endpoints.wait_connected().await;
128 info!("Connected");
129 endpoints.echo().await;
130 }
131 };
132
133 // Run everything concurrently.
134 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
135 join(usb_fut, webusb_fut).await;
136}
137
138struct WebEndpoints<'d, D: Driver<'d>> {
139 write_ep: D::EndpointIn,
140 read_ep: D::EndpointOut,
141}
142
143impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
144 fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self {
145 let mut func = builder.function(0xff, 0x00, 0x00);
146 let mut iface = func.interface();
147 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
148
149 let write_ep = alt.endpoint_bulk_in(config.max_packet_size);
150 let read_ep = alt.endpoint_bulk_out(config.max_packet_size);
151
152 WebEndpoints { write_ep, read_ep }
153 }
154
155 // Wait until the device's endpoints are enabled.
156 async fn wait_connected(&mut self) {
157 self.read_ep.wait_enabled().await
158 }
159
160 // Echo data back to the host.
161 async fn echo(&mut self) {
162 let mut buf = [0; 64];
163 loop {
164 let n = self.read_ep.read(&mut buf).await.unwrap();
165 let data = &buf[..n];
166 info!("Data read: {:x}", data);
167 self.write_ep.write(data).await.unwrap();
168 }
169 }
170}
diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs
new file mode 100644
index 000000000..a901c1164
--- /dev/null
+++ b/examples/rp23/src/bin/watchdog.rs
@@ -0,0 +1,66 @@
1//! This example shows how to use Watchdog in the RP2040 chip.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor.
4
5#![no_std]
6#![no_main]
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_rp::watchdog::*;
13use embassy_time::{Duration, Timer};
14use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 info!("Hello world!");
35
36 let mut watchdog = Watchdog::new(p.WATCHDOG);
37 let mut led = Output::new(p.PIN_25, Level::Low);
38
39 // Set the LED high for 2 seconds so we know when we're about to start the watchdog
40 led.set_high();
41 Timer::after_secs(2).await;
42
43 // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it
44 watchdog.start(Duration::from_millis(1_050));
45 info!("Started the watchdog timer");
46
47 // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset
48 for _ in 1..=5 {
49 led.set_low();
50 Timer::after_millis(500).await;
51 led.set_high();
52 Timer::after_millis(500).await;
53 info!("Feeding watchdog");
54 watchdog.feed();
55 }
56
57 info!("Stopped feeding, device will reset in 1.05 seconds");
58 // Blink 10 times per second, not feeding the watchdog.
59 // The processor should reset in 1.05 seconds.
60 loop {
61 led.set_low();
62 Timer::after_millis(100).await;
63 led.set_high();
64 Timer::after_millis(100).await;
65 }
66}
diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs
new file mode 100644
index 000000000..86fca6f12
--- /dev/null
+++ b/examples/rp23/src/bin/zerocopy.rs
@@ -0,0 +1,109 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA.
4#![no_std]
5#![no_main]
6
7use core::sync::atomic::{AtomicU16, Ordering};
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::gpio::Pull;
15use embassy_rp::peripherals::DMA_CH0;
16use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
18use embassy_time::{Duration, Ticker, Timer};
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36type SampleBuffer = [u16; 512];
37
38bind_interrupts!(struct Irqs {
39 ADC_IRQ_FIFO => InterruptHandler;
40});
41
42const BLOCK_SIZE: usize = 512;
43const NUM_BLOCKS: usize = 2;
44static MAX: AtomicU16 = AtomicU16::new(0);
45
46struct AdcParts {
47 adc: Adc<'static, Async>,
48 pin: adc::Channel<'static>,
49 dma: DMA_CH0,
50}
51
52#[embassy_executor::main]
53async fn main(spawner: Spawner) {
54 let p = embassy_rp::init(Default::default());
55 info!("Here we go!");
56
57 let adc_parts = AdcParts {
58 adc: Adc::new(p.ADC, Irqs, Config::default()),
59 pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
60 dma: p.DMA_CH0,
61 };
62
63 static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
64 let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
65
66 static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
67 let channel = CHANNEL.init(Channel::new(buf));
68 let (sender, receiver) = channel.split();
69
70 spawner.must_spawn(consumer(receiver));
71 spawner.must_spawn(producer(sender, adc_parts));
72
73 let mut ticker = Ticker::every(Duration::from_secs(1));
74 loop {
75 ticker.next().await;
76 let max = MAX.load(Ordering::Relaxed);
77 info!("latest block's max value: {:?}", max);
78 }
79}
80
81#[embassy_executor::task]
82async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
83 loop {
84 // Obtain a free buffer from the channel
85 let buf = sender.send().await;
86
87 // Fill it with data
88 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
89
90 // Notify the channel that the buffer is now ready to be received
91 sender.send_done();
92 }
93}
94
95#[embassy_executor::task]
96async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
97 loop {
98 // Receive a buffer from the channel
99 let buf = receiver.receive().await;
100
101 // Simulate using the data, while the producer is filling up the next buffer
102 Timer::after_micros(1000).await;
103 let max = buf.iter().max().unwrap();
104 MAX.store(*max, Ordering::Relaxed);
105
106 // Notify the channel that the buffer is now ready to be reused
107 receiver.receive_done();
108 }
109}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index f05565e84..87491b1d2 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "std", ] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] }
11embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } 11embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
13embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} 13embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]}
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index dad93d0a1..cefa5448c 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,9 +1,7 @@
1use std::default::Default;
2
3use clap::Parser; 1use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
5use embassy_net::tcp::TcpSocket; 3use embassy_net::tcp::TcpSocket;
6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
7use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
8use embassy_time::Duration; 6use embassy_time::Duration;
9use embedded_io_async::Write; 7use embedded_io_async::Write;
@@ -24,8 +22,8 @@ struct Opts {
24} 22}
25 23
26#[embassy_executor::task] 24#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 25async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
28 stack.run().await 26 runner.run().await
29} 27}
30 28
31#[embassy_executor::task] 29#[embassy_executor::task]
@@ -52,17 +50,11 @@ async fn main_task(spawner: Spawner) {
52 let seed = u64::from_le_bytes(seed); 50 let seed = u64::from_le_bytes(seed);
53 51
54 // Init network stack 52 // Init network stack
55 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
56 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
57 let stack = &*STACK.init(Stack::new( 54 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
58 device,
59 config,
60 RESOURCES.init(StackResources::<3>::new()),
61 seed,
62 ));
63 55
64 // Launch network task 56 // Launch network task
65 spawner.spawn(net_task(stack)).unwrap(); 57 spawner.spawn(net_task(runner)).unwrap();
66 58
67 // Then we can use it! 59 // Then we can use it!
68 let mut rx_buffer = [0; 4096]; 60 let mut rx_buffer = [0; 4096];
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index fca1e076e..a42c5dbb7 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -1,9 +1,7 @@
1use std::default::Default;
2
3use clap::Parser; 1use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
5use embassy_net::dns::DnsQueryType; 3use embassy_net::dns::DnsQueryType;
6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
7use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
8use heapless::Vec; 6use heapless::Vec;
9use log::*; 7use log::*;
@@ -22,8 +20,8 @@ struct Opts {
22} 20}
23 21
24#[embassy_executor::task] 22#[embassy_executor::task]
25async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 23async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
26 stack.run().await 24 runner.run().await
27} 25}
28 26
29#[embassy_executor::task] 27#[embassy_executor::task]
@@ -51,17 +49,11 @@ async fn main_task(spawner: Spawner) {
51 let seed = u64::from_le_bytes(seed); 49 let seed = u64::from_le_bytes(seed);
52 50
53 // Init network stack 51 // Init network stack
54 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
55 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
56 let stack: &Stack<_> = &*STACK.init(Stack::new( 53 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
57 device,
58 config,
59 RESOURCES.init(StackResources::<3>::new()),
60 seed,
61 ));
62 54
63 // Launch network task 55 // Launch network task
64 spawner.spawn(net_task(stack)).unwrap(); 56 spawner.spawn(net_task(runner)).unwrap();
65 57
66 let host = "example.com"; 58 let host = "example.com";
67 info!("querying host {:?}...", host); 59 info!("querying host {:?}...", host);
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
index 9ec0ea91f..7d0f1327f 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -37,16 +37,12 @@ struct Opts {
37} 37}
38 38
39#[embassy_executor::task] 39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Device<'static>>) -> ! {
41 stack.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::task] 44#[embassy_executor::task]
45async fn ppp_task( 45async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! {
46 stack: &'static Stack<embassy_net_ppp::Device<'static>>,
47 mut runner: Runner<'static>,
48 port: SerialPort,
49) -> ! {
50 let port = Async::new(port).unwrap(); 46 let port = Async::new(port).unwrap();
51 let port = BufReader::new(port); 47 let port = BufReader::new(port);
52 let port = adapter::FromFutures::new(port); 48 let port = adapter::FromFutures::new(port);
@@ -97,17 +93,16 @@ async fn main_task(spawner: Spawner) {
97 let seed = u64::from_le_bytes(seed); 93 let seed = u64::from_le_bytes(seed);
98 94
99 // Init network stack 95 // Init network stack
100 static STACK: StaticCell<Stack<embassy_net_ppp::Device<'static>>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new( 97 let (stack, net_runner) = embassy_net::new(
103 device, 98 device,
104 Config::default(), // don't configure IP yet 99 Config::default(), // don't configure IP yet
105 RESOURCES.init(StackResources::<3>::new()), 100 RESOURCES.init(StackResources::new()),
106 seed, 101 seed,
107 )); 102 );
108 103
109 // Launch network task 104 // Launch network task
110 spawner.spawn(net_task(stack)).unwrap(); 105 spawner.spawn(net_task(net_runner)).unwrap();
111 spawner.spawn(ppp_task(stack, runner, port)).unwrap(); 106 spawner.spawn(ppp_task(stack, runner, port)).unwrap();
112 107
113 // Then we can use it! 108 // Then we can use it!
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index bee91990d..02d4d3efb 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -1,7 +1,7 @@
1use clap::Parser; 1use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
3use embassy_net::udp::{PacketMetadata, UdpSocket}; 3use embassy_net::udp::{PacketMetadata, UdpSocket};
4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
5use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
6use heapless::Vec; 6use heapless::Vec;
7use log::*; 7use log::*;
@@ -20,8 +20,8 @@ struct Opts {
20} 20}
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 23async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
24 stack.run().await 24 runner.run().await
25} 25}
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
@@ -48,17 +48,11 @@ async fn main_task(spawner: Spawner) {
48 let seed = u64::from_le_bytes(seed); 48 let seed = u64::from_le_bytes(seed);
49 49
50 // Init network stack 50 // Init network stack
51 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 51 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
53 let stack = &*STACK.init(Stack::new( 52 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
54 device,
55 config,
56 RESOURCES.init(StackResources::<3>::new()),
57 seed,
58 ));
59 53
60 // Launch network task 54 // Launch network task
61 spawner.spawn(net_task(stack)).unwrap(); 55 spawner.spawn(net_task(runner)).unwrap();
62 56
63 // Then we can use it! 57 // Then we can use it!
64 let mut rx_meta = [PacketMetadata::EMPTY; 16]; 58 let mut rx_meta = [PacketMetadata::EMPTY; 16];
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index 00ccd83a7..5d36b739d 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -1,10 +1,9 @@
1use core::fmt::Write as _; 1use core::fmt::Write as _;
2use std::default::Default;
3 2
4use clap::Parser; 3use clap::Parser;
5use embassy_executor::{Executor, Spawner}; 4use embassy_executor::{Executor, Spawner};
6use embassy_net::tcp::TcpSocket; 5use embassy_net::tcp::TcpSocket;
7use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
8use embassy_net_tuntap::TunTapDevice; 7use embassy_net_tuntap::TunTapDevice;
9use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
10use embedded_io_async::Write as _; 9use embedded_io_async::Write as _;
@@ -25,8 +24,8 @@ struct Opts {
25} 24}
26 25
27#[embassy_executor::task] 26#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
29 stack.run().await 28 runner.run().await
30} 29}
31 30
32#[derive(Default)] 31#[derive(Default)]
@@ -63,17 +62,11 @@ async fn main_task(spawner: Spawner) {
63 let seed = u64::from_le_bytes(seed); 62 let seed = u64::from_le_bytes(seed);
64 63
65 // Init network stack 64 // Init network stack
66 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
67 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 65 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
68 let stack = &*STACK.init(Stack::new( 66 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
69 device,
70 config,
71 RESOURCES.init(StackResources::<3>::new()),
72 seed,
73 ));
74 67
75 // Launch network task 68 // Launch network task
76 spawner.spawn(net_task(stack)).unwrap(); 69 spawner.spawn(net_task(runner)).unwrap();
77 70
78 // Then we can use it! 71 // Then we can use it!
79 let mut rx_buffer = [0; 4096]; 72 let mut rx_buffer = [0; 4096];
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 7a3e03b75..9102467eb 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32c031c6 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
@@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
23 22
24[profile.release] 23[profile.release]
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index c74980dc4..724efdaff 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -4,8 +4,6 @@ version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
9[dependencies] 7[dependencies]
10# Change stm32f091rc to your chip name, if necessary. 8# Change stm32f091rc to your chip name, if necessary.
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
@@ -14,9 +12,9 @@ cortex-m-rt = "0.7.0"
14defmt = "0.3" 12defmt = "0.3"
15defmt-rtt = "0.4" 13defmt-rtt = "0.4"
16panic-probe = { version = "0.3", features = ["print-defmt"] } 14panic-probe = { version = "0.3", features = ["print-defmt"] }
17embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
18embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
19embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
20static_cell = "2" 18static_cell = "2"
21portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
22 20
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index 8fef062b3..8825e2687 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -4,13 +4,13 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
13 ADC1_COMP => adc::InterruptHandler<ADC>; 13 ADC1_COMP => adc::InterruptHandler<ADC1>;
14}); 14});
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); 21 let mut adc = Adc::new(p.ADC1, Irqs);
22 adc.set_sample_time(SampleTime::Cycles71_5); 22 adc.set_sample_time(SampleTime::CYCLES71_5);
23 let mut pin = p.PA1; 23 let mut pin = p.PA1;
24 24
25 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref();
26 let vrefint_sample = adc.read(&mut vrefint).await; 26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| { 27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf 28 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index e49951726..84e4077ef 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -80,7 +80,7 @@ async fn run_med() {
80 info!(" [med] Starting long computation"); 80 info!(" [med] Starting long computation");
81 81
82 // Spin-wait to simulate a long CPU computation 82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(8_000_000); // ~1 second 83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84 84
85 let end = Instant::now(); 85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33; 86 let ms = end.duration_since(start).as_ticks() / 33;
@@ -97,7 +97,7 @@ async fn run_low() {
97 info!("[low] Starting long computation"); 97 info!("[low] Starting long computation");
98 98
99 // Spin-wait to simulate a long CPU computation 99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(16_000_000); // ~2 seconds 100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101 101
102 let end = Instant::now(); 102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33; 103 let ms = end.duration_since(start).as_ticks() / 33;
@@ -126,6 +126,11 @@ fn main() -> ! {
126 // Initialize and create handle for devicer peripherals 126 // Initialize and create handle for devicer peripherals
127 let _p = embassy_stm32::init(Default::default()); 127 let _p = embassy_stm32::init(Default::default());
128 128
129 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
130 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
131 // In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt
132 // vector would work exactly the same.
133
129 // High-priority executor: USART1, priority level 6 134 // High-priority executor: USART1, priority level 6
130 interrupt::USART1.set_priority(Priority::P6); 135 interrupt::USART1.set_priority(Priority::P6);
131 let spawner = EXECUTOR_HIGH.start(interrupt::USART1); 136 let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index df5d32f70..0084651a3 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f103c8 to your chip name, if necessary. 8# Change stm32f103c8 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
10embassy-sync = { version = "0.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
@@ -20,9 +20,9 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
25nb = "1.0.0" 24nb = "1.0.0"
25static_cell = "2.0.0"
26 26
27[profile.dev] 27[profile.dev]
28opt-level = "s" 28opt-level = "s"
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 1440460a9..541ff159e 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
6use embassy_stm32::adc::Adc; 6use embassy_stm32::adc::Adc;
7use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 21 let mut adc = Adc::new(p.ADC1);
22 let mut pin = p.PB1; 22 let mut pin = p.PB1;
23 23
24 let mut vrefint = adc.enable_vref(&mut Delay); 24 let mut vrefint = adc.enable_vref();
25 let vrefint_sample = adc.read(&mut vrefint).await; 25 let vrefint_sample = adc.read(&mut vrefint).await;
26 let convert_to_millivolts = |sample| { 26 let convert_to_millivolts = |sample| {
27 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf 27 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
index c1c4f8359..ad0c8a5a5 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -3,11 +3,14 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::can::bxcan::filter::Mask32; 6use embassy_stm32::can::frame::Envelope;
7use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; 7use embassy_stm32::can::{
8use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; 8 filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
9 TxInterruptHandler,
10};
9use embassy_stm32::peripherals::CAN; 11use embassy_stm32::peripherals::CAN;
10use embassy_stm32::{bind_interrupts, Config}; 12use embassy_stm32::{bind_interrupts, Config};
13use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
12 15
13bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
@@ -20,6 +23,27 @@ bind_interrupts!(struct Irqs {
20// This example is configured to work with real CAN transceivers on B8/B9. 23// This example is configured to work with real CAN transceivers on B8/B9.
21// See other examples for loopback. 24// See other examples for loopback.
22 25
26fn handle_frame(env: Envelope, read_mode: &str) {
27 match env.frame.id() {
28 Id::Extended(id) => {
29 defmt::println!(
30 "{} Extended Frame id={:x} {:02x}",
31 read_mode,
32 id.as_raw(),
33 env.frame.data()
34 );
35 }
36 Id::Standard(id) => {
37 defmt::println!(
38 "{} Standard Frame id={:x} {:02x}",
39 read_mode,
40 id.as_raw(),
41 env.frame.data()
42 );
43 }
44 }
45}
46
23#[embassy_executor::main] 47#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 48async fn main(_spawner: Spawner) {
25 let p = embassy_stm32::init(Config::default()); 49 let p = embassy_stm32::init(Config::default());
@@ -27,40 +51,90 @@ async fn main(_spawner: Spawner) {
27 // Set alternate pin mapping to B8/B9 51 // Set alternate pin mapping to B8/B9
28 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); 52 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
29 53
54 static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new();
55 static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new();
56
30 let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); 57 let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
31 58
32 can.as_mut() 59 can.modify_filters()
33 .modify_filters() 60 .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all());
34 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
35 61
36 can.as_mut() 62 can.modify_config()
37 .modify_config()
38 .set_loopback(false) 63 .set_loopback(false)
39 .set_silent(false) 64 .set_silent(false)
40 .leave_disabled(); 65 .set_bitrate(250_000);
41
42 can.set_bitrate(250_000);
43 66
44 can.enable().await; 67 can.enable().await;
45
46 let mut i: u8 = 0; 68 let mut i: u8 = 0;
47 loop { 69
48 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 70 /*
49 can.write(&tx_frame).await; 71 // Example for using buffered Tx and Rx without needing to
50 72 // split first as is done below.
51 match can.read().await { 73 let mut can = can.buffered(
52 Ok(env) => match env.frame.id() { 74 TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()),
53 Id::Extended(id) => { 75 RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
54 defmt::println!("Extended Frame id={:x}", id.as_raw()); 76 loop {
55 } 77 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
56 Id::Standard(id) => { 78 can.write(&tx_frame).await;
57 defmt::println!("Standard Frame id={:x}", id.as_raw()); 79
58 } 80 match can.read().await {
59 }, 81 Ok((frame, ts)) => {
82 handle_frame(Envelope { ts, frame }, "Buf");
83 }
84 Err(err) => {
85 defmt::println!("Error {}", err);
86 }
87 }
88 i = i.wrapping_add(1);
89 }
90
91 */
92 let (mut tx, mut rx) = can.split();
93
94 // This example shows using the wait_not_empty API before try read
95 while i < 3 {
96 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
97 tx.write(&tx_frame).await;
98
99 rx.wait_not_empty().await;
100 let env = rx.try_read().unwrap();
101 handle_frame(env, "Wait");
102 i += 1;
103 }
104
105 // This example shows using the full async non-buffered API
106 while i < 6 {
107 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
108 tx.write(&tx_frame).await;
109
110 match rx.read().await {
111 Ok(env) => {
112 handle_frame(env, "NoBuf");
113 }
60 Err(err) => { 114 Err(err) => {
61 defmt::println!("Error {}", err); 115 defmt::println!("Error {}", err);
62 } 116 }
63 } 117 }
64 i += 1; 118 i += 1;
65 } 119 }
120
121 // This example shows using buffered RX and TX. User passes in desired buffer (size)
122 // It's possible this way to have just RX or TX buffered.
123 let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
124 let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()));
125
126 loop {
127 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
128 tx.write(&tx_frame).await;
129
130 match rx.read().await {
131 Ok(envelope) => {
132 handle_frame(envelope, "Buf");
133 }
134 Err(err) => {
135 defmt::println!("Error {}", err);
136 }
137 }
138 i = i.wrapping_add(1);
139 }
66} 140}
diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs
index 7b761ecc1..3c295612c 100644
--- a/examples/stm32f1/src/bin/hello.rs
+++ b/examples/stm32f1/src/bin/hello.rs
@@ -3,15 +3,13 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! { 11async fn main(_spawner: Spawner) -> ! {
13 let mut config = Config::default(); 12 let config = Config::default();
14 config.rcc.sys_ck = Some(Hertz(36_000_000));
15 let _p = embassy_stm32::init(config); 13 let _p = embassy_stm32::init(config);
16 14
17 loop { 15 loop {
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs
new file mode 100644
index 000000000..5e2dab9e6
--- /dev/null
+++ b/examples/stm32f1/src/bin/input_capture.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14/// Connect PA2 and PC13 with a 1k Ohm resistor
15
16#[embassy_executor::task]
17async fn blinky(led: peripherals::PC13) {
18 let mut led = Output::new(led, Level::High, Speed::Low);
19
20 loop {
21 info!("high");
22 led.set_high();
23 Timer::after_millis(300).await;
24
25 info!("low");
26 led.set_low();
27 Timer::after_millis(300).await;
28 }
29}
30
31bind_interrupts!(struct Irqs {
32 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
33});
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_stm32::init(Default::default());
38 info!("Hello World!");
39
40 unwrap!(spawner.spawn(blinky(p.PC13)));
41
42 let ch3 = CapturePin::new_ch3(p.PA2, Pull::None);
43 let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
44
45 loop {
46 info!("wait for rising edge");
47 ic.wait_for_rising_edge(Channel::Ch3).await;
48
49 let capture_value = ic.get_capture_value(Channel::Ch3);
50 info!("new capture! {}", capture_value);
51 }
52}
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs
new file mode 100644
index 000000000..f74853d4e
--- /dev/null
+++ b/examples/stm32f1/src/bin/pwm_input.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13/// Connect PA0 and PC13 with a 1k Ohm resistor
14
15#[embassy_executor::task]
16async fn blinky(led: peripherals::PC13) {
17 let mut led = Output::new(led, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after_millis(300).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after_millis(300).await;
27 }
28}
29
30bind_interrupts!(struct Irqs {
31 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
32});
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 let p = embassy_stm32::init(Default::default());
37 info!("Hello World!");
38
39 unwrap!(spawner.spawn(blinky(p.PC13)));
40
41 let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(10));
42 pwm_input.enable();
43
44 loop {
45 Timer::after_millis(500).await;
46 let period = pwm_input.get_period_ticks();
47 let width = pwm_input.get_width_ticks();
48 let duty_cycle = pwm_input.get_duty_cycle();
49 info!(
50 "period ticks: {} width ticks: {} duty cycle: {}",
51 period, width, duty_cycle
52 );
53 }
54}
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index e28381893..ee99acf41 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -21,9 +21,23 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 config.rcc.hse = Some(Hertz(8_000_000)); 24 {
25 config.rcc.sys_ck = Some(Hertz(48_000_000)); 25 use embassy_stm32::rcc::*;
26 config.rcc.pclk1 = Some(Hertz(24_000_000)); 26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 // Oscillator for bluepill, Bypass for nucleos.
29 mode: HseMode::Oscillator,
30 });
31 config.rcc.pll = Some(Pll {
32 src: PllSource::HSE,
33 prediv: PllPreDiv::DIV1,
34 mul: PllMul::MUL9,
35 });
36 config.rcc.sys = Sysclk::PLL1_P;
37 config.rcc.ahb_pre = AHBPrescaler::DIV1;
38 config.rcc.apb1_pre = APBPrescaler::DIV2;
39 config.rcc.apb2_pre = APBPrescaler::DIV1;
40 }
27 let mut p = embassy_stm32::init(config); 41 let mut p = embassy_stm32::init(config);
28 42
29 info!("Hello World!"); 43 info!("Hello World!");
@@ -46,7 +60,6 @@ async fn main(_spawner: Spawner) {
46 60
47 // Create embassy-usb DeviceBuilder using the driver and config. 61 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 62 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 7]; 65 let mut control_buf = [0; 7];
@@ -56,7 +69,6 @@ async fn main(_spawner: Spawner) {
56 let mut builder = Builder::new( 69 let mut builder = Builder::new(
57 driver, 70 driver,
58 config, 71 config,
59 &mut device_descriptor,
60 &mut config_descriptor, 72 &mut config_descriptor,
61 &mut bos_descriptor, 73 &mut bos_descriptor,
62 &mut [], // no msos descriptors 74 &mut [], // no msos descriptors
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 4cbf1dc84..60eb0eb93 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f207zg to your chip name, if necessary. 8# Change stm32f207zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
@@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
23nb = "1.0.0" 22nb = "1.0.0"
24 23
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs
index e32f283d1..e39e2daec 100644
--- a/examples/stm32f2/src/bin/pll.rs
+++ b/examples/stm32f2/src/bin/pll.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::convert::TryFrom;
5
6use defmt::*; 4use defmt::*;
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 64bb2e560..7fda410d9 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f303ze to your chip name, if necessary. 8# Change stm32f303ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.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", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
@@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
25nb = "1.0.0" 24nb = "1.0.0"
26embedded-storage = "0.3.1" 25embedded-storage = "0.3.1"
diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs
new file mode 100644
index 000000000..5c8dac94f
--- /dev/null
+++ b/examples/stm32f3/src/bin/blocking-tsc.rs
@@ -0,0 +1,98 @@
1// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32F303ZE Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::gpio::{Level, Output, Speed};
21use embassy_stm32::tsc::{self, *};
22use embassy_time::Timer;
23use {defmt_rtt as _, panic_probe as _};
24
25/// This example is written for the nucleo-stm32f303ze, with a stm32f303ze chip.
26///
27/// Make sure you check/update the following (whether you use the F303ZE or another board):
28///
29/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32F303ZETx`chip name.
30/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for F303ZE it should be `stm32f303ze`.
31/// * [ ] If your board has a special clock or power configuration, make sure that it is
32/// set up appropriately.
33/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
34/// to match your schematic
35///
36/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
37///
38/// * Which example you are trying to run
39/// * Which chip and board you are using
40///
41/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
42#[embassy_executor::main]
43async fn main(_spawner: embassy_executor::Spawner) {
44 let device_config = embassy_stm32::Config::default();
45 let context = embassy_stm32::init(device_config);
46
47 let tsc_conf = Config {
48 ct_pulse_high_length: ChargeTransferPulseCycle::_8,
49 ct_pulse_low_length: ChargeTransferPulseCycle::_8,
50 spread_spectrum: false,
51 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
52 spread_spectrum_prescaler: false,
53 pulse_generator_prescaler: PGPrescalerDivider::_32,
54 max_count_value: MaxCount::_255,
55 io_default_mode: false,
56 synchro_pin_polarity: false,
57 acquisition_mode: false,
58 max_count_interrupt: false,
59 channel_ios: TscIOPin::Group1Io1.into(),
60 shield_ios: 0, // no shield
61 sampling_ios: TscIOPin::Group1Io2.into(),
62 };
63
64 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
65 g1.set_io1(context.PA0, PinType::Sample);
66 g1.set_io2(context.PA1, PinType::Channel);
67
68 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, Some(g1), None, None, None, None, None, tsc_conf);
69
70 // LED2 on the STM32F303ZE nucleo-board
71 let mut led = Output::new(context.PB7, Level::High, Speed::Low);
72
73 // smaller sample capacitor discharge faster and can be used with shorter delay.
74 let discharge_delay = 5; // ms
75
76 // the interval at which the loop polls for new touch sensor values
77 let polling_interval = 100; // ms
78
79 info!("polling for touch");
80 loop {
81 touch_controller.start();
82 touch_controller.poll_for_acquisition();
83 touch_controller.discharge_io(true);
84 Timer::after_millis(discharge_delay).await;
85
86 let grp1_status = touch_controller.group_get_status(Group::One);
87 match grp1_status {
88 GroupStatus::Complete => {
89 let group_one_val = touch_controller.group_get_value(Group::One);
90 info!("{}", group_one_val);
91 led.set_high();
92 }
93 GroupStatus::Ongoing => led.set_low(),
94 }
95
96 Timer::after_millis(polling_interval).await;
97 }
98}
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 328447210..b4620888f 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -80,7 +80,7 @@ async fn run_med() {
80 info!(" [med] Starting long computation"); 80 info!(" [med] Starting long computation");
81 81
82 // Spin-wait to simulate a long CPU computation 82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(8_000_000); // ~1 second 83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84 84
85 let end = Instant::now(); 85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33; 86 let ms = end.duration_since(start).as_ticks() / 33;
@@ -97,7 +97,7 @@ async fn run_low() {
97 info!("[low] Starting long computation"); 97 info!("[low] Starting long computation");
98 98
99 // Spin-wait to simulate a long CPU computation 99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(16_000_000); // ~2 seconds 100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101 101
102 let end = Instant::now(); 102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33; 103 let ms = end.duration_since(start).as_ticks() / 33;
@@ -127,6 +127,11 @@ fn main() -> ! {
127 127
128 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
129 129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
130 // High-priority executor: UART4, priority level 6 135 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6); 136 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4); 137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 5234e53b9..573a49f19 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index ee1c43afd..5760f2c1c 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -54,7 +54,6 @@ async fn main(_spawner: Spawner) {
54 54
55 // Create embassy-usb DeviceBuilder using the driver and config. 55 // Create embassy-usb DeviceBuilder using the driver and config.
56 // It needs some buffers for building the descriptors. 56 // It needs some buffers for building the descriptors.
57 let mut device_descriptor = [0; 256];
58 let mut config_descriptor = [0; 256]; 57 let mut config_descriptor = [0; 256];
59 let mut bos_descriptor = [0; 256]; 58 let mut bos_descriptor = [0; 256];
60 let mut control_buf = [0; 7]; 59 let mut control_buf = [0; 7];
@@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) {
64 let mut builder = Builder::new( 63 let mut builder = Builder::new(
65 driver, 64 driver,
66 config, 65 config,
67 &mut device_descriptor,
68 &mut config_descriptor, 66 &mut config_descriptor,
69 &mut bos_descriptor, 67 &mut bos_descriptor,
70 &mut [], // no msos descriptors 68 &mut [], // no msos descriptors
diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml
index caf947be6..f38c90a31 100644
--- a/examples/stm32f334/.cargo/config.toml
+++ b/examples/stm32f334/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list`
3runner = "probe-run --chip STM32F334R8" 3runner = "probe-rs run --chip STM32F334R8"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 3e5a7cc8c..1cc0a97da 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -5,11 +5,11 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
@@ -19,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23heapless = { version = "0.8", default-features = false } 22heapless = { version = "0.8", default-features = false }
24nb = "1.0.0" 23nb = "1.0.0"
25embedded-storage = "0.3.1" 24embedded-storage = "0.3.1"
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
index a9fb7f1a6..0528a9637 100644
--- a/examples/stm32f334/src/bin/adc.rs
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{adc, bind_interrupts, Config}; 9use embassy_stm32::{adc, bind_interrupts, Config};
10use embassy_time::{Delay, Timer}; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13bind_interrupts!(struct Irqs { 13bind_interrupts!(struct Irqs {
@@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! {
38 38
39 info!("create adc..."); 39 info!("create adc...");
40 40
41 let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); 41 let mut adc = Adc::new(p.ADC1, Irqs);
42 42
43 adc.set_sample_time(SampleTime::Cycles601_5); 43 adc.set_sample_time(SampleTime::CYCLES601_5);
44 44
45 info!("enable vrefint..."); 45 info!("enable vrefint...");
46 46
47 let mut vrefint = adc.enable_vref(&mut Delay); 47 let mut vrefint = adc.enable_vref();
48 let mut temperature = adc.enable_temperature(); 48 let mut temperature = adc.enable_temperature();
49 49
50 loop { 50 loop {
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index 6f25191be..2dbf1bdab 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain};
8use embassy_stm32::peripherals::ADC2; 8use embassy_stm32::peripherals::ADC2;
9use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
10use embassy_stm32::{adc, bind_interrupts, Config}; 10use embassy_stm32::{adc, bind_interrupts, Config};
11use embassy_time::{Delay, Timer}; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! {
39 39
40 info!("create adc..."); 40 info!("create adc...");
41 41
42 let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); 42 let mut adc = Adc::new(p.ADC2, Irqs);
43 let mut opamp = OpAmp::new(p.OPAMP2); 43 let mut opamp = OpAmp::new(p.OPAMP2);
44 44
45 adc.set_sample_time(SampleTime::Cycles601_5); 45 adc.set_sample_time(SampleTime::CYCLES601_5);
46 46
47 info!("enable vrefint..."); 47 info!("enable vrefint...");
48 48
49 let mut vrefint = adc.enable_vref(&mut Delay); 49 let mut vrefint = adc.enable_vref();
50 let mut temperature = adc.enable_temperature(); 50 let mut temperature = adc.enable_temperature();
51 let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); 51 let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1);
52 52
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 7fc1ea926..e6d1a6c02 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -27,7 +27,8 @@ async fn main(_spawner: Spawner) {
27 config.rcc.ahb_pre = AHBPrescaler::DIV1; 27 config.rcc.ahb_pre = AHBPrescaler::DIV1;
28 config.rcc.apb1_pre = APBPrescaler::DIV2; 28 config.rcc.apb1_pre = APBPrescaler::DIV2;
29 config.rcc.apb2_pre = APBPrescaler::DIV1; 29 config.rcc.apb2_pre = APBPrescaler::DIV1;
30 config.rcc.hrtim = HrtimClockSource::PllClk; 30
31 config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
31 } 32 }
32 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
33 34
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index cd46fc85b..b85361596 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,12 +6,14 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
15embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 17
16defmt = "0.3" 18defmt = "0.3"
17defmt-rtt = "0.4" 19defmt-rtt = "0.4"
@@ -19,14 +21,16 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-bus = { version = "0.2", features = ["async"] }
22embedded-io = { version = "0.6.0" } 25embedded-io = { version = "0.6.0" }
23embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.6.1" }
24panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "0.3", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures-util = { version = "0.3.30", default-features = false }
26heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
27nb = "1.0.0" 30nb = "1.0.0"
28embedded-storage = "0.3.1" 31embedded-storage = "0.3.1"
29micromath = "2.0.0" 32micromath = "2.0.0"
33usbd-hid = "0.8.1"
30static_cell = "2" 34static_cell = "2"
31chrono = { version = "^0.4", default-features = false} 35chrono = { version = "^0.4", default-features = false}
32 36
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 699c29c05..423d29225 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let mut delay = Delay; 16 let mut delay = Delay;
17 let mut adc = Adc::new(p.ADC1, &mut delay); 17 let mut adc = Adc::new(p.ADC1);
18 let mut pin = p.PC1; 18 let mut pin = p.PC1;
19 19
20 let mut vrefint = adc.enable_vrefint(); 20 let mut vrefint = adc.enable_vrefint();
@@ -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/can.rs b/examples/stm32f4/src/bin/can.rs
index d074b4265..8e3beee24 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -4,9 +4,10 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::bind_interrupts; 6use embassy_stm32::bind_interrupts;
7use embassy_stm32::can::bxcan::filter::Mask32; 7use embassy_stm32::can::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 8use embassy_stm32::can::{
9use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; 9 Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler,
10};
10use embassy_stm32::gpio::{Input, Pull}; 11use embassy_stm32::gpio::{Input, Pull};
11use embassy_stm32::peripherals::CAN1; 12use embassy_stm32::peripherals::CAN1;
12use embassy_time::Instant; 13use embassy_time::Instant;
@@ -34,23 +35,18 @@ async fn main(_spawner: Spawner) {
34 35
35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); 36 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
36 37
37 can.as_mut() 38 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
38 .modify_filters()
39 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
40 39
41 can.as_mut() 40 can.modify_config()
42 .modify_config()
43 .set_loopback(true) // Receive own frames 41 .set_loopback(true) // Receive own frames
44 .set_silent(true) 42 .set_silent(true)
45 .leave_disabled(); 43 .set_bitrate(1_000_000);
46
47 can.set_bitrate(1_000_000);
48 44
49 can.enable().await; 45 can.enable().await;
50 46
51 let mut i: u8 = 0; 47 let mut i: u8 = 0;
52 loop { 48 loop {
53 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
54 let tx_ts = Instant::now(); 50 let tx_ts = Instant::now();
55 can.write(&tx_frame).await; 51 can.write(&tx_frame).await;
56 52
@@ -64,9 +60,9 @@ async fn main(_spawner: Spawner) {
64 60
65 info!( 61 info!(
66 "loopback frame {=u8}, latency: {} us", 62 "loopback frame {=u8}, latency: {} us",
67 unwrap!(envelope.frame.data())[0], 63 envelope.frame.data()[0],
68 latency.as_micros() 64 latency.as_micros()
69 ); 65 );
70 i += 1; 66 i = i.wrapping_add(1);
71 } 67 }
72} 68}
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index 9c7754c4f..dd2a45718 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) -> ! {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World, dude!"); 13 info!("Hello World, dude!");
14 14
15 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4); 15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
16 16
17 loop { 17 loop {
18 for v in 0..=255 { 18 for v in 0..=255 {
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 7f5c8fdb1..baed96449 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs {
24type Device = Ethernet<'static, ETH, GenericSMI>; 24type Device = Ethernet<'static, ETH, GenericSMI>;
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 28 runner.run().await
29} 29}
30 30
31#[embassy_executor::main] 31#[embassy_executor::main]
@@ -62,9 +62,9 @@ async fn main(spawner: Spawner) -> ! {
62 62
63 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 63 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
64 64
65 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 65 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
66 let device = Ethernet::new( 66 let device = Ethernet::new(
67 PACKETS.init(PacketQueue::<16, 16>::new()), 67 PACKETS.init(PacketQueue::<4, 4>::new()),
68 p.ETH, 68 p.ETH,
69 Irqs, 69 Irqs,
70 p.PA1, 70 p.PA1,
@@ -88,17 +88,11 @@ async fn main(spawner: Spawner) -> ! {
88 //}); 88 //});
89 89
90 // Init network stack 90 // Init network stack
91 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 91 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 92 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
93 let stack = &*STACK.init(Stack::new(
94 device,
95 config,
96 RESOURCES.init(StackResources::<2>::new()),
97 seed,
98 ));
99 93
100 // Launch network task 94 // Launch network task
101 unwrap!(spawner.spawn(net_task(stack))); 95 unwrap!(spawner.spawn(net_task(runner)));
102 96
103 // Ensure DHCP configuration is up before trying connect 97 // Ensure DHCP configuration is up before trying connect
104 stack.wait_config_up().await; 98 stack.wait_config_up().await;
@@ -110,7 +104,7 @@ async fn main(spawner: Spawner) -> ! {
110 let mut tx_buffer = [0; 4096]; 104 let mut tx_buffer = [0; 4096];
111 105
112 loop { 106 loop {
113 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 107 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
114 108
115 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 109 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
116 110
diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs
new file mode 100644
index 000000000..5946fed79
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth_compliance_test.rs
@@ -0,0 +1,77 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::eth::generic_smi::GenericSMI;
7use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
10use embassy_time::Timer;
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 ETH => eth::InterruptHandler;
16 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! {
21 let mut config = Config::default();
22 {
23 use embassy_stm32::rcc::*;
24 config.rcc.hse = Some(Hse {
25 freq: Hertz(8_000_000),
26 mode: HseMode::Bypass,
27 });
28 config.rcc.pll_src = PllSource::HSE;
29 config.rcc.pll = Some(Pll {
30 prediv: PllPreDiv::DIV4,
31 mul: PllMul::MUL180,
32 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
33 divq: None,
34 divr: None,
35 });
36 config.rcc.ahb_pre = AHBPrescaler::DIV1;
37 config.rcc.apb1_pre = APBPrescaler::DIV4;
38 config.rcc.apb2_pre = APBPrescaler::DIV2;
39 config.rcc.sys = Sysclk::PLL1_P;
40 }
41 let p = embassy_stm32::init(config);
42
43 info!("Hello Compliance World!");
44
45 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
46
47 const PHY_ADDR: u8 = 0;
48 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
49 let mut device = Ethernet::new(
50 PACKETS.init(PacketQueue::<4, 4>::new()),
51 p.ETH,
52 Irqs,
53 p.PA1,
54 p.PA2,
55 p.PC1,
56 p.PA7,
57 p.PC4,
58 p.PC5,
59 p.PG13,
60 p.PB13,
61 p.PG11,
62 GenericSMI::new(PHY_ADDR),
63 mac_addr,
64 );
65
66 let sm = unsafe { device.station_management() };
67
68 // Just an example. Exact register settings depend on the specific PHY and test.
69 sm.smi_write(PHY_ADDR, 0, 0x2100);
70 sm.smi_write(PHY_ADDR, 11, 0xA000);
71
72 // NB: Remember to reset the PHY after testing before starting the networking stack
73
74 loop {
75 Timer::after_secs(1).await;
76 }
77}
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
new file mode 100644
index 000000000..6e6bef08c
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -0,0 +1,134 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, StackResources};
8use embassy_net_wiznet::chip::W5500;
9use embassy_net_wiznet::{Device, Runner, State};
10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_stm32::mode::Async;
13use embassy_stm32::rng::Rng;
14use embassy_stm32::spi::Spi;
15use embassy_stm32::time::Hertz;
16use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config};
17use embassy_time::{Delay, Timer};
18use embedded_hal_bus::spi::ExclusiveDevice;
19use embedded_io_async::Write;
20use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
25});
26
27type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>;
28#[embassy_executor::task]
29async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! {
30 runner.run().await
31}
32
33#[embassy_executor::task]
34async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
35 runner.run().await
36}
37
38#[embassy_executor::main]
39async fn main(spawner: Spawner) -> ! {
40 let mut config = Config::default();
41 {
42 use embassy_stm32::rcc::*;
43 config.rcc.hse = Some(Hse {
44 freq: Hertz(8_000_000),
45 mode: HseMode::Bypass,
46 });
47 config.rcc.pll_src = PllSource::HSE;
48 config.rcc.pll = Some(Pll {
49 prediv: PllPreDiv::DIV4,
50 mul: PllMul::MUL180,
51 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
52 divq: None,
53 divr: None,
54 });
55 config.rcc.ahb_pre = AHBPrescaler::DIV1;
56 config.rcc.apb1_pre = APBPrescaler::DIV4;
57 config.rcc.apb2_pre = APBPrescaler::DIV2;
58 config.rcc.sys = Sysclk::PLL1_P;
59 }
60 let p = embassy_stm32::init(config);
61
62 info!("Hello World!");
63
64 // Generate random seed
65 let mut rng = Rng::new(p.RNG, Irqs);
66 let mut seed = [0; 8];
67 unwrap!(rng.async_fill_bytes(&mut seed).await);
68 let seed = u64::from_le_bytes(seed);
69
70 let mut spi_cfg = spi::Config::default();
71 spi_cfg.frequency = Hertz(50_000_000); // up to 50m works
72 let (miso, mosi, clk) = (p.PA6, p.PA7, p.PA5);
73 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA2_CH3, p.DMA2_CH0, spi_cfg);
74 let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
75 let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay));
76
77 let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up);
78 let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh);
79
80 let mac_addr = [0x02, 234, 3, 4, 82, 231];
81 static STATE: StaticCell<State<2, 2>> = StaticCell::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)
84 .await
85 .unwrap();
86 unwrap!(spawner.spawn(ethernet_task(runner)));
87
88 let config = embassy_net::Config::dhcpv4(Default::default());
89 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
90 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
91 // dns_servers: Vec::new(),
92 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
93 //});
94
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97
98 // Launch network task
99 unwrap!(spawner.spawn(net_task(runner)));
100
101 // Ensure DHCP configuration is up before trying connect
102 stack.wait_config_up().await;
103
104 info!("Network task initialized");
105
106 // Then we can use it!
107 let mut rx_buffer = [0; 1024];
108 let mut tx_buffer = [0; 1024];
109
110 loop {
111 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
112
113 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
114
115 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
116 info!("connecting...");
117 let r = socket.connect(remote_endpoint).await;
118 if let Err(e) = r {
119 info!("connect error: {:?}", e);
120 Timer::after_secs(1).await;
121 continue;
122 }
123 info!("connected!");
124 let buf = [0; 1024];
125 loop {
126 let r = socket.write_all(&buf).await;
127 if let Err(e) = r {
128 info!("write error: {:?}", e);
129 break;
130 }
131 Timer::after_secs(1).await;
132 }
133 }
134}
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
index 4b5da774d..4a96357a4 100644
--- a/examples/stm32f4/src/bin/i2c.rs
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -3,35 +3,19 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::{Error, I2c}; 6use embassy_stm32::i2c::{Error, I2c};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 info!("Hello world!"); 15 info!("Hello world!");
23 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
24 17
25 let mut i2c = I2c::new( 18 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 19
36 let mut data = [0u8; 1]; 20 let mut data = [0u8; 1];
37 21
diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs
index 30cfbdf57..55c4891e3 100644
--- a/examples/stm32f4/src/bin/i2c_comparison.rs
+++ b/examples/stm32f4/src/bin/i2c_comparison.rs
@@ -13,7 +13,7 @@ use embassy_stm32::i2c::I2c;
13use embassy_stm32::time::Hertz; 13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, i2c, peripherals}; 14use embassy_stm32::{bind_interrupts, i2c, peripherals};
15use embassy_time::Instant; 15use embassy_time::Instant;
16use futures::future::try_join3; 16use futures_util::future::try_join3;
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19const ADDRESS: u8 = 96; 19const ADDRESS: u8 = 96;
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs
index 97a04b2aa..27b165f1b 100644
--- a/examples/stm32f4/src/bin/i2s_dma.rs
+++ b/examples/stm32f4/src/bin/i2s_dma.rs
@@ -15,14 +15,13 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let mut i2s = I2S::new( 18 let mut i2s = I2S::new_txonly(
19 p.SPI2, 19 p.SPI2,
20 p.PC3, // sd 20 p.PC3, // sd
21 p.PB12, // ws 21 p.PB12, // ws
22 p.PB10, // ck 22 p.PB10, // ck
23 p.PC6, // mck 23 p.PC6, // mck
24 p.DMA1_CH4, 24 p.DMA1_CH4,
25 p.DMA1_CH3,
26 Hertz(1_000_000), 25 Hertz(1_000_000),
27 Config::default(), 26 Config::default(),
28 ); 27 );
diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs
new file mode 100644
index 000000000..49de33d2b
--- /dev/null
+++ b/examples/stm32f4/src/bin/input_capture.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14/// Connect PB2 and PB10 with a 1k Ohm resistor
15
16#[embassy_executor::task]
17async fn blinky(led: peripherals::PB2) {
18 let mut led = Output::new(led, Level::High, Speed::Low);
19
20 loop {
21 info!("high");
22 led.set_high();
23 Timer::after_millis(300).await;
24
25 info!("low");
26 led.set_low();
27 Timer::after_millis(300).await;
28 }
29}
30
31bind_interrupts!(struct Irqs {
32 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
33});
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_stm32::init(Default::default());
38 info!("Hello World!");
39
40 unwrap!(spawner.spawn(blinky(p.PB2)));
41
42 let ch3 = CapturePin::new_ch3(p.PB10, Pull::None);
43 let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
44
45 loop {
46 info!("wait for risign edge");
47 ic.wait_for_rising_edge(Channel::Ch3).await;
48
49 let capture_value = ic.get_capture_value(Channel::Ch3);
50 info!("new capture! {}", capture_value);
51 }
52}
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 328447210..b4620888f 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -80,7 +80,7 @@ async fn run_med() {
80 info!(" [med] Starting long computation"); 80 info!(" [med] Starting long computation");
81 81
82 // Spin-wait to simulate a long CPU computation 82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(8_000_000); // ~1 second 83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84 84
85 let end = Instant::now(); 85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33; 86 let ms = end.duration_since(start).as_ticks() / 33;
@@ -97,7 +97,7 @@ async fn run_low() {
97 info!("[low] Starting long computation"); 97 info!("[low] Starting long computation");
98 98
99 // Spin-wait to simulate a long CPU computation 99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(16_000_000); // ~2 seconds 100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101 101
102 let end = Instant::now(); 102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33; 103 let ms = end.duration_since(start).as_ticks() / 33;
@@ -127,6 +127,11 @@ fn main() -> ! {
127 127
128 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
129 129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
130 // High-priority executor: UART4, priority level 6 135 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6); 136 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4); 137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs
new file mode 100644
index 000000000..ce200549d
--- /dev/null
+++ b/examples/stm32f4/src/bin/pwm_input.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13/// Connect PB2 and PA6 with a 1k Ohm resistor
14
15#[embassy_executor::task]
16async fn blinky(led: peripherals::PB2) {
17 let mut led = Output::new(led, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after_millis(300).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after_millis(300).await;
27 }
28}
29
30bind_interrupts!(struct Irqs {
31 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
32});
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 let p = embassy_stm32::init(Default::default());
37 info!("Hello World!");
38
39 unwrap!(spawner.spawn(blinky(p.PB2)));
40
41 let mut pwm_input = PwmInput::new(p.TIM3, p.PA6, Pull::None, khz(10));
42 pwm_input.enable();
43
44 loop {
45 Timer::after_millis(500).await;
46 let period = pwm_input.get_period_ticks();
47 let width = pwm_input.get_width_ticks();
48 let duty_cycle = pwm_input.get_duty_cycle();
49 info!(
50 "period ticks: {} width ticks: {} duty cycle: {}",
51 period, width, duty_cycle
52 );
53 }
54}
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index abab07b6b..82d8a37ba 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 loop { 28 loop {
29 let now: NaiveDateTime = rtc.now().unwrap().into(); 29 let now: NaiveDateTime = rtc.now().unwrap().into();
30 30
31 info!("{}", now.timestamp()); 31 info!("{}", now.and_utc().timestamp());
32 32
33 Timer::after_millis(1000).await; 33 Timer::after_millis(1000).await;
34 } 34 }
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index dc9141c62..970d819fc 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let mut spi_config = Config::default(); 17 let mut spi_config = Config::default();
19 spi_config.frequency = Hertz(1_000_000); 18 spi_config.frequency = Hertz(1_000_000);
20 19
21 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 20 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
22 21
23 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
24 23
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 40d9d70f1..991bf6673 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::usart::{Config, Uart}; 6use embassy_stm32::usart::{Config, Uart};
8use embassy_stm32::{bind_interrupts, peripherals, usart}; 7use embassy_stm32::{bind_interrupts, peripherals, usart};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +18,7 @@ fn main() -> ! {
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
20 19
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); 21 let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap();
23 22
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 24 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index dd6de599c..aaf8d6c4f 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index a196259a8..a9504ec04 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -4,11 +4,11 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
9use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb_otg::Driver; 10use embassy_stm32::usb::Driver;
11use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 11use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
14use embassy_usb::{Builder, UsbDevice}; 14use embassy_usb::{Builder, UsbDevice};
@@ -31,15 +31,20 @@ async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! {
31} 31}
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 34async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
35 stack.run().await 35 runner.run().await
36} 36}
37 37
38bind_interrupts!(struct Irqs { 38bind_interrupts!(struct Irqs {
39 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 39 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
40 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 40 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
41}); 41});
42 42
43// If you are trying this and your USB device doesn't connect, the most
44// common issues are the RCC config and vbus_detection
45//
46// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
47// for more information.
43#[embassy_executor::main] 48#[embassy_executor::main]
44async fn main(spawner: Spawner) { 49async fn main(spawner: Spawner) {
45 info!("Hello World!"); 50 info!("Hello World!");
@@ -63,14 +68,21 @@ async fn main(spawner: Spawner) {
63 config.rcc.apb1_pre = APBPrescaler::DIV4; 68 config.rcc.apb1_pre = APBPrescaler::DIV4;
64 config.rcc.apb2_pre = APBPrescaler::DIV2; 69 config.rcc.apb2_pre = APBPrescaler::DIV2;
65 config.rcc.sys = Sysclk::PLL1_P; 70 config.rcc.sys = Sysclk::PLL1_P;
71 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
66 } 72 }
67 let p = embassy_stm32::init(config); 73 let p = embassy_stm32::init(config);
68 74
69 // Create the driver, from the HAL. 75 // Create the driver, from the HAL.
70 static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); 76 static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new();
71 let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; 77 let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..];
72 let mut config = embassy_stm32::usb_otg::Config::default(); 78 let mut config = embassy_stm32::usb::Config::default();
73 config.vbus_detection = true; 79
80 // Do not enable vbus_detection. This is a safe default that works in all boards.
81 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
82 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
83 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
84 config.vbus_detection = false;
85
74 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); 86 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
75 87
76 // Create embassy-usb Config 88 // Create embassy-usb Config
@@ -88,14 +100,12 @@ async fn main(spawner: Spawner) {
88 config.device_protocol = 0x01; 100 config.device_protocol = 0x01;
89 101
90 // Create embassy-usb DeviceBuilder using the driver and config. 102 // Create embassy-usb DeviceBuilder using the driver and config.
91 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
92 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 103 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
93 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 104 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
94 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); 105 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
95 let mut builder = Builder::new( 106 let mut builder = Builder::new(
96 driver, 107 driver,
97 config, 108 config,
98 &mut DEVICE_DESC.init([0; 256])[..],
99 &mut CONFIG_DESC.init([0; 256])[..], 109 &mut CONFIG_DESC.init([0; 256])[..],
100 &mut BOS_DESC.init([0; 256])[..], 110 &mut BOS_DESC.init([0; 256])[..],
101 &mut [], // no msos descriptors 111 &mut [], // no msos descriptors
@@ -134,16 +144,10 @@ async fn main(spawner: Spawner) {
134 let seed = u64::from_le_bytes(seed); 144 let seed = u64::from_le_bytes(seed);
135 145
136 // Init network stack 146 // Init network stack
137 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 147 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
138 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 148 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
139 let stack = &*STACK.init(Stack::new(
140 device,
141 config,
142 RESOURCES.init(StackResources::<2>::new()),
143 seed,
144 ));
145 149
146 unwrap!(spawner.spawn(net_task(stack))); 150 unwrap!(spawner.spawn(net_task(runner)));
147 151
148 // And now we can use it! 152 // And now we can use it!
149 153
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..1270995c4
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,232 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::gpio::Pull;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::usb::Driver;
13use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
15use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
22});
23
24// If you are trying this and your USB device doesn't connect, the most
25// common issues are the RCC config and vbus_detection
26//
27// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
28// for more information.
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let mut config = Config::default();
32 {
33 use embassy_stm32::rcc::*;
34 config.rcc.hse = Some(Hse {
35 freq: Hertz(8_000_000),
36 mode: HseMode::Bypass,
37 });
38 config.rcc.pll_src = PllSource::HSE;
39 config.rcc.pll = Some(Pll {
40 prediv: PllPreDiv::DIV4,
41 mul: PllMul::MUL168,
42 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
43 divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
44 divr: None,
45 });
46 config.rcc.ahb_pre = AHBPrescaler::DIV1;
47 config.rcc.apb1_pre = APBPrescaler::DIV4;
48 config.rcc.apb2_pre = APBPrescaler::DIV2;
49 config.rcc.sys = Sysclk::PLL1_P;
50 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
51 }
52 let p = embassy_stm32::init(config);
53
54 // Create the driver, from the HAL.
55 let mut ep_out_buffer = [0u8; 256];
56 let mut config = embassy_stm32::usb::Config::default();
57
58 // Do not enable vbus_detection. This is a safe default that works in all boards.
59 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
60 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
61 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
62 config.vbus_detection = false;
63
64 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
65
66 // Create embassy-usb Config
67 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
68 config.manufacturer = Some("Embassy");
69 config.product = Some("HID keyboard example");
70 config.serial_number = Some("12345678");
71 config.max_power = 100;
72 config.max_packet_size_0 = 64;
73
74 // Required for windows compatibility.
75 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
76 config.device_class = 0xEF;
77 config.device_sub_class = 0x02;
78 config.device_protocol = 0x01;
79 config.composite_with_iads = true;
80
81 // Create embassy-usb DeviceBuilder using the driver and config.
82 // It needs some buffers for building the descriptors.
83 let mut config_descriptor = [0; 256];
84 let mut bos_descriptor = [0; 256];
85 // You can also add a Microsoft OS descriptor.
86 let mut msos_descriptor = [0; 256];
87 let mut control_buf = [0; 64];
88
89 let mut request_handler = MyRequestHandler {};
90 let mut device_handler = MyDeviceHandler::new();
91
92 let mut state = State::new();
93
94 let mut builder = Builder::new(
95 driver,
96 config,
97 &mut config_descriptor,
98 &mut bos_descriptor,
99 &mut msos_descriptor,
100 &mut control_buf,
101 );
102
103 builder.handler(&mut device_handler);
104
105 // Create classes on the builder.
106 let config = embassy_usb::class::hid::Config {
107 report_descriptor: KeyboardReport::desc(),
108 request_handler: None,
109 poll_ms: 60,
110 max_packet_size: 8,
111 };
112
113 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
114
115 // Build the builder.
116 let mut usb = builder.build();
117
118 // Run the USB device.
119 let usb_fut = usb.run();
120
121 let (reader, mut writer) = hid.split();
122
123 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
124
125 // Do stuff with the class!
126 let in_fut = async {
127 loop {
128 button.wait_for_rising_edge().await;
129 // signal_pin.wait_for_high().await;
130 info!("Button pressed!");
131 // Create a report with the A key pressed. (no shift modifier)
132 let report = KeyboardReport {
133 keycodes: [4, 0, 0, 0, 0, 0],
134 leds: 0,
135 modifier: 0,
136 reserved: 0,
137 };
138 // Send the report.
139 match writer.write_serialize(&report).await {
140 Ok(()) => {}
141 Err(e) => warn!("Failed to send report: {:?}", e),
142 };
143
144 button.wait_for_falling_edge().await;
145 // signal_pin.wait_for_low().await;
146 info!("Button released!");
147 let report = KeyboardReport {
148 keycodes: [0, 0, 0, 0, 0, 0],
149 leds: 0,
150 modifier: 0,
151 reserved: 0,
152 };
153 match writer.write_serialize(&report).await {
154 Ok(()) => {}
155 Err(e) => warn!("Failed to send report: {:?}", e),
156 };
157 }
158 };
159
160 let out_fut = async {
161 reader.run(false, &mut request_handler).await;
162 };
163
164 // Run everything concurrently.
165 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
166 join(usb_fut, join(in_fut, out_fut)).await;
167}
168
169struct MyRequestHandler {}
170
171impl RequestHandler for MyRequestHandler {
172 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
173 info!("Get report for {:?}", id);
174 None
175 }
176
177 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
178 info!("Set report for {:?}: {=[u8]}", id, data);
179 OutResponse::Accepted
180 }
181
182 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
183 info!("Set idle rate for {:?} to {:?}", id, dur);
184 }
185
186 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
187 info!("Get idle rate for {:?}", id);
188 None
189 }
190}
191
192struct MyDeviceHandler {
193 configured: AtomicBool,
194}
195
196impl MyDeviceHandler {
197 fn new() -> Self {
198 MyDeviceHandler {
199 configured: AtomicBool::new(false),
200 }
201 }
202}
203
204impl Handler for MyDeviceHandler {
205 fn enabled(&mut self, enabled: bool) {
206 self.configured.store(false, Ordering::Relaxed);
207 if enabled {
208 info!("Device enabled");
209 } else {
210 info!("Device disabled");
211 }
212 }
213
214 fn reset(&mut self) {
215 self.configured.store(false, Ordering::Relaxed);
216 info!("Bus reset, the Vbus current limit is 100mA");
217 }
218
219 fn addressed(&mut self, addr: u8) {
220 self.configured.store(false, Ordering::Relaxed);
221 info!("USB address set to: {}", addr);
222 }
223
224 fn configured(&mut self, configured: bool) {
225 self.configured.store(configured, Ordering::Relaxed);
226 if configured {
227 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
228 } else {
229 info!("Device is no longer configured, the Vbus current limit is 100mA.");
230 }
231 }
232}
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..45136f965
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,158 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::Driver;
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_time::Timer;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
12use embassy_usb::control::OutResponse;
13use embassy_usb::Builder;
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
19});
20
21// If you are trying this and your USB device doesn't connect, the most
22// common issues are the RCC config and vbus_detection
23//
24// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
25// for more information.
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut config = Config::default();
29 {
30 use embassy_stm32::rcc::*;
31 config.rcc.hse = Some(Hse {
32 freq: Hertz(8_000_000),
33 mode: HseMode::Bypass,
34 });
35 config.rcc.pll_src = PllSource::HSE;
36 config.rcc.pll = Some(Pll {
37 prediv: PllPreDiv::DIV4,
38 mul: PllMul::MUL168,
39 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
40 divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
41 divr: None,
42 });
43 config.rcc.ahb_pre = AHBPrescaler::DIV1;
44 config.rcc.apb1_pre = APBPrescaler::DIV4;
45 config.rcc.apb2_pre = APBPrescaler::DIV2;
46 config.rcc.sys = Sysclk::PLL1_P;
47 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
48 }
49 let p = embassy_stm32::init(config);
50
51 // Create the driver, from the HAL.
52 let mut ep_out_buffer = [0u8; 256];
53 let mut config = embassy_stm32::usb::Config::default();
54
55 // Do not enable vbus_detection. This is a safe default that works in all boards.
56 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
57 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
58 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
59 config.vbus_detection = false;
60
61 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
62
63 // Create embassy-usb Config
64 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
65 config.manufacturer = Some("Embassy");
66 config.product = Some("HID mouse example");
67 config.serial_number = Some("12345678");
68
69 // Required for windows compatibility.
70 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
71 config.device_class = 0xEF;
72 config.device_sub_class = 0x02;
73 config.device_protocol = 0x01;
74 config.composite_with_iads = true;
75
76 // Create embassy-usb DeviceBuilder using the driver and config.
77 // It needs some buffers for building the descriptors.
78 let mut config_descriptor = [0; 256];
79 let mut bos_descriptor = [0; 256];
80 let mut control_buf = [0; 64];
81
82 let mut request_handler = MyRequestHandler {};
83
84 let mut state = State::new();
85
86 let mut builder = Builder::new(
87 driver,
88 config,
89 &mut config_descriptor,
90 &mut bos_descriptor,
91 &mut [], // no msos descriptors
92 &mut control_buf,
93 );
94
95 // Create classes on the builder.
96 let config = embassy_usb::class::hid::Config {
97 report_descriptor: MouseReport::desc(),
98 request_handler: Some(&mut request_handler),
99 poll_ms: 60,
100 max_packet_size: 8,
101 };
102
103 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
104
105 // Build the builder.
106 let mut usb = builder.build();
107
108 // Run the USB device.
109 let usb_fut = usb.run();
110
111 // Do stuff with the class!
112 let hid_fut = async {
113 let mut y: i8 = 5;
114 loop {
115 Timer::after_millis(500).await;
116
117 y = -y;
118 let report = MouseReport {
119 buttons: 0,
120 x: 0,
121 y,
122 wheel: 0,
123 pan: 0,
124 };
125 match writer.write_serialize(&report).await {
126 Ok(()) => {}
127 Err(e) => warn!("Failed to send report: {:?}", e),
128 }
129 }
130 };
131
132 // Run everything concurrently.
133 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
134 join(usb_fut, hid_fut).await;
135}
136
137struct MyRequestHandler {}
138
139impl RequestHandler for MyRequestHandler {
140 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
141 info!("Get report for {:?}", id);
142 None
143 }
144
145 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
146 info!("Set report for {:?}: {=[u8]}", id, data);
147 OutResponse::Accepted
148 }
149
150 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
151 info!("Set idle rate for {:?} to {:?}", id, dur);
152 }
153
154 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
155 info!("Get idle rate for {:?}", id);
156 None
157 }
158}
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index afff55187..b2d706208 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -52,8 +52,8 @@
52use defmt::*; 52use defmt::*;
53use embassy_executor::Spawner; 53use embassy_executor::Spawner;
54use embassy_stm32::time::Hertz; 54use embassy_stm32::time::Hertz;
55use embassy_stm32::usb_otg::Driver; 55use embassy_stm32::usb::Driver;
56use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 56use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; 57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
58use embassy_usb::msos::{self, windows_version}; 58use embassy_usb::msos::{self, windows_version};
59use embassy_usb::types::InterfaceNumber; 59use embassy_usb::types::InterfaceNumber;
@@ -66,9 +66,14 @@ use {defmt_rtt as _, panic_probe as _};
66const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; 66const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"];
67 67
68bind_interrupts!(struct Irqs { 68bind_interrupts!(struct Irqs {
69 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 69 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
70}); 70});
71 71
72// If you are trying this and your USB device doesn't connect, the most
73// common issues are the RCC config and vbus_detection
74//
75// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
76// for more information.
72#[embassy_executor::main] 77#[embassy_executor::main]
73async fn main(_spawner: Spawner) { 78async fn main(_spawner: Spawner) {
74 info!("Hello World!"); 79 info!("Hello World!");
@@ -92,13 +97,20 @@ async fn main(_spawner: Spawner) {
92 config.rcc.apb1_pre = APBPrescaler::DIV4; 97 config.rcc.apb1_pre = APBPrescaler::DIV4;
93 config.rcc.apb2_pre = APBPrescaler::DIV2; 98 config.rcc.apb2_pre = APBPrescaler::DIV2;
94 config.rcc.sys = Sysclk::PLL1_P; 99 config.rcc.sys = Sysclk::PLL1_P;
100 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
95 } 101 }
96 let p = embassy_stm32::init(config); 102 let p = embassy_stm32::init(config);
97 103
98 // Create the driver, from the HAL. 104 // Create the driver, from the HAL.
99 let mut ep_out_buffer = [0u8; 256]; 105 let mut ep_out_buffer = [0u8; 256];
100 let mut config = embassy_stm32::usb_otg::Config::default(); 106 let mut config = embassy_stm32::usb::Config::default();
101 config.vbus_detection = true; 107
108 // Do not enable vbus_detection. This is a safe default that works in all boards.
109 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
110 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
111 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
112 config.vbus_detection = false;
113
102 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 114 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
103 115
104 // Create embassy-usb Config 116 // Create embassy-usb Config
@@ -116,7 +128,6 @@ async fn main(_spawner: Spawner) {
116 128
117 // Create embassy-usb DeviceBuilder using the driver and config. 129 // Create embassy-usb DeviceBuilder using the driver and config.
118 // It needs some buffers for building the descriptors. 130 // It needs some buffers for building the descriptors.
119 let mut device_descriptor = [0; 256];
120 let mut config_descriptor = [0; 256]; 131 let mut config_descriptor = [0; 256];
121 let mut bos_descriptor = [0; 256]; 132 let mut bos_descriptor = [0; 256];
122 let mut msos_descriptor = [0; 256]; 133 let mut msos_descriptor = [0; 256];
@@ -129,7 +140,6 @@ async fn main(_spawner: Spawner) {
129 let mut builder = Builder::new( 140 let mut builder = Builder::new(
130 driver, 141 driver,
131 config, 142 config,
132 &mut device_descriptor,
133 &mut config_descriptor, 143 &mut config_descriptor,
134 &mut bos_descriptor, 144 &mut bos_descriptor,
135 &mut msos_descriptor, 145 &mut msos_descriptor,
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 58d994a61..328b5effe 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -3,19 +3,24 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join;
6use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 12use embassy_usb::Builder;
12use futures::future::join;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
17}); 17});
18 18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
19#[embassy_executor::main] 24#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 26 info!("Hello World!");
@@ -39,13 +44,20 @@ async fn main(_spawner: Spawner) {
39 config.rcc.apb1_pre = APBPrescaler::DIV4; 44 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 45 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P; 46 config.rcc.sys = Sysclk::PLL1_P;
47 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
42 } 48 }
43 let p = embassy_stm32::init(config); 49 let p = embassy_stm32::init(config);
44 50
45 // Create the driver, from the HAL. 51 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256]; 52 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default(); 53 let mut config = embassy_stm32::usb::Config::default();
48 config.vbus_detection = true; 54
55 // Do not enable vbus_detection. This is a safe default that works in all boards.
56 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
57 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
58 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
59 config.vbus_detection = false;
60
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 61 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50 62
51 // Create embassy-usb Config 63 // Create embassy-usb Config
@@ -63,7 +75,6 @@ async fn main(_spawner: Spawner) {
63 75
64 // Create embassy-usb DeviceBuilder using the driver and config. 76 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors. 77 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256]; 78 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256]; 79 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64]; 80 let mut control_buf = [0; 64];
@@ -73,7 +84,6 @@ async fn main(_spawner: Spawner) {
73 let mut builder = Builder::new( 84 let mut builder = Builder::new(
74 driver, 85 driver,
75 config, 86 config,
76 &mut device_descriptor,
77 &mut config_descriptor, 87 &mut config_descriptor,
78 &mut bos_descriptor, 88 &mut bos_descriptor,
79 &mut [], // no msos descriptors 89 &mut [], // no msos descriptors
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 6122cea2d..cbaff75fc 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -15,8 +15,9 @@
15use embassy_executor::Spawner; 15use embassy_executor::Spawner;
16use embassy_stm32::gpio::OutputType; 16use embassy_stm32::gpio::OutputType;
17use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
18use embassy_stm32::timer::low_level::CountingMode;
18use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 19use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
19use embassy_stm32::timer::{Channel, CountingMode}; 20use embassy_stm32::timer::Channel;
20use embassy_time::{Duration, Ticker, Timer}; 21use embassy_time::{Duration, Ticker, Timer};
21use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
22 23
@@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) {
60 // construct ws2812 non-return-to-zero (NRZ) code bit by bit 61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
61 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low 62 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
62 63
63 let max_duty = ws2812_pwm.get_max_duty(); 64 let max_duty = ws2812_pwm.get_max_duty() as u16;
64 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing 65 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
65 let n1 = 2 * n0; // ws2812 Bit 1 high level timing 66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing
66 67
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
index a280a3b77..e00d14327 100644
--- a/examples/stm32f4/src/bin/ws2812_spi.rs
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -8,13 +8,13 @@
8// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. 8// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA.
9// 9//
10// Warning: 10// Warning:
11// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. 11// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
12 12
13#![no_std] 13#![no_std]
14#![no_main] 14#![no_main]
15 15
16use embassy_stm32::spi;
16use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
17use embassy_stm32::{dma, spi};
18use embassy_time::{Duration, Ticker, Timer}; 18use embassy_time::{Duration, Ticker, Timer};
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
@@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
78 spi_config.frequency = khz(12_800); 78 spi_config.frequency = khz(12_800);
79 79
80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered 80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered
81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); 81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config);
82 82
83 // flip color at 2 Hz 83 // flip color at 2 Hz
84 let mut ticker = Ticker::every(Duration::from_millis(500)); 84 let mut ticker = Ticker::every(Duration::from_millis(500));
diff --git a/examples/stm32f469/.cargo/config.toml b/examples/stm32f469/.cargo/config.toml
new file mode 100644
index 000000000..05250954f
--- /dev/null
+++ b/examples/stm32f469/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32F469NIHx"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml
new file mode 100644
index 000000000..6a5bd0b29
--- /dev/null
+++ b/examples/stm32f469/Cargo.toml
@@ -0,0 +1,22 @@
1[package]
2edition = "2021"
3name = "embassy-stm32f469-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Specific examples only for stm32f469
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12
13defmt = "0.3"
14defmt-rtt = "0.4"
15
16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18embedded-hal = "1.0.0"
19panic-probe = { version = "0.3", features = ["print-defmt"] }
20
21[profile.release]
22debug = 2
diff --git a/examples/stm32f469/build.rs b/examples/stm32f469/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32f469/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs
new file mode 100644
index 000000000..e4e9e9c01
--- /dev/null
+++ b/examples/stm32f469/src/bin/dsi_bsp.rs
@@ -0,0 +1,694 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType};
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::ltdc::Ltdc;
9use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1};
10use embassy_stm32::pac::ltdc::vals::{Bf1, Bf2, Depol, Hspol, Imr, Pcpol, Pf, Vspol};
11use embassy_stm32::pac::{DSIHOST, LTDC};
12use embassy_stm32::rcc::{
13 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk,
14};
15use embassy_stm32::time::mhz;
16use embassy_time::Timer;
17use {defmt_rtt as _, panic_probe as _};
18
19enum _Orientation {
20 Landscape,
21 Portrait,
22}
23
24const _LCD_ORIENTATION: _Orientation = _Orientation::Landscape;
25const LCD_X_SIZE: u16 = 800;
26const LCD_Y_SIZE: u16 = 480;
27
28static FERRIS_IMAGE: &[u8; 1536000] = include_bytes!("ferris.bin");
29
30// This example allows to display an image on the STM32F469NI-DISCO boards
31// with the Revision C, that is at least the boards marked DK32F469I$AU1.
32// These boards have the NT35510 display driver. This example does not work
33// for the older revisions with OTM8009A, though there are lots of C-examples
34// available online where the correct config for the OTM8009A could be gotten from.
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let mut config = embassy_stm32::Config::default();
38 config.rcc.sys = Sysclk::PLL1_P;
39 config.rcc.ahb_pre = AHBPrescaler::DIV1;
40 config.rcc.apb1_pre = APBPrescaler::DIV4;
41 config.rcc.apb2_pre = APBPrescaler::DIV2;
42
43 // HSE is on and ready
44 config.rcc.hse = Some(Hse {
45 freq: mhz(8),
46 mode: HseMode::Oscillator,
47 });
48 config.rcc.pll_src = PllSource::HSE;
49
50 config.rcc.pll = Some(Pll {
51 prediv: PllPreDiv::DIV8, // PLLM
52 mul: PllMul::MUL360, // PLLN
53 divp: Some(PllPDiv::DIV2),
54 divq: Some(PllQDiv::DIV7), // was DIV4, but STM BSP example uses 7
55 divr: Some(PllRDiv::DIV6),
56 });
57
58 // This seems to be working, the values in the RCC.PLLSAICFGR are correct according to the debugger. Also on and ready according to CR
59 config.rcc.pllsai = Some(Pll {
60 prediv: PllPreDiv::DIV8, // Actually ignored
61 mul: PllMul::MUL384, // PLLN
62 divp: None, // PLLP
63 divq: None, // PLLQ
64 divr: Some(PllRDiv::DIV7), // PLLR (Sai actually has special clockdiv register)
65 });
66
67 let p = embassy_stm32::init(config);
68 info!("Starting...");
69
70 let mut led = Output::new(p.PG6, Level::High, Speed::Low);
71
72 // According to UM for the discovery kit, PH7 is an active-low reset for the LCD and touchsensor
73 let mut reset = Output::new(p.PH7, Level::Low, Speed::High);
74
75 // CubeMX example waits 20 ms before de-asserting reset
76 embassy_time::block_for(embassy_time::Duration::from_millis(20));
77
78 // Disable the reset signal and wait 140ms as in the Linux driver (CubeMX waits only 20)
79 reset.set_high();
80 embassy_time::block_for(embassy_time::Duration::from_millis(140));
81
82 let mut ltdc = Ltdc::new(p.LTDC);
83 let mut dsi = DsiHost::new(p.DSIHOST, p.PJ2);
84 let version = dsi.get_version();
85 defmt::warn!("en: {:x}", version);
86
87 // Disable the DSI wrapper
88 dsi.disable_wrapper_dsi();
89
90 // Disable the DSI host
91 dsi.disable();
92
93 // D-PHY clock and digital disable
94 DSIHOST.pctlr().modify(|w| {
95 w.set_cke(false);
96 w.set_den(false)
97 });
98
99 // Turn off the DSI PLL
100 DSIHOST.wrpcr().modify(|w| w.set_pllen(false));
101
102 // Disable the regulator
103 DSIHOST.wrpcr().write(|w| w.set_regen(false));
104
105 // Enable regulator
106 info!("DSIHOST: enabling regulator");
107 DSIHOST.wrpcr().write(|w| w.set_regen(true));
108
109 for _ in 1..1000 {
110 // The regulator status (ready or not) can be monitored with the RRS flag in the DSI_WISR register.
111 // Once it is set, we stop waiting.
112 if DSIHOST.wisr().read().rrs() {
113 info!("DSIHOST Regulator ready");
114 break;
115 }
116 embassy_time::block_for(embassy_time::Duration::from_millis(1));
117 }
118
119 if !DSIHOST.wisr().read().rrs() {
120 defmt::panic!("DSIHOST: enabling regulator FAILED");
121 }
122
123 // Set up PLL and enable it
124 DSIHOST.wrpcr().modify(|w| {
125 w.set_pllen(true);
126 w.set_ndiv(125); // PLL loop division factor set to 125
127 w.set_idf(2); // PLL input divided by 2
128 w.set_odf(0); // PLL output divided by 1
129 });
130
131 /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */
132 const LANE_BYTE_CLK_K_HZ: u16 = 62500; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L224C21-L224C26
133
134 const _LCD_CLOCK: u16 = 27429; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L183
135
136 /* TX_ESCAPE_CKDIV = f(LaneByteClk)/15.62 = 4 */
137 const TX_ESCAPE_CKDIV: u8 = (LANE_BYTE_CLK_K_HZ / 15620) as u8; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L230
138
139 for _ in 1..1000 {
140 embassy_time::block_for(embassy_time::Duration::from_millis(1));
141 // The PLL status (lock or unlock) can be monitored with the PLLLS flag in the DSI_WISR register.
142 // Once it is set, we stop waiting.
143 if DSIHOST.wisr().read().pllls() {
144 info!("DSIHOST PLL locked");
145 break;
146 }
147 }
148
149 if !DSIHOST.wisr().read().pllls() {
150 defmt::panic!("DSIHOST: enabling PLL FAILED");
151 }
152
153 // Set the PHY parameters
154
155 // D-PHY clock and digital enable
156 DSIHOST.pctlr().write(|w| {
157 w.set_cke(true);
158 w.set_den(true);
159 });
160
161 // Set Clock lane to high-speed mode and disable automatic clock lane control
162 DSIHOST.clcr().modify(|w| {
163 w.set_dpcc(true);
164 w.set_acr(false);
165 });
166
167 // Set number of active data lanes to two (lanes 0 and 1)
168 DSIHOST.pconfr().modify(|w| w.set_nl(1));
169
170 // Set the DSI clock parameters
171
172 // Set the TX escape clock division factor to 4
173 DSIHOST.ccr().modify(|w| w.set_txeckdiv(TX_ESCAPE_CKDIV));
174
175 // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4)
176 // The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 )
177 // Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF)
178 // Set the bit period in high-speed mode
179 DSIHOST.wpcr0().modify(|w| w.set_uix4(8)); // 8 is set in the BSP example (confirmed with Debugger)
180
181 // Disable all error interrupts and reset the Error Mask
182 DSIHOST.ier0().write_value(Ier0(0));
183 DSIHOST.ier1().write_value(Ier1(0));
184
185 // Enable this to fix read timeout
186 DSIHOST.pcr().modify(|w| w.set_btae(true));
187
188 const DSI_PIXEL_FORMAT_RGB888: u8 = 0x05;
189 const _DSI_PIXEL_FORMAT_ARGB888: u8 = 0x00;
190
191 const HACT: u16 = LCD_X_SIZE;
192 const VACT: u16 = LCD_Y_SIZE;
193
194 const VSA: u16 = 120;
195 const VBP: u16 = 150;
196 const VFP: u16 = 150;
197 const HSA: u16 = 2;
198 const HBP: u16 = 34;
199 const HFP: u16 = 34;
200
201 const VIRTUAL_CHANNEL_ID: u8 = 0;
202
203 const COLOR_CODING: u8 = DSI_PIXEL_FORMAT_RGB888;
204 const VS_POLARITY: bool = false; // DSI_VSYNC_ACTIVE_HIGH == 0
205 const HS_POLARITY: bool = false; // DSI_HSYNC_ACTIVE_HIGH == 0
206 const DE_POLARITY: bool = false; // DSI_DATA_ENABLE_ACTIVE_HIGH == 0
207 const MODE: u8 = 2; // DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
208 const NULL_PACKET_SIZE: u16 = 0xFFF;
209 const NUMBER_OF_CHUNKS: u16 = 0;
210 const PACKET_SIZE: u16 = HACT; /* Value depending on display orientation choice portrait/landscape */
211 const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16;
212 const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16;
213 const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */
214 // FIXME: Make depend on orientation
215 const VERTICAL_SYNC_ACTIVE: u16 = VSA;
216 const VERTICAL_BACK_PORCH: u16 = VBP;
217 const VERTICAL_FRONT_PORCH: u16 = VFP;
218 const VERTICAL_ACTIVE: u16 = VACT;
219 const LP_COMMAND_ENABLE: bool = true; /* Enable sending commands in mode LP (Low Power) */
220
221 /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */
222 /* Only useful when sending LP packets is allowed while streaming is active in video mode */
223 const LP_LARGEST_PACKET_SIZE: u8 = 16;
224
225 /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
226 /* Only useful when sending LP packets is allowed while streaming is active in video mode */
227 const LPVACT_LARGEST_PACKET_SIZE: u8 = 0;
228
229 const LPHORIZONTAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HFP period */
230 const LPHORIZONTAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HBP period */
231 const LPVERTICAL_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VACT period */
232 const LPVERTICAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VFP period */
233 const LPVERTICAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VBP period */
234 const LPVERTICAL_SYNC_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VSync = VSA period */
235 const FRAME_BTAACKNOWLEDGE_ENABLE: bool = false; /* Frame bus-turn-around acknowledge enable => false according to debugger */
236
237 /* Select video mode by resetting CMDM and DSIM bits */
238 DSIHOST.mcr().modify(|w| w.set_cmdm(false));
239 DSIHOST.wcfgr().modify(|w| w.set_dsim(false));
240
241 /* Configure the video mode transmission type */
242 DSIHOST.vmcr().modify(|w| w.set_vmt(MODE));
243
244 /* Configure the video packet size */
245 DSIHOST.vpcr().modify(|w| w.set_vpsize(PACKET_SIZE));
246
247 /* Set the chunks number to be transmitted through the DSI link */
248 DSIHOST.vccr().modify(|w| w.set_numc(NUMBER_OF_CHUNKS));
249
250 /* Set the size of the null packet */
251 DSIHOST.vnpcr().modify(|w| w.set_npsize(NULL_PACKET_SIZE));
252
253 /* Select the virtual channel for the LTDC interface traffic */
254 DSIHOST.lvcidr().modify(|w| w.set_vcid(VIRTUAL_CHANNEL_ID));
255
256 /* Configure the polarity of control signals */
257 DSIHOST.lpcr().modify(|w| {
258 w.set_dep(DE_POLARITY);
259 w.set_hsp(HS_POLARITY);
260 w.set_vsp(VS_POLARITY);
261 });
262
263 /* Select the color coding for the host */
264 DSIHOST.lcolcr().modify(|w| w.set_colc(COLOR_CODING));
265
266 /* Select the color coding for the wrapper */
267 DSIHOST.wcfgr().modify(|w| w.set_colmux(COLOR_CODING));
268
269 /* Set the Horizontal Synchronization Active (HSA) in lane byte clock cycles */
270 DSIHOST.vhsacr().modify(|w| w.set_hsa(HORIZONTAL_SYNC_ACTIVE));
271
272 /* Set the Horizontal Back Porch (HBP) in lane byte clock cycles */
273 DSIHOST.vhbpcr().modify(|w| w.set_hbp(HORIZONTAL_BACK_PORCH));
274
275 /* Set the total line time (HLINE=HSA+HBP+HACT+HFP) in lane byte clock cycles */
276 DSIHOST.vlcr().modify(|w| w.set_hline(HORIZONTAL_LINE));
277
278 /* Set the Vertical Synchronization Active (VSA) */
279 DSIHOST.vvsacr().modify(|w| w.set_vsa(VERTICAL_SYNC_ACTIVE));
280
281 /* Set the Vertical Back Porch (VBP)*/
282 DSIHOST.vvbpcr().modify(|w| w.set_vbp(VERTICAL_BACK_PORCH));
283
284 /* Set the Vertical Front Porch (VFP)*/
285 DSIHOST.vvfpcr().modify(|w| w.set_vfp(VERTICAL_FRONT_PORCH));
286
287 /* Set the Vertical Active period*/
288 DSIHOST.vvacr().modify(|w| w.set_va(VERTICAL_ACTIVE));
289
290 /* Configure the command transmission mode */
291 DSIHOST.vmcr().modify(|w| w.set_lpce(LP_COMMAND_ENABLE));
292
293 /* Low power largest packet size */
294 DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
295
296 /* Low power VACT largest packet size */
297 DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
298 DSIHOST.lpmcr().modify(|w| w.set_vlpsize(LPVACT_LARGEST_PACKET_SIZE));
299
300 /* Enable LP transition in HFP period */
301 DSIHOST.vmcr().modify(|w| w.set_lphfpe(LPHORIZONTAL_FRONT_PORCH_ENABLE));
302
303 /* Enable LP transition in HBP period */
304 DSIHOST.vmcr().modify(|w| w.set_lphbpe(LPHORIZONTAL_BACK_PORCH_ENABLE));
305
306 /* Enable LP transition in VACT period */
307 DSIHOST.vmcr().modify(|w| w.set_lpvae(LPVERTICAL_ACTIVE_ENABLE));
308
309 /* Enable LP transition in VFP period */
310 DSIHOST.vmcr().modify(|w| w.set_lpvfpe(LPVERTICAL_FRONT_PORCH_ENABLE));
311
312 /* Enable LP transition in VBP period */
313 DSIHOST.vmcr().modify(|w| w.set_lpvbpe(LPVERTICAL_BACK_PORCH_ENABLE));
314
315 /* Enable LP transition in vertical sync period */
316 DSIHOST.vmcr().modify(|w| w.set_lpvsae(LPVERTICAL_SYNC_ACTIVE_ENABLE));
317
318 /* Enable the request for an acknowledge response at the end of a frame */
319 DSIHOST.vmcr().modify(|w| w.set_fbtaae(FRAME_BTAACKNOWLEDGE_ENABLE));
320
321 /* Configure DSI PHY HS2LP and LP2HS timings */
322 const CLOCK_LANE_HS2_LPTIME: u16 = 35;
323 const CLOCK_LANE_LP2_HSTIME: u16 = 35;
324 const DATA_LANE_HS2_LPTIME: u8 = 35;
325 const DATA_LANE_LP2_HSTIME: u8 = 35;
326 const DATA_LANE_MAX_READ_TIME: u16 = 0;
327 const STOP_WAIT_TIME: u8 = 10;
328
329 const MAX_TIME: u16 = if CLOCK_LANE_HS2_LPTIME > CLOCK_LANE_LP2_HSTIME {
330 CLOCK_LANE_HS2_LPTIME
331 } else {
332 CLOCK_LANE_LP2_HSTIME
333 };
334
335 /* Clock lane timer configuration */
336
337 /* In Automatic Clock Lane control mode, the DSI Host can turn off the clock lane between two
338 High-Speed transmission.
339 To do so, the DSI Host calculates the time required for the clock lane to change from HighSpeed
340 to Low-Power and from Low-Power to High-Speed.
341 This timings are configured by the HS2LP_TIME and LP2HS_TIME in the DSI Host Clock Lane Timer Configuration
342 Register (DSI_CLTCR).
343 But the DSI Host is not calculating LP2HS_TIME + HS2LP_TIME but 2 x HS2LP_TIME.
344
345 Workaround : Configure HS2LP_TIME and LP2HS_TIME with the same value being the max of HS2LP_TIME or LP2HS_TIME.
346 */
347
348 DSIHOST.cltcr().modify(|w| {
349 w.set_hs2lp_time(MAX_TIME);
350 w.set_lp2hs_time(MAX_TIME)
351 });
352
353 // Data lane timer configuration
354 DSIHOST.dltcr().modify(|w| {
355 w.set_hs2lp_time(DATA_LANE_HS2_LPTIME);
356 w.set_lp2hs_time(DATA_LANE_LP2_HSTIME);
357 w.set_mrd_time(DATA_LANE_MAX_READ_TIME);
358 });
359
360 // Configure the wait period to request HS transmission after a stop state
361 DSIHOST.pconfr().modify(|w| w.set_sw_time(STOP_WAIT_TIME));
362
363 const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0
364
365 const LTDC_DE_POLARITY: Depol = if !DE_POLARITY {
366 Depol::ACTIVELOW
367 } else {
368 Depol::ACTIVEHIGH
369 };
370 const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY {
371 Vspol::ACTIVEHIGH
372 } else {
373 Vspol::ACTIVELOW
374 };
375
376 const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY {
377 Hspol::ACTIVEHIGH
378 } else {
379 Hspol::ACTIVELOW
380 };
381
382 /* Timing Configuration */
383 const HORIZONTAL_SYNC: u16 = HSA - 1;
384 const VERTICAL_SYNC: u16 = VERTICAL_SYNC_ACTIVE - 1;
385 const ACCUMULATED_HBP: u16 = HSA + HBP - 1;
386 const ACCUMULATED_VBP: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH - 1;
387 const ACCUMULATED_ACTIVE_W: u16 = LCD_X_SIZE + HSA + HBP - 1;
388 const ACCUMULATED_ACTIVE_H: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE - 1;
389 const TOTAL_WIDTH: u16 = LCD_X_SIZE + HSA + HBP + HFP - 1;
390 const TOTAL_HEIGHT: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE + VERTICAL_FRONT_PORCH - 1;
391
392 // DISABLE LTDC before making changes
393 ltdc.disable();
394
395 // Configure the HS, VS, DE and PC polarity
396 LTDC.gcr().modify(|w| {
397 w.set_hspol(LTDC_HS_POLARITY);
398 w.set_vspol(LTDC_VS_POLARITY);
399 w.set_depol(LTDC_DE_POLARITY);
400 w.set_pcpol(Pcpol::RISINGEDGE);
401 });
402
403 // Set Synchronization size
404 LTDC.sscr().modify(|w| {
405 w.set_hsw(HORIZONTAL_SYNC);
406 w.set_vsh(VERTICAL_SYNC)
407 });
408
409 // Set Accumulated Back porch
410 LTDC.bpcr().modify(|w| {
411 w.set_ahbp(ACCUMULATED_HBP);
412 w.set_avbp(ACCUMULATED_VBP);
413 });
414
415 // Set Accumulated Active Width
416 LTDC.awcr().modify(|w| {
417 w.set_aah(ACCUMULATED_ACTIVE_H);
418 w.set_aaw(ACCUMULATED_ACTIVE_W);
419 });
420
421 // Set Total Width
422 LTDC.twcr().modify(|w| {
423 w.set_totalh(TOTAL_HEIGHT);
424 w.set_totalw(TOTAL_WIDTH);
425 });
426
427 // Set the background color value
428 LTDC.bccr().modify(|w| {
429 w.set_bcred(0);
430 w.set_bcgreen(0);
431 w.set_bcblue(0)
432 });
433
434 // Enable the Transfer Error and FIFO underrun interrupts
435 LTDC.ier().modify(|w| {
436 w.set_terrie(true);
437 w.set_fuie(true);
438 });
439
440 // ENABLE LTDC after making changes
441 ltdc.enable();
442
443 dsi.enable();
444 dsi.enable_wrapper_dsi();
445
446 // First, delay 120 ms (reason unknown, STM32 Cube Example does it)
447 blocking_delay_ms(120);
448
449 // 1 to 26
450 dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap();
451 dsi.write_cmd(0, NT35510_WRITES_1[0], &NT35510_WRITES_1[1..]).unwrap();
452 dsi.write_cmd(0, NT35510_WRITES_2[0], &NT35510_WRITES_2[1..]).unwrap();
453 dsi.write_cmd(0, NT35510_WRITES_3[0], &NT35510_WRITES_3[1..]).unwrap();
454 dsi.write_cmd(0, NT35510_WRITES_4[0], &NT35510_WRITES_4[1..]).unwrap();
455 dsi.write_cmd(0, NT35510_WRITES_5[0], &NT35510_WRITES_5[1..]).unwrap();
456 dsi.write_cmd(0, NT35510_WRITES_6[0], &NT35510_WRITES_6[1..]).unwrap();
457 dsi.write_cmd(0, NT35510_WRITES_7[0], &NT35510_WRITES_7[1..]).unwrap();
458 dsi.write_cmd(0, NT35510_WRITES_8[0], &NT35510_WRITES_8[1..]).unwrap();
459 dsi.write_cmd(0, NT35510_WRITES_9[0], &NT35510_WRITES_9[1..]).unwrap();
460 dsi.write_cmd(0, NT35510_WRITES_10[0], &NT35510_WRITES_10[1..]).unwrap();
461 // 11 missing
462 dsi.write_cmd(0, NT35510_WRITES_12[0], &NT35510_WRITES_12[1..]).unwrap();
463 dsi.write_cmd(0, NT35510_WRITES_13[0], &NT35510_WRITES_13[1..]).unwrap();
464 dsi.write_cmd(0, NT35510_WRITES_14[0], &NT35510_WRITES_14[1..]).unwrap();
465 dsi.write_cmd(0, NT35510_WRITES_15[0], &NT35510_WRITES_15[1..]).unwrap();
466 dsi.write_cmd(0, NT35510_WRITES_16[0], &NT35510_WRITES_16[1..]).unwrap();
467 dsi.write_cmd(0, NT35510_WRITES_17[0], &NT35510_WRITES_17[1..]).unwrap();
468 dsi.write_cmd(0, NT35510_WRITES_18[0], &NT35510_WRITES_18[1..]).unwrap();
469 dsi.write_cmd(0, NT35510_WRITES_19[0], &NT35510_WRITES_19[1..]).unwrap();
470 dsi.write_cmd(0, NT35510_WRITES_20[0], &NT35510_WRITES_20[1..]).unwrap();
471 dsi.write_cmd(0, NT35510_WRITES_21[0], &NT35510_WRITES_21[1..]).unwrap();
472 dsi.write_cmd(0, NT35510_WRITES_22[0], &NT35510_WRITES_22[1..]).unwrap();
473 dsi.write_cmd(0, NT35510_WRITES_23[0], &NT35510_WRITES_23[1..]).unwrap();
474 dsi.write_cmd(0, NT35510_WRITES_24[0], &NT35510_WRITES_24[1..]).unwrap();
475
476 // Tear on
477 dsi.write_cmd(0, NT35510_WRITES_26[0], &NT35510_WRITES_26[1..]).unwrap();
478
479 // Set Pixel color format to RGB888
480 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
481
482 // Add a delay, otherwise MADCTL not taken
483 blocking_delay_ms(200);
484
485 // Configure orientation as landscape
486 dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..])
487 .unwrap();
488 dsi.write_cmd(0, NT35510_CASET_LANDSCAPE[0], &NT35510_CASET_LANDSCAPE[1..])
489 .unwrap();
490 dsi.write_cmd(0, NT35510_RASET_LANDSCAPE[0], &NT35510_RASET_LANDSCAPE[1..])
491 .unwrap();
492
493 // Sleep out
494 dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap();
495
496 // Wait for sleep out exit
497 blocking_delay_ms(120);
498
499 // Configure COLOR_CODING
500 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
501
502 /* CABC : Content Adaptive Backlight Control section start >> */
503 /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */
504 dsi.write_cmd(0, NT35510_WRITES_31[0], &NT35510_WRITES_31[1..]).unwrap();
505 /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */
506 dsi.write_cmd(0, NT35510_WRITES_32[0], &NT35510_WRITES_32[1..]).unwrap();
507 /* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */
508 dsi.write_cmd(0, NT35510_WRITES_33[0], &NT35510_WRITES_33[1..]).unwrap();
509 /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */
510 dsi.write_cmd(0, NT35510_WRITES_34[0], &NT35510_WRITES_34[1..]).unwrap();
511 /* CABC : Content Adaptive Backlight Control section end << */
512 /* Display on */
513 dsi.write_cmd(0, NT35510_WRITES_30[0], &NT35510_WRITES_30[1..]).unwrap();
514
515 /* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */
516 /* DSI host from LTDC incoming pixels in video mode */
517 dsi.write_cmd(0, NT35510_WRITES_35[0], &NT35510_WRITES_35[1..]).unwrap();
518
519 /* Initialize the LCD pixel width and pixel height */
520 const WINDOW_X0: u16 = 0;
521 const WINDOW_X1: u16 = LCD_X_SIZE; // 480 for ferris
522 const WINDOW_Y0: u16 = 0;
523 const WINDOW_Y1: u16 = LCD_Y_SIZE; // 800 for ferris
524 const PIXEL_FORMAT: Pf = Pf::ARGB8888;
525 //const FBStartAdress: u16 = FB_Address;
526 const ALPHA: u8 = 255;
527 const ALPHA0: u8 = 0;
528 const BACKCOLOR_BLUE: u8 = 0;
529 const BACKCOLOR_GREEN: u8 = 0;
530 const BACKCOLOR_RED: u8 = 0;
531 const IMAGE_WIDTH: u16 = LCD_X_SIZE; // 480 for ferris
532 const IMAGE_HEIGHT: u16 = LCD_Y_SIZE; // 800 for ferris
533
534 const PIXEL_SIZE: u8 = match PIXEL_FORMAT {
535 Pf::ARGB8888 => 4,
536 Pf::RGB888 => 3,
537 Pf::ARGB4444 | Pf::RGB565 | Pf::ARGB1555 | Pf::AL88 => 2,
538 _ => 1,
539 };
540
541 // Configure the horizontal start and stop position
542 LTDC.layer(0).whpcr().write(|w| {
543 w.set_whstpos(LTDC.bpcr().read().ahbp() + 1 + WINDOW_X0);
544 w.set_whsppos(LTDC.bpcr().read().ahbp() + WINDOW_X1);
545 });
546
547 // Configures the vertical start and stop position
548 LTDC.layer(0).wvpcr().write(|w| {
549 w.set_wvstpos(LTDC.bpcr().read().avbp() + 1 + WINDOW_Y0);
550 w.set_wvsppos(LTDC.bpcr().read().avbp() + WINDOW_Y1);
551 });
552
553 // Specify the pixel format
554 LTDC.layer(0).pfcr().write(|w| w.set_pf(PIXEL_FORMAT));
555
556 // Configures the default color values as zero
557 LTDC.layer(0).dccr().modify(|w| {
558 w.set_dcblue(BACKCOLOR_BLUE);
559 w.set_dcgreen(BACKCOLOR_GREEN);
560 w.set_dcred(BACKCOLOR_RED);
561 w.set_dcalpha(ALPHA0);
562 });
563
564 // Specifies the constant ALPHA value
565 LTDC.layer(0).cacr().write(|w| w.set_consta(ALPHA));
566
567 // Specifies the blending factors
568 LTDC.layer(0).bfcr().write(|w| {
569 w.set_bf1(Bf1::CONSTANT);
570 w.set_bf2(Bf2::CONSTANT);
571 });
572
573 // Configure the color frame buffer start address
574 let fb_start_address: u32 = &FERRIS_IMAGE[0] as *const _ as u32;
575 info!("Setting Framebuffer Start Address: {:010x}", fb_start_address);
576 LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(fb_start_address));
577
578 // Configures the color frame buffer pitch in byte
579 LTDC.layer(0).cfblr().write(|w| {
580 w.set_cfbp(IMAGE_WIDTH * PIXEL_SIZE as u16);
581 w.set_cfbll(((WINDOW_X1 - WINDOW_X0) * PIXEL_SIZE as u16) + 3);
582 });
583
584 // Configures the frame buffer line number
585 LTDC.layer(0).cfblnr().write(|w| w.set_cfblnbr(IMAGE_HEIGHT));
586
587 // Enable LTDC_Layer by setting LEN bit
588 LTDC.layer(0).cr().modify(|w| w.set_len(true));
589
590 //LTDC->SRCR = LTDC_SRCR_IMR;
591 LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD));
592
593 blocking_delay_ms(5000);
594
595 const READ_SIZE: u16 = 1;
596 let mut data = [1u8; READ_SIZE as usize];
597 dsi.read(0, PacketType::DcsShortPktRead(0xDA), READ_SIZE, &mut data)
598 .unwrap();
599 info!("Display ID1: {:#04x}", data);
600
601 dsi.read(0, PacketType::DcsShortPktRead(0xDB), READ_SIZE, &mut data)
602 .unwrap();
603 info!("Display ID2: {:#04x}", data);
604
605 dsi.read(0, PacketType::DcsShortPktRead(0xDC), READ_SIZE, &mut data)
606 .unwrap();
607 info!("Display ID3: {:#04x}", data);
608
609 blocking_delay_ms(500);
610
611 info!("Config done, start blinking LED");
612 loop {
613 led.set_high();
614 Timer::after_millis(1000).await;
615
616 // Increase screen brightness
617 dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0xFF]).unwrap();
618
619 led.set_low();
620 Timer::after_millis(1000).await;
621
622 // Reduce screen brightness
623 dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0x50]).unwrap();
624 }
625}
626
627const NT35510_WRITES_0: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01]; // LV2: Page 1 enable
628const NT35510_WRITES_1: &[u8] = &[0xB0, 0x03, 0x03, 0x03]; // AVDD: 5.2V
629const NT35510_WRITES_2: &[u8] = &[0xB6, 0x46, 0x46, 0x46]; // AVDD: Ratio
630const NT35510_WRITES_3: &[u8] = &[0xB1, 0x03, 0x03, 0x03]; // AVEE: -5.2V
631const NT35510_WRITES_4: &[u8] = &[0xB7, 0x36, 0x36, 0x36]; // AVEE: Ratio
632const NT35510_WRITES_5: &[u8] = &[0xB2, 0x00, 0x00, 0x02]; // VCL: -2.5V
633const NT35510_WRITES_6: &[u8] = &[0xB8, 0x26, 0x26, 0x26]; // VCL: Ratio
634const NT35510_WRITES_7: &[u8] = &[0xBF, 0x01]; // VGH: 15V (Free Pump)
635const NT35510_WRITES_8: &[u8] = &[0xB3, 0x09, 0x09, 0x09];
636const NT35510_WRITES_9: &[u8] = &[0xB9, 0x36, 0x36, 0x36]; // VGH: Ratio
637const NT35510_WRITES_10: &[u8] = &[0xB5, 0x08, 0x08, 0x08]; // VGL_REG: -10V
638const NT35510_WRITES_12: &[u8] = &[0xBA, 0x26, 0x26, 0x26]; // VGLX: Ratio
639const NT35510_WRITES_13: &[u8] = &[0xBC, 0x00, 0x80, 0x00]; // VGMP/VGSP: 4.5V/0V
640const NT35510_WRITES_14: &[u8] = &[0xBD, 0x00, 0x80, 0x00]; // VGMN/VGSN:-4.5V/0V
641const NT35510_WRITES_15: &[u8] = &[0xBE, 0x00, 0x50]; // VCOM: -1.325V
642const NT35510_WRITES_16: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00]; // LV2: Page 0 enable
643const NT35510_WRITES_17: &[u8] = &[0xB1, 0xFC, 0x00]; // Display control
644const NT35510_WRITES_18: &[u8] = &[0xB6, 0x03]; // Src hold time
645const NT35510_WRITES_19: &[u8] = &[0xB5, 0x51];
646const NT35510_WRITES_20: &[u8] = &[0x00, 0x00, 0xB7]; // Gate EQ control
647const NT35510_WRITES_21: &[u8] = &[0xB8, 0x01, 0x02, 0x02, 0x02]; // Src EQ control(Mode2)
648const NT35510_WRITES_22: &[u8] = &[0xBC, 0x00, 0x00, 0x00]; // Inv. mode(2-dot)
649const NT35510_WRITES_23: &[u8] = &[0xCC, 0x03, 0x00, 0x00];
650const NT35510_WRITES_24: &[u8] = &[0xBA, 0x01];
651
652const _NT35510_MADCTL_PORTRAIT: &[u8] = &[NT35510_CMD_MADCTL, 0x00];
653const _NT35510_CASET_PORTRAIT: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x01, 0xDF];
654const _NT35510_RASET_PORTRAIT: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x03, 0x1F];
655const NT35510_MADCTL_LANDSCAPE: &[u8] = &[NT35510_CMD_MADCTL, 0x60];
656const NT35510_CASET_LANDSCAPE: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x03, 0x1F];
657const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0xDF];
658
659const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on
660const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out
661 // 28,29 missing
662const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on
663
664const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F];
665const NT35510_WRITES_32: &[u8] = &[NT35510_CMD_WRCTRLD, 0x2C];
666const NT35510_WRITES_33: &[u8] = &[NT35510_CMD_WRCABC, 0x02];
667const NT35510_WRITES_34: &[u8] = &[NT35510_CMD_WRCABCMB, 0xFF];
668const NT35510_WRITES_35: &[u8] = &[NT35510_CMD_RAMWR, 0x00];
669
670//const NT35510_WRITES_36: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB565]; // FIXME: Example sets it to 888 but rest of the code seems to configure DSI for 565
671const NT35510_WRITES_37: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB888];
672
673// More of these: https://elixir.bootlin.com/linux/latest/source/include/video/mipi_display.h#L83
674const _NT35510_CMD_TEEON_GET_DISPLAY_ID: u8 = 0x04;
675
676const NT35510_CMD_TEEON: u8 = 0x35;
677const NT35510_CMD_MADCTL: u8 = 0x36;
678
679const NT35510_CMD_SLPOUT: u8 = 0x11;
680const NT35510_CMD_DISPON: u8 = 0x29;
681const NT35510_CMD_CASET: u8 = 0x2A;
682const NT35510_CMD_RASET: u8 = 0x2B;
683const NT35510_CMD_RAMWR: u8 = 0x2C; /* Memory write */
684const NT35510_CMD_COLMOD: u8 = 0x3A;
685
686const NT35510_CMD_WRDISBV: u8 = 0x51; /* Write display brightness */
687const _NT35510_CMD_RDDISBV: u8 = 0x52; /* Read display brightness */
688const NT35510_CMD_WRCTRLD: u8 = 0x53; /* Write CTRL display */
689const _NT35510_CMD_RDCTRLD: u8 = 0x54; /* Read CTRL display value */
690const NT35510_CMD_WRCABC: u8 = 0x55; /* Write content adaptative brightness control */
691const NT35510_CMD_WRCABCMB: u8 = 0x5E; /* Write CABC minimum brightness */
692
693const _NT35510_COLMOD_RGB565: u8 = 0x55;
694const NT35510_COLMOD_RGB888: u8 = 0x77;
diff --git a/examples/stm32f469/src/bin/ferris.bin b/examples/stm32f469/src/bin/ferris.bin
new file mode 100644
index 000000000..ae1c466be
--- /dev/null
+++ b/examples/stm32f469/src/bin/ferris.bin
@@ -0,0 +1,70 @@
1��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������f���2���
2���
3���
4�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������=���
5�������������������������������������������������������������������������������������������������������������������������������I���
6���
7�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%���
8���
9���
10���
11���������������������������������������������������������������������������������������������������������������������������T���
12���������������������������������������������������������������������������������������������������2���
13���=���c�����������������������������������G���
14
15
16�
17e��
18
19
20�������������������������������������������������������������������������������������������������������������������������hhh�
21_��
22_��
23�
24(�
25�
26.�
271�
28-�
29�
30.��
31.��Yb��������������
32M��
33.��S]����������������������������������
34.��
35.��
36-�
37.��
38.��
39.��v{������������������������������_f��%9��,��
405�
41.��
42L����������������������������������������������������������������������������������������������
43.��|������������������������������������������������������������������
44-�
45.��
46�
47�
48M��
493�
50-�
510�
522�
53.�
54'�
55.����������������������������������������������������������������������������������������������%T��
56M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������lx��
576�
58M��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fu��
593�
60M��
61/�
622�
63J��
64.��
65.����������������������������������������������������������������������������������������������������������Sl��
66H��
67M��
68.��
69M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������q|��O��
70M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(T��
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index a612c2554..8c591ebd2 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -7,12 +7,13 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f777zi to your chip name, if necessary. 8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embedded-io-async = { version = "0.6.1" } 14embedded-io-async = { version = "0.6.1" }
15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 17
17defmt = "0.3" 18defmt = "0.3"
18defmt-rtt = "0.4" 19defmt-rtt = "0.4"
@@ -21,7 +22,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
21cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26nb = "1.0.0" 26nb = "1.0.0"
27rand_core = "0.6.3" 27rand_core = "0.6.3"
@@ -29,6 +29,8 @@ critical-section = "1.1"
29embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
30static_cell = "2" 30static_cell = "2"
31sha2 = { version = "0.10.8", default-features = false } 31sha2 = { version = "0.10.8", default-features = false }
32hmac = "0.12.1"
33aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
32 34
33[profile.release] 35[profile.release]
34debug = 2 36debug = 2
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index f8d7b691f..6689e3b5d 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::Adc; 6use embassy_stm32::adc::Adc;
7use embassy_time::{Delay, Timer}; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,11 +12,11 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let mut adc = Adc::new(p.ADC1, &mut Delay); 15 let mut adc = Adc::new(p.ADC1);
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/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index bcfdb67a8..a82e335a9 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -1,16 +1,18 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::num::{NonZeroU16, NonZeroU8};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::bind_interrupts; 8use embassy_stm32::can::filter::Mask32;
7use embassy_stm32::can::bxcan::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
9use embassy_stm32::can::{ 9use embassy_stm32::can::{
10 Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, 10 Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
11 TxInterruptHandler,
11}; 12};
12use embassy_stm32::gpio::{Input, Pull}; 13use embassy_stm32::gpio::{Input, Pull};
13use embassy_stm32::peripherals::CAN3; 14use embassy_stm32::peripherals::CAN3;
15use embassy_stm32::{bind_interrupts, can};
14use static_cell::StaticCell; 16use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
16 18
@@ -22,9 +24,9 @@ bind_interrupts!(struct Irqs {
22}); 24});
23 25
24#[embassy_executor::task] 26#[embassy_executor::task]
25pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { 27pub async fn send_can_message(tx: &'static mut CanTx<'static>) {
26 loop { 28 loop {
27 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); 29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
28 tx.write(&frame).await; 30 tx.write(&frame).await;
29 embassy_time::Timer::after_secs(1).await; 31 embassy_time::Timer::after_secs(1).await;
30 } 32 }
@@ -43,21 +45,24 @@ async fn main(spawner: Spawner) {
43 let rx_pin = Input::new(&mut p.PA15, Pull::Up); 45 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
44 core::mem::forget(rx_pin); 46 core::mem::forget(rx_pin);
45 47
46 static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); 48 static CAN: StaticCell<Can<'static>> = StaticCell::new();
47 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); 49 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
48 can.as_mut() 50 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
49 .modify_filters() 51
50 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 52 can.modify_config()
53 .set_bit_timing(can::util::NominalBitTiming {
54 prescaler: NonZeroU16::new(2).unwrap(),
55 seg1: NonZeroU8::new(13).unwrap(),
56 seg2: NonZeroU8::new(2).unwrap(),
57 sync_jump_width: NonZeroU8::new(1).unwrap(),
58 }) // http://www.bittiming.can-wiki.info/
59 .set_loopback(true);
51 60
52 can.as_mut() 61 can.enable().await;
53 .modify_config()
54 .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
55 .set_loopback(true)
56 .enable();
57 62
58 let (tx, mut rx) = can.split(); 63 let (tx, mut rx) = can.split();
59 64
60 static CAN_TX: StaticCell<CanTx<'static, 'static, CAN3>> = StaticCell::new(); 65 static CAN_TX: StaticCell<CanTx<'static>> = StaticCell::new();
61 let tx = CAN_TX.init(tx); 66 let tx = CAN_TX.init(tx);
62 spawner.spawn(send_can_message(tx)).unwrap(); 67 spawner.spawn(send_can_message(tx)).unwrap();
63 68
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
new file mode 100644
index 000000000..235853cb9
--- /dev/null
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -0,0 +1,80 @@
1#![no_std]
2#![no_main]
3
4use aes_gcm::aead::heapless::Vec;
5use aes_gcm::aead::{AeadInPlace, KeyInit};
6use aes_gcm::Aes128Gcm;
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_stm32::cryp::{self, *};
10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_time::Instant;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 CRYP => cryp::InterruptHandler<peripherals::CRYP>;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 let config = Config::default();
21 let p = embassy_stm32::init(config);
22
23 let payload: &[u8] = b"hello world";
24 let aad: &[u8] = b"additional data";
25
26 let mut hw_cryp = Cryp::new(p.CRYP, p.DMA2_CH6, p.DMA2_CH5, Irqs);
27 let key: [u8; 16] = [0; 16];
28 let mut ciphertext: [u8; 11] = [0; 11];
29 let mut plaintext: [u8; 11] = [0; 11];
30 let iv: [u8; 12] = [0; 12];
31
32 let hw_start_time = Instant::now();
33
34 // Encrypt in hardware using AES-GCM 128-bit
35 let aes_gcm = AesGcm::new(&key, &iv);
36 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt).await;
37 hw_cryp.aad(&mut gcm_encrypt, aad, true).await;
38 hw_cryp.payload(&mut gcm_encrypt, payload, &mut ciphertext, true).await;
39 let encrypt_tag = hw_cryp.finish(gcm_encrypt).await;
40
41 // Decrypt in hardware using AES-GCM 128-bit
42 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await;
43 hw_cryp.aad(&mut gcm_decrypt, aad, true).await;
44 hw_cryp
45 .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true)
46 .await;
47 let decrypt_tag = hw_cryp.finish(gcm_decrypt).await;
48
49 let hw_end_time = Instant::now();
50 let hw_execution_time = hw_end_time - hw_start_time;
51
52 info!("AES-GCM Ciphertext: {:?}", ciphertext);
53 info!("AES-GCM Plaintext: {:?}", plaintext);
54 assert_eq!(payload, plaintext);
55 assert_eq!(encrypt_tag, decrypt_tag);
56
57 let sw_start_time = Instant::now();
58
59 // Encrypt in software using AES-GCM 128-bit
60 let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
61 let cipher = Aes128Gcm::new(&key.into());
62 let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
63
64 assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]);
65 assert_eq!(
66 encrypt_tag,
67 payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
68 );
69
70 // Decrypt in software using AES-GCM 128-bit
71 let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
72
73 let sw_end_time = Instant::now();
74 let sw_execution_time = sw_end_time - sw_start_time;
75
76 info!("Hardware Execution Time: {:?}", hw_execution_time);
77 info!("Software Execution Time: {:?}", sw_execution_time);
78
79 loop {}
80}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 9a608e909..1f1eadf37 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -63,9 +63,9 @@ async fn main(spawner: Spawner) -> ! {
63 63
64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
65 65
66 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 66 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
67 let device = Ethernet::new( 67 let device = Ethernet::new(
68 PACKETS.init(PacketQueue::<16, 16>::new()), 68 PACKETS.init(PacketQueue::<4, 4>::new()),
69 p.ETH, 69 p.ETH,
70 Irqs, 70 Irqs,
71 p.PA1, 71 p.PA1,
@@ -89,17 +89,11 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 89 //});
90 90
91 // Init network stack 91 // Init network stack
92 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 93 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 let stack = &*STACK.init(Stack::new(
95 device,
96 config,
97 RESOURCES.init(StackResources::<2>::new()),
98 seed,
99 ));
100 94
101 // Launch network task 95 // Launch network task
102 unwrap!(spawner.spawn(net_task(stack))); 96 unwrap!(spawner.spawn(net_task(runner)));
103 97
104 // Ensure DHCP configuration is up before trying connect 98 // Ensure DHCP configuration is up before trying connect
105 stack.wait_config_up().await; 99 stack.wait_config_up().await;
@@ -111,7 +105,7 @@ async fn main(spawner: Spawner) -> ! {
111 let mut tx_buffer = [0; 4096]; 105 let mut tx_buffer = [0; 4096];
112 106
113 loop { 107 loop {
114 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 108 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
115 109
116 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 110 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
117 111
diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs
index 96e50f84b..c2d1a7158 100644
--- a/examples/stm32f7/src/bin/hash.rs
+++ b/examples/stm32f7/src/bin/hash.rs
@@ -6,9 +6,12 @@ use embassy_executor::Spawner;
6use embassy_stm32::hash::*; 6use embassy_stm32::hash::*;
7use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; 7use embassy_stm32::{bind_interrupts, hash, peripherals, Config};
8use embassy_time::Instant; 8use embassy_time::Instant;
9use hmac::{Hmac, Mac};
9use sha2::{Digest, Sha256}; 10use sha2::{Digest, Sha256};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
13type HmacSha256 = Hmac<Sha256>;
14
12bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
13 HASH_RNG => hash::InterruptHandler<peripherals::HASH>; 16 HASH_RNG => hash::InterruptHandler<peripherals::HASH>;
14}); 17});
@@ -26,7 +29,7 @@ async fn main(_spawner: Spawner) -> ! {
26 let hw_start_time = Instant::now(); 29 let hw_start_time = Instant::now();
27 30
28 // Compute a digest in hardware. 31 // Compute a digest in hardware.
29 let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); 32 let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None);
30 hw_hasher.update(&mut context, test_1).await; 33 hw_hasher.update(&mut context, test_1).await;
31 hw_hasher.update(&mut context, test_2).await; 34 hw_hasher.update(&mut context, test_2).await;
32 let mut hw_digest: [u8; 32] = [0; 32]; 35 let mut hw_digest: [u8; 32] = [0; 32];
@@ -52,5 +55,24 @@ async fn main(_spawner: Spawner) -> ! {
52 info!("Software Execution Time: {:?}", sw_execution_time); 55 info!("Software Execution Time: {:?}", sw_execution_time);
53 assert_eq!(hw_digest, sw_digest[..]); 56 assert_eq!(hw_digest, sw_digest[..]);
54 57
58 let hmac_key: [u8; 64] = [0x55; 64];
59
60 // Compute HMAC in hardware.
61 let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key));
62 hw_hasher.update(&mut sha256hmac_context, test_1).await;
63 hw_hasher.update(&mut sha256hmac_context, test_2).await;
64 let mut hw_hmac: [u8; 32] = [0; 32];
65 hw_hasher.finish(sha256hmac_context, &mut hw_hmac).await;
66
67 // Compute HMAC in software.
68 let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap();
69 sw_mac.update(test_1);
70 sw_mac.update(test_2);
71 let sw_hmac = sw_mac.finalize().into_bytes();
72
73 info!("Hardware HMAC: {:?}", hw_hmac);
74 info!("Software HMAC: {:?}", sw_hmac[..]);
75 assert_eq!(hw_hmac, sw_hmac[..]);
76
55 loop {} 77 loop {}
56} 78}
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs
new file mode 100644
index 000000000..90d319b7a
--- /dev/null
+++ b/examples/stm32f7/src/bin/qspi.rs
@@ -0,0 +1,301 @@
1#![no_std]
2#![no_main]
3#![allow(dead_code)] // Allow dead code as not all commands are used in the example
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_stm32::mode::Async;
8use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *};
9use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig};
10use embassy_stm32::time::mhz;
11use embassy_stm32::Config as StmCfg;
12use {defmt_rtt as _, panic_probe as _};
13
14const MEMORY_PAGE_SIZE: usize = 256;
15
16const CMD_READ: u8 = 0x03;
17const CMD_HS_READ: u8 = 0x0B;
18const CMD_QUAD_READ: u8 = 0x6B;
19
20const CMD_WRITE_PG: u8 = 0xF2;
21const CMD_QUAD_WRITE_PG: u8 = 0x32;
22
23const CMD_READ_ID: u8 = 0x9F;
24const CMD_READ_UUID: u8 = 0x4B;
25
26const CMD_ENABLE_RESET: u8 = 0x66;
27const CMD_RESET: u8 = 0x99;
28
29const CMD_WRITE_ENABLE: u8 = 0x06;
30const CMD_WRITE_DISABLE: u8 = 0x04;
31
32const CMD_CHIP_ERASE: u8 = 0xC7;
33const CMD_SECTOR_ERASE: u8 = 0x20;
34const CMD_BLOCK_ERASE_32K: u8 = 0x52;
35const CMD_BLOCK_ERASE_64K: u8 = 0xD8;
36
37const CMD_READ_SR: u8 = 0x05;
38const CMD_READ_CR: u8 = 0x35;
39
40const CMD_WRITE_SR: u8 = 0x01;
41const CMD_WRITE_CR: u8 = 0x31;
42const MEMORY_ADDR: u32 = 0x00000000u32;
43
44/// Implementation of access to flash chip.
45/// Chip commands are hardcoded as it depends on used chip.
46/// This implementation is using chip GD25Q64C from Giga Device
47pub struct FlashMemory<I: Instance> {
48 qspi: Qspi<'static, I, Async>,
49}
50
51impl<I: Instance> FlashMemory<I> {
52 pub fn new(qspi: Qspi<'static, I, Async>) -> Self {
53 let mut memory = Self { qspi };
54
55 memory.reset_memory();
56 memory.enable_quad();
57
58 memory
59 }
60
61 fn enable_quad(&mut self) {
62 let cr = self.read_cr();
63 self.write_cr(cr | 0x02);
64 }
65
66 fn exec_command(&mut self, cmd: u8) {
67 let transaction = TransferConfig {
68 iwidth: QspiWidth::SING,
69 awidth: QspiWidth::NONE,
70 dwidth: QspiWidth::NONE,
71 instruction: cmd,
72 address: None,
73 dummy: DummyCycles::_0,
74 };
75 self.qspi.command(transaction);
76 }
77
78 pub fn reset_memory(&mut self) {
79 self.exec_command(CMD_ENABLE_RESET);
80 self.exec_command(CMD_RESET);
81 self.wait_write_finish();
82 }
83
84 pub fn enable_write(&mut self) {
85 self.exec_command(CMD_WRITE_ENABLE);
86 }
87
88 pub fn read_id(&mut self) -> [u8; 3] {
89 let mut buffer = [0; 3];
90 let transaction: TransferConfig = TransferConfig {
91 iwidth: QspiWidth::SING,
92 awidth: QspiWidth::NONE,
93 dwidth: QspiWidth::SING,
94 instruction: CMD_READ_ID,
95 address: None,
96 dummy: DummyCycles::_0,
97 };
98 self.qspi.blocking_read(&mut buffer, transaction);
99 buffer
100 }
101
102 pub fn read_uuid(&mut self) -> [u8; 16] {
103 let mut buffer = [0; 16];
104 let transaction: TransferConfig = TransferConfig {
105 iwidth: QspiWidth::SING,
106 awidth: QspiWidth::SING,
107 dwidth: QspiWidth::SING,
108 instruction: CMD_READ_UUID,
109 address: Some(0),
110 dummy: DummyCycles::_8,
111 };
112 self.qspi.blocking_read(&mut buffer, transaction);
113 buffer
114 }
115
116 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
117 let transaction = TransferConfig {
118 iwidth: QspiWidth::SING,
119 awidth: QspiWidth::SING,
120 dwidth: QspiWidth::QUAD,
121 instruction: CMD_QUAD_READ,
122 address: Some(addr),
123 dummy: DummyCycles::_8,
124 };
125 if use_dma {
126 self.qspi.blocking_read_dma(buffer, transaction);
127 } else {
128 self.qspi.blocking_read(buffer, transaction);
129 }
130 }
131
132 fn wait_write_finish(&mut self) {
133 while (self.read_sr() & 0x01) != 0 {}
134 }
135
136 fn perform_erase(&mut self, addr: u32, cmd: u8) {
137 let transaction = TransferConfig {
138 iwidth: QspiWidth::SING,
139 awidth: QspiWidth::SING,
140 dwidth: QspiWidth::NONE,
141 instruction: cmd,
142 address: Some(addr),
143 dummy: DummyCycles::_0,
144 };
145 self.enable_write();
146 self.qspi.command(transaction);
147 self.wait_write_finish();
148 }
149
150 pub fn erase_sector(&mut self, addr: u32) {
151 self.perform_erase(addr, CMD_SECTOR_ERASE);
152 }
153
154 pub fn erase_block_32k(&mut self, addr: u32) {
155 self.perform_erase(addr, CMD_BLOCK_ERASE_32K);
156 }
157
158 pub fn erase_block_64k(&mut self, addr: u32) {
159 self.perform_erase(addr, CMD_BLOCK_ERASE_64K);
160 }
161
162 pub fn erase_chip(&mut self) {
163 self.exec_command(CMD_CHIP_ERASE);
164 }
165
166 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
167 assert!(
168 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
169 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
170 len,
171 addr
172 );
173
174 let transaction = TransferConfig {
175 iwidth: QspiWidth::SING,
176 awidth: QspiWidth::SING,
177 dwidth: QspiWidth::QUAD,
178 instruction: CMD_QUAD_WRITE_PG,
179 address: Some(addr),
180 dummy: DummyCycles::_0,
181 };
182 self.enable_write();
183 if use_dma {
184 self.qspi.blocking_write_dma(buffer, transaction);
185 } else {
186 self.qspi.blocking_write(buffer, transaction);
187 }
188 self.wait_write_finish();
189 }
190
191 pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
192 let mut left = buffer.len();
193 let mut place = addr;
194 let mut chunk_start = 0;
195
196 while left > 0 {
197 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
198 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
199 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
200 self.write_page(place, chunk, chunk_size, use_dma);
201 place += chunk_size as u32;
202 left -= chunk_size;
203 chunk_start += chunk_size;
204 }
205 }
206
207 fn read_register(&mut self, cmd: u8) -> u8 {
208 let mut buffer = [0; 1];
209 let transaction: TransferConfig = TransferConfig {
210 iwidth: QspiWidth::SING,
211 awidth: QspiWidth::NONE,
212 dwidth: QspiWidth::SING,
213 instruction: cmd,
214 address: None,
215 dummy: DummyCycles::_0,
216 };
217 self.qspi.blocking_read(&mut buffer, transaction);
218 buffer[0]
219 }
220
221 fn write_register(&mut self, cmd: u8, value: u8) {
222 let buffer = [value; 1];
223 let transaction: TransferConfig = TransferConfig {
224 iwidth: QspiWidth::SING,
225 awidth: QspiWidth::NONE,
226 dwidth: QspiWidth::SING,
227 instruction: cmd,
228 address: None,
229 dummy: DummyCycles::_0,
230 };
231 self.qspi.blocking_write(&buffer, transaction);
232 }
233
234 pub fn read_sr(&mut self) -> u8 {
235 self.read_register(CMD_READ_SR)
236 }
237
238 pub fn read_cr(&mut self) -> u8 {
239 self.read_register(CMD_READ_CR)
240 }
241
242 pub fn write_sr(&mut self, value: u8) {
243 self.write_register(CMD_WRITE_SR, value);
244 }
245
246 pub fn write_cr(&mut self, value: u8) {
247 self.write_register(CMD_WRITE_CR, value);
248 }
249}
250
251#[embassy_executor::main]
252async fn main(_spawner: Spawner) -> ! {
253 let mut config = StmCfg::default();
254 {
255 use embassy_stm32::rcc::*;
256 config.rcc.hse = Some(Hse {
257 freq: mhz(8),
258 mode: HseMode::Oscillator,
259 });
260 config.rcc.pll_src = PllSource::HSE;
261 config.rcc.pll = Some(Pll {
262 prediv: PllPreDiv::DIV4,
263 mul: PllMul::MUL216,
264 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
265 divq: None,
266 divr: None,
267 });
268 config.rcc.ahb_pre = AHBPrescaler::DIV1;
269 config.rcc.apb1_pre = APBPrescaler::DIV4;
270 config.rcc.apb2_pre = APBPrescaler::DIV2;
271 config.rcc.sys = Sysclk::PLL1_P;
272 }
273 let p = embassy_stm32::init(config);
274 info!("Embassy initialized");
275
276 let config = QspiCfg {
277 memory_size: MemorySize::_8MiB,
278 address_size: AddressSize::_24bit,
279 prescaler: 16,
280 cs_high_time: ChipSelectHighTime::_1Cycle,
281 fifo_threshold: FIFOThresholdLevel::_16Bytes,
282 };
283 let driver = Qspi::new_bank1(
284 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config,
285 );
286 let mut flash = FlashMemory::new(driver);
287 let flash_id = flash.read_id();
288 info!("FLASH ID: {:?}", flash_id);
289 let mut wr_buf = [0u8; 256];
290 for i in 0..256 {
291 wr_buf[i] = i as u8;
292 }
293 let mut rd_buf = [0u8; 256];
294 flash.erase_sector(MEMORY_ADDR);
295 flash.write_memory(MEMORY_ADDR, &wr_buf, true);
296 flash.read_memory(MEMORY_ADDR, &mut rd_buf, true);
297 info!("WRITE BUF: {:?}", wr_buf);
298 info!("READ BUF: {:?}", rd_buf);
299 info!("End of Program, proceed to empty endless loop");
300 loop {}
301}
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index fb604b34f..47456adf2 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs {
19async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); 21 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap();
23 22
24 for n in 0u32.. { 23 for n in 0u32.. {
25 let mut s: String<128> = String::new(); 24 let mut s: String<128> = String::new();
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 97daf6bd1..1906b28ed 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -3,19 +3,24 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join;
6use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 12use embassy_usb::Builder;
12use futures::future::join;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
17}); 17});
18 18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
19#[embassy_executor::main] 24#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 26 info!("Hello World!");
@@ -39,13 +44,20 @@ async fn main(_spawner: Spawner) {
39 config.rcc.apb1_pre = APBPrescaler::DIV4; 44 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 45 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P; 46 config.rcc.sys = Sysclk::PLL1_P;
47 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
42 } 48 }
43 let p = embassy_stm32::init(config); 49 let p = embassy_stm32::init(config);
44 50
45 // Create the driver, from the HAL. 51 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256]; 52 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default(); 53 let mut config = embassy_stm32::usb::Config::default();
48 config.vbus_detection = true; 54
55 // Do not enable vbus_detection. This is a safe default that works in all boards.
56 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
57 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
58 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
59 config.vbus_detection = false;
60
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 61 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50 62
51 // Create embassy-usb Config 63 // Create embassy-usb Config
@@ -63,7 +75,6 @@ async fn main(_spawner: Spawner) {
63 75
64 // Create embassy-usb DeviceBuilder using the driver and config. 76 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors. 77 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256]; 78 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256]; 79 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64]; 80 let mut control_buf = [0; 64];
@@ -73,7 +84,6 @@ async fn main(_spawner: Spawner) {
73 let mut builder = Builder::new( 84 let mut builder = Builder::new(
74 driver, 85 driver,
75 config, 86 config,
76 &mut device_descriptor,
77 &mut config_descriptor, 87 &mut config_descriptor,
78 &mut bos_descriptor, 88 &mut bos_descriptor,
79 &mut [], // no msos descriptors 89 &mut [], // no msos descriptors
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 6ce3418e5..a50074ce0 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32g0b1re to your chip name, if necessary. 8# Change stm32g0b1re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
@@ -20,9 +20,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
25portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 24portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
26 25
26embedded-io-async = { version = "0.6.1" }
27
27[profile.release] 28[profile.release]
28debug = 2 29debug = 2
diff --git a/examples/stm32g0/src/bin/adc.rs b/examples/stm32g0/src/bin/adc.rs
new file mode 100644
index 000000000..6c7f3b48a
--- /dev/null
+++ b/examples/stm32g0/src/bin/adc.rs
@@ -0,0 +1,34 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut adc = Adc::new(p.ADC1);
16 adc.set_sample_time(SampleTime::CYCLES79_5);
17 let mut pin = p.PA1;
18
19 let mut vrefint = adc.enable_vrefint();
20 let vrefint_sample = adc.blocking_read(&mut vrefint);
21 let convert_to_millivolts = |sample| {
22 // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf
23 // 6.3.3 Embedded internal reference voltage
24 const VREFINT_MV: u32 = 1212; // mV
25
26 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
27 };
28
29 loop {
30 let v = adc.blocking_read(&mut pin);
31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
32 Timer::after_millis(100).await;
33 }
34}
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/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 78a779e29..3ea06cdee 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -4,37 +4,36 @@
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::pac::rcc::vals::Tim1sel;
8use embassy_stm32::rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr};
9use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
10use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; 8use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
11use embassy_stm32::timer::simple_pwm::PwmPin; 9use embassy_stm32::timer::simple_pwm::PwmPin;
12use embassy_stm32::timer::Channel; 10use embassy_stm32::timer::Channel;
13use embassy_stm32::{pac, Config as PeripheralConfig}; 11use embassy_stm32::Config as PeripheralConfig;
14use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
15 13
16#[embassy_executor::main] 14#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
18 let mut rcc_config = RccConfig::default(); 16 let mut config = PeripheralConfig::default();
19 rcc_config.mux = ClockSrc::PLL(PllConfig { 17 {
20 source: PllSource::HSI, 18 use embassy_stm32::rcc::*;
21 m: Pllm::DIV1, 19 config.rcc.hsi = true;
22 n: Plln::MUL16, 20 config.rcc.pll = Some(Pll {
23 r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) 21 source: PllSource::HSI,
24 q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) 22 prediv: PllPreDiv::DIV1,
25 p: None, 23 mul: PllMul::MUL16,
26 }); 24 divp: None,
27 25 divq: Some(PllQDiv::DIV2), // 16 / 1 * 16 / 2 = 128 Mhz
28 let mut peripheral_config = PeripheralConfig::default(); 26 divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz
29 peripheral_config.rcc = rcc_config; 27 });
30 28 config.rcc.sys = Sysclk::PLL1_R;
31 let p = embassy_stm32::init(peripheral_config); 29
32 30 // configure TIM1 mux to select PLLQ as clock source
33 // configure TIM1 mux to select PLLQ as clock source 31 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
34 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 32 // RM0444 page 210
35 // RM0444 page 210 33 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
36 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 34 config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
37 pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); 35 }
36 let p = embassy_stm32::init(config);
38 37
39 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 38 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
40 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); 39 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
diff --git a/examples/stm32g0/src/bin/i2c_async.rs b/examples/stm32g0/src/bin/i2c_async.rs
new file mode 100644
index 000000000..7e3189b05
--- /dev/null
+++ b/examples/stm32g0/src/bin/i2c_async.rs
@@ -0,0 +1,48 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::{self, I2c};
7use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
14});
15
16const TMP117_ADDR: u8 = 0x48;
17const TMP117_TEMP_RESULT: u8 = 0x00;
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello world");
22
23 let p = embassy_stm32::init(Default::default());
24
25 let mut data = [0u8; 2];
26 let mut i2c = I2c::new(
27 p.I2C1,
28 p.PB8,
29 p.PB9,
30 Irqs,
31 p.DMA1_CH1,
32 p.DMA1_CH2,
33 Hertz(100_000),
34 Default::default(),
35 );
36
37 loop {
38 match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data).await {
39 Ok(()) => {
40 let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0;
41 info!("Temperature {}", temp);
42 }
43 Err(_) => error!("I2C Error"),
44 }
45
46 Timer::after(Duration::from_millis(1000)).await;
47 }
48}
diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs
new file mode 100644
index 000000000..69fdae96d
--- /dev/null
+++ b/examples/stm32g0/src/bin/input_capture.rs
@@ -0,0 +1,67 @@
1//! Input capture example
2//!
3//! This example showcases how to use the input capture feature of the timer peripheral.
4//! Connect PB1 and PA6 with a 1k Ohm resistor or Connect PB1 and PA8 with a 1k Ohm resistor
5//! to see the output.
6//! When connecting PB1 (software pwm) and PA6 the output is around 10000 (it will be a bit bigger, around 10040)
7//! Output is 1000 when connecting PB1 (PWMOUT) and PA6.
8//!
9#![no_std]
10#![no_main]
11
12use defmt::*;
13use embassy_executor::Spawner;
14use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed};
15use embassy_stm32::time::khz;
16use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
17use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
18use embassy_stm32::timer::Channel;
19use embassy_stm32::{bind_interrupts, peripherals, timer};
20use embassy_time::Timer;
21use {defmt_rtt as _, panic_probe as _};
22
23// Connect PB1 and PA6 with a 1k Ohm resistor
24
25#[embassy_executor::task]
26async fn blinky(led: peripherals::PB1) {
27 let mut led = Output::new(led, Level::High, Speed::Low);
28
29 loop {
30 led.set_high();
31 Timer::after_millis(50).await;
32
33 led.set_low();
34 Timer::after_millis(50).await;
35 }
36}
37
38bind_interrupts!(struct Irqs {
39 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
40});
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_stm32::init(Default::default());
45 info!("Hello World!");
46
47 unwrap!(spawner.spawn(blinky(p.PB1)));
48
49 // Connect PB1 and PA8 with a 1k Ohm resistor
50 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
51 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default());
52 pwm.enable(Channel::Ch1);
53 pwm.set_duty(Channel::Ch1, 50);
54
55 let ch1 = CapturePin::new_ch1(p.PA0, Pull::None);
56 let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default());
57
58 let mut old_capture = 0;
59
60 loop {
61 ic.wait_for_rising_edge(Channel::Ch1).await;
62
63 let capture_value = ic.get_capture_value(Channel::Ch1);
64 info!("{}", capture_value - old_capture);
65 old_capture = capture_value;
66 }
67}
diff --git a/examples/stm32g0/src/bin/pwm_complementary.rs b/examples/stm32g0/src/bin/pwm_complementary.rs
new file mode 100644
index 000000000..97b163c40
--- /dev/null
+++ b/examples/stm32g0/src/bin/pwm_complementary.rs
@@ -0,0 +1,57 @@
1//! PWM complementary example
2//!
3//! This example uses two complementary pwm outputs from TIM1 with different duty cycles
4//! ___ ___
5//! |_________| |_________| PA8
6//! _________ _________
7//! ___| |___| | PA7
8//! _________ _________
9//! |___| |___| PB3
10//! ___ ___
11//! _________| |_________| | PB0
12
13#![no_std]
14#![no_main]
15
16use defmt::info;
17use embassy_executor::Spawner;
18use embassy_stm32::gpio::OutputType;
19use embassy_stm32::time::khz;
20use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
21use embassy_stm32::timer::simple_pwm::PwmPin;
22use embassy_stm32::timer::Channel;
23use {defmt_rtt as _, panic_probe as _};
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let p = embassy_stm32::init(Default::default());
28
29 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
30 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
31 let ch2 = PwmPin::new_ch2(p.PB3, OutputType::PushPull);
32 let ch2n = ComplementaryPwmPin::new_ch2(p.PB0, OutputType::PushPull);
33
34 let mut pwm = ComplementaryPwm::new(
35 p.TIM1,
36 Some(ch1),
37 Some(ch1n),
38 Some(ch2),
39 Some(ch2n),
40 None,
41 None,
42 None,
43 None,
44 khz(100),
45 Default::default(),
46 );
47
48 let max = pwm.get_max_duty();
49 info!("Max duty: {}", max);
50
51 pwm.set_duty(Channel::Ch1, max / 4);
52 pwm.enable(Channel::Ch1);
53 pwm.set_duty(Channel::Ch2, max * 3 / 4);
54 pwm.enable(Channel::Ch2);
55
56 loop {}
57}
diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs
new file mode 100644
index 000000000..152ecda86
--- /dev/null
+++ b/examples/stm32g0/src/bin/pwm_input.rs
@@ -0,0 +1,65 @@
1//! PWM input example
2//!
3//! This program demonstrates how to capture the parameters of the input waveform (frequency, width and duty cycle)
4//! Connect PB1 and PA6 with a 1k Ohm resistor or Connect PB1 and PA8 with a 1k Ohm resistor
5//! to see the output.
6//!
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed};
14use embassy_stm32::time::khz;
15use embassy_stm32::timer::pwm_input::PwmInput;
16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
17use embassy_stm32::timer::Channel;
18use embassy_stm32::{bind_interrupts, peripherals, timer};
19use embassy_time::Timer;
20use {defmt_rtt as _, panic_probe as _};
21
22// Connect PB1 and PA6 with a 1k Ohm resistor
23#[embassy_executor::task]
24async fn blinky(led: peripherals::PB1) {
25 let mut led = Output::new(led, Level::High, Speed::Low);
26
27 loop {
28 led.set_high();
29 Timer::after_millis(50).await;
30
31 led.set_low();
32 Timer::after_millis(50).await;
33 }
34}
35
36bind_interrupts!(struct Irqs {
37 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
38});
39
40#[embassy_executor::main]
41async fn main(spawner: Spawner) {
42 let p = embassy_stm32::init(Default::default());
43
44 unwrap!(spawner.spawn(blinky(p.PB1)));
45 // Connect PA8 and PA6 with a 1k Ohm resistor
46 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
47 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default());
48 let max = pwm.get_max_duty();
49 pwm.set_duty(Channel::Ch1, max / 4);
50 pwm.enable(Channel::Ch1);
51
52 let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000));
53 pwm_input.enable();
54
55 loop {
56 Timer::after_millis(500).await;
57 let period = pwm_input.get_period_ticks();
58 let width = pwm_input.get_width_ticks();
59 let duty_cycle = pwm_input.get_duty_cycle();
60 info!(
61 "period ticks: {} width ticks: {} duty cycle: {}",
62 period, width, duty_cycle
63 );
64 }
65}
diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs
new file mode 100644
index 000000000..c02c1ecd7
--- /dev/null
+++ b/examples/stm32g0/src/bin/rtc.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig};
7use embassy_stm32::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let config = Config::default();
14 let p = embassy_stm32::init(config);
15
16 info!("Hello World!");
17
18 let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10);
19
20 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
21
22 rtc.set_datetime(now.unwrap()).expect("datetime not set");
23
24 loop {
25 let now: DateTime = rtc.now().unwrap().into();
26
27 info!("{}:{}:{}", now.hour(), now.minute(), now.second());
28
29 Timer::after_millis(1000).await;
30 }
31}
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index c5ea51721..edcae74f7 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::word::U5; 6use embassy_stm32::dma::word::U5;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
77 76
78 let mut config = Config::default(); 77 let mut config = Config::default();
79 config.frequency = Hertz(4_000_000); 78 config.frequency = Hertz(4_000_000);
80 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); 79 let mut spi = Spi::new_txonly(p.SPI1, p.PB3, p.PB5, p.DMA1_CH3, config); // SCK is unused.
81 80
82 let mut neopixels = Ws2812::new(); 81 let mut neopixels = Ws2812::new();
83 82
diff --git a/examples/stm32g0/src/bin/usart.rs b/examples/stm32g0/src/bin/usart.rs
new file mode 100644
index 000000000..037a5c833
--- /dev/null
+++ b/examples/stm32g0/src/bin/usart.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::usart::{Config, Uart};
6use {defmt_rtt as _, panic_probe as _};
7
8#[cortex_m_rt::entry]
9fn main() -> ! {
10 info!("Hello World!");
11
12 let p = embassy_stm32::init(Default::default());
13
14 let config = Config::default();
15 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
16
17 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
18 info!("wrote Hello, starting echo");
19
20 let mut buf = [0u8; 1];
21 loop {
22 unwrap!(usart.blocking_read(&mut buf));
23 unwrap!(usart.blocking_write(&buf));
24 }
25}
diff --git a/examples/stm32g0/src/bin/usart_buffered.rs b/examples/stm32g0/src/bin/usart_buffered.rs
new file mode 100644
index 000000000..c097a0c5a
--- /dev/null
+++ b/examples/stm32g0/src/bin/usart_buffered.rs
@@ -0,0 +1,34 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::usart::{BufferedUart, Config};
7use embassy_stm32::{bind_interrupts, peripherals, usart};
8use embedded_io_async::{Read, Write};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 USART1 => usart::BufferedInterruptHandler<peripherals::USART1>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_stm32::init(Default::default());
18 info!("Hi!");
19
20 let mut config = Config::default();
21 config.baudrate = 115200;
22 let mut tx_buf = [0u8; 256];
23 let mut rx_buf = [0u8; 256];
24 let mut usart = BufferedUart::new(p.USART1, Irqs, p.PB7, p.PB6, &mut tx_buf, &mut rx_buf, config).unwrap();
25
26 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0; 4];
30 loop {
31 usart.read_exact(&mut buf[..]).await.unwrap();
32 usart.write_all(&buf[..]).await.unwrap();
33 }
34}
diff --git a/examples/stm32g0/src/bin/usart_dma.rs b/examples/stm32g0/src/bin/usart_dma.rs
new file mode 100644
index 000000000..8212153ab
--- /dev/null
+++ b/examples/stm32g0/src/bin/usart_dma.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::usart::{Config, Uart};
7use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 USART1 => usart::InterruptHandler<peripherals::USART1>;
12});
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()).unwrap();
18
19 usart.write(b"Hello Embassy World!\r\n").await.unwrap();
20 info!("wrote Hello, starting echo");
21
22 let mut buf = [0; 5];
23 loop {
24 usart.read(&mut buf[..]).await.unwrap();
25 usart.write(&buf[..]).await.unwrap();
26 }
27}
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index f5aaa5624..162dfd86b 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
8use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { 21 {
23 sync_from_usb: true, 22 use embassy_stm32::rcc::*;
24 ..Default::default() 23 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
25 })); 24 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
25 }
26 let p = embassy_stm32::init(config); 26 let p = embassy_stm32::init(config);
27 27
28 info!("Hello World!"); 28 info!("Hello World!");
@@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) {
36 36
37 // Create embassy-usb DeviceBuilder using the driver and config. 37 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 38 // It needs some buffers for building the descriptors.
39 let mut device_descriptor = [0; 256];
40 let mut config_descriptor = [0; 256]; 39 let mut config_descriptor = [0; 256];
41 let mut bos_descriptor = [0; 256]; 40 let mut bos_descriptor = [0; 256];
42 let mut control_buf = [0; 7]; 41 let mut control_buf = [0; 7];
@@ -46,7 +45,6 @@ async fn main(_spawner: Spawner) {
46 let mut builder = Builder::new( 45 let mut builder = Builder::new(
47 driver, 46 driver,
48 config, 47 config,
49 &mut device_descriptor,
50 &mut config_descriptor, 48 &mut config_descriptor,
51 &mut bos_descriptor, 49 &mut bos_descriptor,
52 &mut [], // no msos descriptors 50 &mut [], // no msos descriptors
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 895ad3e7c..2768147a1 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -7,12 +7,12 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32g491re to your chip name, if necessary. 8# Change stm32g491re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15usbd-hid = "0.6.0" 15usbd-hid = "0.8.1"
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.4" 18defmt-rtt = "0.4"
@@ -20,9 +20,10 @@ defmt-rtt = "0.4"
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
23embedded-can = { version = "0.4" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26static_cell = "2.0.0"
26 27
27[profile.release] 28[profile.release]
28debug = 2 29debug = 2
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 35324d931..adca846d8 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -4,36 +4,35 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSource};
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::{Delay, Timer}; 8use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
14 let mut config = Config::default(); 13 let mut config = Config::default();
15 14 {
16 config.rcc.pll = Some(Pll { 15 use embassy_stm32::rcc::*;
17 source: PllSource::HSI, 16 config.rcc.pll = Some(Pll {
18 prediv_m: PllM::DIV4, 17 source: PllSource::HSI,
19 mul_n: PllN::MUL85, 18 prediv: PllPreDiv::DIV4,
20 div_p: None, 19 mul: PllMul::MUL85,
21 div_q: None, 20 divp: None,
22 // Main system clock at 170 MHz 21 divq: None,
23 div_r: Some(PllR::DIV2), 22 // Main system clock at 170 MHz
24 }); 23 divr: Some(PllRDiv::DIV2),
25 24 });
26 config.rcc.adc12_clock_source = AdcClockSource::SYS; 25 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
27 config.rcc.mux = ClockSrc::PLL; 26 config.rcc.sys = Sysclk::PLL1_R;
28 27 }
29 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
30 info!("Hello World!"); 29 info!("Hello World!");
31 30
32 let mut adc = Adc::new(p.ADC2, &mut Delay); 31 let mut adc = Adc::new(p.ADC2);
33 adc.set_sample_time(SampleTime::Cycles32_5); 32 adc.set_sample_time(SampleTime::CYCLES24_5);
34 33
35 loop { 34 loop {
36 let measured = adc.read(&mut p.PA7); 35 let measured = adc.blocking_read(&mut p.PA7);
37 info!("measured: {}", measured); 36 info!("measured: {}", measured);
38 Timer::after_millis(500).await; 37 Timer::after_millis(500).await;
39 } 38 }
diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs
new file mode 100644
index 000000000..78d071d45
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_differential.rs
@@ -0,0 +1,47 @@
1//! adc differential mode example
2//!
3//! This example uses adc1 in differential mode
4//! p:pa0 n:pa1
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_stm32::adc::{Adc, SampleTime};
12use embassy_stm32::Config;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI,
23 prediv: PllPreDiv::DIV4,
24 mul: PllMul::MUL85,
25 divp: None,
26 divq: None,
27 // Main system clock at 170 MHz
28 divr: Some(PllRDiv::DIV2),
29 });
30 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
31 config.rcc.sys = Sysclk::PLL1_R;
32 }
33 let mut p = embassy_stm32::init(config);
34
35 let mut adc = Adc::new(p.ADC1);
36 adc.set_sample_time(SampleTime::CYCLES247_5);
37 adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1
38
39 // can also use
40 // adc.set_differential_channel(1, true);
41 info!("adc initialized");
42 loop {
43 let measured = adc.blocking_read(&mut p.PA0);
44 info!("data: {}", measured);
45 Timer::after_millis(500).await;
46 }
47}
diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs
new file mode 100644
index 000000000..d31eb20f8
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_oversampling.rs
@@ -0,0 +1,57 @@
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::vals::{Rovsm, Trovs};
11use embassy_stm32::adc::{Adc, SampleTime};
12use embassy_stm32::Config;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI,
23 prediv: PllPreDiv::DIV4,
24 mul: PllMul::MUL85,
25 divp: None,
26 divq: None,
27 // Main system clock at 170 MHz
28 divr: Some(PllRDiv::DIV2),
29 });
30 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
31 config.rcc.sys = Sysclk::PLL1_R;
32 }
33 let mut p = embassy_stm32::init(config);
34
35 let mut adc = Adc::new(p.ADC1);
36 adc.set_sample_time(SampleTime::CYCLES6_5);
37 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
38 // page652 Oversampler
39 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation
40 // 0x00 oversampling ratio X2
41 // 0x01 oversampling ratio X4
42 // 0x02 oversampling ratio X8
43 // 0x03 oversampling ratio X16
44 // 0x04 oversampling ratio X32
45 // 0x05 oversampling ratio X64
46 // 0x06 oversampling ratio X128
47 // 0x07 oversampling ratio X256
48 adc.set_oversampling_ratio(0x03); // ratio X3
49 adc.set_oversampling_shift(0b0000); // no shift
50 adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true);
51
52 loop {
53 let measured = adc.blocking_read(&mut p.PA0);
54 info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520
55 Timer::after_millis(500).await;
56 }
57}
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 727921fba..90004f874 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -3,8 +3,10 @@
3use defmt::*; 3use defmt::*;
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_stm32::peripherals::*; 5use embassy_stm32::peripherals::*;
6use embassy_stm32::time::Hertz;
6use embassy_stm32::{bind_interrupts, can, Config}; 7use embassy_stm32::{bind_interrupts, can, Config};
7use embassy_time::Timer; 8use embassy_time::Timer;
9use static_cell::StaticCell;
8use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
9 11
10bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -14,43 +16,219 @@ bind_interrupts!(struct Irqs {
14 16
15#[embassy_executor::main] 17#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
17 let config = Config::default(); 19 let mut config = Config::default();
18 20 {
21 use embassy_stm32::rcc::*;
22 config.rcc.hse = Some(Hse {
23 freq: Hertz(24_000_000),
24 mode: HseMode::Oscillator,
25 });
26 config.rcc.pll = Some(Pll {
27 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV6,
29 mul: PllMul::MUL85,
30 divp: None,
31 divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
32 divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
33 });
34 config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
35 config.rcc.sys = Sysclk::PLL1_R;
36 }
19 let peripherals = embassy_stm32::init(config); 37 let peripherals = embassy_stm32::init(config);
20 38
21 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 39 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
40
41 can.properties().set_extended_filter(
42 can::filter::ExtendedFilterSlot::_0,
43 can::filter::ExtendedFilter::accept_all_into_fifo1(),
44 );
22 45
23 // 250k bps 46 // 250k bps
24 can.set_bitrate(250_000); 47 can.set_bitrate(250_000);
25 48
49 let use_fd = false;
50
51 // 1M bps
52 if use_fd {
53 can.set_fd_data_bitrate(1_000_000, false);
54 }
55
26 info!("Configured"); 56 info!("Configured");
27 57
28 //let mut can = can.into_external_loopback_mode(); 58 let mut can = can.start(match use_fd {
29 let mut can = can.into_normal_mode(); 59 true => can::OperatingMode::InternalLoopbackMode,
60 false => can::OperatingMode::NormalOperationMode,
61 });
30 62
31 let mut i = 0; 63 let mut i = 0;
64 let mut last_read_ts = embassy_time::Instant::now();
65
32 loop { 66 loop {
33 let frame = can::TxFrame::new( 67 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
34 can::TxFrameHeader {
35 len: 1,
36 frame_format: can::FrameFormat::Standard,
37 id: can::StandardId::new(0x123).unwrap().into(),
38 bit_rate_switching: false,
39 marker: None,
40 },
41 &[i],
42 )
43 .unwrap();
44 info!("Writing frame"); 68 info!("Writing frame");
69
45 _ = can.write(&frame).await; 70 _ = can.write(&frame).await;
46 71
47 match can.read().await { 72 match can.read().await {
48 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 73 Ok(envelope) => {
74 let (ts, rx_frame) = (envelope.ts, envelope.frame);
75 let delta = (ts - last_read_ts).as_millis();
76 last_read_ts = ts;
77 info!(
78 "Rx: {} {:02x} --- {}ms",
79 rx_frame.header().len(),
80 rx_frame.data()[0..rx_frame.header().len() as usize],
81 delta,
82 )
83 }
84 Err(_err) => error!("Error in frame"),
85 }
86
87 Timer::after_millis(250).await;
88
89 i += 1;
90 if i > 2 {
91 break;
92 }
93 }
94
95 // Use the FD API's even if we don't get FD packets.
96
97 loop {
98 if use_fd {
99 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
100 info!("Writing frame using FD API");
101 _ = can.write_fd(&frame).await;
102 } else {
103 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap();
104 info!("Writing frame using FD API");
105 _ = can.write_fd(&frame).await;
106 }
107
108 match can.read_fd().await {
109 Ok(envelope) => {
110 let (ts, rx_frame) = (envelope.ts, envelope.frame);
111 let delta = (ts - last_read_ts).as_millis();
112 last_read_ts = ts;
113 info!(
114 "Rx: {} {:02x} --- using FD API {}ms",
115 rx_frame.header().len(),
116 rx_frame.data()[0..rx_frame.header().len() as usize],
117 delta,
118 )
119 }
49 Err(_err) => error!("Error in frame"), 120 Err(_err) => error!("Error in frame"),
50 } 121 }
51 122
52 Timer::after_millis(250).await; 123 Timer::after_millis(250).await;
53 124
54 i += 1; 125 i += 1;
126 if i > 4 {
127 break;
128 }
129 }
130 i = 0;
131 let (mut tx, mut rx, _props) = can.split();
132 // With split
133 loop {
134 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
135 info!("Writing frame");
136 _ = tx.write(&frame).await;
137
138 match rx.read().await {
139 Ok(envelope) => {
140 let (ts, rx_frame) = (envelope.ts, envelope.frame);
141 let delta = (ts - last_read_ts).as_millis();
142 last_read_ts = ts;
143 info!(
144 "Rx: {} {:02x} --- {}ms",
145 rx_frame.header().len(),
146 rx_frame.data()[0..rx_frame.header().len() as usize],
147 delta,
148 )
149 }
150 Err(_err) => error!("Error in frame"),
151 }
152
153 Timer::after_millis(250).await;
154
155 i += 1;
156
157 if i > 2 {
158 break;
159 }
160 }
161
162 let can = can::Can::join(tx, rx);
163
164 info!("\n\n\nBuffered\n");
165 if use_fd {
166 static TX_BUF: StaticCell<can::TxFdBuf<8>> = StaticCell::new();
167 static RX_BUF: StaticCell<can::RxFdBuf<10>> = StaticCell::new();
168 let mut can = can.buffered_fd(
169 TX_BUF.init(can::TxFdBuf::<8>::new()),
170 RX_BUF.init(can::RxFdBuf::<10>::new()),
171 );
172 loop {
173 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
174 info!("Writing frame");
175
176 _ = can.write(frame).await;
177
178 match can.read().await {
179 Ok(envelope) => {
180 let (ts, rx_frame) = (envelope.ts, envelope.frame);
181 let delta = (ts - last_read_ts).as_millis();
182 last_read_ts = ts;
183 info!(
184 "Rx: {} {:02x} --- {}ms",
185 rx_frame.header().len(),
186 rx_frame.data()[0..rx_frame.header().len() as usize],
187 delta,
188 )
189 }
190 Err(_err) => error!("Error in frame"),
191 }
192
193 Timer::after_millis(250).await;
194
195 i = i.wrapping_add(1);
196 }
197 } else {
198 static TX_BUF: StaticCell<can::TxBuf<8>> = StaticCell::new();
199 static RX_BUF: StaticCell<can::RxBuf<10>> = StaticCell::new();
200 let mut can = can.buffered(
201 TX_BUF.init(can::TxBuf::<8>::new()),
202 RX_BUF.init(can::RxBuf::<10>::new()),
203 );
204 loop {
205 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
206 info!("Writing frame");
207
208 // You can use any of these approaches to send. The writer makes it
209 // easy to share sending from multiple tasks.
210 //_ = can.write(frame).await;
211 //can.writer().try_write(frame).unwrap();
212 can.writer().write(frame).await;
213
214 match can.read().await {
215 Ok(envelope) => {
216 let (ts, rx_frame) = (envelope.ts, envelope.frame);
217 let delta = (ts - last_read_ts).as_millis();
218 last_read_ts = ts;
219 info!(
220 "Rx: {} {:02x} --- {}ms",
221 rx_frame.header().len(),
222 rx_frame.data()[0..rx_frame.header().len() as usize],
223 delta,
224 )
225 }
226 Err(_err) => error!("Error in frame"),
227 }
228
229 Timer::after_millis(250).await;
230
231 i = i.wrapping_add(1);
232 }
55 } 233 }
56} 234}
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 46ebe0b0d..08ed95b34 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSource};
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -11,19 +10,20 @@ use {defmt_rtt as _, panic_probe as _};
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
13 let mut config = Config::default(); 12 let mut config = Config::default();
14 13 {
15 config.rcc.pll = Some(Pll { 14 use embassy_stm32::rcc::*;
16 source: PllSource::HSI, 15 config.rcc.hsi = true;
17 prediv_m: PllM::DIV4, 16 config.rcc.pll = Some(Pll {
18 mul_n: PllN::MUL85, 17 source: PllSource::HSI,
19 div_p: None, 18 prediv: PllPreDiv::DIV4,
20 div_q: None, 19 mul: PllMul::MUL85,
21 // Main system clock at 170 MHz 20 divp: None,
22 div_r: Some(PllR::DIV2), 21 divq: None,
23 }); 22 // Main system clock at 170 MHz
24 23 divr: Some(PllRDiv::DIV2),
25 config.rcc.mux = ClockSrc::PLL; 24 });
26 25 config.rcc.sys = Sysclk::PLL1_R;
26 }
27 let _p = embassy_stm32::init(config); 27 let _p = embassy_stm32::init(config);
28 info!("Hello World!"); 28 info!("Hello World!");
29 29
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
new file mode 100644
index 000000000..2e87d3931
--- /dev/null
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -0,0 +1,86 @@
1#![no_std]
2#![no_main]
3
4use defmt::{error, info, Format};
5use embassy_executor::Spawner;
6use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd};
7use embassy_stm32::{bind_interrupts, peripherals, Config};
8use embassy_time::{with_timeout, Duration};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>;
13});
14
15#[derive(Debug, Format)]
16enum CableOrientation {
17 Normal,
18 Flipped,
19 DebugAccessoryMode,
20}
21
22// Returns true when the cable
23async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation {
24 loop {
25 let (cc1, cc2) = cc_phy.vstate();
26 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
27 // Detached, wait until attached by monitoring the CC lines.
28 cc_phy.wait_for_vstate_change().await;
29 continue;
30 }
31
32 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
33 if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change())
34 .await
35 .is_ok()
36 {
37 // State has changed, restart detection procedure.
38 continue;
39 };
40
41 // State was stable for the complete debounce period, check orientation.
42 return match (cc1, cc2) {
43 (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected
44 (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected
45 _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable)
46 };
47 }
48}
49
50#[embassy_executor::main]
51async fn main(_spawner: Spawner) {
52 let mut config = Config::default();
53 config.enable_ucpd1_dead_battery = true;
54 let p = embassy_stm32::init(config);
55
56 info!("Hello World!");
57
58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default());
59 ucpd.cc_phy().set_pull(CcPull::Sink);
60
61 info!("Waiting for USB connection...");
62 let cable_orientation = wait_attached(ucpd.cc_phy()).await;
63 info!("USB cable connected, orientation: {}", cable_orientation);
64
65 let cc_sel = match cable_orientation {
66 CableOrientation::Normal => {
67 info!("Starting PD communication on CC1 pin");
68 CcSel::CC1
69 }
70 CableOrientation::Flipped => {
71 info!("Starting PD communication on CC2 pin");
72 CcSel::CC2
73 }
74 CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"),
75 };
76 let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel);
77
78 loop {
79 // Enough space for the longest non-extended data message.
80 let mut buf = [0_u8; 30];
81 match pd_phy.receive(buf.as_mut()).await {
82 Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]),
83 Err(e) => error!("USB PD RX: {}", e),
84 }
85 }
86}
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index c26fa76b7..ed2ac7fac 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -3,14 +3,13 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSource}; 6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{self, Driver, Instance}; 8use embassy_stm32::usb::{self, Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 12use embassy_usb::Builder;
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
16bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
@@ -20,31 +19,27 @@ bind_interrupts!(struct Irqs {
20#[embassy_executor::main] 19#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
22 let mut config = Config::default(); 21 let mut config = Config::default();
23 22 {
24 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. 23 use embassy_stm32::rcc::*;
25 const USE_HSI48: bool = true;
26
27 let plldivq = if USE_HSI48 { None } else { Some(PllQ::DIV6) };
28
29 config.rcc.pll = Some(Pll {
30 source: PllSource::HSE(Hertz(8_000_000)),
31 prediv_m: PllM::DIV2,
32 mul_n: PllN::MUL72,
33 div_p: None,
34 div_q: plldivq,
35 // Main system clock at 144 MHz
36 div_r: Some(PllR::DIV2),
37 });
38
39 config.rcc.mux = ClockSrc::PLL;
40
41 if USE_HSI48 {
42 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. 24 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
43 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); 25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
44 } else { 26 config.rcc.hse = Some(Hse {
45 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); 27 freq: Hertz(8_000_000),
28 mode: HseMode::Oscillator,
29 });
30 config.rcc.pll = Some(Pll {
31 source: PllSource::HSE,
32 prediv: PllPreDiv::DIV2,
33 mul: PllMul::MUL72,
34 divp: None,
35 divq: Some(PllQDiv::DIV6), // 48mhz
36 divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
37 });
38 config.rcc.sys = Sysclk::PLL1_R;
39 config.rcc.boost = true; // BOOST!
40 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
41 //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
46 } 42 }
47
48 let p = embassy_stm32::init(config); 43 let p = embassy_stm32::init(config);
49 44
50 info!("Hello World!"); 45 info!("Hello World!");
@@ -61,7 +56,6 @@ async fn main(_spawner: Spawner) {
61 config.device_protocol = 0x01; 56 config.device_protocol = 0x01;
62 config.composite_with_iads = true; 57 config.composite_with_iads = true;
63 58
64 let mut device_descriptor = [0; 256];
65 let mut config_descriptor = [0; 256]; 59 let mut config_descriptor = [0; 256];
66 let mut bos_descriptor = [0; 256]; 60 let mut bos_descriptor = [0; 256];
67 let mut control_buf = [0; 64]; 61 let mut control_buf = [0; 64];
@@ -71,7 +65,6 @@ async fn main(_spawner: Spawner) {
71 let mut builder = Builder::new( 65 let mut builder = Builder::new(
72 driver, 66 driver,
73 config, 67 config,
74 &mut device_descriptor,
75 &mut config_descriptor, 68 &mut config_descriptor,
76 &mut bos_descriptor, 69 &mut bos_descriptor,
77 &mut [], // no msos descriptors 70 &mut [], // no msos descriptors
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index c9f08d24e..30b1d2be9 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -6,12 +6,13 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32h563zi to your chip name, if necessary. 8# Change stm32h563zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 16
16defmt = "0.3" 17defmt = "0.3"
17defmt-rtt = "0.4" 18defmt-rtt = "0.4"
@@ -24,7 +25,6 @@ embedded-hal-async = { version = "1.0" }
24embedded-io-async = { version = "0.6.1" } 25embedded-io-async = { version = "0.6.1" }
25embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = { version = "0.7.1" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "0.3", features = ["print-defmt"] }
27futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
28heapless = { version = "0.8", default-features = false } 28heapless = { version = "0.8", default-features = false }
29rand_core = "0.6.3" 29rand_core = "0.6.3"
30critical-section = "1.1" 30critical-section = "1.1"
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index 2906d1576..194239d47 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -16,59 +16,83 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 19 config.rcc.hse = Some(rcc::Hse {
20 // configure FDCAN to use PLL1_Q at 64 MHz 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 config.rcc.pll1 = Some(rcc::Pll { 21 mode: rcc::HseMode::Oscillator,
22 source: rcc::PllSource::HSI,
23 prediv: rcc::PllPreDiv::DIV4,
24 mul: rcc::PllMul::MUL8,
25 divp: None,
26 divq: Some(rcc::PllDiv::DIV2),
27 divr: None,
28 }); 22 });
29 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; 23 config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
30 24
31 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
32 26
33 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 27 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
34 28
35 can.can.apply_config( 29 // 250k bps
36 can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { 30 can.set_bitrate(250_000);
37 sync_jump_width: 1.try_into().unwrap(),
38 prescaler: 8.try_into().unwrap(),
39 seg1: 13.try_into().unwrap(),
40 seg2: 2.try_into().unwrap(),
41 }),
42 );
43 31
44 info!("Configured"); 32 //let mut can = can.into_internal_loopback_mode();
33 let mut can = can.into_normal_mode();
45 34
46 let mut can = can.into_external_loopback_mode(); 35 info!("CAN Configured");
47 //let mut can = can.into_normal_mode();
48 36
49 let mut i = 0; 37 let mut i = 0;
38 let mut last_read_ts = embassy_time::Instant::now();
39
50 loop { 40 loop {
51 let frame = can::TxFrame::new( 41 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
52 can::TxFrameHeader {
53 len: 1,
54 frame_format: can::FrameFormat::Standard,
55 id: can::StandardId::new(0x123).unwrap().into(),
56 bit_rate_switching: false,
57 marker: None,
58 },
59 &[i],
60 )
61 .unwrap();
62 info!("Writing frame"); 42 info!("Writing frame");
63 _ = can.write(&frame).await; 43 _ = can.write(&frame).await;
64 44
65 match can.read().await { 45 match can.read().await {
66 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 46 Ok(envelope) => {
47 let (rx_frame, ts) = envelope.parts();
48 let delta = (ts - last_read_ts).as_millis();
49 last_read_ts = ts;
50 info!(
51 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
52 rx_frame.data()[0],
53 rx_frame.data()[1],
54 rx_frame.data()[2],
55 rx_frame.data()[3],
56 delta,
57 )
58 }
67 Err(_err) => error!("Error in frame"), 59 Err(_err) => error!("Error in frame"),
68 } 60 }
69 61
70 Timer::after_millis(250).await; 62 Timer::after_millis(250).await;
71 63
72 i += 1; 64 i += 1;
65 if i > 3 {
66 break;
67 }
68 }
69
70 let (mut tx, mut rx, _props) = can.split();
71 // With split
72 loop {
73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
74 info!("Writing frame");
75 _ = tx.write(&frame).await;
76
77 match rx.read().await {
78 Ok(envelope) => {
79 let (rx_frame, ts) = envelope.parts();
80 let delta = (ts - last_read_ts).as_millis();
81 last_read_ts = ts;
82 info!(
83 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
84 rx_frame.data()[0],
85 rx_frame.data()[1],
86 rx_frame.data()[2],
87 rx_frame.data()[3],
88 delta,
89 )
90 }
91 Err(_err) => error!("Error in frame"),
92 }
93
94 Timer::after_millis(250).await;
95
96 i = i.wrapping_add(1);
73 } 97 }
74} 98}
diff --git a/examples/stm32h5/src/bin/cordic.rs b/examples/stm32h5/src/bin/cordic.rs
new file mode 100644
index 000000000..73e873574
--- /dev/null
+++ b/examples/stm32h5/src/bin/cordic.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::cordic::{self, utils};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let mut dp = embassy_stm32::init(Default::default());
12
13 let mut cordic = cordic::Cordic::new(
14 &mut dp.CORDIC,
15 unwrap!(cordic::Config::new(
16 cordic::Function::Sin,
17 Default::default(),
18 Default::default(),
19 )),
20 );
21
22 // for output buf, the length is not that strict, larger than minimal required is ok.
23 let mut output_f64 = [0f64; 19];
24 let mut output_u32 = [0u32; 21];
25
26 // tips:
27 // CORDIC peripheral has some strict on input value, you can also use ".check_argX_fXX()" methods
28 // to make sure your input values are compatible with current CORDIC setup.
29 let arg1 = [-1.0, -0.5, 0.0, 0.5, 1.0]; // for trigonometric function, the ARG1 value [-pi, pi] should be map to [-1, 1]
30 let arg2 = [0.5]; // and for Sin function, ARG2 should be in [0, 1]
31
32 let mut input_buf = [0u32; 9];
33
34 // convert input from floating point to fixed point
35 input_buf[0] = unwrap!(utils::f64_to_q1_31(arg1[0]));
36 input_buf[1] = unwrap!(utils::f64_to_q1_31(arg2[0]));
37
38 // If input length is small, blocking mode can be used to minimize overhead.
39 let cnt0 = unwrap!(cordic.blocking_calc_32bit(
40 &input_buf[..2], // input length is strict, since driver use its length to detect calculation count
41 &mut output_u32,
42 false,
43 false
44 ));
45
46 // convert result from fixed point into floating point
47 for (&u32_val, f64_val) in output_u32[..cnt0].iter().zip(output_f64.iter_mut()) {
48 *f64_val = utils::q1_31_to_f64(u32_val);
49 }
50
51 // convert input from floating point to fixed point
52 //
53 // first value from arg1 is used, so truncate to arg1[1..]
54 for (&f64_val, u32_val) in arg1[1..].iter().zip(input_buf.iter_mut()) {
55 *u32_val = unwrap!(utils::f64_to_q1_31(f64_val));
56 }
57
58 // If calculation is a little longer, async mode can make use of DMA, and let core do some other stuff.
59 let cnt1 = unwrap!(
60 cordic
61 .async_calc_32bit(
62 &mut dp.GPDMA1_CH0,
63 &mut dp.GPDMA1_CH1,
64 &input_buf[..arg1.len() - 1], // limit input buf to its actual length
65 &mut output_u32,
66 true,
67 false
68 )
69 .await
70 );
71
72 // convert result from fixed point into floating point
73 for (&u32_val, f64_val) in output_u32[..cnt1].iter().zip(output_f64[cnt0..cnt0 + cnt1].iter_mut()) {
74 *f64_val = utils::q1_31_to_f64(u32_val);
75 }
76
77 println!("result: {}", output_f64[..cnt0 + cnt1]);
78}
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 2370656e6..eee1632f5 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs {
28type Device = Ethernet<'static, ETH, GenericSMI>; 28type Device = Ethernet<'static, ETH, GenericSMI>;
29 29
30#[embassy_executor::task] 30#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<Device>) -> ! { 31async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
32 stack.run().await 32 runner.run().await
33} 33}
34 34
35#[embassy_executor::main] 35#[embassy_executor::main]
@@ -92,17 +92,11 @@ async fn main(spawner: Spawner) -> ! {
92 //}); 92 //});
93 93
94 // Init network stack 94 // Init network stack
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 96 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 let stack = &*STACK.init(Stack::new(
98 device,
99 config,
100 RESOURCES.init(StackResources::<2>::new()),
101 seed,
102 ));
103 97
104 // Launch network task 98 // Launch network task
105 unwrap!(spawner.spawn(net_task(&stack))); 99 unwrap!(spawner.spawn(net_task(runner)));
106 100
107 // Ensure DHCP configuration is up before trying connect 101 // Ensure DHCP configuration is up before trying connect
108 stack.wait_config_up().await; 102 stack.wait_config_up().await;
@@ -114,7 +108,7 @@ async fn main(spawner: Spawner) -> ! {
114 let mut tx_buffer = [0; 1024]; 108 let mut tx_buffer = [0; 1024];
115 109
116 loop { 110 loop {
117 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 111 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
118 112
119 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 113 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
120 114
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs
new file mode 100644
index 000000000..0d14c0668
--- /dev/null
+++ b/examples/stm32h5/src/bin/stop.rs
@@ -0,0 +1,71 @@
1// Notice:
2// the MCU might need an extra reset to make the code actually running
3
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
10use embassy_stm32::low_power::Executor;
11use embassy_stm32::rcc::{HSIPrescaler, LsConfig};
12use embassy_stm32::rtc::{Rtc, RtcConfig};
13use embassy_stm32::Config;
14use embassy_time::Timer;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18#[cortex_m_rt::entry]
19fn main() -> ! {
20 Executor::take().run(|spawner| {
21 unwrap!(spawner.spawn(async_main(spawner)));
22 })
23}
24
25#[embassy_executor::task]
26async fn async_main(spawner: Spawner) {
27 defmt::info!("Program Start");
28
29 let mut config = Config::default();
30
31 // System Clock seems need to be equal or lower than 16 MHz
32 config.rcc.hsi = Some(HSIPrescaler::DIV4);
33
34 config.rcc.ls = LsConfig::default_lsi();
35 // when enabled the power-consumption is much higher during stop, but debugging and RTT is working
36 // if you wan't to measure the power-consumption, or for production: uncomment this line
37 // config.enable_debug_during_sleep = false;
38 let p = embassy_stm32::init(config);
39
40 // give the RTC to the executor...
41 let rtc = Rtc::new(p.RTC, RtcConfig::default());
42 static RTC: StaticCell<Rtc> = StaticCell::new();
43 let rtc = RTC.init(rtc);
44 embassy_stm32::low_power::stop_with_rtc(rtc);
45
46 unwrap!(spawner.spawn(blinky(p.PB4.into())));
47 unwrap!(spawner.spawn(timeout()));
48}
49
50#[embassy_executor::task]
51async fn blinky(led: AnyPin) {
52 let mut led = Output::new(led, Level::Low, Speed::Low);
53 loop {
54 info!("high");
55 led.set_high();
56 Timer::after_millis(300).await;
57
58 info!("low");
59 led.set_low();
60 Timer::after_millis(300).await;
61 }
62}
63
64// when enable_debug_during_sleep is false, it is more difficult to reprogram the MCU
65// therefore we block the MCU after 30s to be able to reprogram it easily
66#[embassy_executor::task]
67async fn timeout() -> ! {
68 Timer::after_secs(30).await;
69 #[allow(clippy::empty_loop)]
70 loop {}
71}
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h5/src/bin/usart.rs
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
index caae0dd18..c644e84bd 100644
--- a/examples/stm32h5/src/bin/usart_dma.rs
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index 92047de8d..d26c5003c 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -3,8 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{GPDMA1_CH1, UART7};
8use embassy_stm32::usart::{Config, Uart, UartRx}; 7use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 8use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 9use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +14,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 14 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 15});
17 16
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 17static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 18
32#[embassy_executor::main] 19#[embassy_executor::main]
@@ -50,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
50} 37}
51 38
52#[embassy_executor::task] 39#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { 40async fn reader(mut rx: UartRx<'static, Async>) {
54 let mut buf = [0; 8]; 41 let mut buf = [0; 8];
55 loop { 42 loop {
56 info!("reading..."); 43 info!("reading...");
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 208493d8c..fbcbdb5f9 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -3,13 +3,13 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join;
6use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
7use embassy_stm32::usb::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 12use embassy_usb::Builder;
12use futures::future::join;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
@@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
41 config.rcc.apb3_pre = APBPrescaler::DIV4; 41 config.rcc.apb3_pre = APBPrescaler::DIV4;
42 config.rcc.sys = Sysclk::PLL1_P; 42 config.rcc.sys = Sysclk::PLL1_P;
43 config.rcc.voltage_scale = VoltageScale::Scale0; 43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
44 } 45 }
45 let p = embassy_stm32::init(config); 46 let p = embassy_stm32::init(config);
46 47
47 info!("Hello World!"); 48 info!("Hello World!");
48 49
49 pac::RCC.ccipr4().write(|w| {
50 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
51 });
52
53 // Create the driver, from the HAL. 50 // Create the driver, from the HAL.
54 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 51 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
55 52
@@ -68,7 +65,6 @@ async fn main(_spawner: Spawner) {
68 65
69 // Create embassy-usb DeviceBuilder using the driver and config. 66 // Create embassy-usb DeviceBuilder using the driver and config.
70 // It needs some buffers for building the descriptors. 67 // It needs some buffers for building the descriptors.
71 let mut device_descriptor = [0; 256];
72 let mut config_descriptor = [0; 256]; 68 let mut config_descriptor = [0; 256];
73 let mut bos_descriptor = [0; 256]; 69 let mut bos_descriptor = [0; 256];
74 let mut control_buf = [0; 64]; 70 let mut control_buf = [0; 64];
@@ -78,7 +74,6 @@ async fn main(_spawner: Spawner) {
78 let mut builder = Builder::new( 74 let mut builder = Builder::new(
79 driver, 75 driver,
80 config, 76 config,
81 &mut device_descriptor,
82 &mut config_descriptor, 77 &mut config_descriptor,
83 &mut bos_descriptor, 78 &mut bos_descriptor,
84 &mut [], // no msos descriptors 79 &mut [], // no msos descriptors
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index d9ea2626d..13fce7dc7 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,12 +6,14 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 17
16defmt = "0.3" 18defmt = "0.3"
17defmt-rtt = "0.4" 19defmt-rtt = "0.4"
@@ -24,7 +26,6 @@ embedded-hal-async = { version = "1.0" }
24embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = { version = "0.7.1" }
25embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "0.3", features = ["print-defmt"] }
27futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
28heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
29rand_core = "0.6.3" 30rand_core = "0.6.3"
30critical-section = "1.1" 31critical-section = "1.1"
@@ -33,6 +34,7 @@ stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1" 34embedded-storage = "0.3.1"
34static_cell = "2" 35static_cell = "2"
35chrono = { version = "^0.4", default-features = false } 36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
36 38
37# cargo build/run 39# cargo build/run
38[profile.dev] 40[profile.dev]
diff --git a/examples/stm32h7/build.rs b/examples/stm32h7/build.rs
index 8cd32d7ed..30691aa97 100644
--- a/examples/stm32h7/build.rs
+++ b/examples/stm32h7/build.rs
@@ -1,4 +1,34 @@
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
1fn main() { 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
2 println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
diff --git a/examples/stm32h7/memory.x b/examples/stm32h7/memory.x
new file mode 100644
index 000000000..e5ab1f62c
--- /dev/null
+++ b/examples/stm32h7/memory.x
@@ -0,0 +1,14 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 + BANK_2 */
4 RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3)
13 } > RAM_D3
14} \ No newline at end of file
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index fe6fe69a1..98504ddf6 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -5,7 +5,7 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::Config; 7use embassy_stm32::Config;
8use embassy_time::{Delay, Timer}; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
@@ -38,22 +38,22 @@ async fn main(_spawner: Spawner) {
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.voltage_scale = VoltageScale::Scale1; 40 config.rcc.voltage_scale = VoltageScale::Scale1;
41 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 41 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
42 } 42 }
43 let mut p = embassy_stm32::init(config); 43 let mut p = embassy_stm32::init(config);
44 44
45 info!("Hello World!"); 45 info!("Hello World!");
46 46
47 let mut adc = Adc::new(p.ADC3, &mut Delay); 47 let mut adc = Adc::new(p.ADC3);
48 48
49 adc.set_sample_time(SampleTime::Cycles32_5); 49 adc.set_sample_time(SampleTime::CYCLES32_5);
50 50
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_internal(&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/camera.rs b/examples/stm32h7/src/bin/camera.rs
index e5a104baf..170a5aa28 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) {
78 ); 78 );
79 79
80 defmt::info!("attempting capture"); 80 defmt::info!("attempting capture");
81 defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); 81 defmt::unwrap!(dcmi.capture(unsafe { &mut *core::ptr::addr_of_mut!(FRAME) }).await);
82 82
83 defmt::info!("captured frame: {:x}", unsafe { &FRAME }); 83 defmt::info!("captured frame: {:x}", unsafe { &*core::ptr::addr_of!(FRAME) });
84 84
85 defmt::info!("main loop running"); 85 defmt::info!("main loop running");
86 loop { 86 loop {
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index 2906d1576..0af11ef3e 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -16,59 +16,83 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 19 config.rcc.hse = Some(rcc::Hse {
20 // configure FDCAN to use PLL1_Q at 64 MHz 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 config.rcc.pll1 = Some(rcc::Pll { 21 mode: rcc::HseMode::Oscillator,
22 source: rcc::PllSource::HSI,
23 prediv: rcc::PllPreDiv::DIV4,
24 mul: rcc::PllMul::MUL8,
25 divp: None,
26 divq: Some(rcc::PllDiv::DIV2),
27 divr: None,
28 }); 22 });
29 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; 23 config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
30 24
31 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
32 26
33 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 27 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
34 28
35 can.can.apply_config( 29 // 250k bps
36 can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { 30 can.set_bitrate(250_000);
37 sync_jump_width: 1.try_into().unwrap(),
38 prescaler: 8.try_into().unwrap(),
39 seg1: 13.try_into().unwrap(),
40 seg2: 2.try_into().unwrap(),
41 }),
42 );
43 31
44 info!("Configured"); 32 //let mut can = can.into_internal_loopback_mode();
33 let mut can = can.into_normal_mode();
45 34
46 let mut can = can.into_external_loopback_mode(); 35 info!("CAN Configured");
47 //let mut can = can.into_normal_mode();
48 36
49 let mut i = 0; 37 let mut i = 0;
38 let mut last_read_ts = embassy_time::Instant::now();
39
50 loop { 40 loop {
51 let frame = can::TxFrame::new( 41 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
52 can::TxFrameHeader {
53 len: 1,
54 frame_format: can::FrameFormat::Standard,
55 id: can::StandardId::new(0x123).unwrap().into(),
56 bit_rate_switching: false,
57 marker: None,
58 },
59 &[i],
60 )
61 .unwrap();
62 info!("Writing frame"); 42 info!("Writing frame");
63 _ = can.write(&frame).await; 43 _ = can.write(&frame).await;
64 44
65 match can.read().await { 45 match can.read().await {
66 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 46 Ok(envelope) => {
47 let (rx_frame, ts) = envelope.parts();
48 let delta = (ts - last_read_ts).as_millis();
49 last_read_ts = ts;
50 info!(
51 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
52 rx_frame.data()[0],
53 rx_frame.data()[1],
54 rx_frame.data()[2],
55 rx_frame.data()[3],
56 delta,
57 )
58 }
67 Err(_err) => error!("Error in frame"), 59 Err(_err) => error!("Error in frame"),
68 } 60 }
69 61
70 Timer::after_millis(250).await; 62 Timer::after_millis(250).await;
71 63
72 i += 1; 64 i += 1;
65 if i > 3 {
66 break;
67 }
68 }
69
70 let (mut tx, mut rx, _props) = can.split();
71 // With split
72 loop {
73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
74 info!("Writing frame");
75 _ = tx.write(&frame).await;
76
77 match rx.read().await {
78 Ok(envelope) => {
79 let (rx_frame, ts) = envelope.parts();
80 let delta = (ts - last_read_ts).as_millis();
81 last_read_ts = ts;
82 info!(
83 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
84 rx_frame.data()[0],
85 rx_frame.data()[1],
86 rx_frame.data()[2],
87 rx_frame.data()[3],
88 delta,
89 )
90 }
91 Err(_err) => error!("Error in frame"),
92 }
93
94 Timer::after_millis(250).await;
95
96 i = i.wrapping_add(1);
73 } 97 }
74} 98}
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a9bf46de0..a6f969aba 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -40,7 +40,7 @@ fn main() -> ! {
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1; 42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 43 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
44 } 44 }
45 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
46 46
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index d88bd838f..3a9887e3c 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -6,9 +6,9 @@ use embassy_executor::Spawner;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::pac::timer::vals::Mms; 7use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.voltage_scale = VoltageScale::Scale1; 44 config.rcc.voltage_scale = VoltageScale::Scale1;
45 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 45 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
46 } 46 }
47 47
48 // Initialize the board and obtain a Peripherals instance 48 // Initialize the board and obtain a Peripherals instance
@@ -51,19 +51,19 @@ async fn main(spawner: Spawner) {
51 // Obtain two independent channels (p.DAC1 can only be consumed once, though!) 51 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
52 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); 52 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
53 53
54 spawner.spawn(dac_task1(dac_ch1)).ok(); 54 spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok();
55 spawner.spawn(dac_task2(dac_ch2)).ok(); 55 spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok();
56} 56}
57 57
58#[embassy_executor::task] 58#[embassy_executor::task]
59async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 59async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
60 let data: &[u8; 256] = &calculate_array::<256>(); 60 let data: &[u8; 256] = &calculate_array::<256>();
61 61
62 info!("TIM6 frequency is {}", TIM6::frequency()); 62 info!("TIM6 frequency is {}", frequency::<TIM6>());
63 const FREQUENCY: Hertz = Hertz::hz(200); 63 const FREQUENCY: Hertz = Hertz::hz(200);
64 64
65 // Compute the reload value such that we obtain the FREQUENCY for the sine 65 // Compute the reload value such that we obtain the FREQUENCY for the sine
66 let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; 66 let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32;
67 67
68 // Depends on your clock and on the specific chip used, you may need higher or lower values here 68 // Depends on your clock and on the specific chip used, you may need higher or lower values here
69 if reload < 10 { 69 if reload < 10 {
@@ -74,17 +74,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
74 dac.set_triggering(true); 74 dac.set_triggering(true);
75 dac.enable(); 75 dac.enable();
76 76
77 TIM6::enable_and_reset(); 77 let tim = Timer::new(tim);
78 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 78 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
79 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 79 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
80 TIM6::regs_basic().cr1().modify(|w| { 80 tim.regs_basic().cr1().modify(|w| {
81 w.set_opm(false); 81 w.set_opm(false);
82 w.set_cen(true); 82 w.set_cen(true);
83 }); 83 });
84 84
85 debug!( 85 debug!(
86 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 86 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
87 TIM6::frequency(), 87 frequency::<TIM6>(),
88 FREQUENCY, 88 FREQUENCY,
89 reload, 89 reload,
90 reload as u16, 90 reload as u16,
@@ -99,22 +99,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
99} 99}
100 100
101#[embassy_executor::task] 101#[embassy_executor::task]
102async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 102async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
103 let data: &[u8; 256] = &calculate_array::<256>(); 103 let data: &[u8; 256] = &calculate_array::<256>();
104 104
105 info!("TIM7 frequency is {}", TIM7::frequency()); 105 info!("TIM7 frequency is {}", frequency::<TIM6>());
106 106
107 const FREQUENCY: Hertz = Hertz::hz(600); 107 const FREQUENCY: Hertz = Hertz::hz(600);
108 let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; 108 let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32;
109 109
110 if reload < 10 { 110 if reload < 10 {
111 error!("Reload value {} below threshold!", reload); 111 error!("Reload value {} below threshold!", reload);
112 } 112 }
113 113
114 TIM7::enable_and_reset(); 114 let tim = Timer::new(tim);
115 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 115 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
116 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 116 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
117 TIM7::regs_basic().cr1().modify(|w| { 117 tim.regs_basic().cr1().modify(|w| {
118 w.set_opm(false); 118 w.set_opm(false);
119 w.set_cen(true); 119 w.set_cen(true);
120 }); 120 });
@@ -125,7 +125,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
125 125
126 debug!( 126 debug!(
127 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 127 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
128 TIM7::frequency(), 128 frequency::<TIM7>(),
129 FREQUENCY, 129 FREQUENCY,
130 reload, 130 reload,
131 reload as u16, 131 reload as u16,
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index cd9a27fcd..ec3f2c000 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs {
24type Device = Ethernet<'static, ETH, GenericSMI>; 24type Device = Ethernet<'static, ETH, GenericSMI>;
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 28 runner.run().await
29} 29}
30 30
31#[embassy_executor::main] 31#[embassy_executor::main]
@@ -64,19 +64,21 @@ async fn main(spawner: Spawner) -> ! {
64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
65 65
66 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); 66 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
67 // warning: Not all STM32H7 devices have the exact same pins here
68 // for STM32H747XIH, replace p.PB13 for PG12
67 let device = Ethernet::new( 69 let device = Ethernet::new(
68 PACKETS.init(PacketQueue::<4, 4>::new()), 70 PACKETS.init(PacketQueue::<4, 4>::new()),
69 p.ETH, 71 p.ETH,
70 Irqs, 72 Irqs,
71 p.PA1, 73 p.PA1, // ref_clk
72 p.PA2, 74 p.PA2, // mdio
73 p.PC1, 75 p.PC1, // eth_mdc
74 p.PA7, 76 p.PA7, // CRS_DV: Carrier Sense
75 p.PC4, 77 p.PC4, // RX_D0: Received Bit 0
76 p.PC5, 78 p.PC5, // RX_D1: Received Bit 1
77 p.PG13, 79 p.PG13, // TX_D0: Transmit Bit 0
78 p.PB13, 80 p.PB13, // TX_D1: Transmit Bit 1
79 p.PG11, 81 p.PG11, // TX_EN: Transmit Enable
80 GenericSMI::new(0), 82 GenericSMI::new(0),
81 mac_addr, 83 mac_addr,
82 ); 84 );
@@ -89,17 +91,11 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 91 //});
90 92
91 // Init network stack 93 // Init network stack
92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new( 95 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
95 device,
96 config,
97 RESOURCES.init(StackResources::<3>::new()),
98 seed,
99 ));
100 96
101 // Launch network task 97 // Launch network task
102 unwrap!(spawner.spawn(net_task(&stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
103 99
104 // Ensure DHCP configuration is up before trying connect 100 // Ensure DHCP configuration is up before trying connect
105 stack.wait_config_up().await; 101 stack.wait_config_up().await;
@@ -111,7 +107,7 @@ async fn main(spawner: Spawner) -> ! {
111 let mut tx_buffer = [0; 1024]; 107 let mut tx_buffer = [0; 1024];
112 108
113 loop { 109 loop {
114 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 110 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
115 111
116 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 112 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
117 113
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index aeb169e19..24983ca85 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! {
64 64
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 67 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
68 68
69 let device = Ethernet::new( 69 let device = Ethernet::new(
70 PACKETS.init(PacketQueue::<16, 16>::new()), 70 PACKETS.init(PacketQueue::<4, 4>::new()),
71 p.ETH, 71 p.ETH,
72 Irqs, 72 Irqs,
73 p.PA1, 73 p.PA1,
@@ -91,17 +91,11 @@ async fn main(spawner: Spawner) -> ! {
91 //}); 91 //});
92 92
93 // Init network stack 93 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new( 95 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 device,
98 config,
99 RESOURCES.init(StackResources::<3>::new()),
100 seed,
101 ));
102 96
103 // Launch network task 97 // Launch network task
104 unwrap!(spawner.spawn(net_task(stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
105 99
106 // Ensure DHCP configuration is up before trying connect 100 // Ensure DHCP configuration is up before trying connect
107 stack.wait_config_up().await; 101 stack.wait_config_up().await;
@@ -109,7 +103,7 @@ async fn main(spawner: Spawner) -> ! {
109 info!("Network task initialized"); 103 info!("Network task initialized");
110 104
111 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 105 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
112 let client = TcpClient::new(&stack, &state); 106 let client = TcpClient::new(stack, &state);
113 107
114 loop { 108 loop {
115 // You need to start a server on the host machine, for example: `nc -l 8000` 109 // You need to start a server on the host machine, for example: `nc -l 8000`
diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs
index de6ea522a..768d85993 100644
--- a/examples/stm32h7/src/bin/eth_client_mii.rs
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! {
64 64
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 67 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
68 68
69 let device = Ethernet::new_mii( 69 let device = Ethernet::new_mii(
70 PACKETS.init(PacketQueue::<16, 16>::new()), 70 PACKETS.init(PacketQueue::<4, 4>::new()),
71 p.ETH, 71 p.ETH,
72 Irqs, 72 Irqs,
73 p.PA1, 73 p.PA1,
@@ -97,17 +97,11 @@ async fn main(spawner: Spawner) -> ! {
97 //}); 97 //});
98 98
99 // Init network stack 99 // Init network stack
100 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 100 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new( 101 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
103 device,
104 config,
105 RESOURCES.init(StackResources::<3>::new()),
106 seed,
107 ));
108 102
109 // Launch network task 103 // Launch network task
110 unwrap!(spawner.spawn(net_task(stack))); 104 unwrap!(spawner.spawn(net_task(runner)));
111 105
112 // Ensure DHCP configuration is up before trying connect 106 // Ensure DHCP configuration is up before trying connect
113 stack.wait_config_up().await; 107 stack.wait_config_up().await;
@@ -115,7 +109,7 @@ async fn main(spawner: Spawner) -> ! {
115 info!("Network task initialized"); 109 info!("Network task initialized");
116 110
117 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 111 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
118 let client = TcpClient::new(&stack, &state); 112 let client = TcpClient::new(stack, &state);
119 113
120 loop { 114 loop {
121 // You need to start a server on the host machine, for example: `nc -l 8000` 115 // You need to start a server on the host machine, for example: `nc -l 8000`
diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs
new file mode 100644
index 000000000..6f4815582
--- /dev/null
+++ b/examples/stm32h7/src/bin/i2c_shared.rs
@@ -0,0 +1,111 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
8use embassy_executor::Spawner;
9use embassy_stm32::i2c::{self, I2c};
10use embassy_stm32::mode::Async;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, peripherals};
13use embassy_sync::blocking_mutex::NoopMutex;
14use embassy_time::{Duration, Timer};
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18const TMP117_ADDR: u8 = 0x48;
19const TMP117_TEMP_RESULT: u8 = 0x00;
20
21const SHTC3_ADDR: u8 = 0x70;
22const SHTC3_WAKEUP: [u8; 2] = [0x35, 0x17];
23const SHTC3_MEASURE_RH_FIRST: [u8; 2] = [0x5c, 0x24];
24const SHTC3_SLEEP: [u8; 2] = [0xb0, 0x98];
25
26static I2C_BUS: StaticCell<NoopMutex<RefCell<I2c<'static, Async>>>> = StaticCell::new();
27
28bind_interrupts!(struct Irqs {
29 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
30 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
31});
32
33#[embassy_executor::task]
34async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) {
35 let mut data = [0u8; 2];
36
37 loop {
38 match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data) {
39 Ok(()) => {
40 let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0;
41 info!("Temperature {}", temp);
42 }
43 Err(_) => error!("I2C Error"),
44 }
45
46 Timer::after(Duration::from_millis(1000)).await;
47 }
48}
49
50#[embassy_executor::task]
51async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) {
52 let mut data = [0u8; 6];
53
54 loop {
55 // Wakeup
56 match i2c.write(SHTC3_ADDR, &SHTC3_WAKEUP) {
57 Ok(()) => Timer::after(Duration::from_millis(20)).await,
58 Err(_) => error!("I2C Error"),
59 }
60
61 // Measurement
62 match i2c.write(SHTC3_ADDR, &SHTC3_MEASURE_RH_FIRST) {
63 Ok(()) => Timer::after(Duration::from_millis(5)).await,
64 Err(_) => error!("I2C Error"),
65 }
66
67 // Result
68 match i2c.read(SHTC3_ADDR, &mut data) {
69 Ok(()) => Timer::after(Duration::from_millis(5)).await,
70 Err(_) => error!("I2C Error"),
71 }
72
73 // Sleep
74 match i2c.write(SHTC3_ADDR, &SHTC3_SLEEP) {
75 Ok(()) => {
76 let (bytes, _) = data.split_at(core::mem::size_of::<i16>());
77 let rh = f32::from(u16::from_be_bytes(bytes.try_into().unwrap())) * 100.0 / 65536.0;
78 info!("Humidity: {}", rh);
79 }
80 Err(_) => error!("I2C Error"),
81 }
82
83 Timer::after(Duration::from_millis(1000)).await;
84 }
85}
86
87#[embassy_executor::main]
88async fn main(spawner: Spawner) {
89 let p = embassy_stm32::init(Default::default());
90
91 let i2c = I2c::new(
92 p.I2C1,
93 p.PB8,
94 p.PB9,
95 Irqs,
96 p.DMA1_CH4,
97 p.DMA1_CH5,
98 Hertz(100_000),
99 Default::default(),
100 );
101 let i2c_bus = NoopMutex::new(RefCell::new(i2c));
102 let i2c_bus = I2C_BUS.init(i2c_bus);
103
104 // Device 1, using embedded-hal-async compatible driver for TMP117
105 let i2c_dev1 = I2cDevice::new(i2c_bus);
106 spawner.spawn(temperature(i2c_dev1)).unwrap();
107
108 // Device 2, using embedded-hal-async compatible driver for SHTC3
109 let i2c_dev2 = I2cDevice::new(i2c_bus);
110 spawner.spawn(humidity(i2c_dev2)).unwrap();
111}
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index cc508c3cf..b796996ea 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -3,11 +3,11 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::low_level::AFType; 6use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed};
7use embassy_stm32::gpio::Speed;
8use embassy_stm32::time::{khz, Hertz}; 7use embassy_stm32::time::{khz, Hertz};
9use embassy_stm32::timer::*; 8use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer};
10use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; 9use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel};
10use embassy_stm32::{into_ref, Config, Peripheral};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -56,11 +56,15 @@ async fn main(_spawner: Spawner) {
56 Timer::after_millis(300).await; 56 Timer::after_millis(300).await;
57 } 57 }
58} 58}
59pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { 59pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> {
60 inner: PeripheralRef<'d, T>, 60 tim: LLTimer<'d, T>,
61 _ch1: Flex<'d>,
62 _ch2: Flex<'d>,
63 _ch3: Flex<'d>,
64 _ch4: Flex<'d>,
61} 65}
62 66
63impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { 67impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> {
64 pub fn new( 68 pub fn new(
65 tim: impl Peripheral<P = T> + 'd, 69 tim: impl Peripheral<P = T> + 'd,
66 ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, 70 ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
@@ -69,25 +73,33 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
69 ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, 73 ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd,
70 freq: Hertz, 74 freq: Hertz,
71 ) -> Self { 75 ) -> Self {
72 into_ref!(tim, ch1, ch2, ch3, ch4); 76 into_ref!(ch1, ch2, ch3, ch4);
73 77
74 T::enable_and_reset(); 78 let af1 = ch1.af_num();
75 79 let af2 = ch2.af_num();
76 ch1.set_speed(Speed::VeryHigh); 80 let af3 = ch3.af_num();
77 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); 81 let af4 = ch4.af_num();
78 ch2.set_speed(Speed::VeryHigh); 82 let mut ch1 = Flex::new(ch1);
79 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); 83 let mut ch2 = Flex::new(ch2);
80 ch3.set_speed(Speed::VeryHigh); 84 let mut ch3 = Flex::new(ch3);
81 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); 85 let mut ch4 = Flex::new(ch4);
82 ch4.set_speed(Speed::VeryHigh); 86 ch1.set_as_af_unchecked(af1, AfType::output(OutputType::PushPull, Speed::VeryHigh));
83 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); 87 ch2.set_as_af_unchecked(af2, AfType::output(OutputType::PushPull, Speed::VeryHigh));
84 88 ch3.set_as_af_unchecked(af3, AfType::output(OutputType::PushPull, Speed::VeryHigh));
85 let mut this = Self { inner: tim }; 89 ch4.set_as_af_unchecked(af4, AfType::output(OutputType::PushPull, Speed::VeryHigh));
90
91 let mut this = Self {
92 tim: LLTimer::new(tim),
93 _ch1: ch1,
94 _ch2: ch2,
95 _ch3: ch3,
96 _ch4: ch4,
97 };
86 98
87 this.set_frequency(freq); 99 this.set_frequency(freq);
88 this.inner.start(); 100 this.tim.start();
89 101
90 let r = T::regs_gp32(); 102 let r = this.tim.regs_gp32();
91 r.ccmr_output(0) 103 r.ccmr_output(0)
92 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 104 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
93 r.ccmr_output(0) 105 r.ccmr_output(0)
@@ -101,23 +113,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
101 } 113 }
102 114
103 pub fn enable(&mut self, channel: Channel) { 115 pub fn enable(&mut self, channel: Channel) {
104 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); 116 self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
105 } 117 }
106 118
107 pub fn disable(&mut self, channel: Channel) { 119 pub fn disable(&mut self, channel: Channel) {
108 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); 120 self.tim
121 .regs_gp32()
122 .ccer()
123 .modify(|w| w.set_cce(channel.index(), false));
109 } 124 }
110 125
111 pub fn set_frequency(&mut self, freq: Hertz) { 126 pub fn set_frequency(&mut self, freq: Hertz) {
112 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); 127 self.tim.set_frequency(freq);
113 } 128 }
114 129
115 pub fn get_max_duty(&self) -> u32 { 130 pub fn get_max_duty(&self) -> u32 {
116 T::regs_gp32().arr().read().arr() 131 self.tim.regs_gp32().arr().read()
117 } 132 }
118 133
119 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 134 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
120 defmt::assert!(duty < self.get_max_duty()); 135 defmt::assert!(duty < self.get_max_duty());
121 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) 136 self.tim.regs_gp32().ccr(channel.index()).write_value(duty)
122 } 137 }
123} 138}
diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs
new file mode 100644
index 000000000..b4620888f
--- /dev/null
+++ b/examples/stm32h7/src/bin/multiprio.rs
@@ -0,0 +1,150 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58
59use cortex_m_rt::entry;
60use defmt::*;
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_stm32::interrupt;
63use embassy_stm32::interrupt::{InterruptExt, Priority};
64use embassy_time::{Instant, Timer};
65use static_cell::StaticCell;
66use {defmt_rtt as _, panic_probe as _};
67
68#[embassy_executor::task]
69async fn run_high() {
70 loop {
71 info!(" [high] tick!");
72 Timer::after_ticks(27374).await;
73 }
74}
75
76#[embassy_executor::task]
77async fn run_med() {
78 loop {
79 let start = Instant::now();
80 info!(" [med] Starting long computation");
81
82 // Spin-wait to simulate a long CPU computation
83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84
85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33;
87 info!(" [med] done in {} ms", ms);
88
89 Timer::after_ticks(23421).await;
90 }
91}
92
93#[embassy_executor::task]
94async fn run_low() {
95 loop {
96 let start = Instant::now();
97 info!("[low] Starting long computation");
98
99 // Spin-wait to simulate a long CPU computation
100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101
102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33;
104 info!("[low] done in {} ms", ms);
105
106 Timer::after_ticks(32983).await;
107 }
108}
109
110static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
111static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113
114#[interrupt]
115unsafe fn UART4() {
116 EXECUTOR_HIGH.on_interrupt()
117}
118
119#[interrupt]
120unsafe fn UART5() {
121 EXECUTOR_MED.on_interrupt()
122}
123
124#[entry]
125fn main() -> ! {
126 info!("Hello World!");
127
128 let _p = embassy_stm32::init(Default::default());
129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
135 // High-priority executor: UART4, priority level 6
136 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high()));
139
140 // Medium-priority executor: UART5, priority level 7
141 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med()));
144
145 // Low priority executor: runs in thread mode, using WFE/SEV
146 let executor = EXECUTOR_LOW.init(Executor::new());
147 executor.run(|spawner| {
148 unwrap!(spawner.spawn(run_low()));
149 });
150}
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs
index c6b9cf57e..0adb48877 100644
--- a/examples/stm32h7/src/bin/rtc.rs
+++ b/examples/stm32h7/src/bin/rtc.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 .unwrap(); 24 .unwrap();
25 25
26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
27 info!("Got RTC! {:?}", now.timestamp()); 27 info!("Got RTC! {:?}", now.and_utc().timestamp());
28 28
29 rtc.set_datetime(now.into()).expect("datetime not set"); 29 rtc.set_datetime(now.into()).expect("datetime not set");
30 30
@@ -32,5 +32,5 @@ async fn main(_spawner: Spawner) {
32 Timer::after_millis(20000).await; 32 Timer::after_millis(20000).await;
33 33
34 let then: NaiveDateTime = rtc.now().unwrap().into(); 34 let then: NaiveDateTime = rtc.now().unwrap().into();
35 info!("Got RTC! {:?}", then.timestamp()); 35 info!("Got RTC! {:?}", then.and_utc().timestamp());
36} 36}
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.rs b/examples/stm32h7/src/bin/spi.rs
index aed27723a..ad4a8aaf7 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -7,8 +7,7 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
13use embassy_stm32::{spi, Config}; 12use embassy_stm32::{spi, Config};
14use heapless::String; 13use heapless::String;
@@ -16,7 +15,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18#[embassy_executor::task] 17#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking>) {
20 for n in 0u32.. { 19 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
@@ -62,7 +61,7 @@ fn main() -> ! {
62 let mut spi_config = spi::Config::default(); 61 let mut spi_config = spi::Config::default();
63 spi_config.frequency = mhz(1); 62 spi_config.frequency = mhz(1);
64 63
65 let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); 64 let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
66 65
67 let executor = EXECUTOR.init(Executor::new()); 66 let executor = EXECUTOR.init(Executor::new());
68 67
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
new file mode 100644
index 000000000..43fb6b41c
--- /dev/null
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -0,0 +1,84 @@
1#![no_std]
2#![no_main]
3
4use core::fmt::Write;
5use core::str::from_utf8;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config};
13use grounded::uninit::GroundedArrayCell;
14use heapless::String;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18// Defined in memory.x
19#[link_section = ".ram_d3"]
20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
21
22#[embassy_executor::task]
23async fn main_task(mut spi: spi::Spi<'static, Async>) {
24 let (read_buffer, write_buffer) = unsafe {
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 };
31
32 for n in 0u32.. {
33 let mut write: String<128> = String::new();
34 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
35 let read_buffer = &mut read_buffer[..write.len()];
36 let write_buffer = &mut write_buffer[..write.len()];
37 // copy data to write_buffer which is located in D3 domain, accessable by BDMA
38 write_buffer.clone_from_slice(write.as_bytes());
39
40 spi.transfer(read_buffer, write_buffer).await.ok();
41 info!("read via spi+dma: {}", from_utf8(read_buffer).unwrap());
42 }
43}
44
45static EXECUTOR: StaticCell<Executor> = StaticCell::new();
46
47#[entry]
48fn main() -> ! {
49 info!("Hello World!");
50
51 let mut config = Config::default();
52 {
53 use embassy_stm32::rcc::*;
54 config.rcc.hsi = Some(HSIPrescaler::DIV1);
55 config.rcc.csi = true;
56 config.rcc.pll1 = Some(Pll {
57 source: PllSource::HSI,
58 prediv: PllPreDiv::DIV4,
59 mul: PllMul::MUL50,
60 divp: Some(PllDiv::DIV2),
61 divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz.
62 divr: None,
63 });
64 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
65 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
66 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
67 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
68 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
69 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
70 config.rcc.voltage_scale = VoltageScale::Scale1;
71 }
72 let p = embassy_stm32::init(config);
73
74 let mut spi_config = spi::Config::default();
75 spi_config.frequency = mhz(1);
76
77 let spi = spi::Spi::new(p.SPI6, p.PA5, p.PA7, p.PA6, p.BDMA_CH1, p.BDMA_CH0, spi_config);
78
79 let executor = EXECUTOR.init(Executor::new());
80
81 executor.run(|spawner| {
82 unwrap!(spawner.spawn(main_task(spi)));
83 })
84}
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 54d4d7656..731c7fef5 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -7,7 +7,7 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; 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 heapless::String; 13use heapless::String;
@@ -15,7 +15,7 @@ use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { 18async fn main_task(mut spi: spi::Spi<'static, Async>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index ae1f3a2e9..6f340d40a 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index b98c40877..2bb58be5e 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -3,8 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{DMA1_CH1, UART7};
8use embassy_stm32::usart::{Config, Uart, UartRx}; 7use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 8use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 9use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +14,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 14 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 15});
17 16
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 17static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 18
32#[embassy_executor::main] 19#[embassy_executor::main]
@@ -50,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
50} 37}
51 38
52#[embassy_executor::task] 39#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { 40async fn reader(mut rx: UartRx<'static, Async>) {
54 let mut buf = [0; 8]; 41 let mut buf = [0; 8];
55 loop { 42 loop {
56 info!("reading..."); 43 info!("reading...");
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index d81efb541..65ae597d4 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -3,18 +3,23 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::usb_otg::{Driver, Instance}; 6use embassy_futures::join::join;
7use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
8use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
9use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
10use embassy_usb::Builder; 11use embassy_usb::Builder;
11use futures::future::join;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
15 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 15 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
16}); 16});
17 17
18// If you are trying this and your USB device doesn't connect, the most
19// common issues are the RCC config and vbus_detection
20//
21// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
22// for more information.
18#[embassy_executor::main] 23#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
20 info!("Hello World!"); 25 info!("Hello World!");
@@ -40,13 +45,20 @@ async fn main(_spawner: Spawner) {
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 45 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 46 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1; 47 config.rcc.voltage_scale = VoltageScale::Scale1;
48 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
43 } 49 }
44 let p = embassy_stm32::init(config); 50 let p = embassy_stm32::init(config);
45 51
46 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
47 let mut ep_out_buffer = [0u8; 256]; 53 let mut ep_out_buffer = [0u8; 256];
48 let mut config = embassy_stm32::usb_otg::Config::default(); 54 let mut config = embassy_stm32::usb::Config::default();
49 config.vbus_detection = true; 55
56 // Do not enable vbus_detection. This is a safe default that works in all boards.
57 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
58 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
59 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
60 config.vbus_detection = false;
61
50 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 62 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
51 63
52 // Create embassy-usb Config 64 // Create embassy-usb Config
@@ -64,7 +76,6 @@ async fn main(_spawner: Spawner) {
64 76
65 // Create embassy-usb DeviceBuilder using the driver and config. 77 // Create embassy-usb DeviceBuilder using the driver and config.
66 // It needs some buffers for building the descriptors. 78 // It needs some buffers for building the descriptors.
67 let mut device_descriptor = [0; 256];
68 let mut config_descriptor = [0; 256]; 79 let mut config_descriptor = [0; 256];
69 let mut bos_descriptor = [0; 256]; 80 let mut bos_descriptor = [0; 256];
70 let mut control_buf = [0; 64]; 81 let mut control_buf = [0; 64];
@@ -74,7 +85,6 @@ async fn main(_spawner: Spawner) {
74 let mut builder = Builder::new( 85 let mut builder = Builder::new(
75 driver, 86 driver,
76 config, 87 config,
77 &mut device_descriptor,
78 &mut config_descriptor, 88 &mut config_descriptor,
79 &mut bos_descriptor, 89 &mut bos_descriptor,
80 &mut [], // no msos descriptors 90 &mut [], // no msos descriptors
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..93e9575b6
--- /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.2.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", 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/stm32h755cm4/.cargo/config.toml b/examples/stm32h755cm4/.cargo/config.toml
new file mode 100644
index 000000000..193e6bbc3
--- /dev/null
+++ b/examples/stm32h755cm4/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
new file mode 100644
index 000000000..7a42fbdaa
--- /dev/null
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -0,0 +1,75 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h755cm4-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h755zi-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17
18defmt = "0.3"
19defmt-rtt = "0.4"
20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" }
27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1"
32micromath = "2.0.0"
33stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1"
35static_cell = "2"
36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
38
39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47
48# cargo test
49[profile.test]
50codegen-units = 1
51debug = 2
52debug-assertions = true # <-
53incremental = false
54opt-level = 3 # <-
55overflow-checks = true # <-
56
57# cargo build/run --release
58[profile.release]
59codegen-units = 1
60debug = 2
61debug-assertions = false # <-
62incremental = false
63lto = 'fat'
64opt-level = 3 # <-
65overflow-checks = false # <-
66
67# cargo test --release
68[profile.bench]
69codegen-units = 1
70debug = 2
71debug-assertions = false # <-
72incremental = false
73lto = 'fat'
74opt-level = 3 # <-
75overflow-checks = false # <-
diff --git a/examples/stm32h755cm4/build.rs b/examples/stm32h755cm4/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h755cm4/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/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x
new file mode 100644
index 000000000..7d60354e3
--- /dev/null
+++ b/examples/stm32h755cm4/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08100000, LENGTH = 1024K /* BANK_2 */
4 RAM : ORIGIN = 0x10000000, LENGTH = 128K /* SRAM1 */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3.shared_data)
13 *(.ram_d3)
14 } > RAM_D3
15} \ No newline at end of file
diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs
new file mode 100644
index 000000000..b5c547839
--- /dev/null
+++ b/examples/stm32h755cm4/src/bin/blinky.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".ram_d3.shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init_secondary(&SHARED_DATA);
19 info!("Hello World!");
20
21 let mut led = Output::new(p.PE1, Level::High, Speed::Low);
22
23 loop {
24 info!("high");
25 led.set_high();
26 Timer::after_millis(250).await;
27
28 info!("low");
29 led.set_low();
30 Timer::after_millis(250).await;
31 }
32}
diff --git a/examples/stm32h755cm7/.cargo/config.toml b/examples/stm32h755cm7/.cargo/config.toml
new file mode 100644
index 000000000..193e6bbc3
--- /dev/null
+++ b/examples/stm32h755cm7/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
new file mode 100644
index 000000000..4f0f69c3f
--- /dev/null
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -0,0 +1,75 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h755cm7-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17
18defmt = "0.3"
19defmt-rtt = "0.4"
20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" }
27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1"
32micromath = "2.0.0"
33stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1"
35static_cell = "2"
36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
38
39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47
48# cargo test
49[profile.test]
50codegen-units = 1
51debug = 2
52debug-assertions = true # <-
53incremental = false
54opt-level = 3 # <-
55overflow-checks = true # <-
56
57# cargo build/run --release
58[profile.release]
59codegen-units = 1
60debug = 2
61debug-assertions = false # <-
62incremental = false
63lto = 'fat'
64opt-level = 3 # <-
65overflow-checks = false # <-
66
67# cargo test --release
68[profile.bench]
69codegen-units = 1
70debug = 2
71debug-assertions = false # <-
72incremental = false
73lto = 'fat'
74opt-level = 3 # <-
75overflow-checks = false # <-
diff --git a/examples/stm32h755cm7/build.rs b/examples/stm32h755cm7/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h755cm7/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/stm32h755cm7/memory.x b/examples/stm32h755cm7/memory.x
new file mode 100644
index 000000000..ef884796a
--- /dev/null
+++ b/examples/stm32h755cm7/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 1024K /* BANK_1 */
4 RAM : ORIGIN = 0x24000000, LENGTH = 512K /* AXIRAM */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3.shared_data)
13 *(.ram_d3)
14 } > RAM_D3
15} \ No newline at end of file
diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs
new file mode 100644
index 000000000..94d2226c0
--- /dev/null
+++ b/examples/stm32h755cm7/src/bin/blinky.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".ram_d3.shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = embassy_stm32::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), // 100mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 config.rcc.supply_config = SupplyConfig::DirectSMPS;
39 }
40 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
41 info!("Hello World!");
42
43 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
44
45 loop {
46 info!("high");
47 led.set_high();
48 Timer::after_millis(500).await;
49
50 info!("low");
51 led.set_low();
52 Timer::after_millis(500).await;
53 }
54}
diff --git a/examples/stm32h7rs/.cargo/config.toml b/examples/stm32h7rs/.cargo/config.toml
new file mode 100644
index 000000000..44dbda94f
--- /dev/null
+++ b/examples/stm32h7rs/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H7S3L8Hx'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml
new file mode 100644
index 000000000..f97dfd722
--- /dev/null
+++ b/examples/stm32h7rs/Cargo.toml
@@ -0,0 +1,73 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h7rs-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16
17defmt = "0.3"
18defmt-rtt = "0.4"
19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6"
23embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
24embedded-hal-async = { version = "1.0" }
25embedded-nal-async = { version = "0.7.1" }
26embedded-io-async = { version = "0.6.1" }
27panic-probe = { version = "0.3", features = ["print-defmt"] }
28heapless = { version = "0.8", default-features = false }
29rand_core = "0.6.3"
30critical-section = "1.1"
31micromath = "2.0.0"
32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1"
34static_cell = "2"
35chrono = { version = "^0.4", default-features = false }
36
37# cargo build/run
38[profile.dev]
39codegen-units = 1
40debug = 2
41debug-assertions = true # <-
42incremental = false
43opt-level = 3 # <-
44overflow-checks = true # <-
45
46# cargo test
47[profile.test]
48codegen-units = 1
49debug = 2
50debug-assertions = true # <-
51incremental = false
52opt-level = 3 # <-
53overflow-checks = true # <-
54
55# cargo build/run --release
56[profile.release]
57codegen-units = 1
58debug = 2
59debug-assertions = false # <-
60incremental = false
61lto = 'fat'
62opt-level = 3 # <-
63overflow-checks = false # <-
64
65# cargo test --release
66[profile.bench]
67codegen-units = 1
68debug = 2
69debug-assertions = false # <-
70incremental = false
71lto = 'fat'
72opt-level = 3 # <-
73overflow-checks = false # <-
diff --git a/examples/stm32h7rs/build.rs b/examples/stm32h7rs/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32h7rs/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs
new file mode 100644
index 000000000..137c585b7
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/blinky.rs
@@ -0,0 +1,51 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::time::Hertz;
8use embassy_stm32::Config;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.hse = Some(Hse {
18 freq: Hertz(24_000_000),
19 mode: HseMode::Oscillator,
20 });
21 config.rcc.pll1 = Some(Pll {
22 source: PllSource::HSE,
23 prediv: PllPreDiv::DIV3,
24 mul: PllMul::MUL150,
25 divp: Some(PllDiv::DIV2),
26 divq: None,
27 divr: None,
28 });
29 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
30 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
31 config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz
32 config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz
33 config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz
34 config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz
35 config.rcc.voltage_scale = VoltageScale::HIGH;
36 }
37 let p = embassy_stm32::init(config);
38 info!("Hello World!");
39
40 let mut led = Output::new(p.PD10, Level::High, Speed::Low);
41
42 loop {
43 info!("high");
44 led.set_high();
45 Timer::after_millis(500).await;
46
47 info!("low");
48 led.set_low();
49 Timer::after_millis(500).await;
50 }
51}
diff --git a/examples/stm32h7rs/src/bin/button_exti.rs b/examples/stm32h7rs/src/bin/button_exti.rs
new file mode 100644
index 000000000..34a08bbc6
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/button_exti.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16
17 info!("Press the USER button...");
18
19 loop {
20 button.wait_for_falling_edge().await;
21 info!("Pressed!");
22 button.wait_for_rising_edge().await;
23 info!("Released!");
24 }
25}
diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs
new file mode 100644
index 000000000..0af11ef3e
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/can.rs
@@ -0,0 +1,98 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::peripherals::*;
7use embassy_stm32::{bind_interrupts, can, rcc, Config};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
13 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.rcc.hse = Some(rcc::Hse {
20 freq: embassy_stm32::time::Hertz(25_000_000),
21 mode: rcc::HseMode::Oscillator,
22 });
23 config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
24
25 let peripherals = embassy_stm32::init(config);
26
27 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
28
29 // 250k bps
30 can.set_bitrate(250_000);
31
32 //let mut can = can.into_internal_loopback_mode();
33 let mut can = can.into_normal_mode();
34
35 info!("CAN Configured");
36
37 let mut i = 0;
38 let mut last_read_ts = embassy_time::Instant::now();
39
40 loop {
41 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame");
43 _ = can.write(&frame).await;
44
45 match can.read().await {
46 Ok(envelope) => {
47 let (rx_frame, ts) = envelope.parts();
48 let delta = (ts - last_read_ts).as_millis();
49 last_read_ts = ts;
50 info!(
51 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
52 rx_frame.data()[0],
53 rx_frame.data()[1],
54 rx_frame.data()[2],
55 rx_frame.data()[3],
56 delta,
57 )
58 }
59 Err(_err) => error!("Error in frame"),
60 }
61
62 Timer::after_millis(250).await;
63
64 i += 1;
65 if i > 3 {
66 break;
67 }
68 }
69
70 let (mut tx, mut rx, _props) = can.split();
71 // With split
72 loop {
73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
74 info!("Writing frame");
75 _ = tx.write(&frame).await;
76
77 match rx.read().await {
78 Ok(envelope) => {
79 let (rx_frame, ts) = envelope.parts();
80 let delta = (ts - last_read_ts).as_millis();
81 last_read_ts = ts;
82 info!(
83 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
84 rx_frame.data()[0],
85 rx_frame.data()[1],
86 rx_frame.data()[2],
87 rx_frame.data()[3],
88 delta,
89 )
90 }
91 Err(_err) => error!("Error in frame"),
92 }
93
94 Timer::after_millis(250).await;
95
96 i = i.wrapping_add(1);
97 }
98}
diff --git a/examples/stm32h7rs/src/bin/i2c.rs b/examples/stm32h7rs/src/bin/i2c.rs
new file mode 100644
index 000000000..31e83cbb5
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/i2c.rs
@@ -0,0 +1,42 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::{Error, I2c};
7use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, i2c, peripherals};
9use {defmt_rtt as _, panic_probe as _};
10
11const ADDRESS: u8 = 0x5F;
12const WHOAMI: u8 = 0x0F;
13
14bind_interrupts!(struct Irqs {
15 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
16 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello world!");
22 let p = embassy_stm32::init(Default::default());
23
24 let mut i2c = I2c::new(
25 p.I2C2,
26 p.PB10,
27 p.PB11,
28 Irqs,
29 p.GPDMA1_CH4,
30 p.GPDMA1_CH5,
31 Hertz(100_000),
32 Default::default(),
33 );
34
35 let mut data = [0u8; 1];
36
37 match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
38 Ok(()) => info!("Whoami: {}", data[0]),
39 Err(Error::Timeout) => error!("Operation timed out"),
40 Err(e) => error!("I2c Error: {:?}", e),
41 }
42}
diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs
new file mode 100644
index 000000000..a6ee27625
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/mco.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler};
8use embassy_time::Timer;
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 info!("Hello World!");
15
16 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
17
18 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8);
19
20 loop {
21 info!("high");
22 led.set_high();
23 Timer::after_millis(500).await;
24
25 info!("low");
26 led.set_low();
27 Timer::after_millis(500).await;
28 }
29}
diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs
new file mode 100644
index 000000000..b4620888f
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/multiprio.rs
@@ -0,0 +1,150 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58
59use cortex_m_rt::entry;
60use defmt::*;
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_stm32::interrupt;
63use embassy_stm32::interrupt::{InterruptExt, Priority};
64use embassy_time::{Instant, Timer};
65use static_cell::StaticCell;
66use {defmt_rtt as _, panic_probe as _};
67
68#[embassy_executor::task]
69async fn run_high() {
70 loop {
71 info!(" [high] tick!");
72 Timer::after_ticks(27374).await;
73 }
74}
75
76#[embassy_executor::task]
77async fn run_med() {
78 loop {
79 let start = Instant::now();
80 info!(" [med] Starting long computation");
81
82 // Spin-wait to simulate a long CPU computation
83 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
84
85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33;
87 info!(" [med] done in {} ms", ms);
88
89 Timer::after_ticks(23421).await;
90 }
91}
92
93#[embassy_executor::task]
94async fn run_low() {
95 loop {
96 let start = Instant::now();
97 info!("[low] Starting long computation");
98
99 // Spin-wait to simulate a long CPU computation
100 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
101
102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33;
104 info!("[low] done in {} ms", ms);
105
106 Timer::after_ticks(32983).await;
107 }
108}
109
110static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
111static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113
114#[interrupt]
115unsafe fn UART4() {
116 EXECUTOR_HIGH.on_interrupt()
117}
118
119#[interrupt]
120unsafe fn UART5() {
121 EXECUTOR_MED.on_interrupt()
122}
123
124#[entry]
125fn main() -> ! {
126 info!("Hello World!");
127
128 let _p = embassy_stm32::init(Default::default());
129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
135 // High-priority executor: UART4, priority level 6
136 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high()));
139
140 // Medium-priority executor: UART5, priority level 7
141 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med()));
144
145 // Low priority executor: runs in thread mode, using WFE/SEV
146 let executor = EXECUTOR_LOW.init(Executor::new());
147 executor.run(|spawner| {
148 unwrap!(spawner.spawn(run_low()));
149 });
150}
diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs
new file mode 100644
index 000000000..a9ef7200d
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/rng.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rng::Rng;
7use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 RNG => rng::InterruptHandler<peripherals::RNG>;
12});
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let mut config = Config::default();
17 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
18 let p = embassy_stm32::init(config);
19 info!("Hello World!");
20
21 let mut rng = Rng::new(p.RNG, Irqs);
22
23 let mut buf = [0u8; 16];
24 unwrap!(rng.async_fill_bytes(&mut buf).await);
25 info!("random bytes: {:02x}", buf);
26}
diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs
new file mode 100644
index 000000000..0adb48877
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/rtc.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3
4use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::LsConfig;
8use embassy_stm32::rtc::{Rtc, RtcConfig};
9use embassy_stm32::Config;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let mut config = Config::default();
16 config.rcc.ls = LsConfig::default_lse();
17
18 let p = embassy_stm32::init(config);
19 info!("Hello World!");
20
21 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
22 .unwrap()
23 .and_hms_opt(10, 30, 15)
24 .unwrap();
25
26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
27 info!("Got RTC! {:?}", now.and_utc().timestamp());
28
29 rtc.set_datetime(now.into()).expect("datetime not set");
30
31 // In reality the delay would be much longer
32 Timer::after_millis(20000).await;
33
34 let then: NaiveDateTime = rtc.now().unwrap().into();
35 info!("Got RTC! {:?}", then.and_utc().timestamp());
36}
diff --git a/examples/stm32h7rs/src/bin/signal.rs b/examples/stm32h7rs/src/bin/signal.rs
new file mode 100644
index 000000000..b73360f32
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/signal.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::signal::Signal;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
12
13#[embassy_executor::task]
14async fn my_sending_task() {
15 let mut counter: u32 = 0;
16
17 loop {
18 Timer::after_secs(1).await;
19
20 SIGNAL.signal(counter);
21
22 counter = counter.wrapping_add(1);
23 }
24}
25
26#[embassy_executor::main]
27async fn main(spawner: Spawner) {
28 let _p = embassy_stm32::init(Default::default());
29 unwrap!(spawner.spawn(my_sending_task()));
30
31 loop {
32 let received_counter = SIGNAL.wait().await;
33
34 info!("signalled, counter: {}", received_counter);
35 }
36}
diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs
new file mode 100644
index 000000000..8d6ccc58b
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/spi.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3
4use core::fmt::Write;
5use core::str::from_utf8;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::mode::Blocking;
11use embassy_stm32::spi;
12use embassy_stm32::time::mhz;
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Blocking>) {
19 for n in 0u32.. {
20 let mut write: String<128> = String::new();
21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
22 unsafe {
23 let result = spi.blocking_transfer_in_place(write.as_bytes_mut());
24 if let Err(_) = result {
25 defmt::panic!("crap");
26 }
27 }
28 info!("read via spi: {}", from_utf8(write.as_bytes()).unwrap());
29 }
30}
31
32static EXECUTOR: StaticCell<Executor> = StaticCell::new();
33
34#[entry]
35fn main() -> ! {
36 info!("Hello World!");
37 let p = embassy_stm32::init(Default::default());
38
39 let mut spi_config = spi::Config::default();
40 spi_config.frequency = mhz(1);
41
42 let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
43
44 let executor = EXECUTOR.init(Executor::new());
45
46 executor.run(|spawner| {
47 unwrap!(spawner.spawn(main_task(spi)));
48 })
49}
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs
new file mode 100644
index 000000000..cb305351b
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/spi_dma.rs
@@ -0,0 +1,46 @@
1#![no_std]
2#![no_main]
3
4use core::fmt::Write;
5use core::str::from_utf8;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::mode::Async;
11use embassy_stm32::spi;
12use embassy_stm32::time::mhz;
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Async>) {
19 for n in 0u32.. {
20 let mut write: String<128> = String::new();
21 let mut read = [0; 128];
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
23 // transfer will slice the &mut read down to &write's actual length.
24 spi.transfer(&mut read, write.as_bytes()).await.ok();
25 info!("read via spi+dma: {}", from_utf8(&read).unwrap());
26 }
27}
28
29static EXECUTOR: StaticCell<Executor> = StaticCell::new();
30
31#[entry]
32fn main() -> ! {
33 info!("Hello World!");
34 let p = embassy_stm32::init(Default::default());
35
36 let mut spi_config = spi::Config::default();
37 spi_config.frequency = mhz(1);
38
39 let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, p.GPDMA1_CH0, p.GPDMA1_CH1, spi_config);
40
41 let executor = EXECUTOR.init(Executor::new());
42
43 executor.run(|spawner| {
44 unwrap!(spawner.spawn(main_task(spi)));
45 })
46}
diff --git a/examples/stm32h7rs/src/bin/usart.rs b/examples/stm32h7rs/src/bin/usart.rs
new file mode 100644
index 000000000..cc49c2fdb
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usart.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::entry;
5use defmt::*;
6use embassy_executor::Executor;
7use embassy_stm32::usart::{Config, Uart};
8use static_cell::StaticCell;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::task]
12async fn main_task() {
13 let p = embassy_stm32::init(Default::default());
14
15 let config = Config::default();
16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
17
18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
19 info!("wrote Hello, starting echo");
20
21 let mut buf = [0u8; 1];
22 loop {
23 unwrap!(usart.blocking_read(&mut buf));
24 unwrap!(usart.blocking_write(&buf));
25 }
26}
27
28static EXECUTOR: StaticCell<Executor> = StaticCell::new();
29
30#[entry]
31fn main() -> ! {
32 info!("Hello World!");
33
34 let executor = EXECUTOR.init(Executor::new());
35
36 executor.run(|spawner| {
37 unwrap!(spawner.spawn(main_task()));
38 })
39}
diff --git a/examples/stm32h7rs/src/bin/usart_dma.rs b/examples/stm32h7rs/src/bin/usart_dma.rs
new file mode 100644
index 000000000..c644e84bd
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usart_dma.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3
4use core::fmt::Write;
5
6use cortex_m_rt::entry;
7use defmt::*;
8use embassy_executor::Executor;
9use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String;
12use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 UART7 => usart::InterruptHandler<peripherals::UART7>;
17});
18
19#[embassy_executor::task]
20async fn main_task() {
21 let p = embassy_stm32::init(Default::default());
22
23 let config = Config::default();
24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
25
26 for n in 0u32.. {
27 let mut s: String<128> = String::new();
28 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
29
30 usart.write(s.as_bytes()).await.ok();
31
32 info!("wrote DMA");
33 }
34}
35
36static EXECUTOR: StaticCell<Executor> = StaticCell::new();
37
38#[entry]
39fn main() -> ! {
40 info!("Hello World!");
41
42 let executor = EXECUTOR.init(Executor::new());
43
44 executor.run(|spawner| {
45 unwrap!(spawner.spawn(main_task()));
46 })
47}
diff --git a/examples/stm32h7rs/src/bin/usart_split.rs b/examples/stm32h7rs/src/bin/usart_split.rs
new file mode 100644
index 000000000..d26c5003c
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usart_split.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::mode::Async;
7use embassy_stm32::usart::{Config, Uart, UartRx};
8use embassy_stm32::{bind_interrupts, peripherals, usart};
9use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
10use embassy_sync::channel::Channel;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
18
19#[embassy_executor::main]
20async fn main(spawner: Spawner) -> ! {
21 let p = embassy_stm32::init(Default::default());
22 info!("Hello World!");
23
24 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
26 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
27
28 let (mut tx, rx) = usart.split();
29
30 unwrap!(spawner.spawn(reader(rx)));
31
32 loop {
33 let buf = CHANNEL.receive().await;
34 info!("writing...");
35 unwrap!(tx.write(&buf).await);
36 }
37}
38
39#[embassy_executor::task]
40async fn reader(mut rx: UartRx<'static, Async>) {
41 let mut buf = [0; 8];
42 loop {
43 info!("reading...");
44 unwrap!(rx.read(&mut buf).await);
45 CHANNEL.send(buf).await;
46 }
47}
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs
new file mode 100644
index 000000000..6773f7843
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usb_serial.rs
@@ -0,0 +1,140 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17});
18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 info!("Hello World!");
27
28 let mut config = Config::default();
29
30 {
31 use embassy_stm32::rcc::*;
32 config.rcc.hse = Some(Hse {
33 freq: Hertz(24_000_000),
34 mode: HseMode::Oscillator,
35 });
36 config.rcc.pll1 = Some(Pll {
37 source: PllSource::HSE,
38 prediv: PllPreDiv::DIV12,
39 mul: PllMul::MUL300,
40 divp: Some(PllDiv::DIV1), //600 MHz
41 divq: Some(PllDiv::DIV2), // 300 MHz
42 divr: Some(PllDiv::DIV2), // 300 MHz
43 });
44 config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz
48 config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz
49 config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz
50 config.rcc.voltage_scale = VoltageScale::HIGH;
51 config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE;
52 }
53
54 let p = embassy_stm32::init(config);
55
56 // Create the driver, from the HAL.
57 let mut ep_out_buffer = [0u8; 256];
58 let mut config = embassy_stm32::usb::Config::default();
59
60 // Do not enable vbus_detection. This is a safe default that works in all boards.
61 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
62 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
63 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
64 config.vbus_detection = false;
65
66 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config);
67
68 // Create embassy-usb Config
69 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
70 config.manufacturer = Some("Embassy");
71 config.product = Some("USB-serial example");
72 config.serial_number = Some("12345678");
73 // Required for windows compatibility.
74 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
75 config.device_class = 0xEF;
76 config.device_sub_class = 0x02;
77 config.device_protocol = 0x01;
78 config.composite_with_iads = true;
79
80 // Create embassy-usb DeviceBuilder using the driver and config.
81 // It needs some buffers for building the descriptors.
82 let mut config_descriptor = [0; 256];
83 let mut bos_descriptor = [0; 256];
84 let mut control_buf = [0; 64];
85
86 let mut state = State::new();
87
88 let mut builder = Builder::new(
89 driver,
90 config,
91 &mut config_descriptor,
92 &mut bos_descriptor,
93 &mut [], // no msos descriptors
94 &mut control_buf,
95 );
96
97 // Create classes on the builder.
98 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
99
100 // Build the builder.
101 let mut usb = builder.build();
102
103 // Run the USB device.
104 let usb_fut = usb.run();
105
106 // Do stuff with the class!
107 let echo_fut = async {
108 loop {
109 class.wait_connection().await;
110 info!("Connected");
111 let _ = echo(&mut class).await;
112 info!("Disconnected");
113 }
114 };
115
116 // Run everything concurrently.
117 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
118 join(usb_fut, echo_fut).await;
119}
120
121struct Disconnected {}
122
123impl From<EndpointError> for Disconnected {
124 fn from(val: EndpointError) -> Self {
125 match val {
126 EndpointError::BufferOverflow => panic!("Buffer overflow"),
127 EndpointError::Disabled => Disconnected {},
128 }
129 }
130}
131
132async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
133 let mut buf = [0; 64];
134 loop {
135 let n = class.read_packet(&mut buf).await?;
136 let data = &buf[..n];
137 info!("data: {:x}", data);
138 class.write_packet(data).await?;
139 }
140}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index dd9097c9b..2577f19e0 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -6,10 +6,10 @@ 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.5.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.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
@@ -21,7 +21,6 @@ embedded-io-async = { version = "0.6.1" }
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
26embedded-hal = "0.2.6" 25embedded-hal = "0.2.6"
27static_cell = { version = "2" } 26static_cell = { version = "2" }
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
index adeaa208a..9dd09bc45 100644
--- a/examples/stm32l0/src/bin/adc.rs
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -4,13 +4,13 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
13 ADC1_COMP => adc::InterruptHandler<ADC>; 13 ADC1_COMP => adc::InterruptHandler<ADC1>;
14}); 14});
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); 21 let mut adc = Adc::new(p.ADC1, Irqs);
22 adc.set_sample_time(SampleTime::Cycles79_5); 22 adc.set_sample_time(SampleTime::CYCLES79_5);
23 let mut pin = p.PA1; 23 let mut pin = p.PA1;
24 24
25 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref();
26 let vrefint_sample = adc.read(&mut vrefint).await; 26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| { 27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf 28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs
new file mode 100644
index 000000000..c40b86af9
--- /dev/null
+++ b/examples/stm32l0/src/bin/async-tsc.rs
@@ -0,0 +1,122 @@
1// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32L073RZ Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::bind_interrupts;
21use embassy_stm32::gpio::{Level, Output, Speed};
22use embassy_stm32::tsc::{self, *};
23use embassy_time::Timer;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
28});
29
30#[cortex_m_rt::exception]
31unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! {
32 cortex_m::peripheral::SCB::sys_reset();
33}
34
35/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip.
36///
37/// Make sure you check/update the following (whether you use the L073RZ or another board):
38///
39/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name.
40/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`.
41/// * [ ] If your board has a special clock or power configuration, make sure that it is
42/// set up appropriately.
43/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
44/// to match your schematic
45///
46/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
47///
48/// * Which example you are trying to run
49/// * Which chip and board you are using
50///
51/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
52#[embassy_executor::main]
53async fn main(_spawner: embassy_executor::Spawner) {
54 let device_config = embassy_stm32::Config::default();
55 let context = embassy_stm32::init(device_config);
56
57 let config = tsc::Config {
58 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
59 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
60 spread_spectrum: false,
61 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
62 spread_spectrum_prescaler: false,
63 pulse_generator_prescaler: PGPrescalerDivider::_16,
64 max_count_value: MaxCount::_255,
65 io_default_mode: false,
66 synchro_pin_polarity: false,
67 acquisition_mode: false,
68 max_count_interrupt: false,
69 channel_ios: TscIOPin::Group1Io1.into(),
70 shield_ios: 0, // no shield
71 sampling_ios: TscIOPin::Group1Io2.into(),
72 };
73
74 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
75 g1.set_io1(context.PA0, PinType::Sample);
76 g1.set_io2(context.PA1, PinType::Channel);
77
78 let mut touch_controller = tsc::Tsc::new_async(
79 context.TSC,
80 Some(g1),
81 None,
82 None,
83 None,
84 None,
85 None,
86 None,
87 None,
88 config,
89 Irqs,
90 );
91
92 // Check if TSC is ready
93 if touch_controller.get_state() != State::Ready {
94 info!("TSC not ready!");
95 loop {} // Halt execution
96 }
97 info!("TSC initialized successfully");
98
99 // LED2 on the STM32L073RZ nucleo-board (PA5)
100 let mut led = Output::new(context.PA5, Level::High, Speed::Low);
101
102 // smaller sample capacitor discharge faster and can be used with shorter delay.
103 let discharge_delay = 5; // ms
104
105 info!("Starting touch_controller interface");
106 loop {
107 touch_controller.start();
108 touch_controller.pend_for_acquisition().await;
109 touch_controller.discharge_io(true);
110 Timer::after_millis(discharge_delay).await;
111
112 let grp1_status = touch_controller.group_get_status(Group::One);
113 match grp1_status {
114 GroupStatus::Complete => {
115 let group_one_val = touch_controller.group_get_value(Group::One);
116 info!("{}", group_one_val);
117 led.set_high();
118 }
119 GroupStatus::Ongoing => led.set_low(),
120 }
121 }
122}
diff --git a/examples/stm32l0/src/bin/blocking-tsc.rs b/examples/stm32l0/src/bin/blocking-tsc.rs
new file mode 100644
index 000000000..7e4f40946
--- /dev/null
+++ b/examples/stm32l0/src/bin/blocking-tsc.rs
@@ -0,0 +1,116 @@
1// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32L073RZ Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::gpio::{Level, Output, Speed};
21use embassy_stm32::tsc::{self, *};
22use embassy_time::Timer;
23use {defmt_rtt as _, panic_probe as _};
24
25/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip.
26///
27/// Make sure you check/update the following (whether you use the L073RZ or another board):
28///
29/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name.
30/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`.
31/// * [ ] If your board has a special clock or power configuration, make sure that it is
32/// set up appropriately.
33/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
34/// to match your schematic
35///
36/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
37///
38/// * Which example you are trying to run
39/// * Which chip and board you are using
40///
41/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
42#[embassy_executor::main]
43async fn main(_spawner: embassy_executor::Spawner) {
44 let device_config = embassy_stm32::Config::default();
45 let context = embassy_stm32::init(device_config);
46
47 let tsc_conf = Config {
48 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
49 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
50 spread_spectrum: false,
51 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
52 spread_spectrum_prescaler: false,
53 pulse_generator_prescaler: PGPrescalerDivider::_16,
54 max_count_value: MaxCount::_255,
55 io_default_mode: false,
56 synchro_pin_polarity: false,
57 acquisition_mode: false,
58 max_count_interrupt: false,
59 channel_ios: TscIOPin::Group1Io1.into(),
60 shield_ios: 0, // no shield
61 sampling_ios: TscIOPin::Group1Io2.into(),
62 };
63
64 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
65 g1.set_io1(context.PA0, PinType::Sample);
66 g1.set_io2(context.PA1, PinType::Channel);
67
68 let mut touch_controller = tsc::Tsc::new_blocking(
69 context.TSC,
70 Some(g1),
71 None,
72 None,
73 None,
74 None,
75 None,
76 None,
77 None,
78 tsc_conf,
79 );
80
81 // Check if TSC is ready
82 if touch_controller.get_state() != State::Ready {
83 info!("TSC not ready!");
84 loop {} // Halt execution
85 }
86 info!("TSC initialized successfully");
87
88 // LED2 on the STM32L073RZ nucleo-board (PA5)
89 let mut led = Output::new(context.PA5, Level::High, Speed::Low);
90
91 // smaller sample capacitor discharge faster and can be used with shorter delay.
92 let discharge_delay = 5; // ms
93
94 // the interval at which the loop polls for new touch sensor values
95 let polling_interval = 100; // ms
96
97 info!("polling for touch");
98 loop {
99 touch_controller.start();
100 touch_controller.poll_for_acquisition();
101 touch_controller.discharge_io(true);
102 Timer::after_millis(discharge_delay).await;
103
104 let grp1_status = touch_controller.group_get_status(Group::One);
105 match grp1_status {
106 GroupStatus::Complete => {
107 let group_one_val = touch_controller.group_get_value(Group::One);
108 info!("{}", group_one_val);
109 led.set_high();
110 }
111 GroupStatus::Ongoing => led.set_low(),
112 }
113
114 Timer::after_millis(polling_interval).await;
115 }
116}
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/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index f23a537b8..8e0cfdedb 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 322c41262..062044f32 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -5,11 +5,12 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -18,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
18cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 22heapless = { version = "0.8", default-features = false }
23embedded-storage = "0.3.1" 23embedded-storage = "0.3.1"
24 24
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs
index 8be686c5a..eabf1bac2 100644
--- a/examples/stm32l1/src/bin/spi.rs
+++ b/examples/stm32l1/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs
index 7b1e84cbc..837f7fa57 100644
--- a/examples/stm32l1/src/bin/usb_serial.rs
+++ b/examples/stm32l1/src/bin/usb_serial.rs
@@ -3,12 +3,12 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join;
6use embassy_stm32::usb::{self, Driver, Instance}; 7use embassy_stm32::usb::{self, Driver, Instance};
7use embassy_stm32::{bind_interrupts, peripherals}; 8use embassy_stm32::{bind_interrupts, peripherals};
8use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
9use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
10use embassy_usb::Builder; 11use embassy_usb::Builder;
11use futures::future::join;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -27,7 +27,7 @@ async fn main(_spawner: Spawner) {
27 mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz 27 mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz
28 div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) 28 div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3)
29 }); 29 });
30 config.rcc.mux = ClockSrc::PLL1_R; 30 config.rcc.sys = Sysclk::PLL1_R;
31 } 31 }
32 32
33 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 config.device_protocol = 0x01; 46 config.device_protocol = 0x01;
47 config.composite_with_iads = true; 47 config.composite_with_iads = true;
48 48
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 49 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 50 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
@@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) {
56 let mut builder = Builder::new( 55 let mut builder = Builder::new(
57 driver, 56 driver,
58 config, 57 config,
59 &mut device_descriptor,
60 &mut config_descriptor, 58 &mut config_descriptor,
61 &mut bos_descriptor, 59 &mut bos_descriptor,
62 &mut [], // no msos descriptors 60 &mut [], // no msos descriptors
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index db3a7ceff..83fc6d6f8 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,7 @@
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-run --chip STM32L4S5QI" 5runner = "probe-rs run --chip STM32L4S5QI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index d42e69578..c5478b17b 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -7,11 +7,11 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } 15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" }
16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } 16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -28,7 +28,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
28embedded-hal-async = { version = "1.0" } 28embedded-hal-async = { version = "1.0" }
29embedded-hal-bus = { version = "0.1", features = ["async"] } 29embedded-hal-bus = { version = "0.1", features = ["async"] }
30panic-probe = { version = "0.3", features = ["print-defmt"] } 30panic-probe = { version = "0.3", features = ["print-defmt"] }
31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
32heapless = { version = "0.8", default-features = false } 31heapless = { version = "0.8", default-features = false }
33chrono = { version = "^0.4", default-features = false } 32chrono = { version = "^0.4", default-features = false }
34rand = { version = "0.8.5", default-features = false } 33rand = { version = "0.8.5", default-features = false }
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index d01e9f1b3..c557ac6d7 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,28 +3,27 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution}; 5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::pac; 6use embassy_stm32::Config;
7use embassy_time::Delay;
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
9 8
10#[cortex_m_rt::entry] 9#[cortex_m_rt::entry]
11fn main() -> ! { 10fn main() -> ! {
12 info!("Hello World!"); 11 info!("Hello World!");
13 12
14 pac::RCC.ccipr().modify(|w| { 13 let mut config = Config::default();
15 w.set_adcsel(pac::rcc::vals::Adcsel::SYS); 14 {
16 }); 15 use embassy_stm32::rcc::*;
17 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); 16 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 17 }
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(config);
20 19
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 20 let mut adc = Adc::new(p.ADC1);
22 //adc.enable_vref(); 21 //adc.enable_vref();
23 adc.set_resolution(Resolution::EightBit); 22 adc.set_resolution(Resolution::BITS8);
24 let mut channel = p.PC0; 23 let mut channel = p.PC0;
25 24
26 loop { 25 loop {
27 let v = adc.read(&mut channel); 26 let v = adc.blocking_read(&mut channel);
28 info!("--> {}", v); 27 info!("--> {}", v);
29 } 28 }
30} 29}
diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs
new file mode 100644
index 000000000..3c4cdac24
--- /dev/null
+++ b/examples/stm32l4/src/bin/can.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::can::filter::Mask32;
7use embassy_stm32::can::{
8 Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
9};
10use embassy_stm32::peripherals::CAN1;
11use embassy_stm32::{bind_interrupts, Config};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
17 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
18 CAN1_SCE => SceInterruptHandler<CAN1>;
19 CAN1_TX => TxInterruptHandler<CAN1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_stm32::init(Config::default());
25
26 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
27
28 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
29
30 can.modify_config()
31 .set_loopback(true) // Receive own frames
32 .set_silent(true)
33 .set_bitrate(250_000);
34
35 can.enable().await;
36 println!("CAN enabled");
37
38 let mut i = 0;
39 let mut last_read_ts = embassy_time::Instant::now();
40 loop {
41 let frame = Frame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame");
43
44 _ = can.write(&frame).await;
45
46 match can.read().await {
47 Ok(envelope) => {
48 let (ts, rx_frame) = (envelope.ts, envelope.frame);
49 let delta = (ts - last_read_ts).as_millis();
50 last_read_ts = ts;
51 info!(
52 "Rx: {} {:02x} --- {}ms",
53 rx_frame.header().len(),
54 rx_frame.data()[0..rx_frame.header().len() as usize],
55 delta,
56 )
57 }
58 Err(err) => error!("Error in frame: {}", err),
59 }
60
61 Timer::after_millis(250).await;
62
63 i += 1;
64 if i > 2 {
65 break;
66 }
67 }
68}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index f227812cd..d01b016c0 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -6,9 +6,9 @@ use embassy_executor::Spawner;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::pac::timer::vals::Mms; 7use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -22,19 +22,19 @@ async fn main(spawner: Spawner) {
22 // Obtain two independent channels (p.DAC1 can only be consumed once, though!) 22 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
23 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); 23 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
24 24
25 spawner.spawn(dac_task1(dac_ch1)).ok(); 25 spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok();
26 spawner.spawn(dac_task2(dac_ch2)).ok(); 26 spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok();
27} 27}
28 28
29#[embassy_executor::task] 29#[embassy_executor::task]
30async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 30async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
31 let data: &[u8; 256] = &calculate_array::<256>(); 31 let data: &[u8; 256] = &calculate_array::<256>();
32 32
33 info!("TIM6 frequency is {}", TIM6::frequency()); 33 info!("TIM6 frequency is {}", frequency::<TIM6>());
34 const FREQUENCY: Hertz = Hertz::hz(200); 34 const FREQUENCY: Hertz = Hertz::hz(200);
35 35
36 // Compute the reload value such that we obtain the FREQUENCY for the sine 36 // Compute the reload value such that we obtain the FREQUENCY for the sine
37 let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; 37 let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32;
38 38
39 // Depends on your clock and on the specific chip used, you may need higher or lower values here 39 // Depends on your clock and on the specific chip used, you may need higher or lower values here
40 if reload < 10 { 40 if reload < 10 {
@@ -45,17 +45,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
45 dac.set_triggering(true); 45 dac.set_triggering(true);
46 dac.enable(); 46 dac.enable();
47 47
48 TIM6::enable_and_reset(); 48 let tim = Timer::new(tim);
49 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 49 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
50 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 50 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
51 TIM6::regs_basic().cr1().modify(|w| { 51 tim.regs_basic().cr1().modify(|w| {
52 w.set_opm(false); 52 w.set_opm(false);
53 w.set_cen(true); 53 w.set_cen(true);
54 }); 54 });
55 55
56 debug!( 56 debug!(
57 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 57 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
58 TIM6::frequency(), 58 frequency::<TIM6>(),
59 FREQUENCY, 59 FREQUENCY,
60 reload, 60 reload,
61 reload as u16, 61 reload as u16,
@@ -70,22 +70,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
70} 70}
71 71
72#[embassy_executor::task] 72#[embassy_executor::task]
73async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 73async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
74 let data: &[u8; 256] = &calculate_array::<256>(); 74 let data: &[u8; 256] = &calculate_array::<256>();
75 75
76 info!("TIM7 frequency is {}", TIM7::frequency()); 76 info!("TIM7 frequency is {}", frequency::<TIM7>());
77 77
78 const FREQUENCY: Hertz = Hertz::hz(600); 78 const FREQUENCY: Hertz = Hertz::hz(600);
79 let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; 79 let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32;
80 80
81 if reload < 10 { 81 if reload < 10 {
82 error!("Reload value {} below threshold!", reload); 82 error!("Reload value {} below threshold!", reload);
83 } 83 }
84 84
85 TIM7::enable_and_reset(); 85 let tim = Timer::new(tim);
86 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 86 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
87 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 87 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
88 TIM7::regs_basic().cr1().modify(|w| { 88 tim.regs_basic().cr1().modify(|w| {
89 w.set_opm(false); 89 w.set_opm(false);
90 w.set_cen(true); 90 w.set_cen(true);
91 }); 91 });
@@ -96,7 +96,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
96 96
97 debug!( 97 debug!(
98 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 98 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
99 TIM7::frequency(), 99 frequency::<TIM7>(),
100 FREQUENCY, 100 FREQUENCY,
101 reload, 101 reload,
102 reload as u16, 102 reload as u16,
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index f553deb82..2861bc091 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -3,33 +3,17 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c; 6use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new( 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
24 p.I2C2,
25 p.PB10,
26 p.PB11,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33 17
34 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index 1b8652bcc..a014b23e0 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -4,34 +4,18 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::I2c; 7use embassy_stm32::i2c::I2c;
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_stm32::{bind_interrupts, i2c, peripherals};
11use embedded_hal_async::i2c::I2c as I2cTrait; 9use embedded_hal_async::i2c::I2c as I2cTrait;
12use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
13 11
14const ADDRESS: u8 = 0x5F; 12const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
16 14
17bind_interrupts!(struct Irqs {
18 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
19 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
20});
21
22#[embassy_executor::main] 15#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
24 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
25 let i2c = I2c::new( 18 let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 let mut i2c = BlockingAsync::new(i2c); 19 let mut i2c = BlockingAsync::new(i2c);
36 20
37 let mut data = [0u8; 1]; 21 let mut data = [0u8; 1];
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs
index 638b3e9e4..14d0e3c1e 100644
--- a/examples/stm32l4/src/bin/rng.rs
+++ b/examples/stm32l4/src/bin/rng.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource}; 6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk};
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.mux = ClockSrc::PLL1_R; 18 config.rcc.sys = Sysclk::PLL1_R;
19 config.rcc.hsi = true; 19 config.rcc.hsi = true;
20 config.rcc.pll = Some(Pll { 20 config.rcc.pll = Some(Pll {
21 source: PllSource::HSI, 21 source: PllSource::HSI,
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index 526620bfb..f554f0f78 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 15 let mut config = Config::default();
16 { 16 {
17 use embassy_stm32::rcc::*; 17 use embassy_stm32::rcc::*;
18 config.rcc.mux = ClockSrc::PLL1_R; 18 config.rcc.sys = Sysclk::PLL1_R;
19 config.rcc.hse = Some(Hse { 19 config.rcc.hse = Some(Hse {
20 freq: Hertz::mhz(8), 20 freq: Hertz::mhz(8),
21 mode: HseMode::Oscillator, 21 mode: HseMode::Oscillator,
@@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
40 .unwrap(); 40 .unwrap();
41 41
42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
43 info!("Got RTC! {:?}", now.timestamp()); 43 info!("Got RTC! {:?}", now.and_utc().timestamp());
44 44
45 rtc.set_datetime(now.into()).expect("datetime not set"); 45 rtc.set_datetime(now.into()).expect("datetime not set");
46 46
@@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) {
48 Timer::after_millis(20000).await; 48 Timer::after_millis(20000).await;
49 49
50 let then: NaiveDateTime = rtc.now().unwrap().into(); 50 let then: NaiveDateTime = rtc.now().unwrap().into();
51 info!("Got RTC! {:?}", then.timestamp()); 51 info!("Got RTC! {:?}", then.and_utc().timestamp());
52} 52}
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 026a3a477..be4270ada 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
23use embassy_futures::yield_now; 23use embassy_futures::yield_now;
24use embassy_net::tcp::TcpSocket; 24use embassy_net::tcp::TcpSocket;
25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; 25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
26use embassy_net_adin1110::{Device, Runner, ADIN1110};
27use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
26use embassy_time::{Delay, Duration, Ticker, Timer}; 34use embassy_time::{Delay, Duration, Ticker, Timer};
27use embedded_hal_async::i2c::I2c as I2cBus; 35use embedded_hal_async::i2c::I2c as I2cBus;
36use embedded_hal_bus::spi::ExclusiveDevice;
28use embedded_io::Write as bWrite; 37use embedded_io::Write as bWrite;
29use embedded_io_async::Write; 38use embedded_io_async::Write;
30use hal::gpio::{Input, Level, Output, Speed};
31use hal::i2c::{self, I2c};
32use hal::rng::{self, Rng};
33use hal::{bind_interrupts, exti, pac, peripherals};
34use heapless::Vec; 39use heapless::Vec;
40use panic_probe as _;
35use rand::RngCore; 41use rand::RngCore;
36use static_cell::StaticCell; 42use static_cell::StaticCell;
37use {embassy_stm32 as hal, panic_probe as _};
38 43
39bind_interrupts!(struct Irqs { 44bind_interrupts!(struct Irqs {
40 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; 45 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
@@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
42 RNG => rng::InterruptHandler<peripherals::RNG>; 47 RNG => rng::InterruptHandler<peripherals::RNG>;
43}); 48});
44 49
45use embassy_net_adin1110::{self, Device, Runner, ADIN1110};
46use embedded_hal_bus::spi::ExclusiveDevice;
47use hal::gpio::Pull;
48use hal::i2c::Config as I2C_Config;
49use hal::spi::{Config as SPI_Config, Spi};
50use hal::time::Hertz;
51
52// Basic settings 50// Basic settings
53// MAC-address used by the adin1110 51// MAC-address used by the adin1110
54const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; 52const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
@@ -57,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
57// Listen port for the webserver 55// Listen port for the webserver
58const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
59 57
60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; 58pub type SpeSpi = Spi<'static, Async>;
61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
62pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
63pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
64pub type Adin1110T = ADIN1110<SpeSpiCs>; 62pub type Adin1110T = ADIN1110<SpeSpiCs>;
65pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; 63pub type TempSensI2c = I2c<'static, Async>;
66 64
67static TEMP: AtomicI32 = AtomicI32::new(0); 65static TEMP: AtomicI32 = AtomicI32::new(0);
68 66
@@ -75,7 +73,7 @@ async fn main(spawner: Spawner) {
75 use embassy_stm32::rcc::*; 73 use embassy_stm32::rcc::*;
76 // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2) 74 // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2)
77 // 80MHz highest frequency for flash 0 wait. 75 // 80MHz highest frequency for flash 0 wait.
78 config.rcc.mux = ClockSrc::PLL1_R; 76 config.rcc.sys = Sysclk::PLL1_R;
79 config.rcc.hse = Some(Hse { 77 config.rcc.hse = Some(Hse {
80 freq: Hertz::mhz(8), 78 freq: Hertz::mhz(8),
81 mode: HseMode::Oscillator, 79 mode: HseMode::Oscillator,
@@ -93,12 +91,6 @@ async fn main(spawner: Spawner) {
93 91
94 let dp = embassy_stm32::init(config); 92 let dp = embassy_stm32::init(config);
95 93
96 // RM0432rev9, 5.1.2: Independent I/O supply rail
97 // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and
98 // therefore are not available. The isolation must be removed before using any I/O from
99 // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present
100 pac::PWR.cr2().modify(|w| w.set_iosv(true));
101
102 let reset_status = pac::RCC.bdcr().read().0; 94 let reset_status = pac::RCC.bdcr().read().0;
103 defmt::println!("bdcr before: 0x{:X}", reset_status); 95 defmt::println!("bdcr before: 0x{:X}", reset_status);
104 96
@@ -214,17 +206,11 @@ async fn main(spawner: Spawner) {
214 }; 206 };
215 207
216 // Init network stack 208 // Init network stack
217 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 209 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
218 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 210 let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed);
219 let stack = &*STACK.init(Stack::new(
220 device,
221 ip_cfg,
222 RESOURCES.init(StackResources::<2>::new()),
223 seed,
224 ));
225 211
226 // Launch network task 212 // Launch network task
227 unwrap!(spawner.spawn(net_task(stack))); 213 unwrap!(spawner.spawn(net_task(runner)));
228 214
229 let cfg = wait_for_config(stack).await; 215 let cfg = wait_for_config(stack).await;
230 let local_addr = cfg.address.address(); 216 let local_addr = cfg.address.address();
@@ -287,7 +273,7 @@ async fn main(spawner: Spawner) {
287 } 273 }
288} 274}
289 275
290async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 276async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
291 loop { 277 loop {
292 if let Some(config) = stack.config_v4() { 278 if let Some(config) = stack.config_v4() {
293 return config; 279 return config;
@@ -336,8 +322,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! {
336} 322}
337 323
338#[embassy_executor::task] 324#[embassy_executor::task]
339async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 325async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
340 stack.run().await 326 runner.run().await
341} 327}
342 328
343// same panicking *behavior* as `panic-probe` but doesn't print a panic message 329// same panicking *behavior* as `panic-probe` but doesn't print a panic message
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 6653e4516..5693a3765 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::gpio::{Level, Output, Speed}; 5use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::spi::{Config, Spi}; 6use embassy_stm32::spi::{Config, Spi};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ fn main() -> ! {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
21 20
22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
index 68dbb70ad..1f1089101 100644
--- a/examples/stm32l4/src/bin/spi_blocking_async.rs
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 7use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::spi::{Config, Spi}; 8use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
19 let mut spi_config = Config::default(); 18 let mut spi_config = Config::default();
20 spi_config.frequency = Hertz(1_000_000); 19 spi_config.frequency = Hertz(1_000_000);
21 20
22 let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 21 let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
23 22
24 let mut spi = BlockingAsync::new(spi); 23 let mut spi = BlockingAsync::new(spi);
25 24
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 7bab23950..d9b388026 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::usart::{Config, Uart}; 5use embassy_stm32::usart::{Config, Uart};
7use embassy_stm32::{bind_interrupts, peripherals, usart}; 6use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
19 18
20 let config = Config::default(); 19 let config = Config::default();
21 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); 20 let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap();
22 21
23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
24 info!("wrote Hello, starting echo"); 23 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 031888f70..b4f7a1643 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 8cc9a7aed..c3b1211d8 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -4,42 +4,55 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::*; 7use embassy_futures::join::join;
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 12use embassy_usb::Builder;
13use futures::future::join;
14use panic_probe as _; 13use panic_probe as _;
15 14
16bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
18}); 17});
19 18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
20#[embassy_executor::main] 24#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 26 info!("Hello World!");
23 27
24 let mut config = Config::default(); 28 let mut config = Config::default();
25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 29 {
26 config.rcc.mux = ClockSrc::PLL1_R; 30 use embassy_stm32::rcc::*;
27 config.rcc.hsi = true; 31 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
28 config.rcc.pll = Some(Pll { 32 config.rcc.sys = Sysclk::PLL1_R;
29 source: PllSource::HSI, 33 config.rcc.hsi = true;
30 prediv: PllPreDiv::DIV1, 34 config.rcc.pll = Some(Pll {
31 mul: PllMul::MUL10, 35 source: PllSource::HSI,
32 divp: None, 36 prediv: PllPreDiv::DIV1,
33 divq: None, 37 mul: PllMul::MUL10,
34 divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) 38 divp: None,
35 }); 39 divq: None,
36 40 divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2)
41 });
42 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
43 }
37 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
38 45
39 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
40 let mut ep_out_buffer = [0u8; 256]; 47 let mut ep_out_buffer = [0u8; 256];
41 let mut config = embassy_stm32::usb_otg::Config::default(); 48 let mut config = embassy_stm32::usb::Config::default();
42 config.vbus_detection = true; 49
50 // Do not enable vbus_detection. This is a safe default that works in all boards.
51 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
52 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
53 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
54 config.vbus_detection = false;
55
43 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 56 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
44 57
45 // Create embassy-usb Config 58 // Create embassy-usb Config
@@ -58,7 +71,6 @@ async fn main(_spawner: Spawner) {
58 71
59 // Create embassy-usb DeviceBuilder using the driver and config. 72 // Create embassy-usb DeviceBuilder using the driver and config.
60 // It needs some buffers for building the descriptors. 73 // It needs some buffers for building the descriptors.
61 let mut device_descriptor = [0; 256];
62 let mut config_descriptor = [0; 256]; 74 let mut config_descriptor = [0; 256];
63 let mut bos_descriptor = [0; 256]; 75 let mut bos_descriptor = [0; 256];
64 let mut control_buf = [0; 64]; 76 let mut control_buf = [0; 64];
@@ -68,7 +80,6 @@ async fn main(_spawner: Spawner) {
68 let mut builder = Builder::new( 80 let mut builder = Builder::new(
69 driver, 81 driver,
70 config, 82 config,
71 &mut device_descriptor,
72 &mut config_descriptor, 83 &mut config_descriptor,
73 &mut bos_descriptor, 84 &mut bos_descriptor,
74 &mut [], // no msos descriptors 85 &mut [], // no msos descriptors
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 0c6beb72c..16c184de2 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -7,13 +7,13 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16usbd-hid = "0.6.0" 16usbd-hid = "0.8.1"
17 17
18defmt = "0.3" 18defmt = "0.3"
19defmt-rtt = "0.4" 19defmt-rtt = "0.4"
@@ -22,7 +22,6 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
22cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 22cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
23cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
27rand_core = { version = "0.6.3", default-features = false } 26rand_core = { version = "0.6.3", default-features = false }
28embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs
index 50da6c946..0a644e73d 100644
--- a/examples/stm32l5/src/bin/rng.rs
+++ b/examples/stm32l5/src/bin/rng.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllRDiv, PllSource}; 6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk};
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs {
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.hsi = true; 18 config.rcc.hsi = true;
19 config.rcc.mux = ClockSrc::PLL1_R; 19 config.rcc.sys = Sysclk::PLL1_R;
20 config.rcc.pll = Some(Pll { 20 config.rcc.pll = Some(Pll {
21 // 64Mhz clock (16 / 1 * 8 / 2) 21 // 64Mhz clock (16 / 1 * 8 / 2)
22 source: PllSource::HSI, 22 source: PllSource::HSI,
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 88060b6b0..095d50c73 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -4,8 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::rcc::*;
9use embassy_stm32::rng::Rng; 8use embassy_stm32::rng::Rng;
10use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
11use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config};
@@ -37,24 +36,29 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
37} 36}
38 37
39#[embassy_executor::task] 38#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
41 stack.run().await 40 runner.run().await
42} 41}
43 42
44#[embassy_executor::main] 43#[embassy_executor::main]
45async fn main(spawner: Spawner) { 44async fn main(spawner: Spawner) {
46 let mut config = Config::default(); 45 let mut config = Config::default();
47 config.rcc.hsi = true; 46 {
48 config.rcc.mux = ClockSrc::PLL1_R; 47 use embassy_stm32::rcc::*;
49 config.rcc.pll = Some(Pll { 48 config.rcc.hsi = true;
50 // 80Mhz clock (16 / 1 * 10 / 2) 49 config.rcc.sys = Sysclk::PLL1_R;
51 source: PllSource::HSI, 50 config.rcc.pll = Some(Pll {
52 prediv: PllPreDiv::DIV1, 51 // 80Mhz clock (16 / 1 * 10 / 2)
53 mul: PllMul::MUL10, 52 source: PllSource::HSI,
54 divp: None, 53 prediv: PllPreDiv::DIV1,
55 divq: None, 54 mul: PllMul::MUL10,
56 divr: Some(PllRDiv::DIV2), 55 divp: None,
57 }); 56 divq: None,
57 divr: Some(PllRDiv::DIV2),
58 });
59 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
60 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
61 }
58 let p = embassy_stm32::init(config); 62 let p = embassy_stm32::init(config);
59 63
60 // Create the driver, from the HAL. 64 // Create the driver, from the HAL.
@@ -75,14 +79,12 @@ async fn main(spawner: Spawner) {
75 config.device_protocol = 0x01; 79 config.device_protocol = 0x01;
76 80
77 // Create embassy-usb DeviceBuilder using the driver and config. 81 // Create embassy-usb DeviceBuilder using the driver and config.
78 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
79 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 82 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
80 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 83 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
81 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); 84 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
82 let mut builder = Builder::new( 85 let mut builder = Builder::new(
83 driver, 86 driver,
84 config, 87 config,
85 &mut DEVICE_DESC.init([0; 256])[..],
86 &mut CONFIG_DESC.init([0; 256])[..], 88 &mut CONFIG_DESC.init([0; 256])[..],
87 &mut BOS_DESC.init([0; 256])[..], 89 &mut BOS_DESC.init([0; 256])[..],
88 &mut [], // no msos descriptors 90 &mut [], // no msos descriptors
@@ -119,16 +121,10 @@ async fn main(spawner: Spawner) {
119 let seed = rng.next_u64(); 121 let seed = rng.next_u64();
120 122
121 // Init network stack 123 // Init network stack
122 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 124 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
123 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 125 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
124 let stack = &*STACK.init(Stack::new(
125 device,
126 config,
127 RESOURCES.init(StackResources::<2>::new()),
128 seed,
129 ));
130 126
131 unwrap!(spawner.spawn(net_task(stack))); 127 unwrap!(spawner.spawn(net_task(runner)));
132 128
133 // And now we can use it! 129 // And now we can use it!
134 130
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index 7c8a8ebfb..3f8c52b82 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb::Driver; 7use embassy_stm32::usb::Driver;
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 20#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 22 let mut config = Config::default();
24 config.rcc.hsi = true; 23 {
25 config.rcc.mux = ClockSrc::PLL1_R; 24 use embassy_stm32::rcc::*;
26 config.rcc.pll = Some(Pll { 25 config.rcc.hsi = true;
27 // 80Mhz clock (16 / 1 * 10 / 2) 26 config.rcc.sys = Sysclk::PLL1_R;
28 source: PllSource::HSI, 27 config.rcc.pll = Some(Pll {
29 prediv: PllPreDiv::DIV1, 28 // 80Mhz clock (16 / 1 * 10 / 2)
30 mul: PllMul::MUL10, 29 source: PllSource::HSI,
31 divp: None, 30 prediv: PllPreDiv::DIV1,
32 divq: None, 31 mul: PllMul::MUL10,
33 divr: Some(PllRDiv::DIV2), 32 divp: None,
34 }); 33 divq: None,
34 divr: Some(PllRDiv::DIV2),
35 });
36 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
37 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
38 }
35 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
36 40
37 // Create the driver, from the HAL. 41 // Create the driver, from the HAL.
@@ -47,18 +51,16 @@ async fn main(_spawner: Spawner) {
47 51
48 // Create embassy-usb DeviceBuilder using the driver and config. 52 // Create embassy-usb DeviceBuilder using the driver and config.
49 // It needs some buffers for building the descriptors. 53 // It needs some buffers for building the descriptors.
50 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256]; 54 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256]; 55 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {}; 57 let mut request_handler = MyRequestHandler {};
55 58
56 let mut state = State::new(); 59 let mut state = State::new();
57 60
58 let mut builder = Builder::new( 61 let mut builder = Builder::new(
59 driver, 62 driver,
60 config, 63 config,
61 &mut device_descriptor,
62 &mut config_descriptor, 64 &mut config_descriptor,
63 &mut bos_descriptor, 65 &mut bos_descriptor,
64 &mut [], // no msos descriptors 66 &mut [], // no msos descriptors
@@ -68,7 +70,7 @@ async fn main(_spawner: Spawner) {
68 // Create classes on the builder. 70 // Create classes on the builder.
69 let config = embassy_usb::class::hid::Config { 71 let config = embassy_usb::class::hid::Config {
70 report_descriptor: MouseReport::desc(), 72 report_descriptor: MouseReport::desc(),
71 request_handler: Some(&request_handler), 73 request_handler: Some(&mut request_handler),
72 poll_ms: 60, 74 poll_ms: 60,
73 max_packet_size: 8, 75 max_packet_size: 8,
74 }; 76 };
@@ -110,21 +112,21 @@ async fn main(_spawner: Spawner) {
110struct MyRequestHandler {} 112struct MyRequestHandler {}
111 113
112impl RequestHandler for MyRequestHandler { 114impl RequestHandler for MyRequestHandler {
113 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { 115 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
114 info!("Get report for {:?}", id); 116 info!("Get report for {:?}", id);
115 None 117 None
116 } 118 }
117 119
118 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { 120 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
119 info!("Set report for {:?}: {=[u8]}", id, data); 121 info!("Set report for {:?}: {=[u8]}", id, data);
120 OutResponse::Accepted 122 OutResponse::Accepted
121 } 123 }
122 124
123 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { 125 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
124 info!("Set idle rate for {:?} to {:?}", id, dur); 126 info!("Set idle rate for {:?} to {:?}", id, dur);
125 } 127 }
126 128
127 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { 129 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
128 info!("Get idle rate for {:?}", id); 130 info!("Get idle rate for {:?}", id);
129 None 131 None
130 } 132 }
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 75053ce4b..a64bda31b 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.hsi = true; 21 {
23 config.rcc.mux = ClockSrc::PLL1_R; 22 use embassy_stm32::rcc::*;
24 config.rcc.pll = Some(Pll { 23 config.rcc.hsi = true;
25 // 80Mhz clock (16 / 1 * 10 / 2) 24 config.rcc.sys = Sysclk::PLL1_R;
26 source: PllSource::HSI, 25 config.rcc.pll = Some(Pll {
27 prediv: PllPreDiv::DIV1, 26 // 80Mhz clock (16 / 1 * 10 / 2)
28 mul: PllMul::MUL10, 27 source: PllSource::HSI,
29 divp: None, 28 prediv: PllPreDiv::DIV1,
30 divq: None, 29 mul: PllMul::MUL10,
31 divr: Some(PllRDiv::DIV2), 30 divp: None,
32 }); 31 divq: None,
32 divr: Some(PllRDiv::DIV2),
33 });
34 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
35 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
36 }
33 let p = embassy_stm32::init(config); 37 let p = embassy_stm32::init(config);
34 38
35 info!("Hello World!"); 39 info!("Hello World!");
@@ -43,7 +47,6 @@ async fn main(_spawner: Spawner) {
43 47
44 // Create embassy-usb DeviceBuilder using the driver and config. 48 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors. 49 // It needs some buffers for building the descriptors.
46 let mut device_descriptor = [0; 256];
47 let mut config_descriptor = [0; 256]; 50 let mut config_descriptor = [0; 256];
48 let mut bos_descriptor = [0; 256]; 51 let mut bos_descriptor = [0; 256];
49 let mut control_buf = [0; 7]; 52 let mut control_buf = [0; 7];
@@ -53,7 +56,6 @@ async fn main(_spawner: Spawner) {
53 let mut builder = Builder::new( 56 let mut builder = Builder::new(
54 driver, 57 driver,
55 config, 58 config,
56 &mut device_descriptor,
57 &mut config_descriptor, 59 &mut config_descriptor,
58 &mut bos_descriptor, 60 &mut bos_descriptor,
59 &mut [], // no msos descriptors 61 &mut [], // no msos descriptors
diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml
new file mode 100644
index 000000000..688347084
--- /dev/null
+++ b/examples/stm32u0/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip stm32u083rctx"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
new file mode 100644
index 000000000..2e890cdb5
--- /dev/null
+++ b/examples/stm32u0/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2edition = "2021"
3name = "embassy-stm32u0-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15
16defmt = "0.3"
17defmt-rtt = "0.4"
18
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false }
24
25micromath = "2.0.0"
26chrono = { version = "0.4.38", default-features = false }
27
28[profile.release]
29debug = 2
diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32u0/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
new file mode 100644
index 000000000..c8252e4e1
--- /dev/null
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::Config;
7use embassy_time::Duration;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 }
19 let p = embassy_stm32::init(config);
20
21 let mut adc = Adc::new(p.ADC1);
22 adc.set_resolution(Resolution::BITS8);
23 let mut channel = p.PC0;
24
25 loop {
26 let v = adc.blocking_read(&mut channel);
27 info!("--> {}", v);
28 embassy_time::block_for(Duration::from_millis(200));
29 }
30}
diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs
new file mode 100644
index 000000000..90e479aae
--- /dev/null
+++ b/examples/stm32u0/src/bin/blinky.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
16
17 loop {
18 info!("high");
19 led.set_high();
20 Timer::after_millis(300).await;
21
22 info!("low");
23 led.set_low();
24 Timer::after_millis(300).await;
25 }
26}
diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs
new file mode 100644
index 000000000..8017f0274
--- /dev/null
+++ b/examples/stm32u0/src/bin/button.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::entry;
5use defmt::*;
6use embassy_stm32::gpio::{Input, Pull};
7use {defmt_rtt as _, panic_probe as _};
8
9#[entry]
10fn main() -> ! {
11 info!("Hello World!");
12
13 let p = embassy_stm32::init(Default::default());
14
15 let button = Input::new(p.PC13, Pull::Up);
16
17 loop {
18 if button.is_high() {
19 info!("high");
20 } else {
21 info!("low");
22 }
23 }
24}
diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs
new file mode 100644
index 000000000..34a08bbc6
--- /dev/null
+++ b/examples/stm32u0/src/bin/button_exti.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16
17 info!("Press the USER button...");
18
19 loop {
20 button.wait_for_falling_edge().await;
21 info!("Pressed!");
22 button.wait_for_rising_edge().await;
23 info!("Released!");
24 }
25}
diff --git a/examples/stm32u0/src/bin/crc.rs b/examples/stm32u0/src/bin/crc.rs
new file mode 100644
index 000000000..d1b545d5b
--- /dev/null
+++ b/examples/stm32u0/src/bin/crc.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0
15 let mut crc = Crc::new(
16 p.CRC,
17 unwrap!(Config::new(
18 InputReverseConfig::Byte,
19 true,
20 PolySize::Width32,
21 0xFFFFFFFF,
22 0x04C11DB7
23 )),
24 );
25
26 let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF;
27
28 defmt::assert_eq!(output, 0x33F0E26B);
29
30 cortex_m::asm::bkpt();
31}
diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs
new file mode 100644
index 000000000..fdbf1d374
--- /dev/null
+++ b/examples/stm32u0/src/bin/dac.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::dac::{DacCh1, Value};
6use embassy_stm32::dma::NoDma;
7use {defmt_rtt as _, panic_probe as _};
8
9#[cortex_m_rt::entry]
10fn main() -> ! {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
15
16 loop {
17 for v in 0..=255 {
18 dac.set(Value::Bit8(to_sine_wave(v)));
19 }
20 }
21}
22
23use micromath::F32Ext;
24
25fn to_sine_wave(v: u8) -> u8 {
26 if v >= 128 {
27 // top half
28 let r = 3.14 * ((v - 128) as f32 / 128.0);
29 (r.sin() * 128.0 + 127.0) as u8
30 } else {
31 // bottom half
32 let r = 3.14 + 3.14 * (v as f32 / 128.0);
33 (r.sin() * 128.0 + 127.0) as u8
34 }
35}
diff --git a/examples/stm32u0/src/bin/flash.rs b/examples/stm32u0/src/bin/flash.rs
new file mode 100644
index 000000000..01b80a76b
--- /dev/null
+++ b/examples/stm32u0/src/bin/flash.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let addr: u32 = 0x40000 - 2 * 1024;
15
16 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
17
18 info!("Reading...");
19 let mut buf = [0u8; 32];
20 unwrap!(f.blocking_read(addr, &mut buf));
21 info!("Read: {=[u8]:x}", buf);
22 info!("Erasing...");
23 unwrap!(f.blocking_erase(addr, addr + 2 * 1024));
24
25 info!("Reading...");
26 let mut buf = [0u8; 32];
27 unwrap!(f.blocking_read(addr, &mut buf));
28 info!("Read after erase: {=[u8]:x}", buf);
29
30 info!("Writing...");
31 unwrap!(f.blocking_write(
32 addr,
33 &[
34 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
35 30, 31, 32
36 ]
37 ));
38
39 info!("Reading...");
40 let mut buf = [0u8; 32];
41 unwrap!(f.blocking_read(addr, &mut buf));
42 info!("Read: {=[u8]:x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/i2c.rs b/examples/stm32u0/src/bin/i2c.rs
new file mode 100644
index 000000000..2861bc091
--- /dev/null
+++ b/examples/stm32u0/src/bin/i2c.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::I2c;
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10const ADDRESS: u8 = 0x5F;
11const WHOAMI: u8 = 0x0F;
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default());
16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
17
18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
20 info!("Whoami: {}", data[0]);
21}
diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs
new file mode 100644
index 000000000..89445b042
--- /dev/null
+++ b/examples/stm32u0/src/bin/rng.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rcc::mux::Clk48sel;
7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 RNG_CRYP => rng::InterruptHandler<peripherals::RNG>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let mut config = Config::default();
18 {
19 use embassy_stm32::rcc::*;
20 config.rcc.hsi = true;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI, // 16 MHz
23 prediv: PllPreDiv::DIV1,
24 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
25 divp: None,
26 divq: None,
27 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
28 });
29 config.rcc.sys = Sysclk::PLL1_R;
30 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG
31 config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want)
32 }
33
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 let mut rng = Rng::new(p.RNG, Irqs);
39
40 let mut buf = [0u8; 16];
41 unwrap!(rng.async_fill_bytes(&mut buf).await);
42 info!("random bytes: {:02x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs
new file mode 100644
index 000000000..72fa0fde4
--- /dev/null
+++ b/examples/stm32u0/src/bin/rtc.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3
4use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::Config;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.sys = Sysclk::PLL1_R;
18 config.rcc.hsi = true;
19 config.rcc.pll = Some(Pll {
20 source: PllSource::HSI, // 16 MHz
21 prediv: PllPreDiv::DIV1,
22 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
23 divp: None,
24 divq: None,
25 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
26 });
27 config.rcc.ls = LsConfig::default();
28 }
29
30 let p = embassy_stm32::init(config);
31
32 info!("Hello World!");
33
34 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
35 .unwrap()
36 .and_hms_opt(10, 30, 15)
37 .unwrap();
38
39 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
40 info!("Got RTC! {:?}", now.and_utc().timestamp());
41
42 rtc.set_datetime(now.into()).expect("datetime not set");
43
44 // In reality the delay would be much longer
45 Timer::after_millis(20000).await;
46
47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.and_utc().timestamp());
49}
diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs
new file mode 100644
index 000000000..5693a3765
--- /dev/null
+++ b/examples/stm32u0/src/bin/spi.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::gpio::{Level, Output, Speed};
6use embassy_stm32::spi::{Config, Spi};
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let p = embassy_stm32::init(Default::default());
15
16 let mut spi_config = Config::default();
17 spi_config.frequency = Hertz(1_000_000);
18
19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
20
21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
22
23 loop {
24 let mut buf = [0x0Au8; 4];
25 cs.set_low();
26 unwrap!(spi.blocking_transfer_in_place(&mut buf));
27 cs.set_high();
28 info!("xfer {=[u8]:x}", buf);
29 }
30}
diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs
new file mode 100644
index 000000000..037a5c833
--- /dev/null
+++ b/examples/stm32u0/src/bin/usart.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::usart::{Config, Uart};
6use {defmt_rtt as _, panic_probe as _};
7
8#[cortex_m_rt::entry]
9fn main() -> ! {
10 info!("Hello World!");
11
12 let p = embassy_stm32::init(Default::default());
13
14 let config = Config::default();
15 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
16
17 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
18 info!("wrote Hello, starting echo");
19
20 let mut buf = [0u8; 1];
21 loop {
22 unwrap!(usart.blocking_read(&mut buf));
23 unwrap!(usart.blocking_write(&buf));
24 }
25}
diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs
new file mode 100644
index 000000000..273f40643
--- /dev/null
+++ b/examples/stm32u0/src/bin/usb_serial.rs
@@ -0,0 +1,109 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use panic_probe as _;
14
15bind_interrupts!(struct Irqs {
16 USB_DRD_FS => usb::InterruptHandler<peripherals::USB>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let mut config = Config::default();
22 {
23 use embassy_stm32::rcc::*;
24 config.rcc.hsi = true;
25 config.rcc.pll = Some(Pll {
26 source: PllSource::HSI, // 16 MHz
27 prediv: PllPreDiv::DIV1,
28 mul: PllMul::MUL7,
29 divp: None,
30 divq: None,
31 divr: Some(PllRDiv::DIV2), // 56 MHz
32 });
33 config.rcc.sys = Sysclk::PLL1_R;
34 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
35 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK
36 }
37
38 let p = embassy_stm32::init(config);
39
40 info!("Hello World!");
41
42 // Create the driver, from the HAL.
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44
45 // Create embassy-usb Config
46 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
47 //config.max_packet_size_0 = 64;
48
49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors.
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 7];
54
55 let mut state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut config_descriptor,
61 &mut bos_descriptor,
62 &mut [], // no msos descriptors
63 &mut control_buf,
64 );
65
66 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
68
69 // Build the builder.
70 let mut usb = builder.build();
71
72 // Run the USB device.
73 let usb_fut = usb.run();
74
75 // Do stuff with the class!
76 let echo_fut = async {
77 loop {
78 class.wait_connection().await;
79 info!("Connected");
80 let _ = echo(&mut class).await;
81 info!("Disconnected");
82 }
83 };
84
85 // Run everything concurrently.
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
87 join(usb_fut, echo_fut).await;
88}
89
90struct Disconnected {}
91
92impl From<EndpointError> for Disconnected {
93 fn from(val: EndpointError) -> Self {
94 match val {
95 EndpointError::BufferOverflow => panic!("Buffer overflow"),
96 EndpointError::Disabled => Disconnected {},
97 }
98 }
99}
100
101async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
102 let mut buf = [0; 64];
103 loop {
104 let n = class.read_packet(&mut buf).await?;
105 let data = &buf[..n];
106 info!("data: {:x}", data);
107 class.write_packet(data).await?;
108 }
109}
diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs
new file mode 100644
index 000000000..f6276e2e9
--- /dev/null
+++ b/examples/stm32u0/src/bin/wdt.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::Timer;
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 info!("Hello World!");
15
16 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
17
18 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
19 wdt.unleash();
20
21 let mut i = 0;
22
23 loop {
24 info!("high");
25 led.set_high();
26 Timer::after_millis(300).await;
27
28 info!("low");
29 led.set_low();
30 Timer::after_millis(300).await;
31
32 // Pet watchdog for 5 iterations and then stop.
33 // MCU should restart in 1 second after the last pet.
34 if i < 5 {
35 info!("Petting watchdog");
36 wdt.pet();
37 }
38
39 i += 1;
40 }
41}
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 03294339d..20d64c6f7 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -7,10 +7,11 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u585ai to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 15
15defmt = "0.3" 16defmt = "0.3"
16defmt-rtt = "0.4" 17defmt-rtt = "0.4"
@@ -19,10 +20,13 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
19cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24 24
25micromath = "2.0.0" 25micromath = "2.0.0"
26 26
27[features]
28## Use secure registers when TrustZone is enabled
29trustzone-secure = ["embassy-stm32/trustzone-secure"]
30
27[profile.release] 31[profile.release]
28debug = 2 32debug = 2
diff --git a/examples/stm32u5/src/bin/flash.rs b/examples/stm32u5/src/bin/flash.rs
new file mode 100644
index 000000000..e4fd6bb9c
--- /dev/null
+++ b/examples/stm32u5/src/bin/flash.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash;
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello Flash!");
14
15 const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000.
16
17 // wait a bit before accessing the flash
18 Timer::after_millis(300).await;
19
20 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
21
22 info!("Reading...");
23 let mut buf = [0u8; 32];
24 unwrap!(f.blocking_read(ADDR, &mut buf));
25 info!("Read: {=[u8]:x}", buf);
26
27 info!("Erasing...");
28 unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024));
29
30 info!("Reading...");
31 let mut buf = [0u8; 32];
32 unwrap!(f.blocking_read(ADDR, &mut buf));
33 info!("Read after erase: {=[u8]:x}", buf);
34
35 info!("Writing...");
36 unwrap!(f.blocking_write(
37 ADDR,
38 &[
39 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
40 30, 31, 32
41 ]
42 ));
43
44 info!("Reading...");
45 let mut buf = [0u8; 32];
46 unwrap!(f.blocking_read(ADDR, &mut buf));
47 info!("Read: {=[u8]:x}", buf);
48 assert_eq!(
49 &buf[..],
50 &[
51 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
52 30, 31, 32
53 ]
54 );
55}
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
new file mode 100644
index 000000000..19a78eac9
--- /dev/null
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::I2c;
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10const HTS221_ADDRESS: u8 = 0x5F;
11const WHOAMI: u8 = 0x0F;
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default());
16 let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default());
17
18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
20
21 // HTS221 data sheet is here: https://www.st.com/resource/en/datasheet/hts221.pdf
22 // 7.1 WHO_AM_I command is x0F which expected response xBC.
23 info!("Whoami: 0x{:02x}", data[0]);
24 assert_eq!(0xBC, data[0]);
25}
diff --git a/examples/stm32u5/src/bin/rng.rs b/examples/stm32u5/src/bin/rng.rs
new file mode 100644
index 000000000..3a5bce097
--- /dev/null
+++ b/examples/stm32u5/src/bin/rng.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rng::Rng;
7use embassy_stm32::{bind_interrupts, peripherals, rng};
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 RNG => rng::InterruptHandler<peripherals::RNG>;
12});
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17
18 info!("Hello World!");
19
20 let mut rng = Rng::new(p.RNG, Irqs);
21
22 let mut buf = [0u8; 16];
23 unwrap!(rng.async_fill_bytes(&mut buf).await);
24 info!("random bytes: {:02x}", buf);
25}
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
new file mode 100644
index 000000000..eb15d275a
--- /dev/null
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -0,0 +1,95 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::bind_interrupts;
6use embassy_stm32::tsc::{self, *};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
12});
13
14#[cortex_m_rt::exception]
15unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! {
16 cortex_m::peripheral::SCB::sys_reset();
17}
18
19#[embassy_executor::main]
20async fn main(_spawner: embassy_executor::Spawner) {
21 let device_config = embassy_stm32::Config::default();
22 let context = embassy_stm32::init(device_config);
23
24 let config = tsc::Config {
25 ct_pulse_high_length: ChargeTransferPulseCycle::_2,
26 ct_pulse_low_length: ChargeTransferPulseCycle::_2,
27 spread_spectrum: false,
28 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
29 spread_spectrum_prescaler: false,
30 pulse_generator_prescaler: PGPrescalerDivider::_4,
31 max_count_value: MaxCount::_8191,
32 io_default_mode: false,
33 synchro_pin_polarity: false,
34 acquisition_mode: false,
35 max_count_interrupt: false,
36 channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3,
37 shield_ios: TscIOPin::Group1Io3.into(),
38 sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2,
39 };
40
41 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
42 g1.set_io2(context.PB13, PinType::Sample);
43 g1.set_io3(context.PB14, PinType::Shield);
44
45 let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new();
46 g2.set_io1(context.PB4, PinType::Sample);
47 g2.set_io2(context.PB5, PinType::Channel);
48
49 let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new();
50 g7.set_io2(context.PE3, PinType::Sample);
51 g7.set_io3(context.PE4, PinType::Channel);
52
53 let mut touch_controller = tsc::Tsc::new_async(
54 context.TSC,
55 Some(g1),
56 Some(g2),
57 None,
58 None,
59 None,
60 None,
61 Some(g7),
62 None,
63 config,
64 Irqs,
65 );
66
67 touch_controller.discharge_io(true);
68 Timer::after_millis(1).await;
69
70 touch_controller.start();
71
72 let mut group_two_val = 0;
73 let mut group_seven_val = 0;
74 info!("Starting touch_controller interface");
75 loop {
76 touch_controller.pend_for_acquisition().await;
77 touch_controller.discharge_io(true);
78 Timer::after_millis(1).await;
79
80 if touch_controller.group_get_status(Group::Two) == GroupStatus::Complete {
81 group_two_val = touch_controller.group_get_value(Group::Two);
82 }
83
84 if touch_controller.group_get_status(Group::Seven) == GroupStatus::Complete {
85 group_seven_val = touch_controller.group_get_value(Group::Seven);
86 }
87
88 info!(
89 "Group Two value: {}, Group Seven value: {},",
90 group_two_val, group_seven_val
91 );
92
93 touch_controller.start();
94 }
95}
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index dca34fd0e..4d56395da 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -4,17 +4,16 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::*; 7use embassy_futures::join::join;
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 12use embassy_usb::Builder;
13use futures::future::join;
14use panic_probe as _; 13use panic_probe as _;
15 14
16bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
18}); 17});
19 18
20#[embassy_executor::main] 19#[embassy_executor::main]
@@ -22,22 +21,33 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.mux = ClockSrc::PLL1_R(PllConfig { 24 {
26 source: PllSource::HSI, 25 use embassy_stm32::rcc::*;
27 m: Pllm::DIV2, 26 config.rcc.hsi = true;
28 n: Plln::MUL10, 27 config.rcc.pll1 = Some(Pll {
29 p: Plldiv::DIV1, 28 source: PllSource::HSI, // 16 MHz
30 q: Plldiv::DIV1, 29 prediv: PllPreDiv::DIV1,
31 r: Plldiv::DIV1, 30 mul: PllMul::MUL10,
32 }); 31 divp: None,
33 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 32 divq: None,
33 divr: Some(PllDiv::DIV1), // 160 MHz
34 });
35 config.rcc.sys = Sysclk::PLL1_R;
36 config.rcc.voltage_range = VoltageScale::RANGE1;
37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
38 config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK
39 }
34 40
35 let p = embassy_stm32::init(config); 41 let p = embassy_stm32::init(config);
36 42
37 // Create the driver, from the HAL. 43 // Create the driver, from the HAL.
38 let mut ep_out_buffer = [0u8; 256]; 44 let mut ep_out_buffer = [0u8; 256];
39 let mut config = embassy_stm32::usb_otg::Config::default(); 45 let mut config = embassy_stm32::usb::Config::default();
40 config.vbus_detection = true; 46 // Do not enable vbus_detection. This is a safe default that works in all boards.
47 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
48 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
49 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
50 config.vbus_detection = false;
41 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 51 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
42 52
43 // Create embassy-usb Config 53 // Create embassy-usb Config
@@ -55,7 +65,6 @@ async fn main(_spawner: Spawner) {
55 65
56 // Create embassy-usb DeviceBuilder using the driver and config. 66 // Create embassy-usb DeviceBuilder using the driver and config.
57 // It needs some buffers for building the descriptors. 67 // It needs some buffers for building the descriptors.
58 let mut device_descriptor = [0; 256];
59 let mut config_descriptor = [0; 256]; 68 let mut config_descriptor = [0; 256];
60 let mut bos_descriptor = [0; 256]; 69 let mut bos_descriptor = [0; 256];
61 let mut control_buf = [0; 64]; 70 let mut control_buf = [0; 64];
@@ -65,7 +74,6 @@ async fn main(_spawner: Spawner) {
65 let mut builder = Builder::new( 74 let mut builder = Builder::new(
66 driver, 75 driver,
67 config, 76 config,
68 &mut device_descriptor,
69 &mut config_descriptor, 77 &mut config_descriptor,
70 &mut bos_descriptor, 78 &mut bos_descriptor,
71 &mut [], // no msos descriptors 79 &mut [], // no msos descriptors
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 51c499ee7..8b6d6d754 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 94a5141f5..1e1a0efe2 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32wb55rg to your chip name in both dependencies, if necessary. 8# Change stm32wb55rg to your chip name in both dependencies, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
15 15
16defmt = "0.3" 16defmt = "0.3"
@@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
25static_cell = "2" 24static_cell = "2"
26 25
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index d3b3c15ca..3bd8b4a63 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 46 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
47 - Select "Start Wireless Stack". 47 - Select "Start Wireless Stack".
48 - Disconnect from the device. 48 - Disconnect from the device.
49 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
50 - Run this example. 49 - Run this example.
51 50
52 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 51 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 3b50d6c31..1cc50e134 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) {
57 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 57 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
58 - Select "Start Wireless Stack". 58 - Select "Start Wireless Stack".
59 - Disconnect from the device. 59 - Disconnect from the device.
60 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
61 - Run this example. 60 - Run this example.
62 61
63 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 62 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
index 5cd660543..d139aa61b 100644
--- a/examples/stm32wb/src/bin/mac_ffd.rs
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -43,7 +43,6 @@ async fn main(spawner: Spawner) {
43 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 43 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
44 - Select "Start Wireless Stack". 44 - Select "Start Wireless Stack".
45 - Disconnect from the device. 45 - Disconnect from the device.
46 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
47 - Run this example. 46 - Run this example.
48 47
49 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 48 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs
index 7a42bf577..6a97daf4d 100644
--- a/examples/stm32wb/src/bin/mac_ffd_net.rs
+++ b/examples/stm32wb/src/bin/mac_ffd_net.rs
@@ -49,7 +49,6 @@ async fn main(spawner: Spawner) {
49 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 49 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
50 - Select "Start Wireless Stack". 50 - Select "Start Wireless Stack".
51 - Disconnect from the device. 51 - Disconnect from the device.
52 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
53 - Run this example. 52 - Run this example.
54 53
55 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 54 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
index 7949211fb..9062bdcd2 100644
--- a/examples/stm32wb/src/bin/mac_rfd.rs
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -45,7 +45,6 @@ async fn main(spawner: Spawner) {
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Select "Start Wireless Stack". 46 - Select "Start Wireless Stack".
47 - Disconnect from the device. 47 - Disconnect from the device.
48 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
49 - Run this example. 48 - Run this example.
50 49
51 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 50 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index cb92d462d..4e7f2304d 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
35 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 35 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
36 - Select "Start Wireless Stack". 36 - Select "Start Wireless Stack".
37 - Disconnect from the device. 37 - Disconnect from the device.
38 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
39 - Run this example. 38 - Run this example.
40 39
41 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 40 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 2599e1151..72a4c18e6 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -34,7 +34,6 @@ async fn main(_spawner: Spawner) {
34 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 34 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
35 - Select "Start Wireless Stack". 35 - Select "Start Wireless Stack".
36 - Disconnect from the device. 36 - Disconnect from the device.
37 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
38 - Run this example. 37 - Run this example.
39 38
40 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 39 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index 5d868412a..9224e626d 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -40,7 +40,6 @@ async fn main(spawner: Spawner) {
40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
41 - Select "Start Wireless Stack". 41 - Select "Start Wireless Stack".
42 - Disconnect from the device. 42 - Disconnect from the device.
43 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
44 - Run this example. 43 - Run this example.
45 44
46 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. 45 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index 47279a012..401281c0b 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
13 13
14defmt = "0.3" 14defmt = "0.3"
@@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
23static_cell = "2" 22static_cell = "2"
24 23
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 4cb55930b..46af5218c 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32wl55jc-cm4 to your chip name, if necessary. 8# Change stm32wl55jc-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.5.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 = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -20,7 +20,6 @@ cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21embedded-storage = "0.3.1" 21embedded-storage = "0.3.1"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
25chrono = { version = "^0.4", default-features = false } 24chrono = { version = "^0.4", default-features = false }
26 25
diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x
new file mode 100644
index 000000000..4590867a8
--- /dev/null
+++ b/examples/stm32wl/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K
5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
6 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128
7}
8
9SECTIONS
10{
11 .shared_data :
12 {
13 *(.shared_data)
14 } > SHARED_RAM
15}
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs
index 347bd093f..ce7d0ec58 100644
--- a/examples/stm32wl/src/bin/blinky.rs
+++ b/examples/stm32wl/src/bin/blinky.rs
@@ -1,15 +1,21 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
7use embassy_time::Timer; 10use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
9 12
13#[link_section = ".shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
10#[embassy_executor::main] 16#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
13 info!("Hello World!"); 19 info!("Hello World!");
14 20
15 let mut led = Output::new(p.PB15, Level::High, Speed::Low); 21 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs
index eccd211e2..8b5204479 100644
--- a/examples/stm32wl/src/bin/button.rs
+++ b/examples/stm32wl/src/bin/button.rs
@@ -1,16 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use cortex_m_rt::entry; 6use cortex_m_rt::entry;
5use defmt::*; 7use defmt::*;
6use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::SharedData;
7use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
8 11
12#[link_section = ".shared_data"]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14
9#[entry] 15#[entry]
10fn main() -> ! { 16fn main() -> ! {
11 info!("Hello World!"); 17 info!("Hello World!");
12 18
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
14 20
15 let button = Input::new(p.PA0, Pull::Up); 21 let button = Input::new(p.PA0, Pull::Up);
16 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); 22 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index 27d5330bd..8dd1a6a5e 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -1,15 +1,21 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 8use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::Pull; 9use embassy_stm32::gpio::Pull;
10use embassy_stm32::SharedData;
8use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
9 12
13#[link_section = ".shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
10#[embassy_executor::main] 16#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
13 info!("Hello World!"); 19 info!("Hello World!");
14 20
15 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); 21 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 0b7417c01..147f5d293 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -1,14 +1,20 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::{info, unwrap}; 6use defmt::{info, unwrap};
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash; 8use embassy_stm32::flash::Flash;
9use embassy_stm32::SharedData;
7use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
8 11
12#[link_section = ".shared_data"]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14
9#[embassy_executor::main] 15#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
12 info!("Hello Flash!"); 18 info!("Hello Flash!");
13 19
14 const ADDR: u32 = 0x36000; 20 const ADDR: u32 = 0x36000;
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 3610392be..df2ed0054 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -1,17 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
7use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, peripherals}; 10use embassy_stm32::{bind_interrupts, peripherals, SharedData};
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
11bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
12 RNG => rng::InterruptHandler<peripherals::RNG>; 14 RNG => rng::InterruptHandler<peripherals::RNG>;
13}); 15});
14 16
17#[link_section = ".shared_data"]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19
15#[embassy_executor::main] 20#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
17 let mut config = embassy_stm32::Config::default(); 22 let mut config = embassy_stm32::Config::default();
@@ -22,7 +27,7 @@ async fn main(_spawner: Spawner) {
22 mode: HseMode::Bypass, 27 mode: HseMode::Bypass,
23 prescaler: HsePrescaler::DIV1, 28 prescaler: HsePrescaler::DIV1,
24 }); 29 });
25 config.rcc.mux = ClockSrc::PLL1_R; 30 config.rcc.sys = Sysclk::PLL1_R;
26 config.rcc.pll = Some(Pll { 31 config.rcc.pll = Some(Pll {
27 source: PllSource::HSE, 32 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV2, 33 prediv: PllPreDiv::DIV2,
@@ -32,7 +37,7 @@ async fn main(_spawner: Spawner) {
32 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) 37 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2)
33 }); 38 });
34 } 39 }
35 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
36 41
37 info!("Hello World!"); 42 info!("Hello World!");
38 43
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index 4738d5770..69a9ddc4c 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -1,15 +1,20 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use chrono::{NaiveDate, NaiveDateTime}; 6use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*; 7use defmt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig}; 9use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
9use embassy_stm32::Config; 11use embassy_stm32::{Config, SharedData};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
15#[link_section = ".shared_data"]
16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
17
13#[embassy_executor::main] 18#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 20 let mut config = Config::default();
@@ -21,7 +26,7 @@ async fn main(_spawner: Spawner) {
21 mode: HseMode::Bypass, 26 mode: HseMode::Bypass,
22 prescaler: HsePrescaler::DIV1, 27 prescaler: HsePrescaler::DIV1,
23 }); 28 });
24 config.rcc.mux = ClockSrc::PLL1_R; 29 config.rcc.sys = Sysclk::PLL1_R;
25 config.rcc.pll = Some(Pll { 30 config.rcc.pll = Some(Pll {
26 source: PllSource::HSE, 31 source: PllSource::HSE,
27 prediv: PllPreDiv::DIV2, 32 prediv: PllPreDiv::DIV2,
@@ -31,7 +36,7 @@ async fn main(_spawner: Spawner) {
31 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) 36 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2)
32 }); 37 });
33 } 38 }
34 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
35 info!("Hello World!"); 40 info!("Hello World!");
36 41
37 let now = NaiveDate::from_ymd_opt(2020, 5, 15) 42 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
@@ -40,7 +45,7 @@ async fn main(_spawner: Spawner) {
40 .unwrap(); 45 .unwrap();
41 46
42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 47 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
43 info!("Got RTC! {:?}", now.timestamp()); 48 info!("Got RTC! {:?}", now.and_utc().timestamp());
44 49
45 rtc.set_datetime(now.into()).expect("datetime not set"); 50 rtc.set_datetime(now.into()).expect("datetime not set");
46 51
@@ -48,5 +53,5 @@ async fn main(_spawner: Spawner) {
48 Timer::after_millis(20000).await; 53 Timer::after_millis(20000).await;
49 54
50 let then: NaiveDateTime = rtc.now().unwrap().into(); 55 let then: NaiveDateTime = rtc.now().unwrap().into();
51 info!("Got RTC! {:?}", then.timestamp()); 56 info!("Got RTC! {:?}", then.and_utc().timestamp());
52} 57}
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index 8e545834c..ece9b9201 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -1,10 +1,12 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::usart::{Config, InterruptHandler, Uart}; 8use embassy_stm32::usart::{Config, InterruptHandler, Uart};
7use embassy_stm32::{bind_interrupts, peripherals}; 9use embassy_stm32::{bind_interrupts, peripherals, SharedData};
8use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
9 11
10bind_interrupts!(struct Irqs{ 12bind_interrupts!(struct Irqs{
@@ -12,6 +14,9 @@ bind_interrupts!(struct Irqs{
12 LPUART1 => InterruptHandler<peripherals::LPUART1>; 14 LPUART1 => InterruptHandler<peripherals::LPUART1>;
13}); 15});
14 16
17#[link_section = ".shared_data"]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19
15/* 20/*
16Pass Incoming data from LPUART1 to USART1 21Pass Incoming data from LPUART1 to USART1
17Example is written for the LoRa-E5 mini v1.0, 22Example is written for the LoRa-E5 mini v1.0,
@@ -20,8 +25,8 @@ but can be surely changed for your needs.
20#[embassy_executor::main] 25#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
22 let mut config = embassy_stm32::Config::default(); 27 let mut config = embassy_stm32::Config::default();
23 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; 28 config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE;
24 let p = embassy_stm32::init(config); 29 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
25 30
26 defmt::info!("Starting system"); 31 defmt::info!("Starting system");
27 32
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 3d2300b59..75de079b7 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -8,15 +8,14 @@ license = "MIT OR Apache-2.0"
8crate-type = ["cdylib"] 8crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] }
13embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "wasm", ] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] }
14 14
15wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
16wasm-bindgen = "0.2" 16wasm-bindgen = "0.2"
17web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } 17web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] }
18log = "0.4.11" 18log = "0.4.11"
19critical-section = { version = "1.1", features = ["std"] }
20 19
21[profile.release] 20[profile.release]
22debug = 2 21debug = 2