aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/boot/application/nrf/Cargo.toml18
-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.toml18
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml16
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml16
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml16
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml16
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml16
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml16
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml18
-rw-r--r--examples/boot/application/stm32wb-dfu/memory.x8
-rw-r--r--examples/boot/application/stm32wb-dfu/secrets/key.sec2
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs32
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml16
-rw-r--r--examples/boot/application/stm32wl/memory.x6
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs2
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml6
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs6
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml6
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml6
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml6
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml9
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/README.md58
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/memory.x8
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short1
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs44
-rw-r--r--examples/lpc55s69/.cargo/config.toml (renamed from examples/rp23/.cargo/config.toml)3
-rw-r--r--examples/lpc55s69/Cargo.toml22
-rw-r--r--examples/lpc55s69/build.rs (renamed from examples/rp23/build.rs)0
-rw-r--r--examples/lpc55s69/memory.x28
-rw-r--r--examples/lpc55s69/src/bin/blinky_nop.rs33
-rw-r--r--examples/lpc55s69/src/bin/button_executor.rs25
-rw-r--r--examples/mimxrt6/.cargo/config.toml17
-rw-r--r--examples/mimxrt6/.gitignore14
-rw-r--r--examples/mimxrt6/Cargo.toml60
-rw-r--r--examples/mimxrt6/README.md18
-rw-r--r--examples/mimxrt6/build.rs45
-rw-r--r--examples/mimxrt6/memory.x34
-rw-r--r--examples/mimxrt6/src/bin/blinky.rs30
-rw-r--r--examples/mimxrt6/src/bin/button.rs29
-rw-r--r--examples/mimxrt6/src/bin/crc.rs175
-rw-r--r--examples/mimxrt6/src/bin/hello.rs17
-rw-r--r--examples/mimxrt6/src/bin/rng.rs39
-rw-r--r--examples/mimxrt6/src/bin/uart-async.rs87
-rw-r--r--examples/mimxrt6/src/bin/uart.rs55
-rw-r--r--examples/mimxrt6/src/lib.rs20
-rw-r--r--examples/mspm0c1104/.cargo/config.toml11
-rw-r--r--examples/mspm0c1104/Cargo.toml32
-rw-r--r--examples/mspm0c1104/README.md27
-rw-r--r--examples/mspm0c1104/build.rs37
-rw-r--r--examples/mspm0c1104/memory.x5
-rw-r--r--examples/mspm0c1104/src/bin/blinky.rs25
-rw-r--r--examples/mspm0c1104/src/bin/button.rs33
-rw-r--r--examples/mspm0c1104/src/bin/uart.rs35
-rw-r--r--examples/mspm0g3507/.cargo/config.toml9
-rw-r--r--examples/mspm0g3507/Cargo.toml21
-rw-r--r--examples/mspm0g3507/README.md27
-rw-r--r--examples/mspm0g3507/build.rs37
-rw-r--r--examples/mspm0g3507/memory.x6
-rw-r--r--examples/mspm0g3507/src/bin/blinky.rs25
-rw-r--r--examples/mspm0g3507/src/bin/button.rs33
-rw-r--r--examples/mspm0g3507/src/bin/uart.rs35
-rw-r--r--examples/mspm0g3519/.cargo/config.toml9
-rw-r--r--examples/mspm0g3519/Cargo.toml21
-rw-r--r--examples/mspm0g3519/README.md27
-rw-r--r--examples/mspm0g3519/build.rs37
-rw-r--r--examples/mspm0g3519/memory.x6
-rw-r--r--examples/mspm0g3519/src/bin/blinky.rs25
-rw-r--r--examples/mspm0g3519/src/bin/button.rs33
-rw-r--r--examples/mspm0g3519/src/bin/uart.rs35
-rw-r--r--examples/mspm0l1306/.cargo/config.toml9
-rw-r--r--examples/mspm0l1306/Cargo.toml21
-rw-r--r--examples/mspm0l1306/README.md27
-rw-r--r--examples/mspm0l1306/build.rs37
-rw-r--r--examples/mspm0l1306/memory.x5
-rw-r--r--examples/mspm0l1306/src/bin/blinky.rs25
-rw-r--r--examples/mspm0l1306/src/bin/button.rs33
-rw-r--r--examples/mspm0l1306/src/bin/uart.rs35
-rw-r--r--examples/mspm0l2228/.cargo/config.toml9
-rw-r--r--examples/mspm0l2228/Cargo.toml21
-rw-r--r--examples/mspm0l2228/README.md27
-rw-r--r--examples/mspm0l2228/build.rs37
-rw-r--r--examples/mspm0l2228/memory.x6
-rw-r--r--examples/mspm0l2228/src/bin/blinky.rs25
-rw-r--r--examples/mspm0l2228/src/bin/button.rs33
-rw-r--r--examples/mspm0l2228/src/bin/uart.rs35
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml11
-rw-r--r--examples/nrf51/Cargo.toml12
-rw-r--r--examples/nrf52810/Cargo.toml14
-rw-r--r--examples/nrf52840-rtic/Cargo.toml13
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs6
-rw-r--r--examples/nrf52840/Cargo.toml24
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs4
-rw-r--r--examples/nrf52840/src/bin/channel.rs4
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs11
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs14
-rw-r--r--examples/nrf52840/src/bin/ieee802154_receive.rs38
-rw-r--r--examples/nrf52840/src/bin/ieee802154_send.rs39
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs16
-rw-r--r--examples/nrf52840/src/bin/nfct.rs79
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs4
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs10
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs14
-rwxr-xr-x[-rw-r--r--]examples/nrf52840/src/bin/rng.rs2
-rw-r--r--examples/nrf52840/src/bin/saadc.rs2
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs12
-rw-r--r--examples/nrf52840/src/bin/spis.rs2
-rw-r--r--examples/nrf52840/src/bin/twim.rs6
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs12
-rw-r--r--examples/nrf52840/src/bin/twis.rs2
-rw-r--r--examples/nrf52840/src/bin/uart.rs4
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs4
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs4
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs26
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs8
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs9
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs16
-rw-r--r--examples/nrf52840/src/bin/wdt.rs4
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs11
-rw-r--r--examples/nrf5340/Cargo.toml19
-rw-r--r--examples/nrf5340/src/bin/uart.rs2
-rw-r--r--examples/nrf54l15/.cargo/config.toml9
-rw-r--r--examples/nrf54l15/Cargo.toml20
-rw-r--r--examples/nrf54l15/build.rs35
-rw-r--r--examples/nrf54l15/memory.x5
-rw-r--r--examples/nrf54l15/src/bin/blinky.rs23
-rw-r--r--examples/nrf9151/ns/Cargo.toml12
-rw-r--r--examples/nrf9151/ns/src/bin/uart.rs4
-rw-r--r--examples/nrf9151/s/Cargo.toml12
-rw-r--r--examples/nrf9160/.cargo/config.toml3
-rw-r--r--examples/nrf9160/Cargo.toml18
-rw-r--r--examples/nrf9160/memory.x8
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs197
-rw-r--r--examples/rp/Cargo.toml59
-rw-r--r--examples/rp/src/bin/adc.rs9
-rw-r--r--examples/rp/src/bin/adc_dma.rs4
-rw-r--r--examples/rp/src/bin/assign_resources.rs7
-rw-r--r--examples/rp/src/bin/blinky_two_channels.rs4
-rw-r--r--examples/rp/src/bin/blinky_two_tasks.rs4
-rw-r--r--examples/rp/src/bin/bluetooth.rs148
-rw-r--r--examples/rp/src/bin/ethernet_w5500_icmp.rs143
-rw-r--r--examples/rp/src/bin/ethernet_w5500_icmp_ping.rs134
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs22
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs16
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs16
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs16
-rw-r--r--examples/rp/src/bin/i2c_slave.rs12
-rw-r--r--examples/rp/src/bin/interrupt.rs1
-rw-r--r--examples/rp/src/bin/orchestrate_tasks.rs318
-rw-r--r--examples/rp/src/bin/overclock.rs64
-rw-r--r--examples/rp/src/bin/overclock_manual.rs81
-rw-r--r--examples/rp/src/bin/pio_async.rs15
-rw-r--r--examples/rp/src/bin/pio_dma.rs13
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs201
-rw-r--r--examples/rp/src/bin/pio_i2s.rs76
-rw-r--r--examples/rp/src/bin/pio_onewire.rs87
-rw-r--r--examples/rp/src/bin/pio_pwm.rs90
-rw-r--r--examples/rp/src/bin/pio_rotary_encoder.rs83
-rw-r--r--examples/rp/src/bin/pio_servo.rs96
-rw-r--r--examples/rp/src/bin/pio_stepper.rs135
-rw-r--r--examples/rp/src/bin/pio_uart.rs230
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs105
-rw-r--r--examples/rp/src/bin/pwm.rs63
-rw-r--r--examples/rp/src/bin/shared_bus.rs6
-rw-r--r--examples/rp/src/bin/sharing.rs3
-rw-r--r--examples/rp/src/bin/spi_display.rs165
-rw-r--r--examples/rp/src/bin/spi_gc9a01.rs125
-rw-r--r--examples/rp/src/bin/spi_sdmmc.rs4
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs4
-rw-r--r--examples/rp/src/bin/uart_unidir.rs2
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs18
-rwxr-xr-x[-rw-r--r--]examples/rp/src/bin/usb_hid_mouse.rs11
-rw-r--r--examples/rp/src/bin/usb_midi.rs7
-rw-r--r--examples/rp/src/bin/usb_raw.rs7
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs7
-rw-r--r--examples/rp/src/bin/usb_serial.rs7
-rw-r--r--examples/rp/src/bin/usb_serial_with_handler.rs64
-rw-r--r--examples/rp/src/bin/usb_serial_with_logger.rs7
-rw-r--r--examples/rp/src/bin/usb_webusb.rs6
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs32
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs17
-rw-r--r--examples/rp/src/bin/wifi_scan.rs19
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs41
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs37
-rw-r--r--examples/rp/src/bin/zerocopy.rs9
-rw-r--r--examples/rp23/Cargo.toml80
-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_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/spi_display.rs327
-rw-r--r--examples/rp235x/.cargo/config.toml10
-rw-r--r--examples/rp235x/Cargo.toml65
-rw-r--r--examples/rp235x/assets/ferris.raw (renamed from examples/rp23/assets/ferris.raw)bin11008 -> 11008 bytes
-rw-r--r--examples/rp235x/build.rs35
-rw-r--r--examples/rp235x/memory.x (renamed from examples/rp23/memory.x)1
-rw-r--r--examples/rp235x/src/bin/adc.rs (renamed from examples/rp23/src/bin/adc.rs)19
-rw-r--r--examples/rp235x/src/bin/adc_dma.rs (renamed from examples/rp23/src/bin/adc_dma.rs)21
-rw-r--r--examples/rp235x/src/bin/assign_resources.rs (renamed from examples/rp23/src/bin/assign_resources.rs)22
-rw-r--r--examples/rp235x/src/bin/blinky.rs (renamed from examples/rp23/src/bin/blinky.rs)24
-rw-r--r--examples/rp235x/src/bin/blinky_two_channels.rs (renamed from examples/rp23/src/bin/blinky_two_channels.rs)19
-rw-r--r--examples/rp235x/src/bin/blinky_two_tasks.rs (renamed from examples/rp23/src/bin/blinky_two_tasks.rs)19
-rw-r--r--examples/rp235x/src/bin/blinky_wifi.rs89
-rw-r--r--examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs88
-rw-r--r--examples/rp235x/src/bin/button.rs (renamed from examples/rp23/src/bin/button.rs)15
-rw-r--r--examples/rp235x/src/bin/debounce.rs (renamed from examples/rp23/src/bin/debounce.rs)15
-rw-r--r--examples/rp235x/src/bin/flash.rs (renamed from examples/rp23/src/bin/flash.rs)30
-rw-r--r--examples/rp235x/src/bin/gpio_async.rs (renamed from examples/rp23/src/bin/gpio_async.rs)17
-rw-r--r--examples/rp235x/src/bin/gpout.rs (renamed from examples/rp23/src/bin/gpout.rs)15
-rw-r--r--examples/rp235x/src/bin/i2c_async.rs (renamed from examples/rp23/src/bin/i2c_async.rs)15
-rw-r--r--examples/rp235x/src/bin/i2c_async_embassy.rs (renamed from examples/rp23/src/bin/i2c_async_embassy.rs)15
-rw-r--r--examples/rp235x/src/bin/i2c_blocking.rs (renamed from examples/rp23/src/bin/i2c_blocking.rs)15
-rw-r--r--examples/rp235x/src/bin/i2c_slave.rs (renamed from examples/rp23/src/bin/i2c_slave.rs)15
-rw-r--r--examples/rp235x/src/bin/interrupt.rs (renamed from examples/rp23/src/bin/interrupt.rs)16
-rw-r--r--examples/rp235x/src/bin/multicore.rs (renamed from examples/rp23/src/bin/multicore.rs)17
-rw-r--r--examples/rp235x/src/bin/multiprio.rs (renamed from examples/rp23/src/bin/multiprio.rs)15
-rw-r--r--examples/rp235x/src/bin/otp.rs31
-rw-r--r--examples/rp235x/src/bin/overclock.rs74
-rw-r--r--examples/rp235x/src/bin/pio_async.rs (renamed from examples/rp23/src/bin/pio_async.rs)28
-rw-r--r--examples/rp235x/src/bin/pio_dma.rs (renamed from examples/rp23/src/bin/pio_dma.rs)30
-rw-r--r--examples/rp235x/src/bin/pio_hd44780.rs87
-rw-r--r--examples/rp235x/src/bin/pio_i2s.rs93
-rw-r--r--examples/rp235x/src/bin/pio_onewire.rs83
-rw-r--r--examples/rp235x/src/bin/pio_pwm.rs38
-rw-r--r--examples/rp235x/src/bin/pio_rotary_encoder.rs55
-rw-r--r--examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs (renamed from examples/rp23/src/bin/pio_rotary_encoder.rs)77
-rw-r--r--examples/rp235x/src/bin/pio_servo.rs (renamed from examples/rp23/src/bin/pio_servo.rs)113
-rw-r--r--examples/rp235x/src/bin/pio_stepper.rs49
-rw-r--r--examples/rp235x/src/bin/pio_uart.rs190
-rw-r--r--examples/rp235x/src/bin/pio_ws2812.rs68
-rw-r--r--examples/rp235x/src/bin/pwm.rs80
-rw-r--r--examples/rp235x/src/bin/pwm_input.rs (renamed from examples/rp23/src/bin/pwm_input.rs)15
-rw-r--r--examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs105
-rw-r--r--examples/rp235x/src/bin/rosc.rs (renamed from examples/rp23/src/bin/rosc.rs)15
-rw-r--r--examples/rp235x/src/bin/shared_bus.rs (renamed from examples/rp23/src/bin/shared_bus.rs)21
-rw-r--r--examples/rp235x/src/bin/sharing.rs (renamed from examples/rp23/src/bin/sharing.rs)18
-rw-r--r--examples/rp235x/src/bin/spi.rs (renamed from examples/rp23/src/bin/spi.rs)17
-rw-r--r--examples/rp235x/src/bin/spi_async.rs (renamed from examples/rp23/src/bin/spi_async.rs)17
-rw-r--r--examples/rp235x/src/bin/spi_display.rs177
-rw-r--r--examples/rp235x/src/bin/spi_sdmmc.rs (renamed from examples/rp23/src/bin/spi_sdmmc.rs)20
-rw-r--r--examples/rp235x/src/bin/trng.rs48
-rw-r--r--examples/rp235x/src/bin/uart.rs (renamed from examples/rp23/src/bin/uart.rs)17
-rw-r--r--examples/rp235x/src/bin/uart_buffered_split.rs (renamed from examples/rp23/src/bin/uart_buffered_split.rs)21
-rw-r--r--examples/rp235x/src/bin/uart_r503.rs (renamed from examples/rp23/src/bin/uart_r503.rs)15
-rw-r--r--examples/rp235x/src/bin/uart_unidir.rs (renamed from examples/rp23/src/bin/uart_unidir.rs)19
-rw-r--r--examples/rp235x/src/bin/usb_hid_keyboard.rs188
-rw-r--r--examples/rp235x/src/bin/usb_webusb.rs (renamed from examples/rp23/src/bin/usb_webusb.rs)23
-rw-r--r--examples/rp235x/src/bin/watchdog.rs (renamed from examples/rp23/src/bin/watchdog.rs)17
-rw-r--r--examples/rp235x/src/bin/zerocopy.rs (renamed from examples/rp23/src/bin/zerocopy.rs)26
-rw-r--r--examples/std/Cargo.toml12
-rw-r--r--examples/std/README.md125
-rw-r--r--examples/std/src/bin/net.rs23
-rw-r--r--examples/std/src/bin/net_dns.rs15
-rw-r--r--examples/std/src/bin/net_ppp.rs79
-rw-r--r--examples/std/src/bin/net_udp.rs15
-rw-r--r--examples/std/src/bin/tcp_accept.rs32
-rw-r--r--examples/std/tap.sh7
-rw-r--r--examples/stm32c0/Cargo.toml14
-rw-r--r--examples/stm32c0/src/bin/adc.rs58
-rw-r--r--examples/stm32f0/Cargo.toml14
-rw-r--r--examples/stm32f0/src/bin/button_controlled_blink.rs7
-rw-r--r--examples/stm32f1/Cargo.toml16
-rw-r--r--examples/stm32f1/src/bin/input_capture.rs4
-rw-r--r--examples/stm32f1/src/bin/pwm_input.rs4
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f2/Cargo.toml14
-rw-r--r--examples/stm32f3/Cargo.toml16
-rw-r--r--examples/stm32f3/README.md24
-rw-r--r--examples/stm32f3/src/bin/blocking-tsc.rs98
-rw-r--r--examples/stm32f3/src/bin/tsc_blocking.rs138
-rw-r--r--examples/stm32f3/src/bin/tsc_multipin.rs204
-rw-r--r--examples/stm32f334/Cargo.toml16
-rw-r--r--examples/stm32f334/src/bin/opamp.rs4
-rw-r--r--examples/stm32f334/src/bin/pwm.rs4
-rw-r--r--examples/stm32f4/Cargo.toml21
-rw-r--r--examples/stm32f4/src/bin/can.rs2
-rw-r--r--examples/stm32f4/src/bin/dac.rs3
-rw-r--r--examples/stm32f4/src/bin/eth.rs20
-rw-r--r--examples/stm32f4/src/bin/eth_compliance_test.rs76
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs11
-rw-r--r--examples/stm32f4/src/bin/flash_async.rs8
-rw-r--r--examples/stm32f4/src/bin/i2s_dma.rs91
-rw-r--r--examples/stm32f4/src/bin/input_capture.rs4
-rw-r--r--examples/stm32f4/src/bin/pwm.rs19
-rw-r--r--examples/stm32f4/src/bin/pwm_input.rs4
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs2
-rw-r--r--examples/stm32f4/src/bin/usart_buffered.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs17
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_uac_speaker.rs383
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs6
-rw-r--r--examples/stm32f469/Cargo.toml12
-rw-r--r--examples/stm32f469/src/bin/dsi_bsp.rs14
-rw-r--r--examples/stm32f7/Cargo.toml21
-rw-r--r--examples/stm32f7/src/bin/can.rs2
-rw-r--r--examples/stm32f7/src/bin/eth.rs21
-rw-r--r--examples/stm32f7/src/bin/qspi.rs4
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs2
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32g0/Cargo.toml16
-rw-r--r--examples/stm32g0/src/bin/adc_dma.rs2
-rw-r--r--examples/stm32g0/src/bin/hf_timer.rs4
-rw-r--r--examples/stm32g0/src/bin/input_capture.rs12
-rw-r--r--examples/stm32g0/src/bin/onewire_ds18b20.rs274
-rw-r--r--examples/stm32g0/src/bin/pwm_input.rs14
-rw-r--r--examples/stm32g0/src/bin/rtc.rs2
-rw-r--r--examples/stm32g0/src/bin/usart_buffered.rs2
-rw-r--r--examples/stm32g4/Cargo.toml16
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs47
-rw-r--r--examples/stm32g4/src/bin/adc_dma.rs60
-rw-r--r--examples/stm32g4/src/bin/adc_oversampling.rs57
-rw-r--r--examples/stm32g4/src/bin/pwm.rs19
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs2
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs5
-rw-r--r--examples/stm32h5/Cargo.toml21
-rw-r--r--examples/stm32h5/src/bin/adc.rs59
-rw-r--r--examples/stm32h5/src/bin/cordic.rs6
-rw-r--r--examples/stm32h5/src/bin/dts.rs75
-rw-r--r--examples/stm32h5/src/bin/eth.rs21
-rw-r--r--examples/stm32h5/src/bin/stop.rs4
-rw-r--r--examples/stm32h5/src/bin/usb_c_pd.rs93
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32h5/src/bin/usb_uac_speaker.rs374
-rw-r--r--examples/stm32h7/Cargo.toml23
-rw-r--r--examples/stm32h7/src/bin/adc_dma.rs4
-rw-r--r--examples/stm32h7/src/bin/dac.rs3
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs8
-rw-r--r--examples/stm32h7/src/bin/eth.rs21
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs25
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs25
-rw-r--r--examples/stm32h7/src/bin/i2c_shared.rs6
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs14
-rw-r--r--examples/stm32h7/src/bin/pwm.rs19
-rw-r--r--examples/stm32h7/src/bin/sai.rs21
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs2
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs9
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32h723/.cargo/config.toml8
-rw-r--r--examples/stm32h723/Cargo.toml68
-rw-r--r--examples/stm32h723/build.rs35
-rw-r--r--examples/stm32h723/memory.x106
-rw-r--r--examples/stm32h723/src/bin/spdifrx.rs175
-rw-r--r--examples/stm32h735/Cargo.toml16
-rw-r--r--examples/stm32h742/.cargo/config.toml9
-rw-r--r--examples/stm32h742/Cargo.toml65
-rw-r--r--examples/stm32h742/build.rs5
-rw-r--r--examples/stm32h742/src/bin/qspi.rs292
-rw-r--r--examples/stm32h755cm4/Cargo.toml23
-rw-r--r--examples/stm32h755cm4/src/bin/blinky.rs2
-rw-r--r--examples/stm32h755cm7/Cargo.toml23
-rw-r--r--examples/stm32h755cm7/src/bin/blinky.rs2
-rw-r--r--examples/stm32h7b0/.cargo/config.toml8
-rw-r--r--examples/stm32h7b0/Cargo.toml73
-rw-r--r--examples/stm32h7b0/build.rs35
-rw-r--r--examples/stm32h7b0/memory.x5
-rw-r--r--examples/stm32h7b0/src/bin/ospi_memory_mapped.rs433
-rw-r--r--examples/stm32h7rs/Cargo.toml21
-rw-r--r--examples/stm32h7rs/src/bin/eth.rs118
-rw-r--r--examples/stm32h7rs/src/bin/usb_serial.rs134
-rw-r--r--examples/stm32h7rs/src/bin/xspi_memory_mapped.rs448
-rw-r--r--examples/stm32l0/.cargo/config.toml2
-rw-r--r--examples/stm32l0/Cargo.toml14
-rw-r--r--examples/stm32l0/README.md24
-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/eeprom.rs32
-rw-r--r--examples/stm32l0/src/bin/tsc_async.rs116
-rw-r--r--examples/stm32l0/src/bin/tsc_blocking.rs142
-rw-r--r--examples/stm32l0/src/bin/tsc_multipin.rs209
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs2
-rw-r--r--examples/stm32l1/Cargo.toml16
-rw-r--r--examples/stm32l1/src/bin/eeprom.rs32
-rw-r--r--examples/stm32l1/src/bin/usart.rs37
-rw-r--r--examples/stm32l1/src/bin/usb_serial.rs5
-rw-r--r--examples/stm32l4/.cargo/config.toml3
-rw-r--r--examples/stm32l4/Cargo.toml23
-rw-r--r--examples/stm32l4/README.md24
-rw-r--r--examples/stm32l4/src/bin/dac.rs3
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs8
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs14
-rw-r--r--examples/stm32l4/src/bin/tsc_async.rs108
-rw-r--r--examples/stm32l4/src/bin/tsc_blocking.rs147
-rw-r--r--examples/stm32l4/src/bin/tsc_multipin.rs198
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32l432/.cargo/config.toml13
-rw-r--r--examples/stm32l432/Cargo.toml30
-rw-r--r--examples/stm32l432/README.md30
-rw-r--r--examples/stm32l432/build.rs5
-rw-r--r--examples/stm32l432/src/bin/qspi_mmap.rs274
-rw-r--r--examples/stm32l5/Cargo.toml19
-rw-r--r--examples/stm32l5/src/bin/stop.rs4
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs18
-rw-r--r--examples/stm32u0/Cargo.toml16
-rw-r--r--examples/stm32u0/src/bin/dac.rs3
-rw-r--r--examples/stm32u0/src/bin/spi.rs2
-rw-r--r--examples/stm32u5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/Cargo.toml20
-rw-r--r--examples/stm32u5/src/bin/adc.rs109
-rw-r--r--examples/stm32u5/src/bin/blinky.rs3
-rw-r--r--examples/stm32u5/src/bin/ferris.bmpbin0 -> 6794 bytes
-rw-r--r--examples/stm32u5/src/bin/hspi_memory_mapped.rs455
-rw-r--r--examples/stm32u5/src/bin/i2c.rs2
-rw-r--r--examples/stm32u5/src/bin/ltdc.rs461
-rw-r--r--examples/stm32u5/src/bin/tsc.rs75
-rw-r--r--examples/stm32u5/src/bin/usb_hs_serial.rs122
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs11
-rw-r--r--examples/stm32wb/Cargo.toml18
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs5
-rw-r--r--examples/stm32wba/.cargo/config.toml2
-rw-r--r--examples/stm32wba/Cargo.toml18
-rw-r--r--examples/stm32wl/Cargo.toml16
-rw-r--r--examples/stm32wl/memory.x6
-rw-r--r--examples/stm32wl/src/bin/blinky.rs2
-rw-r--r--examples/stm32wl/src/bin/button.rs2
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs2
-rw-r--r--examples/stm32wl/src/bin/flash.rs2
-rw-r--r--examples/stm32wl/src/bin/random.rs2
-rw-r--r--examples/stm32wl/src/bin/rtc.rs2
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs2
-rw-r--r--examples/wasm/Cargo.toml7
429 files changed, 13058 insertions, 4936 deletions
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 93e49faef..4d633e8a8 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -5,16 +5,16 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
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"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.3.1", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } 12embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] }
13embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } 13embassy-boot-nrf = { version = "0.4.0", path = "../../../../embassy-boot-nrf", features = [] }
14embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
15 15
16defmt = { version = "0.3", optional = true } 16defmt = { version = "1.0.1", optional = true }
17defmt-rtt = { version = "0.4", optional = true } 17defmt-rtt = { version = "1.0.0", optional = true }
18panic-reset = { version = "0.1.1" } 18panic-reset = { version = "0.1.1" }
19embedded-hal = { version = "0.2.6" } 19embedded-hal = { version = "0.2.6" }
20 20
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 8bb8afdfe..be283fb27 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -5,16 +5,16 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
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"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } 11embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
12embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } 12embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "1.0.1"
16defmt-rtt = "0.4" 16defmt-rtt = "1.0.0"
17panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } 17panic-probe = { version = "1.0.0", features = ["print-defmt"], optional = true }
18panic-reset = { version = "0.1.1", optional = true } 18panic-reset = { version = "0.1.1", optional = true }
19embedded-hal = { version = "0.2.6" } 19embedded-hal = { version = "0.2.6" }
20 20
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 1c2934298..b3466e288 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32" }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 09e34c7df..72dbded5f 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.1" 19embedded-storage = "0.3.1"
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 5e7f4d5e7..57fb8312c 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.1" 19embedded-storage = "0.3.1"
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 60fdcfafb..7dbbba138 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index fe3ab2c04..9549b2048 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 169856358..03daeb0bc 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 7cef8fe0d..e582628aa 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -5,17 +5,17 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.4.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 = "1.0.1", optional = true }
18defmt-rtt = { version = "0.4", optional = true } 18defmt-rtt = { version = "1.0.0", optional = true }
19panic-reset = { version = "0.1.1" } 19panic-reset = { version = "0.1.1" }
20embedded-hal = { version = "0.2.6" } 20embedded-hal = { version = "0.2.6" }
21 21
diff --git a/examples/boot/application/stm32wb-dfu/memory.x b/examples/boot/application/stm32wb-dfu/memory.x
index ff1b800d2..f1e6b053c 100644
--- a/examples/boot/application/stm32wb-dfu/memory.x
+++ b/examples/boot/application/stm32wb-dfu/memory.x
@@ -1,10 +1,10 @@
1MEMORY 1MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 48K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 128K 6 FLASH : ORIGIN = 0x0800D000, LENGTH = 120K
7 DFU : ORIGIN = 0x08028000, LENGTH = 132K 7 DFU : ORIGIN = 0x0802B000, LENGTH = 120K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32wb-dfu/secrets/key.sec b/examples/boot/application/stm32wb-dfu/secrets/key.sec
new file mode 100644
index 000000000..52e7f125b
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/secrets/key.sec
@@ -0,0 +1,2 @@
1untrusted comment: signify secret key
2RWRCSwAAAAATdHQF3B4jEIoNZrjADRp2LbjJjNdNNzKwTCe4IB6mDNq96pe53nbNxwbdCc/T4hrz7W+Kx1MwrZ0Yz5xebSK5Z0Kh/3Cdf039U5f+eoTDS2fIGbohyUbrtwKzjyE0qXI=
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index 0ab99ff90..5e7b71f5a 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -13,7 +13,7 @@ use embassy_stm32::usb::{self, Driver};
13use embassy_stm32::{bind_interrupts, peripherals}; 13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_sync::blocking_mutex::Mutex; 14use embassy_sync::blocking_mutex::Mutex;
15use embassy_time::Duration; 15use embassy_time::Duration;
16use embassy_usb::Builder; 16use embassy_usb::{msos, Builder};
17use embassy_usb_dfu::consts::DfuAttributes; 17use embassy_usb_dfu::consts::DfuAttributes;
18use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; 18use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
19use panic_reset as _; 19use panic_reset as _;
@@ -22,6 +22,11 @@ bind_interrupts!(struct Irqs {
22 USB_LP => usb::InterruptHandler<peripherals::USB>; 22 USB_LP => usb::InterruptHandler<peripherals::USB>;
23}); 23});
24 24
25// This is a randomly generated GUID to allow clients on Windows to find your device.
26//
27// N.B. update to a custom GUID for your own device!
28const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
29
25#[embassy_executor::main] 30#[embassy_executor::main]
26async fn main(_spawner: Spawner) { 31async fn main(_spawner: Spawner) {
27 let mut config = embassy_stm32::Config::default(); 32 let mut config = embassy_stm32::Config::default();
@@ -44,7 +49,7 @@ async fn main(_spawner: Spawner) {
44 let mut config_descriptor = [0; 256]; 49 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256]; 50 let mut bos_descriptor = [0; 256];
46 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
47 let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD); 52 let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
48 let mut builder = Builder::new( 53 let mut builder = Builder::new(
49 driver, 54 driver,
50 config, 55 config,
@@ -54,7 +59,28 @@ async fn main(_spawner: Spawner) {
54 &mut control_buf, 59 &mut control_buf,
55 ); 60 );
56 61
57 usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500)); 62 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
63 // Otherwise users need to do this manually using a tool like Zadig.
64 //
65 // It seems these always need to be at added at the device level for this to work and for
66 // composite devices they also need to be added on the function level (as shown later).
67 //
68 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
69 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
70 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
71 "DeviceInterfaceGUIDs",
72 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
73 ));
74
75 usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), |func| {
76 // You likely don't have to add these function level headers if your USB device is not composite
77 // (i.e. if your device does not expose another interface in addition to DFU)
78 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
79 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
80 "DeviceInterfaceGUIDs",
81 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
82 ));
83 });
58 84
59 let mut dev = builder.build(); 85 let mut dev = builder.build();
60 dev.run().await 86 dev.run().await
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 860a835a9..3ed04b472 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -5,15 +5,15 @@ 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.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.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.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "1.0.1", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "1.0.0", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index 5af1723f5..20109e37e 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -5,8 +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 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 8 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
9 RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 32K - 64 9 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128
10} 10}
11 11
12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); 12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
@@ -21,4 +21,4 @@ SECTIONS
21 { 21 {
22 *(.shared_data) 22 *(.shared_data)
23 } > SHARED_RAM 23 } > SHARED_RAM
24} \ No newline at end of file 24}
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 127de0237..e4526927f 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -20,7 +20,7 @@ static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))] 20#[cfg(not(feature = "skip-include"))]
21static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
22 22
23#[link_section = ".shared_data"] 23#[unsafe(link_section = ".shared_data")]
24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
25 25
26#[embassy_executor::main] 26#[embassy_executor::main]
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index 768dadf8b..6016a9555 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -11,7 +11,7 @@ use embassy_stm32::SharedData;
11use embassy_time::Timer; 11use embassy_time::Timer;
12use panic_reset as _; 12use panic_reset as _;
13 13
14#[link_section = ".shared_data"] 14#[unsafe(link_section = ".shared_data")]
15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
16 16
17#[embassy_executor::main] 17#[embassy_executor::main]
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index 9d5d51a13..897890ca4 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -6,13 +6,13 @@ description = "Bootloader for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "1.0.0", optional = true }
11 11
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.6.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.7.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
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 67c700437..b849a0df3 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -8,7 +8,7 @@ use cortex_m_rt::{entry, exception};
8use defmt_rtt as _; 8use defmt_rtt as _;
9use embassy_boot_nrf::*; 9use embassy_boot_nrf::*;
10use embassy_nrf::nvmc::Nvmc; 10use embassy_nrf::nvmc::Nvmc;
11use embassy_nrf::wdt; 11use embassy_nrf::wdt::{self, HaltConfig, SleepConfig};
12use embassy_sync::blocking_mutex::Mutex; 12use embassy_sync::blocking_mutex::Mutex;
13 13
14#[entry] 14#[entry]
@@ -25,8 +25,8 @@ fn main() -> ! {
25 25
26 let mut wdt_config = wdt::Config::default(); 26 let mut wdt_config = wdt::Config::default();
27 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds 27 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
28 wdt_config.run_during_sleep = true; 28 wdt_config.action_during_sleep = SleepConfig::RUN;
29 wdt_config.run_during_debug_halt = false; 29 wdt_config.action_during_debug_halt = HaltConfig::PAUSE;
30 30
31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); 31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
32 let flash = Mutex::new(RefCell::new(flash)); 32 let flash = Mutex::new(RefCell::new(flash));
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index 9df396e5e..090a581d4 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -6,12 +6,12 @@ description = "Example bootloader for RP2040 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "1.0.0", optional = true }
11 11
12embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } 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.6.0", path = "../../../../embassy-sync" } 14embassy-sync = { version = "0.7.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"] }
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
index b91b05412..67edc6a6c 100644
--- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -6,8 +6,8 @@ description = "Example bootloader for dual-bank flash STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "1.0.0", optional = true }
11 11
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" }
@@ -15,7 +15,7 @@ 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.6.0", path = "../../../../embassy-sync" } 18embassy-sync = { version = "0.7.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"
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 541186949..fe81b5151 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -6,13 +6,13 @@ description = "Example bootloader for STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "1.0.0", optional = true }
11 11
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.6.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.7.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"
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 050b672ce..0bb93b12e 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -6,19 +6,19 @@ description = "Example USB DFUbootloader for the STM32WB series of chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "1.0.0", optional = true }
11 11
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.6.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.7.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.3.0", path = "../../../../embassy-usb", default-features = false } 21embassy-usb = { version = "0.4.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]
@@ -30,6 +30,7 @@ defmt = [
30 "embassy-usb/defmt", 30 "embassy-usb/defmt",
31 "embassy-usb-dfu/defmt" 31 "embassy-usb-dfu/defmt"
32] 32]
33verify = ["embassy-usb-dfu/ed25519-salty"]
33 34
34[profile.dev] 35[profile.dev]
35debug = 2 36debug = 2
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
index d5c6ea57c..99a7002c4 100644
--- a/examples/boot/bootloader/stm32wb-dfu/README.md
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -1,11 +1,63 @@
1# Bootloader for STM32 1# Bootloader for STM32
2 2
3The bootloader uses `embassy-boot` to interact with the flash. 3This bootloader implementation uses `embassy-boot` and `embassy-usb-dfu` to manage firmware updates and interact with the flash memory on STM32WB55 devices.
4 4
5# Usage 5## Prerequisites
6 6
7Flash the bootloader 7- Rust toolchain with `cargo` installed
8- `cargo-flash` for flashing the bootloader
9- `dfu-util` for firmware updates
10- `cargo-binutils` for binary generation
11
12## Usage
13
14### 1. Flash the Bootloader
15
16First, flash the bootloader to your device:
8 17
9``` 18```
10cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx 19cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx
11``` 20```
21
22### 2. Build and Flash Application
23
24Generate your application binary and flash it using DFU:
25
26```
27cargo objcopy --release -- -O binary fw.bin
28dfu-util -d c0de:cafe -w -D fw.bin
29```
30
31### 3. Sign Updates Before Flashing (Optional)
32
33Currently, embassy-usb-dfu only supports a limited implementation of the generic support for ed25519-based update verfication in embassy-boot. This implementation assumes that a signature is simply concatenated to the end of an update binary. For more details, please see https://embassy.dev/book/#_verification and/or refer to the documentation for embassy-boot-dfu.
34
35To sign (and then verify) application updates, you will first need to generate a key pair:
36
37```
38signify-openbsd -G -n -p secrets/key.pub -s secrets/key.sec
39tail -n1 secrets/key.pub | base64 -d -i - | dd ibs=10 skip=1 > secrets/key.pub.short
40```
41
42Then you will need to sign all you binaries with the private key:
43
44```
45cargo objcopy --release -- -O binary fw.bin
46shasum -a 512 -b fw.bin | head -c128 | xxd -p -r > target/fw-hash.txt
47signify-openbsd -S -s secrets/key.sec -m target/fw-hash.txt -x target/fw-hash.sig
48cp fw.bin fw-signed.bin
49tail -n1 target/fw-hash.sig | base64 -d -i - | dd ibs=10 skip=1 >> fw-signed.bin
50dfu-util -d c0de:cafe -w -D fw-signed.bin
51```
52
53Finally, as shown in this example with the `verify` feature flag enabled, you then need to embed the public key into your bootloader so that it can verify update signatures.
54
55N.B. Please note that the exact steps above are NOT a good example of how to manage your keys securely. In a production environment, you should take great care to ensure that (at least the private key) is protected and not leaked into your version control system.
56
57## Troubleshooting
58
59- Make sure your device is in DFU mode before flashing
60- Verify the USB VID:PID matches your device (c0de:cafe)
61- Check USB connections if the device is not detected
62- Make sure the transfer size option of `dfu-util` matches the bootloader configuration. By default, `dfu-util` will use the transfer size reported by the device, but you can override it with the `-t` option if needed.
63- Make sure `control_buf` size is larger than or equal to the `usb_dfu` `BLOCK_SIZE` parameter (in this example, both are set to 4096 bytes).
diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x
index 858062631..77c4d2ee2 100644
--- a/examples/boot/bootloader/stm32wb-dfu/memory.x
+++ b/examples/boot/bootloader/stm32wb-dfu/memory.x
@@ -1,10 +1,10 @@
1MEMORY 1MEMORY
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 = 48K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K 6 ACTIVE : ORIGIN = 0x0800D000, LENGTH = 120K
7 DFU : ORIGIN = 0x08028000, LENGTH = 132K 7 DFU : ORIGIN = 0x0802B000, LENGTH = 120K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short
new file mode 100644
index 000000000..7a4de8585
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short
@@ -0,0 +1 @@
gB��p�M�S��z��Kg��!�F���!4�r \ No newline at end of file
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index 093b39f9d..107f243fd 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -12,7 +12,7 @@ use embassy_stm32::rcc::WPAN_DEFAULT;
12use embassy_stm32::usb::Driver; 12use embassy_stm32::usb::Driver;
13use embassy_stm32::{bind_interrupts, peripherals, usb}; 13use embassy_stm32::{bind_interrupts, peripherals, usb};
14use embassy_sync::blocking_mutex::Mutex; 14use embassy_sync::blocking_mutex::Mutex;
15use embassy_usb::Builder; 15use embassy_usb::{msos, Builder};
16use embassy_usb_dfu::consts::DfuAttributes; 16use embassy_usb_dfu::consts::DfuAttributes;
17use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; 17use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
18 18
@@ -20,6 +20,17 @@ bind_interrupts!(struct Irqs {
20 USB_LP => usb::InterruptHandler<peripherals::USB>; 20 USB_LP => usb::InterruptHandler<peripherals::USB>;
21}); 21});
22 22
23// This is a randomly generated GUID to allow clients on Windows to find your device.
24//
25// N.B. update to a custom GUID for your own device!
26const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
27
28// This is a randomly generated example key.
29//
30// N.B. Please replace with your own!
31#[cfg(feature = "verify")]
32static PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../secrets/key.pub.short");
33
23#[entry] 34#[entry]
24fn main() -> ! { 35fn main() -> ! {
25 let mut config = embassy_stm32::Config::default(); 36 let mut config = embassy_stm32::Config::default();
@@ -52,7 +63,13 @@ fn main() -> ! {
52 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 4096]; 65 let mut control_buf = [0; 4096];
55 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); 66
67 #[cfg(not(feature = "verify"))]
68 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
69
70 #[cfg(feature = "verify")]
71 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate, PUBLIC_SIGNING_KEY);
72
56 let mut builder = Builder::new( 73 let mut builder = Builder::new(
57 driver, 74 driver,
58 config, 75 config,
@@ -62,7 +79,28 @@ fn main() -> ! {
62 &mut control_buf, 79 &mut control_buf,
63 ); 80 );
64 81
65 usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); 82 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
83 // Otherwise users need to do this manually using a tool like Zadig.
84 //
85 // It seems these always need to be at added at the device level for this to work and for
86 // composite devices they also need to be added on the function level (as shown later).
87 //
88 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
89 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
90 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
91 "DeviceInterfaceGUIDs",
92 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
93 ));
94
95 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, |func| {
96 // You likely don't have to add these function level headers if your USB device is not composite
97 // (i.e. if your device does not expose another interface in addition to DFU)
98 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
99 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
100 "DeviceInterfaceGUIDs",
101 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
102 ));
103 });
66 104
67 let mut dev = builder.build(); 105 let mut dev = builder.build();
68 embassy_futures::block_on(dev.run()); 106 embassy_futures::block_on(dev.run());
diff --git a/examples/rp23/.cargo/config.toml b/examples/lpc55s69/.cargo/config.toml
index f77e004dc..9556de72f 100644
--- a/examples/rp23/.cargo/config.toml
+++ b/examples/lpc55s69/.cargo/config.toml
@@ -1,6 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "probe-rs run --chip RP2040" 2runner = "probe-rs run --chip LPC55S69JBD100"
3runner = "elf2uf2-rs -d"
4 3
5[build] 4[build]
6target = "thumbv8m.main-none-eabihf" 5target = "thumbv8m.main-none-eabihf"
diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml
new file mode 100644
index 000000000..7f81e9c7f
--- /dev/null
+++ b/examples/lpc55s69/Cargo.toml
@@ -0,0 +1,22 @@
1[package]
2edition = "2021"
3name = "embassy-nxp-lpc55s69-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7
8[dependencies]
9embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] }
10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
13panic-halt = "1.0.0"
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15cortex-m-rt = { version = "0.7.0"}
16defmt = "1.0.1"
17defmt-rtt = "1.0.0"
18panic-probe = { version = "1.0.0", features = ["print-defmt"] }
19panic-semihosting = "0.6.0"
20
21[profile.release]
22debug = 2
diff --git a/examples/rp23/build.rs b/examples/lpc55s69/build.rs
index 30691aa97..30691aa97 100644
--- a/examples/rp23/build.rs
+++ b/examples/lpc55s69/build.rs
diff --git a/examples/lpc55s69/memory.x b/examples/lpc55s69/memory.x
new file mode 100644
index 000000000..1483b2fad
--- /dev/null
+++ b/examples/lpc55s69/memory.x
@@ -0,0 +1,28 @@
1/* File originally from lpc55-hal repo: https://github.com/lpc55/lpc55-hal/blob/main/memory.x */
2MEMORY
3{
4 FLASH : ORIGIN = 0x00000000, LENGTH = 512K
5
6 /* for use with standard link.x */
7 RAM : ORIGIN = 0x20000000, LENGTH = 256K
8
9 /* would be used with proper link.x */
10 /* needs changes to r0 (initialization code) */
11 /* SRAM0 : ORIGIN = 0x20000000, LENGTH = 64K */
12 /* SRAM1 : ORIGIN = 0x20010000, LENGTH = 64K */
13 /* SRAM2 : ORIGIN = 0x20020000, LENGTH = 64K */
14 /* SRAM3 : ORIGIN = 0x20030000, LENGTH = 64K */
15
16 /* CASPER SRAM regions */
17 /* SRAMX0: ORIGIN = 0x1400_0000, LENGTH = 4K /1* to 0x1400_0FFF *1/ */
18 /* SRAMX1: ORIGIN = 0x1400_4000, LENGTH = 4K /1* to 0x1400_4FFF *1/ */
19
20 /* USB1 SRAM regin */
21 /* USB1_SRAM : ORIGIN = 0x40100000, LENGTH = 16K */
22
23 /* To define our own USB RAM section in one regular */
24 /* RAM, probably easiest to shorten length of RAM */
25 /* above, and use this freed RAM section */
26
27}
28
diff --git a/examples/lpc55s69/src/bin/blinky_nop.rs b/examples/lpc55s69/src/bin/blinky_nop.rs
new file mode 100644
index 000000000..58e2d9808
--- /dev/null
+++ b/examples/lpc55s69/src/bin/blinky_nop.rs
@@ -0,0 +1,33 @@
1//! This example has been made with the LPCXpresso55S69 board in mind, which has a built-in LED on PIO1_6.
2
3#![no_std]
4#![no_main]
5
6use cortex_m::asm::nop;
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nxp::gpio::{Level, Output};
10use {defmt_rtt as _, panic_halt as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_nxp::init(Default::default());
15
16 let mut led = Output::new(p.PIO1_6, Level::Low);
17
18 loop {
19 info!("led off!");
20 led.set_high();
21
22 for _ in 0..200_000 {
23 nop();
24 }
25
26 info!("led on!");
27 led.set_low();
28
29 for _ in 0..200_000 {
30 nop();
31 }
32 }
33}
diff --git a/examples/lpc55s69/src/bin/button_executor.rs b/examples/lpc55s69/src/bin/button_executor.rs
new file mode 100644
index 000000000..836b1c9eb
--- /dev/null
+++ b/examples/lpc55s69/src/bin/button_executor.rs
@@ -0,0 +1,25 @@
1//! This example has been made with the LPCXpresso55S69 board in mind, which has a built-in LED on
2//! PIO1_6 and a button (labeled "user") on PIO1_9.
3
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nxp::gpio::{Input, Level, Output, Pull};
10use {defmt_rtt as _, panic_halt as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! {
14 let p = embassy_nxp::init(Default::default());
15
16 let mut led = Output::new(p.PIO1_6, Level::Low);
17 let mut button = Input::new(p.PIO1_9, Pull::Up);
18
19 info!("Entered main loop");
20 loop {
21 button.wait_for_rising_edge().await;
22 info!("Button pressed");
23 led.toggle();
24 }
25}
diff --git a/examples/mimxrt6/.cargo/config.toml b/examples/mimxrt6/.cargo/config.toml
new file mode 100644
index 000000000..db42be81d
--- /dev/null
+++ b/examples/mimxrt6/.cargo/config.toml
@@ -0,0 +1,17 @@
1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs run --chip MIMXRT685SFVKB'
3
4rustflags = [
5 "-C", "linker=flip-link",
6 "-C", "link-arg=-Tlink.x",
7 "-C", "link-arg=-Tdefmt.x",
8 # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
9 # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
10 "-C", "link-arg=--nmagic",
11]
12
13[build]
14target = "thumbv8m.main-none-eabihf" # Cortex-M33
15
16[env]
17DEFMT_LOG = "trace"
diff --git a/examples/mimxrt6/.gitignore b/examples/mimxrt6/.gitignore
new file mode 100644
index 000000000..418e01907
--- /dev/null
+++ b/examples/mimxrt6/.gitignore
@@ -0,0 +1,14 @@
1# Generated by Cargo
2# will have compiled files and executables
3/debug
4/target
5
6# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8Cargo.lock
9
10# These are backup files generated by rustfmt
11**/*.rs.bk
12
13# MSVC Windows builds of rustc generate these, which store debugging information
14*.pdb
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
new file mode 100644
index 000000000..65cb9e3ca
--- /dev/null
+++ b/examples/mimxrt6/Cargo.toml
@@ -0,0 +1,60 @@
1[package]
2name = "embassy-imxrt-examples"
3version = "0.1.0"
4edition = "2021"
5license = "MIT or Apache-2.0"
6
7[dependencies]
8cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] }
9cortex-m-rt = "0.7.3"
10defmt = "1.0.1"
11defmt-rtt = "1.0.0"
12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] }
16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
17embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0"
20
21mimxrt600-fcb = "0.2.2"
22panic-probe = { version = "1.0.0", features = ["print-defmt"] }
23
24# cargo build/run
25[profile.dev]
26codegen-units = 1
27debug = 2
28debug-assertions = true # <-
29incremental = false
30opt-level = 3 # <-
31overflow-checks = true # <-
32
33# cargo test
34[profile.test]
35codegen-units = 1
36debug = 2
37debug-assertions = true # <-
38incremental = false
39opt-level = 3 # <-
40overflow-checks = true # <-
41
42# cargo build/run --release
43[profile.release]
44codegen-units = 1
45debug = 2
46debug-assertions = false # <-
47incremental = false
48lto = 'fat'
49opt-level = 3 # <-
50overflow-checks = false # <-
51
52# cargo test --release
53[profile.bench]
54codegen-units = 1
55debug = 2
56debug-assertions = false # <-
57incremental = false
58lto = 'fat'
59opt-level = 3 # <-
60overflow-checks = false # <-
diff --git a/examples/mimxrt6/README.md b/examples/mimxrt6/README.md
new file mode 100644
index 000000000..6d5031cf9
--- /dev/null
+++ b/examples/mimxrt6/README.md
@@ -0,0 +1,18 @@
1# embassy-imxrt-examples
2
3## Introduction
4
5These examples illustrates how to use the embassy-imxrt HAL.
6
7## Adding Examples
8Add uniquely named example to `src/bin` like `adc.rs`
9
10## Build
11`cd` to examples folder
12`cargo build --bin <example_name>` for example, `cargo build --bin adc`
13
14## Run
15Assuming RT685 is powered and connected to Jlink debug probe and the latest probe-rs is installed via
16 `$ cargo install probe-rs-tools --git https://github.com/probe-rs/probe-rs --locked`
17`cd` to examples folder
18`cargo run --bin <example_name>` for example, `cargo run --bin adc` \ No newline at end of file
diff --git a/examples/mimxrt6/build.rs b/examples/mimxrt6/build.rs
new file mode 100644
index 000000000..56010dfd6
--- /dev/null
+++ b/examples/mimxrt6/build.rs
@@ -0,0 +1,45 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 // Inject crate version into the .biv section.
23 File::create(out.join("biv.rs"))
24 .unwrap()
25 .write_all(
26 format!(
27 r##"
28#[unsafe(link_section = ".biv")]
29#[used]
30static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00;
31"##,
32 env!("CARGO_PKG_VERSION_MAJOR")
33 .parse::<u8>()
34 .expect("should have major version"),
35 env!("CARGO_PKG_VERSION_MINOR")
36 .parse::<u8>()
37 .expect("should have minor version"),
38 env!("CARGO_PKG_VERSION_PATCH")
39 .parse::<u8>()
40 .expect("should have patch version"),
41 )
42 .as_bytes(),
43 )
44 .unwrap();
45}
diff --git a/examples/mimxrt6/memory.x b/examples/mimxrt6/memory.x
new file mode 100644
index 000000000..6c4410f57
--- /dev/null
+++ b/examples/mimxrt6/memory.x
@@ -0,0 +1,34 @@
1MEMORY {
2 OTFAD : ORIGIN = 0x08000000, LENGTH = 256
3 FCB : ORIGIN = 0x08000400, LENGTH = 512
4 BIV : ORIGIN = 0x08000600, LENGTH = 4
5 KEYSTORE : ORIGIN = 0x08000800, LENGTH = 2K
6 FLASH : ORIGIN = 0x08001000, LENGTH = 1M
7 RAM : ORIGIN = 0x20080000, LENGTH = 1536K
8}
9
10SECTIONS {
11 .otfad : {
12 . = ALIGN(4);
13 KEEP(* (.otfad))
14 . = ALIGN(4);
15 } > OTFAD
16
17 .fcb : {
18 . = ALIGN(4);
19 KEEP(* (.fcb))
20 . = ALIGN(4);
21 } > FCB
22
23 .biv : {
24 . = ALIGN(4);
25 KEEP(* (.biv))
26 . = ALIGN(4);
27 } > BIV
28
29 .keystore : {
30 . = ALIGN(4);
31 KEEP(* (.keystore))
32 . = ALIGN(4);
33 } > KEYSTORE
34}
diff --git a/examples/mimxrt6/src/bin/blinky.rs b/examples/mimxrt6/src/bin/blinky.rs
new file mode 100644
index 000000000..de079d505
--- /dev/null
+++ b/examples/mimxrt6/src/bin/blinky.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::gpio;
9use embassy_time::Timer;
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_imxrt::init(Default::default());
14
15 info!("Initializing GPIO");
16
17 let mut led = gpio::Output::new(
18 p.PIO0_26,
19 gpio::Level::Low,
20 gpio::DriveMode::PushPull,
21 gpio::DriveStrength::Normal,
22 gpio::SlewRate::Standard,
23 );
24
25 loop {
26 info!("Toggling LED");
27 led.toggle();
28 Timer::after_secs(1).await;
29 }
30}
diff --git a/examples/mimxrt6/src/bin/button.rs b/examples/mimxrt6/src/bin/button.rs
new file mode 100644
index 000000000..efb7f14af
--- /dev/null
+++ b/examples/mimxrt6/src/bin/button.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_futures::select::{select, Either};
7use embassy_imxrt::gpio;
8use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_imxrt::init(Default::default());
13
14 let mut user1 = gpio::Input::new(p.PIO1_1, gpio::Pull::None, gpio::Inverter::Disabled);
15 let mut user2 = gpio::Input::new(p.PIO0_10, gpio::Pull::None, gpio::Inverter::Disabled);
16
17 loop {
18 let res = select(user1.wait_for_falling_edge(), user2.wait_for_falling_edge()).await;
19
20 match res {
21 Either::First(()) => {
22 info!("Button `USER1' pressed");
23 }
24 Either::Second(()) => {
25 info!("Button `USER2' pressed");
26 }
27 }
28 }
29}
diff --git a/examples/mimxrt6/src/bin/crc.rs b/examples/mimxrt6/src/bin/crc.rs
new file mode 100644
index 000000000..005a250e5
--- /dev/null
+++ b/examples/mimxrt6/src/bin/crc.rs
@@ -0,0 +1,175 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_imxrt::crc::{Config, Crc, Polynomial};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let mut p = embassy_imxrt::init(Default::default());
14 let data = b"123456789";
15
16 info!("Initializing CRC");
17
18 // CRC-CCITT
19 let mut crc = Crc::new(p.CRC.reborrow(), Default::default());
20 let output = crc.feed_bytes(data);
21 defmt::assert_eq!(output, 0x29b1);
22
23 // CRC16-ARC
24 let mut crc = Crc::new(
25 p.CRC.reborrow(),
26 Config {
27 polynomial: Polynomial::Crc16,
28 reverse_in: true,
29 reverse_out: true,
30 complement_out: false,
31 seed: 0,
32 ..Default::default()
33 },
34 );
35 let output = crc.feed_bytes(data);
36 defmt::assert_eq!(output, 0xbb3d);
37
38 // CRC16-CMS
39 let mut crc = Crc::new(
40 p.CRC.reborrow(),
41 Config {
42 polynomial: Polynomial::Crc16,
43 reverse_in: false,
44 reverse_out: false,
45 complement_out: false,
46 seed: 0xffff,
47 ..Default::default()
48 },
49 );
50 let output = crc.feed_bytes(data);
51 defmt::assert_eq!(output, 0xaee7);
52
53 // CRC16-DDS-110
54 let mut crc = Crc::new(
55 p.CRC.reborrow(),
56 Config {
57 polynomial: Polynomial::Crc16,
58 reverse_in: false,
59 reverse_out: false,
60 complement_out: false,
61 seed: 0x800d,
62 ..Default::default()
63 },
64 );
65 let output = crc.feed_bytes(data);
66 defmt::assert_eq!(output, 0x9ecf);
67
68 // CRC16-MAXIM-DOW
69 let mut crc = Crc::new(
70 p.CRC.reborrow(),
71 Config {
72 polynomial: Polynomial::Crc16,
73 reverse_in: true,
74 reverse_out: true,
75 complement_out: true,
76 seed: 0,
77 ..Default::default()
78 },
79 );
80 let output = crc.feed_bytes(data);
81 defmt::assert_eq!(output, 0x44c2);
82
83 // CRC16-MODBUS
84 let mut crc = Crc::new(
85 p.CRC.reborrow(),
86 Config {
87 polynomial: Polynomial::Crc16,
88 reverse_in: true,
89 reverse_out: true,
90 complement_out: false,
91 seed: 0xffff,
92 ..Default::default()
93 },
94 );
95 let output = crc.feed_bytes(data);
96 defmt::assert_eq!(output, 0x4b37);
97
98 // CRC32-BZIP2
99 let mut crc = Crc::new(
100 p.CRC.reborrow(),
101 Config {
102 polynomial: Polynomial::Crc32,
103 reverse_in: false,
104 reverse_out: false,
105 complement_out: true,
106 seed: 0xffff_ffff,
107 ..Default::default()
108 },
109 );
110 let output = crc.feed_bytes(data);
111 defmt::assert_eq!(output, 0xfc89_1918);
112
113 // CRC32-CKSUM
114 let mut crc = Crc::new(
115 p.CRC.reborrow(),
116 Config {
117 polynomial: Polynomial::Crc32,
118 reverse_in: false,
119 reverse_out: false,
120 complement_out: true,
121 seed: 0,
122 ..Default::default()
123 },
124 );
125 let output = crc.feed_bytes(data);
126 defmt::assert_eq!(output, 0x765e_7680);
127
128 // CRC32-ISO-HDLC
129 let mut crc = Crc::new(
130 p.CRC.reborrow(),
131 Config {
132 polynomial: Polynomial::Crc32,
133 reverse_in: true,
134 reverse_out: true,
135 complement_out: true,
136 seed: 0xffff_ffff,
137 ..Default::default()
138 },
139 );
140 let output = crc.feed_bytes(data);
141 defmt::assert_eq!(output, 0xcbf4_3926);
142
143 // CRC32-JAMCRC
144 let mut crc = Crc::new(
145 p.CRC.reborrow(),
146 Config {
147 polynomial: Polynomial::Crc32,
148 reverse_in: true,
149 reverse_out: true,
150 complement_out: false,
151 seed: 0xffff_ffff,
152 ..Default::default()
153 },
154 );
155 let output = crc.feed_bytes(data);
156 defmt::assert_eq!(output, 0x340b_c6d9);
157
158 // CRC32-MPEG-2
159 let mut crc = Crc::new(
160 p.CRC.reborrow(),
161 Config {
162 polynomial: Polynomial::Crc32,
163 reverse_in: false,
164 reverse_out: false,
165 complement_out: false,
166 seed: 0xffff_ffff,
167 ..Default::default()
168 },
169 );
170 let output = crc.feed_bytes(data);
171 defmt::assert_eq!(output, 0x0376_e6e7);
172
173 info!("end program");
174 cortex_m::asm::bkpt();
175}
diff --git a/examples/mimxrt6/src/bin/hello.rs b/examples/mimxrt6/src/bin/hello.rs
new file mode 100644
index 000000000..c640241ce
--- /dev/null
+++ b/examples/mimxrt6/src/bin/hello.rs
@@ -0,0 +1,17 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 let _p = embassy_imxrt::init(Default::default());
13 loop {
14 info!("Hello");
15 cortex_m::asm::delay(5_000_000);
16 }
17}
diff --git a/examples/mimxrt6/src/bin/rng.rs b/examples/mimxrt6/src/bin/rng.rs
new file mode 100644
index 000000000..9468dd109
--- /dev/null
+++ b/examples/mimxrt6/src/bin/rng.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_imxrt::rng::Rng;
9use embassy_imxrt::{bind_interrupts, peripherals, rng};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 RNG => rng::InterruptHandler<peripherals::RNG>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_imxrt::init(Default::default());
19
20 info!("Initializing RNG");
21 let mut rng = Rng::new(p.RNG, Irqs);
22 let mut buf = [0u8; 65];
23
24 // Async interface
25 unwrap!(rng.async_fill_bytes(&mut buf).await);
26 info!("random bytes: {:02x}", buf);
27
28 // RngCore interface
29 let mut random_bytes = [0; 16];
30
31 let random_u32 = rng.blocking_next_u32();
32 let random_u64 = rng.blocking_next_u64();
33
34 rng.blocking_fill_bytes(&mut random_bytes);
35
36 info!("random_u32 {}", random_u32);
37 info!("random_u64 {}", random_u64);
38 info!("random_bytes {}", random_bytes);
39}
diff --git a/examples/mimxrt6/src/bin/uart-async.rs b/examples/mimxrt6/src/bin/uart-async.rs
new file mode 100644
index 000000000..58e31f379
--- /dev/null
+++ b/examples/mimxrt6/src/bin/uart-async.rs
@@ -0,0 +1,87 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::flexcomm::uart::{self, Async, Uart};
9use embassy_imxrt::{bind_interrupts, peripherals};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 FLEXCOMM2 => uart::InterruptHandler<peripherals::FLEXCOMM2>;
15 FLEXCOMM4 => uart::InterruptHandler<peripherals::FLEXCOMM4>;
16});
17
18const BUFLEN: usize = 16;
19
20#[embassy_executor::task]
21async fn usart4_task(mut uart: Uart<'static, Async>) {
22 info!("RX Task");
23
24 loop {
25 let mut rx_buf = [0; BUFLEN];
26 uart.read(&mut rx_buf).await.unwrap();
27 info!("usart4: rx_buf {:02x}", rx_buf);
28
29 Timer::after_millis(10).await;
30
31 let tx_buf = [0xaa; BUFLEN];
32 uart.write(&tx_buf).await.unwrap();
33 info!("usart4: tx_buf {:02x}", tx_buf);
34 }
35}
36
37#[embassy_executor::task]
38async fn usart2_task(mut uart: Uart<'static, Async>) {
39 info!("TX Task");
40
41 loop {
42 let tx_buf = [0x55; BUFLEN];
43 uart.write(&tx_buf).await.unwrap();
44 info!("usart2: tx_buf {:02x}", tx_buf);
45
46 Timer::after_millis(10).await;
47
48 let mut rx_buf = [0x00; BUFLEN];
49 uart.read(&mut rx_buf).await.unwrap();
50 info!("usart2: rx_buf {:02x}", rx_buf);
51 }
52}
53
54#[embassy_executor::main]
55async fn main(spawner: Spawner) {
56 let p = embassy_imxrt::init(Default::default());
57
58 info!("UART test start");
59
60 let usart4 = Uart::new_with_rtscts(
61 p.FLEXCOMM4,
62 p.PIO0_29,
63 p.PIO0_30,
64 p.PIO1_0,
65 p.PIO0_31,
66 Irqs,
67 p.DMA0_CH9,
68 p.DMA0_CH8,
69 Default::default(),
70 )
71 .unwrap();
72 spawner.must_spawn(usart4_task(usart4));
73
74 let usart2 = Uart::new_with_rtscts(
75 p.FLEXCOMM2,
76 p.PIO0_15,
77 p.PIO0_16,
78 p.PIO0_18,
79 p.PIO0_17,
80 Irqs,
81 p.DMA0_CH5,
82 p.DMA0_CH4,
83 Default::default(),
84 )
85 .unwrap();
86 spawner.must_spawn(usart2_task(usart2));
87}
diff --git a/examples/mimxrt6/src/bin/uart.rs b/examples/mimxrt6/src/bin/uart.rs
new file mode 100644
index 000000000..d6a75f85d
--- /dev/null
+++ b/examples/mimxrt6/src/bin/uart.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::flexcomm::uart::{Blocking, Uart, UartRx, UartTx};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn usart4_task(mut uart: UartRx<'static, Blocking>) {
14 info!("RX Task");
15
16 loop {
17 let mut buf = [0; 8];
18
19 Timer::after_millis(10).await;
20
21 uart.blocking_read(&mut buf).unwrap();
22
23 let s = core::str::from_utf8(&buf).unwrap();
24
25 info!("Received '{}'", s);
26 }
27}
28
29#[embassy_executor::task]
30async fn usart2_task(mut uart: UartTx<'static, Blocking>) {
31 info!("TX Task");
32
33 loop {
34 let buf = "Testing\0".as_bytes();
35
36 uart.blocking_write(buf).unwrap();
37
38 Timer::after_millis(10).await;
39 }
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_imxrt::init(Default::default());
45
46 info!("UART test start");
47
48 let usart4 = Uart::new_blocking(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Default::default()).unwrap();
49
50 let (_, usart4) = usart4.split();
51 spawner.must_spawn(usart4_task(usart4));
52
53 let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap();
54 spawner.must_spawn(usart2_task(usart2));
55}
diff --git a/examples/mimxrt6/src/lib.rs b/examples/mimxrt6/src/lib.rs
new file mode 100644
index 000000000..3c3ea1981
--- /dev/null
+++ b/examples/mimxrt6/src/lib.rs
@@ -0,0 +1,20 @@
1#![no_std]
2
3use mimxrt600_fcb::FlexSPIFlashConfigurationBlock;
4use {defmt_rtt as _, panic_probe as _};
5
6// auto-generated version information from Cargo.toml
7include!(concat!(env!("OUT_DIR"), "/biv.rs"));
8
9#[unsafe(link_section = ".otfad")]
10#[used]
11static OTFAD: [u8; 256] = [0; 256];
12
13#[rustfmt::skip]
14#[unsafe(link_section = ".fcb")]
15#[used]
16static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build();
17
18#[unsafe(link_section = ".keystore")]
19#[used]
20static KEYSTORE: [u8; 2048] = [0; 2048];
diff --git a/examples/mspm0c1104/.cargo/config.toml b/examples/mspm0c1104/.cargo/config.toml
new file mode 100644
index 000000000..204a56b1c
--- /dev/null
+++ b/examples/mspm0c1104/.cargo/config.toml
@@ -0,0 +1,11 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0C1104 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0C1104 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
10# defmt's buffer needs to be shrunk since the MSPM0C1104 only has 1KB of ram.
11DEFMT_RTT_BUFFER_SIZE = "72"
diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml
new file mode 100644
index 000000000..79f9c0959
--- /dev/null
+++ b/examples/mspm0c1104/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-c1104-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c1104dgs20", "defmt", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "1.0.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20# The chip only has 1KB of ram, so we must optimize binaries regardless
21[profile.dev]
22debug = 0
23opt-level = "z"
24lto = true
25codegen-units = 1
26# strip = true
27
28[profile.release]
29debug = 0
30opt-level = "z"
31lto = true
32codegen-units = 1
diff --git a/examples/mspm0c1104/README.md b/examples/mspm0c1104/README.md
new file mode 100644
index 000000000..86b6c3918
--- /dev/null
+++ b/examples/mspm0c1104/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0C1104
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0C1104](https://www.ti.com/tool/LP-MSPM0C1104) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for C1104 it should be `probe-rs run --chip MSPM0C1104`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0C1104 it should be `mspm0c1104dgs20`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0c1104/build.rs b/examples/mspm0c1104/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0c1104/build.rs
@@ -0,0 +1,37 @@
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 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0c1104/memory.x b/examples/mspm0c1104/memory.x
new file mode 100644
index 000000000..a9108835a
--- /dev/null
+++ b/examples/mspm0c1104/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 16K
4 RAM : ORIGIN = 0x20000000, LENGTH = 1K
5}
diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs
new file mode 100644
index 000000000..0d974cc5e
--- /dev/null
+++ b/examples/mspm0c1104/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA22, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs
new file mode 100644
index 000000000..7face1618
--- /dev/null
+++ b/examples/mspm0c1104/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA22;
17 let s2 = p.PA16;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0c1104/src/bin/uart.rs b/examples/mspm0c1104/src/bin/uart.rs
new file mode 100644
index 000000000..da611aaac
--- /dev/null
+++ b/examples/mspm0c1104/src/bin/uart.rs
@@ -0,0 +1,35 @@
1//! Example of using blocking uart
2//!
3//! This uses the virtual COM port provided on the LP-MSPM0C1104 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::uart::{Config, Uart};
11use {defmt_rtt as _, panic_halt as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) -> ! {
15 info!("Hello world!");
16
17 let p = embassy_mspm0::init(Default::default());
18
19 let instance = p.UART0;
20 let tx = p.PA27;
21 let rx = p.PA26;
22
23 let config = Config::default();
24 let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
25
26 unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0u8; 1];
30
31 loop {
32 unwrap!(uart.blocking_read(&mut buf));
33 unwrap!(uart.blocking_write(&buf));
34 }
35}
diff --git a/examples/mspm0g3507/.cargo/config.toml b/examples/mspm0g3507/.cargo/config.toml
new file mode 100644
index 000000000..34c720cdd
--- /dev/null
+++ b/examples/mspm0g3507/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0G3507 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0G3507 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml
new file mode 100644
index 000000000..b6621c9c5
--- /dev/null
+++ b/examples/mspm0g3507/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-g3507-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3507pm", "defmt", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "1.0.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0g3507/README.md b/examples/mspm0g3507/README.md
new file mode 100644
index 000000000..be91dc5a0
--- /dev/null
+++ b/examples/mspm0g3507/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0M3507
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0G3507](https://www.ti.com/tool/LP-MSPM0G3507) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3507 it should be `probe-rs run --chip MSPM0G3507`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0G3507 it should be `mspm0g3507pm`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0g3507/build.rs b/examples/mspm0g3507/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0g3507/build.rs
@@ -0,0 +1,37 @@
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 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0g3507/memory.x b/examples/mspm0g3507/memory.x
new file mode 100644
index 000000000..37e381fbd
--- /dev/null
+++ b/examples/mspm0g3507/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 32K
6}
diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs
new file mode 100644
index 000000000..cde1f2892
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB21;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0g3507/src/bin/uart.rs b/examples/mspm0g3507/src/bin/uart.rs
new file mode 100644
index 000000000..7e7e6db0e
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/uart.rs
@@ -0,0 +1,35 @@
1//! Example of using blocking uart
2//!
3//! This uses the virtual COM port provided on the LP-MSPM0G3507 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::uart::{Config, Uart};
11use {defmt_rtt as _, panic_halt as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) -> ! {
15 info!("Hello world!");
16
17 let p = embassy_mspm0::init(Default::default());
18
19 let instance = p.UART0;
20 let tx = p.PA10;
21 let rx = p.PA11;
22
23 let config = Config::default();
24 let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
25
26 unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0u8; 1];
30
31 loop {
32 unwrap!(uart.blocking_read(&mut buf));
33 unwrap!(uart.blocking_write(&buf));
34 }
35}
diff --git a/examples/mspm0g3519/.cargo/config.toml b/examples/mspm0g3519/.cargo/config.toml
new file mode 100644
index 000000000..7bba4646f
--- /dev/null
+++ b/examples/mspm0g3519/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0G3519 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml
new file mode 100644
index 000000000..fd0e97c01
--- /dev/null
+++ b/examples/mspm0g3519/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-g3519-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3519pz", "defmt", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "1.0.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0g3519/README.md b/examples/mspm0g3519/README.md
new file mode 100644
index 000000000..c392c9e25
--- /dev/null
+++ b/examples/mspm0g3519/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0G3519
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0G3519](https://www.ti.com/tool/LP-MSPM0G3519) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3519 it should be `probe-rs run --chip MSPM0G3519`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0G3519 it should be `mspm0g3519pz`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0g3519/build.rs b/examples/mspm0g3519/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0g3519/build.rs
@@ -0,0 +1,37 @@
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 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0g3519/memory.x b/examples/mspm0g3519/memory.x
new file mode 100644
index 000000000..e6e0ec9e9
--- /dev/null
+++ b/examples/mspm0g3519/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 512K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 128K
6}
diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0g3519/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs
new file mode 100644
index 000000000..c81cc2918
--- /dev/null
+++ b/examples/mspm0g3519/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB3;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0g3519/src/bin/uart.rs b/examples/mspm0g3519/src/bin/uart.rs
new file mode 100644
index 000000000..498377c61
--- /dev/null
+++ b/examples/mspm0g3519/src/bin/uart.rs
@@ -0,0 +1,35 @@
1//! Example of using blocking uart
2//!
3//! This uses the virtual COM port provided on the LP-MSPM0G3519 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::uart::{Config, Uart};
11use {defmt_rtt as _, panic_halt as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) -> ! {
15 info!("Hello world!");
16
17 let p = embassy_mspm0::init(Default::default());
18
19 let instance = p.UART0;
20 let tx = p.PA10;
21 let rx = p.PA11;
22
23 let config = Config::default();
24 let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
25
26 unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0u8; 1];
30
31 loop {
32 unwrap!(uart.blocking_read(&mut buf));
33 unwrap!(uart.blocking_write(&buf));
34 }
35}
diff --git a/examples/mspm0l1306/.cargo/config.toml b/examples/mspm0l1306/.cargo/config.toml
new file mode 100644
index 000000000..93f148a71
--- /dev/null
+++ b/examples/mspm0l1306/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0L1306 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0L1306 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml
new file mode 100644
index 000000000..6b1125810
--- /dev/null
+++ b/examples/mspm0l1306/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-l1306-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l1306rhb", "defmt", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "1.0.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0l1306/README.md b/examples/mspm0l1306/README.md
new file mode 100644
index 000000000..4d698e0fa
--- /dev/null
+++ b/examples/mspm0l1306/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0L1306
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0L1306](https://www.ti.com/tool/LP-MSPM0L1306) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L1306 it should be `probe-rs run --chip MSPM0L1306`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0L1306 it should be `mspm0l1306rhb`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0l1306/build.rs b/examples/mspm0l1306/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0l1306/build.rs
@@ -0,0 +1,37 @@
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 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0l1306/memory.x b/examples/mspm0l1306/memory.x
new file mode 100644
index 000000000..d93b61f44
--- /dev/null
+++ b/examples/mspm0l1306/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 64K
4 RAM : ORIGIN = 0x20000000, LENGTH = 4K
5}
diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs
new file mode 100644
index 000000000..d8c85947f
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PA14;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0l1306/src/bin/uart.rs b/examples/mspm0l1306/src/bin/uart.rs
new file mode 100644
index 000000000..95c56fdd3
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/uart.rs
@@ -0,0 +1,35 @@
1//! Example of using blocking uart
2//!
3//! This uses the virtual COM port provided on the LP-MSPM0L1306 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::uart::{Config, Uart};
11use {defmt_rtt as _, panic_halt as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) -> ! {
15 info!("Hello world!");
16
17 let p = embassy_mspm0::init(Default::default());
18
19 let instance = p.UART0;
20 let tx = p.PA8;
21 let rx = p.PA9;
22
23 let config = Config::default();
24 let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
25
26 unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0u8; 1];
30
31 loop {
32 unwrap!(uart.blocking_read(&mut buf));
33 unwrap!(uart.blocking_write(&buf));
34 }
35}
diff --git a/examples/mspm0l2228/.cargo/config.toml b/examples/mspm0l2228/.cargo/config.toml
new file mode 100644
index 000000000..f383afd9e
--- /dev/null
+++ b/examples/mspm0l2228/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0L2228 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml
new file mode 100644
index 000000000..08dfd5ff6
--- /dev/null
+++ b/examples/mspm0l2228/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-l2228-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l2228pn", "defmt", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "1.0.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0l2228/README.md b/examples/mspm0l2228/README.md
new file mode 100644
index 000000000..191022258
--- /dev/null
+++ b/examples/mspm0l2228/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0L2228
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0L2228](https://www.ti.com/tool/LP-MSPM0L2228) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L2228 it should be `probe-rs run --chip MSPM0L2228`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for LP-MSPM0L2228 it should be `mspm0l2228pn`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0l2228/build.rs b/examples/mspm0l2228/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0l2228/build.rs
@@ -0,0 +1,37 @@
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 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0l2228/memory.x b/examples/mspm0l2228/memory.x
new file mode 100644
index 000000000..aba414a88
--- /dev/null
+++ b/examples/mspm0l2228/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 256K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 32K
6}
diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0l2228/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs
new file mode 100644
index 000000000..47bfd274b
--- /dev/null
+++ b/examples/mspm0l2228/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB8;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0l2228/src/bin/uart.rs b/examples/mspm0l2228/src/bin/uart.rs
new file mode 100644
index 000000000..a266add47
--- /dev/null
+++ b/examples/mspm0l2228/src/bin/uart.rs
@@ -0,0 +1,35 @@
1//! Example of using blocking uart
2//!
3//! This uses the virtual COM port provided on the LP-MSPM0L2228 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::uart::{Config, Uart};
11use {defmt_rtt as _, panic_halt as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) -> ! {
15 info!("Hello world!");
16
17 let p = embassy_mspm0::init(Default::default());
18
19 let instance = p.UART0;
20 let tx = p.PA10;
21 let rx = p.PA11;
22
23 let config = Config::default();
24 let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
25
26 unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
27 info!("wrote Hello, starting echo");
28
29 let mut buf = [0u8; 1];
30
31 loop {
32 unwrap!(uart.blocking_read(&mut buf));
33 unwrap!(uart.blocking_write(&buf));
34 }
35}
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 98a678815..d9e8ca2f9 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.6.0", path = "../../embassy-sync" } 18embassy-sync = { version = "0.7.0", path = "../../embassy-sync" }
19embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } 19embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] }
20embassy-time = { version = "0.3.2", path = "../../embassy-time" } 20embassy-time = { version = "0.4.0", path = "../../embassy-time" }
21embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 21embassy-nrf = { version = "0.3.1", 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 = "1.0.0"
26rand = { version = "0.8.4", default-features = false }
27serde = { version = "1.0.136", default-features = false } 26serde = { version = "1.0.136", default-features = false }
28rtos-trace = "0.1.3" 27rtos-trace = "0.1.3"
29systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] } 28systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index 93a19bea7..91f78737f 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -5,16 +5,16 @@ 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.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 10embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11 11
12defmt = "0.3" 12defmt = "1.0.1"
13defmt-rtt = "0.4" 13defmt-rtt = "1.0.0"
14 14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7" 16cortex-m-rt = "0.7"
17panic-probe = { version = "0.3", features = ["print-defmt"] } 17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18 18
19[profile.release] 19[profile.release]
20debug = 2 20debug = 2
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
index 0e3e81c3f..87da89efe 100644
--- a/examples/nrf52810/Cargo.toml
+++ b/examples/nrf52810/Cargo.toml
@@ -6,19 +6,19 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.7.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"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.4.0", 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"] } 12embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13 13
14defmt = "0.3" 14defmt = "1.0.1"
15defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
16 16
17fixed = "1.10.0" 17fixed = "1.10.0"
18static_cell = { version = "2" } 18static_cell = { version = "2" }
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
22 22
23[profile.release] 23[profile.release]
24debug = 2 24debug = 2
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index 7fae7aefc..afd269f72 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -8,16 +8,17 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] }
14embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 15
15defmt = "0.3" 16defmt = "1.0.1"
16defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
17 18
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
21 22
22[profile.release] 23[profile.release]
23debug = 2 24debug = 2
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
index 060bb9ebc..719e22729 100644
--- a/examples/nrf52840-rtic/src/bin/blinky.rs
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -4,11 +4,11 @@
4 4
5use {defmt_rtt as _, panic_probe as _}; 5use {defmt_rtt as _, panic_probe as _};
6 6
7#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])] 7#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [EGU0_SWI0, EGU1_SWI1])]
8mod app { 8mod app {
9 use defmt::info; 9 use defmt::info;
10 use embassy_nrf::gpio::{Level, Output, OutputDrive}; 10 use embassy_nrf::gpio::{Level, Output, OutputDrive};
11 use embassy_nrf::peripherals; 11 use embassy_nrf::{peripherals, Peri};
12 use embassy_time::Timer; 12 use embassy_time::Timer;
13 13
14 #[shared] 14 #[shared]
@@ -28,7 +28,7 @@ mod app {
28 } 28 }
29 29
30 #[task(priority = 1)] 30 #[task(priority = 1)]
31 async fn blink(_cx: blink::Context, pin: peripherals::P0_13) { 31 async fn blink(_cx: blink::Context, pin: Peri<'static, peripherals::P0_13>) {
32 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); 32 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
33 33
34 loop { 34 loop {
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 17fa6234d..4140e49d2 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,26 +6,26 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.3.1", 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.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.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.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } 18embassy-net-enc28j60 = { version = "0.2.0", path = "../../embassy-net-enc28j60", features = ["defmt"] }
19 19
20defmt = "0.3" 20defmt = "1.0.1"
21defmt-rtt = "0.4" 21defmt-rtt = "1.0.0"
22 22
23fixed = "1.10.0" 23fixed = "1.10.0"
24static_cell = { version = "2" } 24static_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 = "1.0.0", features = ["print-defmt"] }
28rand = { version = "0.8.4", default-features = false } 28rand = { version = "0.9.0", default-features = false }
29embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
30usbd-hid = "0.8.1" 30usbd-hid = "0.8.1"
31serde = { version = "1.0.136", default-features = false } 31serde = { version = "1.0.136", default-features = false }
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
index 6ac72bcaf..f0a066818 100644
--- a/examples/nrf52840/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -9,7 +9,7 @@ use embedded_io_async::Write;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs { 11bind_interrupts!(struct Irqs {
12 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; 12 UARTE0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
13}); 13});
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
@@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) {
28 p.PPI_CH0, 28 p.PPI_CH0,
29 p.PPI_CH1, 29 p.PPI_CH1,
30 p.PPI_GROUP0, 30 p.PPI_GROUP0,
31 Irqs,
32 p.P0_08, 31 p.P0_08,
33 p.P0_06, 32 p.P0_06,
33 Irqs,
34 config, 34 config,
35 &mut rx_buffer, 35 &mut rx_buffer,
36 &mut tx_buffer, 36 &mut tx_buffer,
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..74c62ca20 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -3,7 +3,8 @@
3 3
4use defmt::unwrap; 4use defmt::unwrap;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; 6use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive};
7use embassy_nrf::Peri;
7use embassy_sync::blocking_mutex::raw::NoopRawMutex; 8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
8use embassy_sync::channel::{Channel, Receiver, Sender}; 9use embassy_sync::channel::{Channel, Receiver, Sender};
9use embassy_time::Timer; 10use embassy_time::Timer;
@@ -28,13 +29,13 @@ async fn send_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) {
28} 29}
29 30
30#[embassy_executor::task] 31#[embassy_executor::task]
31async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) { 32async fn recv_task(led: Peri<'static, AnyPin>, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) {
32 let mut led = Output::new(led, Level::Low, OutputDrive::Standard); 33 let mut led = Output::new(led, Level::Low, OutputDrive::Standard);
33 34
34 loop { 35 loop {
35 match receiver.receive().await { 36 match receiver.receive().await {
36 LedState::On => led.set_high(), 37 LedState::On => led.set_low(),
37 LedState::Off => led.set_low(), 38 LedState::Off => led.set_high(),
38 } 39 }
39 } 40 }
40} 41}
@@ -45,5 +46,5 @@ async fn main(spawner: Spawner) {
45 let channel = CHANNEL.init(Channel::new()); 46 let channel = CHANNEL.init(Channel::new());
46 47
47 unwrap!(spawner.spawn(send_task(channel.sender()))); 48 unwrap!(spawner.spawn(send_task(channel.sender())));
48 unwrap!(spawner.spawn(recv_task(p.P0_13.degrade(), channel.receiver()))); 49 unwrap!(spawner.spawn(recv_task(p.P0_13.into(), channel.receiver())));
49} 50}
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 94cf09c88..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]
@@ -67,12 +68,9 @@ async fn main(spawner: Spawner) {
67 68
68 // Init network stack 69 // Init network stack
69 static RESOURCES: StaticCell<StackResources<3>> = 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 > = StaticCell::new();
73 let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
74 72
75 unwrap!(spawner.spawn(net_task(stack))); 73 unwrap!(spawner.spawn(net_task(runner)));
76 74
77 // And now we can use it! 75 // And now we can use it!
78 76
diff --git a/examples/nrf52840/src/bin/ieee802154_receive.rs b/examples/nrf52840/src/bin/ieee802154_receive.rs
new file mode 100644
index 000000000..ede8fca65
--- /dev/null
+++ b/examples/nrf52840/src/bin/ieee802154_receive.rs
@@ -0,0 +1,38 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::config::{Config, HfclkSource};
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_nrf::radio::ieee802154::{self, Packet};
8use embassy_nrf::{peripherals, radio};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12embassy_nrf::bind_interrupts!(struct Irqs {
13 RADIO => radio::InterruptHandler<peripherals::RADIO>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.hfclk_source = HfclkSource::ExternalXtal;
20 let peripherals = embassy_nrf::init(config);
21
22 // assumes LED on P0_15 with active-high polarity
23 let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard);
24
25 let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs);
26 let mut packet = Packet::new();
27
28 loop {
29 gpo_led.set_low();
30 let rv = radio.receive(&mut packet).await;
31 gpo_led.set_high();
32 match rv {
33 Err(_) => defmt::error!("receive() Err"),
34 Ok(_) => defmt::info!("receive() {:?}", *packet),
35 }
36 Timer::after_millis(100u64).await;
37 }
38}
diff --git a/examples/nrf52840/src/bin/ieee802154_send.rs b/examples/nrf52840/src/bin/ieee802154_send.rs
new file mode 100644
index 000000000..7af9d1d06
--- /dev/null
+++ b/examples/nrf52840/src/bin/ieee802154_send.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::config::{Config, HfclkSource};
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_nrf::radio::ieee802154::{self, Packet};
8use embassy_nrf::{peripherals, radio};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12embassy_nrf::bind_interrupts!(struct Irqs {
13 RADIO => radio::InterruptHandler<peripherals::RADIO>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.hfclk_source = HfclkSource::ExternalXtal;
20 let peripherals = embassy_nrf::init(config);
21
22 // assumes LED on P0_15 with active-high polarity
23 let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard);
24
25 let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs);
26 let mut packet = Packet::new();
27
28 loop {
29 packet.copy_from_slice(&[0_u8; 16]);
30 gpo_led.set_high();
31 let rv = radio.try_send(&mut packet).await;
32 gpo_led.set_low();
33 match rv {
34 Err(_) => defmt::error!("try_send() Err"),
35 Ok(_) => defmt::info!("try_send() {:?}", *packet),
36 }
37 Timer::after_millis(1000u64).await;
38 }
39}
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 797be93a7..d58613da4 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -112,12 +112,12 @@ static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113 113
114#[interrupt] 114#[interrupt]
115unsafe fn SWI1_EGU1() { 115unsafe fn EGU1_SWI1() {
116 EXECUTOR_HIGH.on_interrupt() 116 EXECUTOR_HIGH.on_interrupt()
117} 117}
118 118
119#[interrupt] 119#[interrupt]
120unsafe fn SWI0_EGU0() { 120unsafe fn EGU0_SWI0() {
121 EXECUTOR_MED.on_interrupt() 121 EXECUTOR_MED.on_interrupt()
122} 122}
123 123
@@ -127,14 +127,14 @@ fn main() -> ! {
127 127
128 let _p = embassy_nrf::init(Default::default()); 128 let _p = embassy_nrf::init(Default::default());
129 129
130 // High-priority executor: SWI1_EGU1, priority level 6 130 // High-priority executor: EGU1_SWI1, priority level 6
131 interrupt::SWI1_EGU1.set_priority(Priority::P6); 131 interrupt::EGU1_SWI1.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1); 132 let spawner = EXECUTOR_HIGH.start(interrupt::EGU1_SWI1);
133 unwrap!(spawner.spawn(run_high())); 133 unwrap!(spawner.spawn(run_high()));
134 134
135 // Medium-priority executor: SWI0_EGU0, priority level 7 135 // Medium-priority executor: EGU0_SWI0, priority level 7
136 interrupt::SWI0_EGU0.set_priority(Priority::P7); 136 interrupt::EGU0_SWI0.set_priority(Priority::P7);
137 let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); 137 let spawner = EXECUTOR_MED.start(interrupt::EGU0_SWI0);
138 unwrap!(spawner.spawn(run_med())); 138 unwrap!(spawner.spawn(run_med()));
139 139
140 // Low priority executor: runs in thread mode, using WFE/SEV 140 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/nrf52840/src/bin/nfct.rs b/examples/nrf52840/src/bin/nfct.rs
new file mode 100644
index 000000000..d559d006a
--- /dev/null
+++ b/examples/nrf52840/src/bin/nfct.rs
@@ -0,0 +1,79 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_nrf::config::HfclkSource;
7use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT};
8use embassy_nrf::{bind_interrupts, nfct};
9use {defmt_rtt as _, embassy_nrf as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 NFCT => nfct::InterruptHandler;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let mut config = embassy_nrf::config::Config::default();
18 config.hfclk_source = HfclkSource::ExternalXtal;
19 let p = embassy_nrf::init(config);
20
21 dbg!("Setting up...");
22 let config = NfcConfig {
23 nfcid1: NfcId::DoubleSize([0x04, 0x68, 0x95, 0x71, 0xFA, 0x5C, 0x64]),
24 sdd_pat: nfct::SddPat::SDD00100,
25 plat_conf: 0b0000,
26 protocol: nfct::SelResProtocol::Type4A,
27 };
28
29 let mut nfc = NfcT::new(p.NFCT, Irqs, &config);
30
31 let mut buf = [0u8; 256];
32
33 loop {
34 info!("activating");
35 nfc.activate().await;
36
37 loop {
38 info!("rxing");
39 let n = match nfc.receive(&mut buf).await {
40 Ok(n) => n,
41 Err(e) => {
42 error!("rx error {}", e);
43 break;
44 }
45 };
46 let req = &buf[..n];
47 info!("received frame {:02x}", req);
48
49 let mut deselect = false;
50 let resp = match req {
51 [0xe0, ..] => {
52 info!("Got RATS, tx'ing ATS");
53 &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80][..]
54 }
55 [0xc2] => {
56 info!("Got deselect!");
57 deselect = true;
58 &[0xc2]
59 }
60 _ => {
61 info!("Got unknown command!");
62 &[0xFF]
63 }
64 };
65
66 match nfc.transmit(resp).await {
67 Ok(()) => {}
68 Err(e) => {
69 error!("tx error {}", e);
70 break;
71 }
72 }
73
74 if deselect {
75 break;
76 }
77 }
78 }
79}
diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
index e948203a5..0d76636b0 100644
--- a/examples/nrf52840/src/bin/pdm_continuous.rs
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -20,14 +20,14 @@ bind_interrupts!(struct Irqs {
20 20
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_p: Spawner) { 22async fn main(_p: Spawner) {
23 let mut p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense. 25 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
26 config.frequency = Frequency::_1280K; // 16 kHz sample rate 26 config.frequency = Frequency::_1280K; // 16 kHz sample rate
27 config.ratio = Ratio::RATIO80; 27 config.ratio = Ratio::RATIO80;
28 config.operation_mode = OperationMode::Mono; 28 config.operation_mode = OperationMode::Mono;
29 config.gain_left = I7F1::from_bits(5); // 2.5 dB 29 config.gain_left = I7F1::from_bits(5); // 2.5 dB
30 let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config); 30 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_00, p.P0_01, config);
31 31
32 let mut bufs = [[0; 1024]; 2]; 32 let mut bufs = [[0; 1024]; 2];
33 33
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
index 751cf4425..df8da8800 100644
--- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
@@ -14,6 +14,16 @@ use {defmt_rtt as _, panic_probe as _};
14// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf. 14// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf.
15// This demo lights up a single LED in blue. It then proceeds 15// This demo lights up a single LED in blue. It then proceeds
16// to pulsate the LED rapidly. 16// to pulsate the LED rapidly.
17//
18// /!\ NOTE FOR nRF52840-DK users /!\
19//
20// If you're using the nRF52840-DK, the default "Vdd" power source
21// will set the GPIO I/O voltage to 3.0v, using the onboard regulator.
22// This can sometimes not be enough to drive the WS2812B signal if you
23// are not using an external level shifter. If you set the board to "USB"
24// power instead (and provide power via the "nRF USB" connector), the board
25// will instead power the I/Os at 3.3v, which is often enough (but still
26// out of official spec) for the WS2812Bs to work properly.
17 27
18// In the following declarations, setting the high bit tells the PWM 28// In the following declarations, setting the high bit tells the PWM
19// to reverse polarity, which is what the WS2812B expects. 29// to reverse polarity, which is what the WS2812B expects.
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 516c9b481..238a0d941 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -37,14 +37,14 @@ async fn main(_p: Spawner) {
37 }); 37 });
38 38
39 let mut q = qspi::Qspi::new( 39 let mut q = qspi::Qspi::new(
40 &mut p.QSPI, 40 p.QSPI.reborrow(),
41 Irqs, 41 Irqs,
42 &mut p.P0_19, 42 p.P0_19.reborrow(),
43 &mut p.P0_17, 43 p.P0_17.reborrow(),
44 &mut p.P0_20, 44 p.P0_20.reborrow(),
45 &mut p.P0_21, 45 p.P0_21.reborrow(),
46 &mut p.P0_22, 46 p.P0_22.reborrow(),
47 &mut p.P0_23, 47 p.P0_23.reborrow(),
48 config, 48 config,
49 ); 49 );
50 50
diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
index 326054c9a..f32d17cd9 100644..100755
--- a/examples/nrf52840/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 defmt::info!("Some random bytes: {:?}", bytes); 22 defmt::info!("Some random bytes: {:?}", bytes);
23 23
24 // Sync API with `rand` 24 // Sync API with `rand`
25 defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); 25 defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10));
26 26
27 let mut bytes = [0; 1024]; 27 let mut bytes = [0; 1024];
28 rng.fill_bytes(&mut bytes).await; 28 rng.fill_bytes(&mut bytes).await;
diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index 653b7d606..cf2d860ab 100644
--- a/examples/nrf52840/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs {
16async fn main(_p: Spawner) { 16async fn main(_p: Spawner) {
17 let mut p = embassy_nrf::init(Default::default()); 17 let mut p = embassy_nrf::init(Default::default());
18 let config = Config::default(); 18 let config = Config::default();
19 let channel_config = ChannelConfig::single_ended(&mut p.P0_02); 19 let channel_config = ChannelConfig::single_ended(p.P0_02.reborrow());
20 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]); 20 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
21 21
22 loop { 22 loop {
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index f76fa3570..e8f169c8c 100644
--- a/examples/nrf52840/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -18,9 +18,9 @@ bind_interrupts!(struct Irqs {
18async fn main(_p: Spawner) { 18async fn main(_p: Spawner) {
19 let mut p = embassy_nrf::init(Default::default()); 19 let mut p = embassy_nrf::init(Default::default());
20 let config = Config::default(); 20 let config = Config::default();
21 let channel_1_config = ChannelConfig::single_ended(&mut p.P0_02); 21 let channel_1_config = ChannelConfig::single_ended(p.P0_02.reborrow());
22 let channel_2_config = ChannelConfig::single_ended(&mut p.P0_03); 22 let channel_2_config = ChannelConfig::single_ended(p.P0_03.reborrow());
23 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); 23 let channel_3_config = ChannelConfig::single_ended(p.P0_04.reborrow());
24 let mut saadc = Saadc::new( 24 let mut saadc = Saadc::new(
25 p.SAADC, 25 p.SAADC,
26 Irqs, 26 Irqs,
@@ -40,9 +40,9 @@ async fn main(_p: Spawner) {
40 40
41 saadc 41 saadc
42 .run_task_sampler( 42 .run_task_sampler(
43 &mut p.TIMER0, 43 p.TIMER0.reborrow(),
44 &mut p.PPI_CH0, 44 p.PPI_CH0.reborrow(),
45 &mut p.PPI_CH1, 45 p.PPI_CH1.reborrow(),
46 Frequency::F1MHz, 46 Frequency::F1MHz,
47 1000, // We want to sample at 1KHz 47 1000, // We want to sample at 1KHz
48 &mut bufs, 48 &mut bufs,
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
index 613cd37ab..4f28da07e 100644
--- a/examples/nrf52840/src/bin/spis.rs
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spis};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs { 10bind_interrupts!(struct Irqs {
11 SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>; 11 SPI2 => spis::InterruptHandler<peripherals::SPI2>;
12}); 12});
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index a9a0765e8..e30a3855d 100644
--- a/examples/nrf52840/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -9,12 +9,13 @@ use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_nrf::twim::{self, Twim}; 10use embassy_nrf::twim::{self, Twim};
11use embassy_nrf::{bind_interrupts, peripherals}; 11use embassy_nrf::{bind_interrupts, peripherals};
12use static_cell::ConstStaticCell;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
14const ADDRESS: u8 = 0x50; 15const ADDRESS: u8 = 0x50;
15 16
16bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
17 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; 18 TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
18}); 19});
19 20
20#[embassy_executor::main] 21#[embassy_executor::main]
@@ -22,7 +23,8 @@ async fn main(_spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
23 info!("Initializing TWI..."); 24 info!("Initializing TWI...");
24 let config = twim::Config::default(); 25 let config = twim::Config::default();
25 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); 26 static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]);
27 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config, RAM_BUFFER.take());
26 28
27 info!("Reading..."); 29 info!("Reading...");
28 30
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index c743614b8..f7380e20d 100644
--- a/examples/nrf52840/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _};
19const ADDRESS: u8 = 0x50; 19const ADDRESS: u8 = 0x50;
20 20
21bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
22 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; 22 TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
23}); 23});
24 24
25#[embassy_executor::main] 25#[embassy_executor::main]
@@ -30,9 +30,17 @@ async fn main(_p: Spawner) {
30 loop { 30 loop {
31 info!("Initializing TWI..."); 31 info!("Initializing TWI...");
32 let config = twim::Config::default(); 32 let config = twim::Config::default();
33 let mut ram_buffer = [0u8; 16];
33 34
34 // Create the TWIM instance with borrowed singletons, so they're not consumed. 35 // Create the TWIM instance with borrowed singletons, so they're not consumed.
35 let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config); 36 let mut twi = Twim::new(
37 p.TWISPI0.reborrow(),
38 Irqs,
39 p.P0_03.reborrow(),
40 p.P0_04.reborrow(),
41 config,
42 &mut ram_buffer,
43 );
36 44
37 info!("Reading..."); 45 info!("Reading...");
38 46
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
index 88bd4cceb..856b34140 100644
--- a/examples/nrf52840/src/bin/twis.rs
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -10,7 +10,7 @@ use embassy_nrf::{bind_interrupts, peripherals};
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 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>; 13 TWISPI0 => twis::InterruptHandler<peripherals::TWISPI0>;
14}); 14});
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index accaccea1..f9f8d74ab 100644
--- a/examples/nrf52840/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -7,7 +7,7 @@ use embassy_nrf::{bind_interrupts, peripherals, uarte};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9bind_interrupts!(struct Irqs { 9bind_interrupts!(struct Irqs {
10 UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>; 10 UARTE0 => uarte::InterruptHandler<peripherals::UARTE0>;
11}); 11});
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 config.parity = uarte::Parity::EXCLUDED; 17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200; 18 config.baudrate = uarte::Baudrate::BAUD115200;
19 19
20 let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 20 let mut uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
21 21
22 info!("uarte initialized!"); 22 info!("uarte initialized!");
23 23
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
index fa93bcf21..00e3ae904 100644
--- a/examples/nrf52840/src/bin/uart_idle.rs
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, uarte};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs { 10bind_interrupts!(struct Irqs {
11 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; 11 UARTE0 => uarte::InterruptHandler<UARTE0>;
12}); 12});
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
18 config.parity = uarte::Parity::EXCLUDED; 18 config.parity = uarte::Parity::EXCLUDED;
19 config.baudrate = uarte::Baudrate::BAUD115200; 19 config.baudrate = uarte::Baudrate::BAUD115200;
20 20
21 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 21 let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
22 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); 22 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
23 23
24 info!("uarte initialized!"); 24 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index c7510a9a8..46be8f636 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -13,7 +13,7 @@ use {defmt_rtt as _, panic_probe as _};
13static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 13static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; 16 UARTE0 => uarte::InterruptHandler<UARTE0>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -23,7 +23,7 @@ async fn main(spawner: Spawner) {
23 config.parity = uarte::Parity::EXCLUDED; 23 config.parity = uarte::Parity::EXCLUDED;
24 config.baudrate = uarte::Baudrate::BAUD115200; 24 config.baudrate = uarte::Baudrate::BAUD115200;
25 25
26 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 26 let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
27 let (mut tx, rx) = uart.split(); 27 let (mut tx, rx) = uart.split();
28 28
29 info!("uarte initialized!"); 29 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index e56b215e3..49856012d 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -1,12 +1,10 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::*; 4use defmt::*;
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
9use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
10use embassy_nrf::rng::Rng; 8use embassy_nrf::rng::Rng;
11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 9use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
12use embassy_nrf::usb::Driver; 10use embassy_nrf::usb::Driver;
@@ -20,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _};
20 18
21bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
22 USBD => usb::InterruptHandler<peripherals::USBD>; 20 USBD => usb::InterruptHandler<peripherals::USBD>;
23 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 21 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
24 RNG => rng::InterruptHandler<peripherals::RNG>; 22 RNG => rng::InterruptHandler<peripherals::RNG>;
25}); 23});
26 24
@@ -39,18 +37,17 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39} 37}
40 38
41#[embassy_executor::task] 39#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
43 stack.run().await 41 runner.run().await
44} 42}
45 43
46#[embassy_executor::main] 44#[embassy_executor::main]
47async fn main(spawner: Spawner) { 45async fn main(spawner: Spawner) {
48 let p = embassy_nrf::init(Default::default()); 46 let p = embassy_nrf::init(Default::default());
49 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
50 47
51 info!("Enabling ext hfosc..."); 48 info!("Enabling ext hfosc...");
52 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 49 pac::CLOCK.tasks_hfclkstart().write_value(1);
53 while clock.events_hfclkstarted.read().bits() != 1 {} 50 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
54 51
55 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
56 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 53 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -63,12 +60,6 @@ async fn main(spawner: Spawner) {
63 config.max_power = 100; 60 config.max_power = 100;
64 config.max_packet_size_0 = 64; 61 config.max_packet_size_0 = 64;
65 62
66 // Required for Windows support.
67 config.composite_with_iads = true;
68 config.device_class = 0xEF;
69 config.device_sub_class = 0x02;
70 config.device_protocol = 0x01;
71
72 // Create embassy-usb DeviceBuilder using the driver and config. 63 // Create embassy-usb DeviceBuilder using the driver and config.
73 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 64 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
74 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 65 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
@@ -116,10 +107,9 @@ async fn main(spawner: Spawner) {
116 107
117 // Init network stack 108 // Init network stack
118 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 109 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
119 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 110 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
120 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
121 111
122 unwrap!(spawner.spawn(net_task(stack))); 112 unwrap!(spawner.spawn(net_task(runner)));
123 113
124 // And now we can use it! 114 // And now we can use it!
125 115
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index e33ee5866..5a9dc90a2 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, Ordering};
6 5
7use defmt::*; 6use defmt::*;
@@ -22,7 +21,7 @@ use {defmt_rtt as _, panic_probe as _};
22 21
23bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
24 USBD => usb::InterruptHandler<peripherals::USBD>; 23 USBD => usb::InterruptHandler<peripherals::USBD>;
25 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 24 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
26}); 25});
27 26
28static SUSPENDED: AtomicBool = AtomicBool::new(false); 27static SUSPENDED: AtomicBool = AtomicBool::new(false);
@@ -30,11 +29,10 @@ static SUSPENDED: AtomicBool = AtomicBool::new(false);
30#[embassy_executor::main] 29#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 30async fn main(_spawner: Spawner) {
32 let p = embassy_nrf::init(Default::default()); 31 let p = embassy_nrf::init(Default::default());
33 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
34 32
35 info!("Enabling ext hfosc..."); 33 info!("Enabling ext hfosc...");
36 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 34 pac::CLOCK.tasks_hfclkstart().write_value(1);
37 while clock.events_hfclkstarted.read().bits() != 1 {} 35 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
38 36
39 // Create the driver, from the HAL. 37 // Create the driver, from the HAL.
40 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 38 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 8076ac283..80cda70e3 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::*; 4use defmt::*;
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_futures::join::join; 6use embassy_futures::join::join;
@@ -18,17 +16,16 @@ use {defmt_rtt as _, panic_probe as _};
18 16
19bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
20 USBD => usb::InterruptHandler<peripherals::USBD>; 18 USBD => usb::InterruptHandler<peripherals::USBD>;
21 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 19 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
22}); 20});
23 21
24#[embassy_executor::main] 22#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
26 let p = embassy_nrf::init(Default::default()); 24 let p = embassy_nrf::init(Default::default());
27 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
28 25
29 info!("Enabling ext hfosc..."); 26 info!("Enabling ext hfosc...");
30 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 27 pac::CLOCK.tasks_hfclkstart().write_value(1);
31 while clock.events_hfclkstarted.read().bits() != 1 {} 28 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
32 29
33 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
34 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 31 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 02048e692..8d05df791 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic}; 4use defmt::{info, panic};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_futures::join::join; 6use embassy_futures::join::join;
@@ -16,17 +14,16 @@ use {defmt_rtt as _, panic_probe as _};
16 14
17bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
18 USBD => usb::InterruptHandler<peripherals::USBD>; 16 USBD => usb::InterruptHandler<peripherals::USBD>;
19 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 17 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 18});
21 19
22#[embassy_executor::main] 20#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
25 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
26 23
27 info!("Enabling ext hfosc..."); 24 info!("Enabling ext hfosc...");
28 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 25 pac::CLOCK.tasks_hfclkstart().write_value(1);
29 while clock.events_hfclkstarted.read().bits() != 1 {} 26 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
30 27
31 // Create the driver, from the HAL. 28 // Create the driver, from the HAL.
32 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 29 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -39,13 +36,6 @@ async fn main(_spawner: Spawner) {
39 config.max_power = 100; 36 config.max_power = 100;
40 config.max_packet_size_0 = 64; 37 config.max_packet_size_0 = 64;
41 38
42 // Required for windows compatibility.
43 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
44 config.device_class = 0xEF;
45 config.device_sub_class = 0x02;
46 config.device_protocol = 0x01;
47 config.composite_with_iads = true;
48
49 // Create embassy-usb DeviceBuilder using the driver and config. 39 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 40 // It needs some buffers for building the descriptors.
51 let mut config_descriptor = [0; 256]; 41 let mut config_descriptor = [0; 256];
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 895cca8b9..5e5b4de35 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic, unwrap}; 4use defmt::{info, panic, unwrap};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 6use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
@@ -16,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _};
16 14
17bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
18 USBD => usb::InterruptHandler<peripherals::USBD>; 16 USBD => usb::InterruptHandler<peripherals::USBD>;
19 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 17 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 18});
21 19
22type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 20type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
@@ -39,11 +37,10 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) {
39#[embassy_executor::main] 37#[embassy_executor::main]
40async fn main(spawner: Spawner) { 38async fn main(spawner: Spawner) {
41 let p = embassy_nrf::init(Default::default()); 39 let p = embassy_nrf::init(Default::default());
42 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
43 40
44 info!("Enabling ext hfosc..."); 41 info!("Enabling ext hfosc...");
45 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 42 pac::CLOCK.tasks_hfclkstart().write_value(1);
46 while clock.events_hfclkstarted.read().bits() != 1 {} 43 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
47 44
48 // Create the driver, from the HAL. 45 // Create the driver, from the HAL.
49 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 46 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -56,13 +53,6 @@ async fn main(spawner: Spawner) {
56 config.max_power = 100; 53 config.max_power = 100;
57 config.max_packet_size_0 = 64; 54 config.max_packet_size_0 = 64;
58 55
59 // Required for windows compatibility.
60 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
61 config.device_class = 0xEF;
62 config.device_sub_class = 0x02;
63 config.device_protocol = 0x01;
64 config.composite_with_iads = true;
65
66 static STATE: StaticCell<State> = StaticCell::new(); 56 static STATE: StaticCell<State> = StaticCell::new();
67 let state = STATE.init(State::new()); 57 let state = STATE.init(State::new());
68 58
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index c6675a3d3..8a20ce673 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic}; 4use defmt::{info, panic};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_futures::join::join; 6use embassy_futures::join::join;
@@ -18,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _};
18 16
19bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
20 USBD => usb::InterruptHandler<peripherals::USBD>; 18 USBD => usb::InterruptHandler<peripherals::USBD>;
21 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 19 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
22}); 20});
23 21
24// This is a randomly generated GUID to allow clients on Windows to find our device 22// This is a randomly generated GUID to allow clients on Windows to find our device
@@ -27,11 +25,10 @@ const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321
27#[embassy_executor::main] 25#[embassy_executor::main]
28async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
29 let p = embassy_nrf::init(Default::default()); 27 let p = embassy_nrf::init(Default::default());
30 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
31 28
32 info!("Enabling ext hfosc..."); 29 info!("Enabling ext hfosc...");
33 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 30 pac::CLOCK.tasks_hfclkstart().write_value(1);
34 while clock.events_hfclkstarted.read().bits() != 1 {} 31 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
35 32
36 // Create the driver, from the HAL. 33 // Create the driver, from the HAL.
37 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 34 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -44,13 +41,6 @@ async fn main(_spawner: Spawner) {
44 config.max_power = 100; 41 config.max_power = 100;
45 config.max_packet_size_0 = 64; 42 config.max_packet_size_0 = 64;
46 43
47 // Required for windows compatibility.
48 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
49 config.device_class = 0xEF;
50 config.device_sub_class = 0x02;
51 config.device_protocol = 0x01;
52 config.composite_with_iads = true;
53
54 // Create embassy-usb DeviceBuilder using the driver and config. 44 // Create embassy-usb DeviceBuilder using the driver and config.
55 // It needs some buffers for building the descriptors. 45 // It needs some buffers for building the descriptors.
56 let mut config_descriptor = [0; 256]; 46 let mut config_descriptor = [0; 256];
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index ede88cc26..0d9ee3cf8 100644
--- a/examples/nrf52840/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Input, Pull}; 6use embassy_nrf::gpio::{Input, Pull};
7use embassy_nrf::wdt::{Config, Watchdog}; 7use embassy_nrf::wdt::{Config, HaltConfig, Watchdog};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 17
18 // This is needed for `probe-rs run` to be able to catch the panic message 18 // This is needed for `probe-rs run` to be able to catch the panic message
19 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. 19 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
20 config.run_during_debug_halt = false; 20 config.action_during_debug_halt = HaltConfig::PAUSE;
21 21
22 let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) { 22 let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) {
23 Ok(x) => x, 23 Ok(x) => x,
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index a3b69a99b..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]
@@ -90,10 +90,9 @@ async fn main(spawner: Spawner) {
90 90
91 // Init network stack 91 // Init network stack
92 static RESOURCES: StaticCell<StackResources<3>> = 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(device, config, RESOURCES.init(StackResources::new()), seed));
95 94
96 unwrap!(spawner.spawn(net_task(stack))); 95 unwrap!(spawner.spawn(net_task(runner)));
97 96
98 // And now we can use it! 97 // And now we can use it!
99 98
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 0da85be07..dc4fba4fd 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -6,22 +6,21 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 12embassy-nrf = { version = "0.3.1", 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.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.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 = "1.0.1"
18defmt-rtt = "0.4" 18defmt-rtt = "1.0.0"
19 19
20static_cell = "2" 20static_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 = "1.0.0", features = ["print-defmt"] }
24rand = { version = "0.8.4", default-features = false }
25embedded-storage = "0.3.1" 24embedded-storage = "0.3.1"
26usbd-hid = "0.8.1" 25usbd-hid = "0.8.1"
27serde = { version = "1.0.136", default-features = false } 26serde = { version = "1.0.136", default-features = false }
diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs
index 7b41d7463..7e8b8d418 100644
--- a/examples/nrf5340/src/bin/uart.rs
+++ b/examples/nrf5340/src/bin/uart.rs
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
18 config.parity = uarte::Parity::EXCLUDED; 18 config.parity = uarte::Parity::EXCLUDED;
19 config.baudrate = uarte::Baudrate::BAUD115200; 19 config.baudrate = uarte::Baudrate::BAUD115200;
20 20
21 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config); 21 let mut uart = uarte::Uarte::new(p.SERIAL0, p.P1_00, p.P1_01, Irqs, config);
22 22
23 info!("uarte initialized!"); 23 info!("uarte initialized!");
24 24
diff --git a/examples/nrf54l15/.cargo/config.toml b/examples/nrf54l15/.cargo/config.toml
new file mode 100644
index 000000000..443bd7418
--- /dev/null
+++ b/examples/nrf54l15/.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 nrf54l15"
4
5[build]
6target = "thumbv8m.main-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
new file mode 100644
index 000000000..4b229d06d
--- /dev/null
+++ b/examples/nrf54l15/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf54l15-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11
12defmt = "1.0.1"
13defmt-rtt = "1.0.0"
14panic-probe = { version = "1.0.0", features = ["print-defmt"] }
15
16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf54l15/build.rs b/examples/nrf54l15/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf54l15/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/nrf54l15/memory.x b/examples/nrf54l15/memory.x
new file mode 100644
index 000000000..1064c8a5c
--- /dev/null
+++ b/examples/nrf54l15/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1536K
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5}
diff --git a/examples/nrf54l15/src/bin/blinky.rs b/examples/nrf54l15/src/bin/blinky.rs
new file mode 100644
index 000000000..71fcc461f
--- /dev/null
+++ b/examples/nrf54l15/src/bin/blinky.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
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_nrf::init(Default::default());
13 let mut led = Output::new(p.P2_09, Level::Low, OutputDrive::Standard);
14
15 loop {
16 info!("high!");
17 led.set_high();
18 Timer::after_millis(300).await;
19 info!("low!");
20 led.set_low();
21 Timer::after_millis(300).await;
22 }
23}
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
index 17fe27b67..a083aa5e7 100644
--- a/examples/nrf9151/ns/Cargo.toml
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -5,16 +5,16 @@ 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.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.4.0", 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"] } 10embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11 11
12defmt = "0.3" 12defmt = "1.0.1"
13defmt-rtt = "0.4" 13defmt-rtt = "1.0.0"
14 14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] } 17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18 18
19[profile.release] 19[profile.release]
20debug = 2 20debug = 2
diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs
index 2220dccfb..6fd377978 100644
--- a/examples/nrf9151/ns/src/bin/uart.rs
+++ b/examples/nrf9151/ns/src/bin/uart.rs
@@ -7,7 +7,7 @@ use embassy_nrf::{bind_interrupts, peripherals, uarte};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9bind_interrupts!(struct Irqs { 9bind_interrupts!(struct Irqs {
10 SPIM0_SPIS0_TWIM0_TWIS0_UARTE0 => uarte::InterruptHandler<peripherals::SERIAL0>; 10 SERIAL0 => uarte::InterruptHandler<peripherals::SERIAL0>;
11}); 11});
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 config.parity = uarte::Parity::EXCLUDED; 17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200; 18 config.baudrate = uarte::Baudrate::BAUD115200;
19 19
20 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P0_26, p.P0_27, config); 20 let mut uart = uarte::Uarte::new(p.SERIAL0, p.P0_26, p.P0_27, Irqs, config);
21 21
22 info!("uarte initialized!"); 22 info!("uarte initialized!");
23 23
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
index 7253fc4be..ae98631ef 100644
--- a/examples/nrf9151/s/Cargo.toml
+++ b/examples/nrf9151/s/Cargo.toml
@@ -5,16 +5,16 @@ 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.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.4.0", 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"] } 10embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11 11
12defmt = "0.3" 12defmt = "1.0.1"
13defmt-rtt = "0.4" 13defmt-rtt = "1.0.0"
14 14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] } 17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18 18
19[profile.release] 19[profile.release]
20debug = 2 20debug = 2
diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml
index f64c63966..6072b8595 100644
--- a/examples/nrf9160/.cargo/config.toml
+++ b/examples/nrf9160/.cargo/config.toml
@@ -1,5 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip nRF9160_xxAA" 2# runner = "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}" ]
3 4
4[build] 5[build]
5target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index c30b54ebd..25aedf624 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.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.3.1", 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.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
11 13
12defmt = "0.3" 14defmt = "1.0.1"
13defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
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 = "1.0.0", 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..a36b14626
--- /dev/null
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -0,0 +1,197 @@
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::{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};
17use embassy_nrf::uarte::Baudrate;
18use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte, Peri};
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 SERIAL0 => 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
74 let gateway = match status.gateway {
75 Some(IpAddr::V4(addr)) => Some(addr),
76 _ => None,
77 };
78
79 let mut dns_servers = Vec::new();
80 for dns in status.dns.iter() {
81 if let IpAddr::V4(ip) = dns {
82 unwrap!(dns_servers.push(*ip));
83 }
84 }
85
86 embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
87 address: Ipv4Cidr::new(addr, 32),
88 gateway,
89 dns_servers,
90 })
91}
92
93#[embassy_executor::task]
94async fn blink_task(pin: Peri<'static, AnyPin>) {
95 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
96 loop {
97 led.set_high();
98 Timer::after_millis(1000).await;
99 led.set_low();
100 Timer::after_millis(1000).await;
101 }
102}
103
104extern "C" {
105 static __start_ipc: u8;
106 static __end_ipc: u8;
107}
108
109#[embassy_executor::main]
110async fn main(spawner: Spawner) {
111 let p = embassy_nrf::init(Default::default());
112
113 info!("Hello World!");
114
115 unwrap!(spawner.spawn(blink_task(p.P0_02.into())));
116
117 let ipc_mem = unsafe {
118 let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit<u8>;
119 let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit<u8>;
120 let ipc_len = ipc_end.offset_from(ipc_start) as usize;
121 slice::from_raw_parts_mut(ipc_start, ipc_len)
122 };
123
124 static mut TRACE_BUF: [u8; 4096] = [0u8; 4096];
125 let mut config = uarte::Config::default();
126 config.baudrate = Baudrate::BAUD1M;
127 let uart = BufferedUarteTx::new(
128 //let trace_uart = BufferedUarteTx::new(
129 unsafe { peripherals::SERIAL0::steal() },
130 unsafe { peripherals::P0_01::steal() },
131 Irqs,
132 //unsafe { peripherals::P0_14::steal() },
133 config,
134 unsafe { &mut *addr_of_mut!(TRACE_BUF) },
135 );
136
137 static STATE: StaticCell<State> = StaticCell::new();
138 static TRACE: StaticCell<TraceBuffer> = StaticCell::new();
139 let (device, control, runner, tracer) =
140 embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await;
141 unwrap!(spawner.spawn(modem_task(runner)));
142 unwrap!(spawner.spawn(trace_task(uart, tracer)));
143
144 let config = embassy_net::Config::default();
145
146 // Generate "random" seed. nRF91 has no RNG, TODO figure out something...
147 let seed = 123456;
148
149 // Init network stack
150 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
151 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed);
152
153 unwrap!(spawner.spawn(net_task(runner)));
154
155 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
156 let control = CONTROL.init(context::Control::new(control, 0).await);
157
158 unwrap!(spawner.spawn(control_task(
159 control,
160 context::Config {
161 apn: b"iot.nat.es",
162 auth_prot: context::AuthProt::Pap,
163 auth: Some((b"orange", b"orange")),
164 pin: None,
165 },
166 stack
167 )));
168
169 stack.wait_config_up().await;
170
171 let mut rx_buffer = [0; 4096];
172 let mut tx_buffer = [0; 4096];
173 loop {
174 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
175 socket.set_timeout(Some(Duration::from_secs(10)));
176
177 info!("Connecting...");
178 let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
179 if let Err(e) = socket.connect((host_addr, 4242)).await {
180 warn!("connect error: {:?}", e);
181 Timer::after_secs(10).await;
182 continue;
183 }
184 info!("Connected to {:?}", socket.remote_endpoint());
185
186 let msg = b"Hello world!\n";
187 for _ in 0..10 {
188 if let Err(e) = socket.write_all(msg).await {
189 warn!("write error: {:?}", e);
190 break;
191 }
192 info!("txd: {}", core::str::from_utf8(msg).unwrap());
193 Timer::after_secs(1).await;
194 }
195 Timer::after_secs(4).await;
196 }
197}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 83d5792b6..c8a132a5e 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -6,43 +6,43 @@ license = "MIT OR Apache-2.0"
6 6
7 7
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.4.0", 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", "rp2040"] } 13embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } 15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.2.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.2.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } 19cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } 20cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] }
21 21
22defmt = "0.3" 22defmt = "1.0.1"
23defmt-rtt = "0.4" 23defmt-rtt = "1.0.0"
24fixed = "1.23.1" 24fixed = "1.23.1"
25fixed-macro = "1.2" 25fixed-macro = "1.2"
26 26
27# for web request example 27# for web request example
28reqwless = { version = "0.12.0", features = ["defmt",]} 28reqwless = { version = "0.13.0", features = ["defmt"] }
29serde = { version = "1.0.203", default-features = false, features = ["derive"] } 29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1" 30serde-json-core = "0.5.1"
31 31
32# for assign resources example 32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } 33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "bd22cb7a92031fb16f74a5da42469d466c33383e" }
34 34
35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
36cortex-m = { version = "0.7.6", features = ["inline-asm"] } 36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
37cortex-m-rt = "0.7.0" 37cortex-m-rt = "0.7.0"
38critical-section = "1.1" 38critical-section = "1.1"
39panic-probe = { version = "0.3", features = ["print-defmt"] } 39panic-probe = { version = "1.0.0", features = ["print-defmt"] }
40display-interface-spi = "0.4.1" 40display-interface-spi = "0.5.0"
41embedded-graphics = "0.7.1" 41embedded-graphics = "0.8.1"
42st7789 = "0.6.1" 42mipidsi = "0.8.0"
43display-interface = "0.4.1" 43display-interface = "0.5.0"
44byte-slice-cast = { version = "1.2.0", default-features = false } 44byte-slice-cast = { version = "1.2.0", default-features = false }
45smart-leds = "0.3.0" 45smart-leds = "0.4.0"
46heapless = "0.8" 46heapless = "0.8"
47usbd-hid = "0.8.1" 47usbd-hid = "0.8.1"
48 48
@@ -54,14 +54,9 @@ embedded-storage = { version = "0.3" }
54static_cell = "2.1" 54static_cell = "2.1"
55portable-atomic = { version = "1.5", features = ["critical-section"] } 55portable-atomic = { version = "1.5", features = ["critical-section"] }
56log = "0.4" 56log = "0.4"
57pio-proc = "0.2" 57rand = { version = "0.9.0", default-features = false }
58pio = "0.2.1"
59rand = { version = "0.8.5", default-features = false }
60embedded-sdmmc = "0.7.0" 58embedded-sdmmc = "0.7.0"
61 59
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
64
65[profile.release] 60[profile.release]
66debug = 2 61debug = 2
67lto = true 62lto = true
@@ -71,13 +66,3 @@ opt-level = 'z'
71debug = 2 66debug = 2
72lto = true 67lto = true
73opt-level = "z" 68opt-level = "z"
74
75[patch.crates-io]
76trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
77bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" }
78embassy-executor = { path = "../../embassy-executor" }
79embassy-sync = { path = "../../embassy-sync" }
80embassy-futures = { path = "../../embassy-futures" }
81embassy-time = { path = "../../embassy-time" }
82embassy-time-driver = { path = "../../embassy-time-driver" }
83embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
index 1bb7c2249..015915586 100644
--- a/examples/rp/src/bin/adc.rs
+++ b/examples/rp/src/bin/adc.rs
@@ -12,9 +12,12 @@ use embassy_rp::gpio::Pull;
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(
16 ADC_IRQ_FIFO => InterruptHandler; 16 /// Binds the ADC interrupts.
17}); 17 struct Irqs {
18 ADC_IRQ_FIFO => InterruptHandler;
19 }
20);
18 21
19#[embassy_executor::main] 22#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
diff --git a/examples/rp/src/bin/adc_dma.rs b/examples/rp/src/bin/adc_dma.rs
index f755cf5bf..b42c13fde 100644
--- a/examples/rp/src/bin/adc_dma.rs
+++ b/examples/rp/src/bin/adc_dma.rs
@@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) {
38 // Read 100 samples from a single channel 38 // Read 100 samples from a single channel
39 let mut buf = [0_u16; BLOCK_SIZE]; 39 let mut buf = [0_u16; BLOCK_SIZE];
40 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) 40 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1)
41 adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); 41 adc.read_many(&mut pin, &mut buf, div, dma.reborrow()).await.unwrap();
42 info!("single: {:?} ...etc", buf[..8]); 42 info!("single: {:?} ...etc", buf[..8]);
43 43
44 // Read 100 samples from 4 channels interleaved 44 // Read 100 samples from 4 channels interleaved
45 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; 45 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }];
46 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) 46 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1)
47 adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) 47 adc.read_many_multichannel(&mut pins, &mut buf, div, dma.reborrow())
48 .await 48 .await
49 .unwrap(); 49 .unwrap();
50 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); 50 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]);
diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs
index ff6eff4a2..341f54d22 100644
--- a/examples/rp/src/bin/assign_resources.rs
+++ b/examples/rp/src/bin/assign_resources.rs
@@ -16,6 +16,7 @@ use defmt::*;
16use embassy_executor::Spawner; 16use embassy_executor::Spawner;
17use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
18use embassy_rp::peripherals::{self, PIN_20, PIN_21}; 18use embassy_rp::peripherals::{self, PIN_20, PIN_21};
19use embassy_rp::Peri;
19use embassy_time::Timer; 20use embassy_time::Timer;
20use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
21 22
@@ -38,7 +39,11 @@ async fn main(spawner: Spawner) {
38 39
39// 1) Assigning a resource to a task by passing parts of the peripherals. 40// 1) Assigning a resource to a task by passing parts of the peripherals.
40#[embassy_executor::task] 41#[embassy_executor::task]
41async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { 42async fn double_blinky_manually_assigned(
43 _spawner: Spawner,
44 pin_20: Peri<'static, PIN_20>,
45 pin_21: Peri<'static, PIN_21>,
46) {
42 let mut led_20 = Output::new(pin_20, Level::Low); 47 let mut led_20 = Output::new(pin_20, Level::Low);
43 let mut led_21 = Output::new(pin_21, Level::High); 48 let mut led_21 = Output::new(pin_21, Level::High);
44 49
diff --git a/examples/rp/src/bin/blinky_two_channels.rs b/examples/rp/src/bin/blinky_two_channels.rs
index b2eec2a21..51e139e94 100644
--- a/examples/rp/src/bin/blinky_two_channels.rs
+++ b/examples/rp/src/bin/blinky_two_channels.rs
@@ -11,7 +11,7 @@ use embassy_rp::gpio;
11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
12use embassy_sync::channel::{Channel, Sender}; 12use embassy_sync::channel::{Channel, Sender};
13use embassy_time::{Duration, Ticker}; 13use embassy_time::{Duration, Ticker};
14use gpio::{AnyPin, Level, Output}; 14use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17enum LedState { 17enum LedState {
@@ -22,7 +22,7 @@ static CHANNEL: Channel<ThreadModeRawMutex, LedState, 64> = Channel::new();
22#[embassy_executor::main] 22#[embassy_executor::main]
23async fn main(spawner: Spawner) { 23async fn main(spawner: Spawner) {
24 let p = embassy_rp::init(Default::default()); 24 let p = embassy_rp::init(Default::default());
25 let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); 25 let mut led = Output::new(p.PIN_25, Level::High);
26 26
27 let dt = 100 * 1_000_000; 27 let dt = 100 * 1_000_000;
28 let k = 1.003; 28 let k = 1.003;
diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs
index a57b513d6..67a9108c0 100644
--- a/examples/rp/src/bin/blinky_two_tasks.rs
+++ b/examples/rp/src/bin/blinky_two_tasks.rs
@@ -11,7 +11,7 @@ use embassy_rp::gpio;
11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use embassy_time::{Duration, Ticker}; 13use embassy_time::{Duration, Ticker};
14use gpio::{AnyPin, Level, Output}; 14use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>; 17type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>;
@@ -21,7 +21,7 @@ static LED: LedType = Mutex::new(None);
21async fn main(spawner: Spawner) { 21async fn main(spawner: Spawner) {
22 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
23 // set the content of the global LED reference to the real LED pin 23 // set the content of the global LED reference to the real LED pin
24 let led = Output::new(AnyPin::from(p.PIN_25), Level::High); 24 let led = Output::new(p.PIN_25, Level::High);
25 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the 25 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the
26 // Mutex is released 26 // Mutex is released
27 { 27 {
diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs
deleted file mode 100644
index 901521b60..000000000
--- a/examples/rp/src/bin/bluetooth.rs
+++ /dev/null
@@ -1,148 +0,0 @@
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 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
47 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
48
49 let pwr = Output::new(p.PIN_23, Level::Low);
50 let cs = Output::new(p.PIN_25, Level::High);
51 let mut pio = Pio::new(p.PIO0, Irqs);
52 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
53
54 static STATE: StaticCell<cyw43::State> = StaticCell::new();
55 let state = STATE.init(cyw43::State::new());
56 let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
57 unwrap!(spawner.spawn(cyw43_task(runner)));
58 control.init(clm).await;
59
60 let controller: ExternalController<_, 10> = ExternalController::new(bt_device);
61 static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new();
62 let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None));
63
64 let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources);
65
66 ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff]));
67 let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();
68
69 // Generic Access Service (mandatory)
70 let id = b"Pico W Bluetooth";
71 let appearance = [0x80, 0x07];
72 let mut bat_level = [0; 1];
73 let handle = {
74 let mut svc = table.add_service(Service::new(0x1800));
75 let _ = svc.add_characteristic_ro(0x2a00, id);
76 let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
77 svc.build();
78
79 // Generic attribute service (mandatory)
80 table.add_service(Service::new(0x1801));
81
82 // Battery service
83 let mut svc = table.add_service(Service::new(0x180f));
84
85 svc.add_characteristic(
86 0x2a19,
87 &[CharacteristicProp::Read, CharacteristicProp::Notify],
88 &mut bat_level,
89 )
90 .build()
91 };
92
93 let mut adv_data = [0; 31];
94 AdStructure::encode_slice(
95 &[
96 AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
97 AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]),
98 AdStructure::CompleteLocalName(b"Pico W Bluetooth"),
99 ],
100 &mut adv_data[..],
101 )
102 .unwrap();
103
104 let server = ble.gatt_server(&table);
105
106 info!("Starting advertising and GATT service");
107 let _ = join3(
108 ble.run(),
109 async {
110 loop {
111 match server.next().await {
112 Ok(GattEvent::Write { handle, connection: _ }) => {
113 let _ = table.get(handle, |value| {
114 info!("Write event. Value written: {:?}", value);
115 });
116 }
117 Ok(GattEvent::Read { .. }) => {
118 info!("Read event");
119 }
120 Err(e) => {
121 error!("Error processing GATT events: {:?}", e);
122 }
123 }
124 }
125 },
126 async {
127 let mut advertiser = ble
128 .advertise(
129 &Default::default(),
130 Advertisement::ConnectableScannableUndirected {
131 adv_data: &adv_data[..],
132 scan_data: &[],
133 },
134 )
135 .await
136 .unwrap();
137 let conn = advertiser.accept().await.unwrap();
138 // Keep connection alive
139 let mut tick: u8 = 0;
140 loop {
141 Timer::after(Duration::from_secs(10)).await;
142 tick += 1;
143 server.notify(handle, &conn, &[tick]).await.unwrap();
144 }
145 },
146 )
147 .await;
148}
diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs
new file mode 100644
index 000000000..e434b3bbc
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs
@@ -0,0 +1,143 @@
1//! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results.
2//!
3//! Although there is a better way to execute pings using the child module ping of the icmp module,
4//! this example allows for other icmp messages like `Destination unreachable` to be sent aswell.
5//!
6//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::icmp::{ChecksumCapabilities, IcmpEndpoint, IcmpSocket, Icmpv4Packet, Icmpv4Repr, PacketMetadata};
15use embassy_net::{Stack, StackResources};
16use embassy_net_wiznet::chip::W5500;
17use embassy_net_wiznet::*;
18use embassy_rp::clocks::RoscRng;
19use embassy_rp::gpio::{Input, Level, Output, Pull};
20use embassy_rp::peripherals::SPI0;
21use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
22use embassy_time::{Delay, Instant, Timer};
23use embedded_hal_bus::spi::ExclusiveDevice;
24use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _};
26
27type ExclusiveSpiDevice = ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>;
28
29#[embassy_executor::task]
30async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! {
31 runner.run().await
32}
33
34#[embassy_executor::task]
35async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
36 runner.run().await
37}
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let mut rng = RoscRng;
43
44 let mut spi_cfg = SpiConfig::default();
45 spi_cfg.frequency = 50_000_000;
46 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
47 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
48 let cs = Output::new(p.PIN_17, Level::High);
49 let w5500_int = Input::new(p.PIN_21, Pull::Up);
50 let w5500_reset = Output::new(p.PIN_20, Level::High);
51
52 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
53 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
54 let state = STATE.init(State::<8, 8>::new());
55 let (device, runner) = embassy_net_wiznet::new(
56 mac_addr,
57 state,
58 ExclusiveDevice::new(spi, cs, Delay),
59 w5500_int,
60 w5500_reset,
61 )
62 .await
63 .unwrap();
64 unwrap!(spawner.spawn(ethernet_task(runner)));
65
66 // Generate random seed
67 let seed = rng.next_u64();
68
69 // Init network stack
70 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
71 let (stack, runner) = embassy_net::new(
72 device,
73 embassy_net::Config::dhcpv4(Default::default()),
74 RESOURCES.init(StackResources::new()),
75 seed,
76 );
77
78 // Launch network task
79 unwrap!(spawner.spawn(net_task(runner)));
80
81 info!("Waiting for DHCP...");
82 let cfg = wait_for_config(stack).await;
83 let local_addr = cfg.address.address();
84 info!("IP address: {:?}", local_addr);
85
86 // Then we can use it!
87 let mut rx_buffer = [0; 256];
88 let mut tx_buffer = [0; 256];
89 let mut rx_meta = [PacketMetadata::EMPTY];
90 let mut tx_meta = [PacketMetadata::EMPTY];
91
92 // Identifier used for the ICMP socket
93 let ident = 42;
94
95 // Create and bind the socket
96 let mut socket = IcmpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
97 socket.bind(IcmpEndpoint::Ident(ident)).unwrap();
98
99 // Create the repr for the packet
100 let icmp_repr = Icmpv4Repr::EchoRequest {
101 ident,
102 seq_no: 0,
103 data: b"Hello, icmp!",
104 };
105
106 // Send the packet and store the starting instant to mesure latency later
107 let start = socket
108 .send_to_with(icmp_repr.buffer_len(), cfg.gateway.unwrap(), |buf| {
109 // Create and populate the packet buffer allocated by `send_to_with`
110 let mut icmp_packet = Icmpv4Packet::new_unchecked(buf);
111 icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default());
112 Instant::now() // Return the instant where the packet was sent
113 })
114 .await
115 .unwrap();
116
117 // Recieve and log the data of the reply
118 socket
119 .recv_from_with(|(buf, addr)| {
120 let packet = Icmpv4Packet::new_checked(buf).unwrap();
121 info!(
122 "Recieved {:?} from {} in {}ms",
123 packet.data(),
124 addr,
125 start.elapsed().as_millis()
126 );
127 })
128 .await
129 .unwrap();
130
131 loop {
132 Timer::after_secs(10).await;
133 }
134}
135
136async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
137 loop {
138 if let Some(config) = stack.config_v4() {
139 return config.clone();
140 }
141 yield_now().await;
142 }
143}
diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs
new file mode 100644
index 000000000..0ec594fd5
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs
@@ -0,0 +1,134 @@
1//! This example implements a LAN ping scan with the ping utilities in the icmp module of embassy-net.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
4
5#![no_std]
6#![no_main]
7
8use core::net::Ipv4Addr;
9use core::ops::Not;
10use core::str::FromStr;
11
12use defmt::*;
13use embassy_executor::Spawner;
14use embassy_futures::yield_now;
15use embassy_net::icmp::ping::{PingManager, PingParams};
16use embassy_net::icmp::PacketMetadata;
17use embassy_net::{Ipv4Cidr, Stack, StackResources};
18use embassy_net_wiznet::chip::W5500;
19use embassy_net_wiznet::*;
20use embassy_rp::clocks::RoscRng;
21use embassy_rp::gpio::{Input, Level, Output, Pull};
22use embassy_rp::peripherals::SPI0;
23use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
24use embassy_time::{Delay, Duration};
25use embedded_hal_bus::spi::ExclusiveDevice;
26use static_cell::StaticCell;
27use {defmt_rtt as _, panic_probe as _};
28
29type ExclusiveSpiDevice = ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>;
30
31#[embassy_executor::task]
32async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! {
33 runner.run().await
34}
35
36#[embassy_executor::task]
37async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
38 runner.run().await
39}
40
41#[embassy_executor::main]
42async fn main(spawner: Spawner) {
43 let p = embassy_rp::init(Default::default());
44 let mut rng = RoscRng;
45
46 let mut spi_cfg = SpiConfig::default();
47 spi_cfg.frequency = 50_000_000;
48 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
49 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
50 let cs = Output::new(p.PIN_17, Level::High);
51 let w5500_int = Input::new(p.PIN_21, Pull::Up);
52 let w5500_reset = Output::new(p.PIN_20, Level::High);
53
54 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
55 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
56 let state = STATE.init(State::<8, 8>::new());
57 let (device, runner) = embassy_net_wiznet::new(
58 mac_addr,
59 state,
60 ExclusiveDevice::new(spi, cs, Delay),
61 w5500_int,
62 w5500_reset,
63 )
64 .await
65 .unwrap();
66 unwrap!(spawner.spawn(ethernet_task(runner)));
67
68 // Generate random seed
69 let seed = rng.next_u64();
70
71 // Init network stack
72 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
73 let (stack, runner) = embassy_net::new(
74 device,
75 embassy_net::Config::dhcpv4(Default::default()),
76 RESOURCES.init(StackResources::new()),
77 seed,
78 );
79
80 // Launch network task
81 unwrap!(spawner.spawn(net_task(runner)));
82
83 info!("Waiting for DHCP...");
84 let cfg = wait_for_config(stack).await;
85 let local_addr = cfg.address.address();
86 info!("IP address: {:?}", local_addr);
87 let gateway = cfg.gateway.unwrap();
88 let mask = cfg.address.netmask();
89 let lower_bound = (gateway.to_bits() & mask.to_bits()) + 1;
90 let upper_bound = gateway.to_bits() | mask.to_bits().not();
91 let addr_range = lower_bound..=upper_bound;
92
93 // Then we can use it!
94 let mut rx_buffer = [0; 256];
95 let mut tx_buffer = [0; 256];
96 let mut rx_meta = [PacketMetadata::EMPTY];
97 let mut tx_meta = [PacketMetadata::EMPTY];
98
99 // Create the ping manager instance
100 let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
101 let addr = "192.168.8.1"; // Address to ping to
102 // Create the PingParams with the target address
103 let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap());
104 // (optional) Set custom properties of the ping
105 ping_params.set_payload(b"Hello, Ping!"); // custom payload
106 ping_params.set_count(1); // ping 1 times per ping call
107 ping_params.set_timeout(Duration::from_millis(500)); // wait .5 seconds instead of 4
108
109 info!("Online hosts in {}:", Ipv4Cidr::from_netmask(gateway, mask).unwrap());
110 let mut total_online_hosts = 0u32;
111 for addr in addr_range {
112 let ip_addr = Ipv4Addr::from_bits(addr);
113 // Set the target address in the ping params
114 ping_params.set_target(ip_addr);
115 // Execute the ping with the given parameters and wait for the reply
116 match ping_manager.ping(&ping_params).await {
117 Ok(time) => {
118 info!("{} is online\n- latency: {}ms\n", ip_addr, time.as_millis());
119 total_online_hosts += 1;
120 }
121 _ => continue,
122 }
123 }
124 info!("Ping scan complete, total online hosts: {}", total_online_hosts);
125}
126
127async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
128 loop {
129 if let Some(config) = stack.config_v4() {
130 return config.clone();
131 }
132 yield_now().await;
133 }
134}
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index aaa035a72..27e2f3c30 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -1,6 +1,6 @@
1//! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port. 1//! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port.
2//! 2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. 3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
@@ -18,7 +18,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{Delay, Duration}; 18use embassy_time::{Delay, Duration};
19use embedded_hal_bus::spi::ExclusiveDevice; 19use embedded_hal_bus::spi::ExclusiveDevice;
20use embedded_io_async::Write; 20use embedded_io_async::Write;
21use rand::RngCore;
22use static_cell::StaticCell; 21use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
24 23
@@ -36,8 +35,8 @@ async fn ethernet_task(
36} 35}
37 36
38#[embassy_executor::task] 37#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 38async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 39 runner.run().await
41} 40}
42 41
43#[embassy_executor::main] 42#[embassy_executor::main]
@@ -71,17 +70,16 @@ async fn main(spawner: Spawner) {
71 let seed = rng.next_u64(); 70 let seed = rng.next_u64();
72 71
73 // Init network stack 72 // Init network stack
74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 73 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new( 74 let (stack, runner) = embassy_net::new(
77 device, 75 device,
78 embassy_net::Config::dhcpv4(Default::default()), 76 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::new()), 77 RESOURCES.init(StackResources::new()),
80 seed, 78 seed,
81 )); 79 );
82 80
83 // Launch network task 81 // Launch network task
84 unwrap!(spawner.spawn(net_task(&stack))); 82 unwrap!(spawner.spawn(net_task(runner)));
85 83
86 info!("Waiting for DHCP..."); 84 info!("Waiting for DHCP...");
87 let cfg = wait_for_config(stack).await; 85 let cfg = wait_for_config(stack).await;
@@ -89,12 +87,12 @@ async fn main(spawner: Spawner) {
89 info!("IP address: {:?}", local_addr); 87 info!("IP address: {:?}", local_addr);
90 88
91 // Create two sockets listening to the same port, to handle simultaneous connections 89 // Create two sockets listening to the same port, to handle simultaneous connections
92 unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); 90 unwrap!(spawner.spawn(listen_task(stack, 0, 1234)));
93 unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); 91 unwrap!(spawner.spawn(listen_task(stack, 1, 1234)));
94} 92}
95 93
96#[embassy_executor::task(pool_size = 2)] 94#[embassy_executor::task(pool_size = 2)]
97async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) { 95async fn listen_task(stack: Stack<'static>, id: u8, port: u16) {
98 let mut rx_buffer = [0; 4096]; 96 let mut rx_buffer = [0; 4096];
99 let mut tx_buffer = [0; 4096]; 97 let mut tx_buffer = [0; 4096];
100 let mut buf = [0; 4096]; 98 let mut buf = [0; 4096];
@@ -131,7 +129,7 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16)
131 } 129 }
132} 130}
133 131
134async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 132async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
135 loop { 133 loop {
136 if let Some(config) = stack.config_v4() { 134 if let Some(config) = stack.config_v4() {
137 return config.clone(); 135 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 8e96a114c..ba82f2a60 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -1,6 +1,6 @@
1//! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second. 1//! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second.
2//! 2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. 3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
@@ -20,7 +20,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Delay, Duration, Timer}; 20use embassy_time::{Delay, Duration, Timer};
21use embedded_hal_bus::spi::ExclusiveDevice; 21use embedded_hal_bus::spi::ExclusiveDevice;
22use embedded_io_async::Write; 22use embedded_io_async::Write;
23use rand::RngCore;
24use static_cell::StaticCell; 23use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
26 25
@@ -38,8 +37,8 @@ async fn ethernet_task(
38} 37}
39 38
40#[embassy_executor::task] 39#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
42 stack.run().await 41 runner.run().await
43} 42}
44 43
45#[embassy_executor::main] 44#[embassy_executor::main]
@@ -74,17 +73,16 @@ async fn main(spawner: Spawner) {
74 let seed = rng.next_u64(); 73 let seed = rng.next_u64();
75 74
76 // Init network stack 75 // Init network stack
77 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
78 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 76 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
79 let stack = &*STACK.init(Stack::new( 77 let (stack, runner) = embassy_net::new(
80 device, 78 device,
81 embassy_net::Config::dhcpv4(Default::default()), 79 embassy_net::Config::dhcpv4(Default::default()),
82 RESOURCES.init(StackResources::new()), 80 RESOURCES.init(StackResources::new()),
83 seed, 81 seed,
84 )); 82 );
85 83
86 // Launch network task 84 // Launch network task
87 unwrap!(spawner.spawn(net_task(&stack))); 85 unwrap!(spawner.spawn(net_task(runner)));
88 86
89 info!("Waiting for DHCP..."); 87 info!("Waiting for DHCP...");
90 let cfg = wait_for_config(stack).await; 88 let cfg = wait_for_config(stack).await;
@@ -119,7 +117,7 @@ async fn main(spawner: Spawner) {
119 } 117 }
120} 118}
121 119
122async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 120async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
123 loop { 121 loop {
124 if let Some(config) = stack.config_v4() { 122 if let Some(config) = stack.config_v4() {
125 return config.clone(); 123 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 40736bf3c..5c56dcafa 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -1,7 +1,7 @@
1//! This example implements a TCP echo server on port 1234 and using DHCP. 1//! This example implements a TCP echo server on port 1234 and using DHCP.
2//! Send it some data, you should see it echoed back and printed in the console. 2//! Send it some data, you should see it echoed back and printed in the console.
3//! 3//!
4//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. 4//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
5 5
6#![no_std] 6#![no_std]
7#![no_main] 7#![no_main]
@@ -19,7 +19,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::{Delay, Duration}; 19use embassy_time::{Delay, Duration};
20use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
21use embedded_io_async::Write; 21use embedded_io_async::Write;
22use rand::RngCore;
23use static_cell::StaticCell; 22use static_cell::StaticCell;
24use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
25 24
@@ -37,8 +36,8 @@ async fn ethernet_task(
37} 36}
38 37
39#[embassy_executor::task] 38#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
41 stack.run().await 40 runner.run().await
42} 41}
43 42
44#[embassy_executor::main] 43#[embassy_executor::main]
@@ -73,17 +72,16 @@ async fn main(spawner: Spawner) {
73 let seed = rng.next_u64(); 72 let seed = rng.next_u64();
74 73
75 // Init network stack 74 // Init network stack
76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
77 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
78 let stack = &*STACK.init(Stack::new( 76 let (stack, runner) = embassy_net::new(
79 device, 77 device,
80 embassy_net::Config::dhcpv4(Default::default()), 78 embassy_net::Config::dhcpv4(Default::default()),
81 RESOURCES.init(StackResources::new()), 79 RESOURCES.init(StackResources::new()),
82 seed, 80 seed,
83 )); 81 );
84 82
85 // Launch network task 83 // Launch network task
86 unwrap!(spawner.spawn(net_task(&stack))); 84 unwrap!(spawner.spawn(net_task(runner)));
87 85
88 info!("Waiting for DHCP..."); 86 info!("Waiting for DHCP...");
89 let cfg = wait_for_config(stack).await; 87 let cfg = wait_for_config(stack).await;
@@ -128,7 +126,7 @@ async fn main(spawner: Spawner) {
128 } 126 }
129} 127}
130 128
131async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 129async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
132 loop { 130 loop {
133 if let Some(config) = stack.config_v4() { 131 if let Some(config) = stack.config_v4() {
134 return config.clone(); 132 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index c79f01538..c5fc8de1d 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -1,6 +1,6 @@
1//! This example implements a UDP server listening on port 1234 and echoing back the data. 1//! This example implements a UDP server listening on port 1234 and echoing back the data.
2//! 2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. 3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board.
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
@@ -18,7 +18,6 @@ use embassy_rp::peripherals::SPI0;
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::Delay; 19use embassy_time::Delay;
20use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
21use rand::RngCore;
22use static_cell::StaticCell; 21use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
24 23
@@ -36,8 +35,8 @@ async fn ethernet_task(
36} 35}
37 36
38#[embassy_executor::task] 37#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 38async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 39 runner.run().await
41} 40}
42 41
43#[embassy_executor::main] 42#[embassy_executor::main]
@@ -71,17 +70,16 @@ async fn main(spawner: Spawner) {
71 let seed = rng.next_u64(); 70 let seed = rng.next_u64();
72 71
73 // Init network stack 72 // Init network stack
74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 73 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new( 74 let (stack, runner) = embassy_net::new(
77 device, 75 device,
78 embassy_net::Config::dhcpv4(Default::default()), 76 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::new()), 77 RESOURCES.init(StackResources::new()),
80 seed, 78 seed,
81 )); 79 );
82 80
83 // Launch network task 81 // Launch network task
84 unwrap!(spawner.spawn(net_task(&stack))); 82 unwrap!(spawner.spawn(net_task(runner)));
85 83
86 info!("Waiting for DHCP..."); 84 info!("Waiting for DHCP...");
87 let cfg = wait_for_config(stack).await; 85 let cfg = wait_for_config(stack).await;
@@ -108,7 +106,7 @@ async fn main(spawner: Spawner) {
108 } 106 }
109} 107}
110 108
111async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 109async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
112 loop { 110 loop {
113 if let Some(config) = stack.config_v4() { 111 if let Some(config) = stack.config_v4() {
114 return config.clone(); 112 return config.clone();
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
index 9fffb4646..08f31001b 100644
--- a/examples/rp/src/bin/i2c_slave.rs
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -99,19 +99,19 @@ async fn main(spawner: Spawner) {
99 let p = embassy_rp::init(Default::default()); 99 let p = embassy_rp::init(Default::default());
100 info!("Hello World!"); 100 info!("Hello World!");
101 101
102 let d_sda = p.PIN_3; 102 let d_sda = p.PIN_2;
103 let d_scl = p.PIN_2; 103 let d_scl = p.PIN_3;
104 let mut config = i2c_slave::Config::default(); 104 let mut config = i2c_slave::Config::default();
105 config.addr = DEV_ADDR as u16; 105 config.addr = DEV_ADDR as u16;
106 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); 106 let device = i2c_slave::I2cSlave::new(p.I2C1, d_scl, d_sda, Irqs, config);
107 107
108 unwrap!(spawner.spawn(device_task(device))); 108 unwrap!(spawner.spawn(device_task(device)));
109 109
110 let c_sda = p.PIN_1; 110 let c_sda = p.PIN_0;
111 let c_scl = p.PIN_0; 111 let c_scl = p.PIN_1;
112 let mut config = i2c::Config::default(); 112 let mut config = i2c::Config::default();
113 config.frequency = 1_000_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_scl, c_sda, Irqs, config);
115 115
116 unwrap!(spawner.spawn(controller_task(controller))); 116 unwrap!(spawner.spawn(controller_task(controller)));
117} 117}
diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs
index 5b9d7027e..787cdc112 100644
--- a/examples/rp/src/bin/interrupt.rs
+++ b/examples/rp/src/bin/interrupt.rs
@@ -32,7 +32,6 @@ static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
32 32
33#[embassy_executor::main] 33#[embassy_executor::main]
34async fn main(spawner: Spawner) { 34async fn main(spawner: Spawner) {
35 embassy_rp::pac::SIO.spinlock(31).write_value(1);
36 let p = embassy_rp::init(Default::default()); 35 let p = embassy_rp::init(Default::default());
37 36
38 let adc = Adc::new_blocking(p.ADC, Default::default()); 37 let adc = Adc::new_blocking(p.ADC, Default::default());
diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs
new file mode 100644
index 000000000..c35679251
--- /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//! The system consists of several tasks:
4//! - Three tasks that generate random numbers at different intervals (simulating i.e. sensor readings)
5//! - A task that monitors USB power connection (hardware event handling)
6//! - A task that reads system voltage (ADC sampling)
7//! - A consumer task that processes all this information
8//!
9//! The system maintains state in a single place, wrapped in a Mutex.
10//!
11//! We demonstrate how to:
12//! - use a mutex to maintain shared state between tasks
13//! - use a channel to send events between tasks
14//! - use an orchestrator task to coordinate tasks and handle state transitions
15//! - use signals to notify about state changes and terminate tasks
16
17#![no_std]
18#![no_main]
19
20use assign_resources::assign_resources;
21use defmt::*;
22use embassy_executor::Spawner;
23use embassy_futures::select::{select, Either};
24use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
25use embassy_rp::clocks::RoscRng;
26use embassy_rp::gpio::{Input, Pull};
27use embassy_rp::{bind_interrupts, peripherals, Peri};
28use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
29use embassy_sync::mutex::Mutex;
30use embassy_sync::{channel, signal};
31use embassy_time::{Duration, Timer};
32use {defmt_rtt as _, panic_probe as _};
33
34// Hardware resource assignment. See other examples for different ways of doing this.
35assign_resources! {
36 vsys: Vsys {
37 adc: ADC,
38 pin_29: PIN_29,
39 },
40 vbus: Vbus {
41 pin_24: PIN_24,
42 },
43}
44
45// Interrupt binding - required for hardware peripherals like ADC
46bind_interrupts!(struct Irqs {
47 ADC_IRQ_FIFO => InterruptHandler;
48});
49
50/// Events that worker tasks send to the orchestrator
51enum Events {
52 UsbPowered(bool), // USB connection state changed
53 VsysVoltage(f32), // New voltage reading
54 FirstRandomSeed(u32), // Random number from 30s timer
55 SecondRandomSeed(u32), // Random number from 60s timer
56 ThirdRandomSeed(u32), // Random number from 90s timer
57 ResetFirstRandomSeed, // Signal to reset the first counter
58}
59
60/// Commands that can control task behavior.
61/// Currently only used to stop tasks, but could be extended for other controls.
62enum Commands {
63 /// Signals a task to stop execution
64 Stop,
65}
66
67/// The central state of our system, shared between tasks.
68#[derive(Clone, Format)]
69struct State {
70 usb_powered: bool,
71 vsys_voltage: f32,
72 first_random_seed: u32,
73 second_random_seed: u32,
74 third_random_seed: u32,
75 first_random_seed_task_running: bool,
76 times_we_got_first_random_seed: u8,
77 maximum_times_we_want_first_random_seed: u8,
78}
79
80/// A formatted view of the system status, used for logging. Used for the below `get_system_summary` fn.
81#[derive(Format)]
82struct SystemStatus {
83 power_source: &'static str,
84 voltage: f32,
85}
86
87impl State {
88 const fn new() -> Self {
89 Self {
90 usb_powered: false,
91 vsys_voltage: 0.0,
92 first_random_seed: 0,
93 second_random_seed: 0,
94 third_random_seed: 0,
95 first_random_seed_task_running: false,
96 times_we_got_first_random_seed: 0,
97 maximum_times_we_want_first_random_seed: 3,
98 }
99 }
100
101 /// Returns a formatted summary of power state and voltage.
102 /// Shows how to create methods that work with shared state.
103 fn get_system_summary(&self) -> SystemStatus {
104 SystemStatus {
105 power_source: if self.usb_powered {
106 "USB powered"
107 } else {
108 "Battery powered"
109 },
110 voltage: self.vsys_voltage,
111 }
112 }
113}
114
115/// The shared state protected by a mutex
116static SYSTEM_STATE: Mutex<CriticalSectionRawMutex, State> = Mutex::new(State::new());
117
118/// Channel for events from worker tasks to the orchestrator
119static EVENT_CHANNEL: channel::Channel<CriticalSectionRawMutex, Events, 10> = channel::Channel::new();
120
121/// Signal used to stop the first random number task
122static STOP_FIRST_RANDOM_SIGNAL: signal::Signal<CriticalSectionRawMutex, Commands> = signal::Signal::new();
123
124/// Signal for notifying about state changes
125static STATE_CHANGED: signal::Signal<CriticalSectionRawMutex, ()> = signal::Signal::new();
126
127#[embassy_executor::main]
128async fn main(spawner: Spawner) {
129 let p = embassy_rp::init(Default::default());
130 let r = split_resources! {p};
131
132 spawner.spawn(orchestrate(spawner)).unwrap();
133 spawner.spawn(random_60s(spawner)).unwrap();
134 spawner.spawn(random_90s(spawner)).unwrap();
135 // `random_30s` is not spawned here, butin the orchestrate task depending on state
136 spawner.spawn(usb_power(spawner, r.vbus)).unwrap();
137 spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap();
138 spawner.spawn(consumer(spawner)).unwrap();
139}
140
141/// Main task that processes all events and updates system state.
142#[embassy_executor::task]
143async fn orchestrate(spawner: Spawner) {
144 let receiver = EVENT_CHANNEL.receiver();
145
146 loop {
147 // Do nothing until we receive any event
148 let event = receiver.receive().await;
149
150 // Scope in which we want to lock the system state. As an alternative we could also call `drop` on the state
151 {
152 let mut state = SYSTEM_STATE.lock().await;
153
154 match event {
155 Events::UsbPowered(usb_powered) => {
156 state.usb_powered = usb_powered;
157 info!("Usb powered: {}", usb_powered);
158 info!("System summary: {}", state.get_system_summary());
159 }
160 Events::VsysVoltage(voltage) => {
161 state.vsys_voltage = voltage;
162 info!("Vsys voltage: {}", voltage);
163 }
164 Events::FirstRandomSeed(seed) => {
165 state.first_random_seed = seed;
166 state.times_we_got_first_random_seed += 1;
167 info!(
168 "First random seed: {}, and that was iteration {} of receiving this.",
169 seed, &state.times_we_got_first_random_seed
170 );
171 }
172 Events::SecondRandomSeed(seed) => {
173 state.second_random_seed = seed;
174 info!("Second random seed: {}", seed);
175 }
176 Events::ThirdRandomSeed(seed) => {
177 state.third_random_seed = seed;
178 info!("Third random seed: {}", seed);
179 }
180 Events::ResetFirstRandomSeed => {
181 state.times_we_got_first_random_seed = 0;
182 state.first_random_seed = 0;
183 info!("Resetting the first random seed counter");
184 }
185 }
186
187 // Handle task orchestration based on state
188 // Just placed as an example here, could be hooked into the event system, puton a timer, ...
189 match state.times_we_got_first_random_seed {
190 max if max == state.maximum_times_we_want_first_random_seed => {
191 info!("Stopping the first random signal task");
192 STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop);
193 EVENT_CHANNEL.sender().send(Events::ResetFirstRandomSeed).await;
194 }
195 0 => {
196 let respawn_first_random_seed_task = !state.first_random_seed_task_running;
197 // Deliberately dropping the Mutex lock here to release it before a lengthy operation
198 drop(state);
199 if respawn_first_random_seed_task {
200 info!("(Re)-Starting the first random signal task");
201 spawner.spawn(random_30s(spawner)).unwrap();
202 }
203 }
204 _ => {}
205 }
206 }
207
208 STATE_CHANGED.signal(());
209 }
210}
211
212/// Task that monitors state changes and logs system status.
213#[embassy_executor::task]
214async fn consumer(_spawner: Spawner) {
215 loop {
216 // Wait for state change notification
217 STATE_CHANGED.wait().await;
218
219 let state = SYSTEM_STATE.lock().await;
220 info!(
221 "State update - {} | Seeds - First: {} (count: {}/{}, running: {}), Second: {}, Third: {}",
222 state.get_system_summary(),
223 state.first_random_seed,
224 state.times_we_got_first_random_seed,
225 state.maximum_times_we_want_first_random_seed,
226 state.first_random_seed_task_running,
227 state.second_random_seed,
228 state.third_random_seed
229 );
230 }
231}
232
233/// Task that generates random numbers every 30 seconds until stopped.
234/// Shows how to handle both timer events and stop signals.
235/// As an example of some routine we want to be on or off depending on other needs.
236#[embassy_executor::task]
237async fn random_30s(_spawner: Spawner) {
238 {
239 let mut state = SYSTEM_STATE.lock().await;
240 state.first_random_seed_task_running = true;
241 }
242
243 let mut rng = RoscRng;
244 let sender = EVENT_CHANNEL.sender();
245
246 loop {
247 // Wait for either 30s timer or stop signal (like select() in Go)
248 match select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await {
249 Either::First(_) => {
250 info!("30s are up, generating random number");
251 let random_number = rng.next_u32();
252 sender.send(Events::FirstRandomSeed(random_number)).await;
253 }
254 Either::Second(_) => {
255 info!("Received signal to stop, goodbye!");
256
257 let mut state = SYSTEM_STATE.lock().await;
258 state.first_random_seed_task_running = false;
259
260 break;
261 }
262 }
263 }
264}
265
266/// Task that generates random numbers every 60 seconds. As an example of some routine.
267#[embassy_executor::task]
268async fn random_60s(_spawner: Spawner) {
269 let mut rng = RoscRng;
270 let sender = EVENT_CHANNEL.sender();
271
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/// Task that generates random numbers every 90 seconds. . As an example of some routine.
280#[embassy_executor::task]
281async fn random_90s(_spawner: Spawner) {
282 let mut rng = RoscRng;
283 let sender = EVENT_CHANNEL.sender();
284
285 loop {
286 Timer::after(Duration::from_secs(90)).await;
287 let random_number = rng.next_u32();
288 sender.send(Events::ThirdRandomSeed(random_number)).await;
289 }
290}
291
292/// Task that monitors USB power connection. As an example of some Interrupt somewhere.
293#[embassy_executor::task]
294pub async fn usb_power(_spawner: Spawner, r: Vbus) {
295 let mut vbus_in = Input::new(r.pin_24, Pull::None);
296 let sender = EVENT_CHANNEL.sender();
297
298 loop {
299 sender.send(Events::UsbPowered(vbus_in.is_high())).await;
300 vbus_in.wait_for_any_edge().await;
301 }
302}
303
304/// Task that reads system voltage through ADC. As an example of some continuous sensor reading.
305#[embassy_executor::task]
306pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) {
307 let mut adc = Adc::new(r.adc, Irqs, Config::default());
308 let vsys_in = r.pin_29;
309 let mut channel = Channel::new_pin(vsys_in, Pull::None);
310 let sender = EVENT_CHANNEL.sender();
311
312 loop {
313 Timer::after(Duration::from_secs(30)).await;
314 let adc_value = adc.read(&mut channel).await.unwrap();
315 let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0;
316 sender.send(Events::VsysVoltage(voltage)).await;
317 }
318}
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs
new file mode 100644
index 000000000..83b17308b
--- /dev/null
+++ b/examples/rp/src/bin/overclock.rs
@@ -0,0 +1,64 @@
1//! # Overclocking the RP2040 to 200 MHz
2//!
3//! This example demonstrates how to configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig};
11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
21 let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap());
22
23 // Initialize the peripherals
24 let p = embassy_rp::init(config);
25
26 // Show CPU frequency for verification
27 let sys_freq = clk_sys_freq();
28 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
29 // Show core voltage for verification
30 let core_voltage = core_voltage().unwrap();
31 info!("Core voltage: {}", core_voltage);
32
33 // LED to indicate the system is running
34 let mut led = Output::new(p.PIN_25, Level::Low);
35
36 loop {
37 // Reset the counter at the start of measurement period
38 let mut counter = 0;
39
40 // Turn LED on while counting
41 led.set_high();
42
43 let start = Instant::now();
44
45 // This is a busy loop that will take some time to complete
46 while counter < COUNT_TO {
47 counter += 1;
48 }
49
50 let elapsed = Instant::now() - start;
51
52 // Report the elapsed time
53 led.set_low();
54 info!(
55 "At {}Mhz: Elapsed time to count to {}: {}ms",
56 sys_freq / 1_000_000,
57 counter,
58 elapsed.as_millis()
59 );
60
61 // Wait 2 seconds before starting the next measurement
62 Timer::after(Duration::from_secs(2)).await;
63 }
64}
diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs
new file mode 100644
index 000000000..dea5cfb3c
--- /dev/null
+++ b/examples/rp/src/bin/overclock_manual.rs
@@ -0,0 +1,81 @@
1//! # Overclocking the RP2040 to 200 MHz manually
2//!
3//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig};
11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings.
19fn configure_manual_overclock() -> Config {
20 // Set the PLL configuration manually, starting from default values
21 let mut config = Config::default();
22
23 // Set the system clock to 200 MHz
24 config.clocks = ClockConfig::manual_pll(
25 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value.
26 PllConfig {
27 refdiv: 1, // Reference divider
28 fbdiv: 100, // Feedback divider
29 post_div1: 3, // Post divider 1
30 post_div2: 2, // Post divider 2
31 },
32 CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz
33 );
34
35 config
36}
37
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) -> ! {
40 // Initialize with our manual overclock configuration
41 let p = embassy_rp::init(configure_manual_overclock());
42
43 // Show CPU frequency for verification
44 let sys_freq = clk_sys_freq();
45 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
46 // Show core voltage for verification
47 let core_voltage = core_voltage().unwrap();
48 info!("Core voltage: {}", core_voltage);
49
50 // LED to indicate the system is running
51 let mut led = Output::new(p.PIN_25, Level::Low);
52
53 loop {
54 // Reset the counter at the start of measurement period
55 let mut counter = 0;
56
57 // Turn LED on while counting
58 led.set_high();
59
60 let start = Instant::now();
61
62 // This is a busy loop that will take some time to complete
63 while counter < COUNT_TO {
64 counter += 1;
65 }
66
67 let elapsed = Instant::now() - start;
68
69 // Report the elapsed time
70 led.set_low();
71 info!(
72 "At {}Mhz: Elapsed time to count to {}: {}ms",
73 sys_freq / 1_000_000,
74 counter,
75 elapsed.as_millis()
76 );
77
78 // Wait 2 seconds before starting the next measurement
79 Timer::after(Duration::from_secs(2)).await;
80 }
81}
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index ee248591b..bf6dbee69 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -4,9 +4,10 @@
4#![no_main] 4#![no_main]
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0; 7use embassy_rp::peripherals::PIO0;
8use embassy_rp::pio::program::pio_asm;
9use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; 9use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
10use embassy_rp::{bind_interrupts, Peri};
10use fixed::traits::ToFixed; 11use fixed::traits::ToFixed;
11use fixed_macro::types::U56F8; 12use fixed_macro::types::U56F8;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -15,11 +16,11 @@ bind_interrupts!(struct Irqs {
15 PIO0_IRQ_0 => InterruptHandler<PIO0>; 16 PIO0_IRQ_0 => InterruptHandler<PIO0>;
16}); 17});
17 18
18fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { 19fn setup_pio_task_sm0<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 0>, pin: Peri<'d, impl PioPin>) {
19 // Setup sm0 20 // Setup sm0
20 21
21 // Send data serially to pin 22 // Send data serially to pin
22 let prg = pio_proc::pio_asm!( 23 let prg = pio_asm!(
23 ".origin 16", 24 ".origin 16",
24 "set pindirs, 1", 25 "set pindirs, 1",
25 ".wrap_target", 26 ".wrap_target",
@@ -49,11 +50,11 @@ async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
49 } 50 }
50} 51}
51 52
52fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) { 53fn setup_pio_task_sm1<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 1>) {
53 // Setupm sm1 54 // Setupm sm1
54 55
55 // Read 0b10101 repeatedly until ISR is full 56 // Read 0b10101 repeatedly until ISR is full
56 let prg = pio_proc::pio_asm!( 57 let prg = pio_asm!(
57 // 58 //
58 ".origin 8", 59 ".origin 8",
59 "set x, 0x15", 60 "set x, 0x15",
@@ -79,11 +80,11 @@ async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
79 } 80 }
80} 81}
81 82
82fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) { 83fn setup_pio_task_sm2<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 2>) {
83 // Setup sm2 84 // Setup sm2
84 85
85 // Repeatedly trigger IRQ 3 86 // Repeatedly trigger IRQ 3
86 let prg = pio_proc::pio_asm!( 87 let prg = pio_asm!(
87 ".origin 0", 88 ".origin 0",
88 ".wrap_target", 89 ".wrap_target",
89 "set x,10", 90 "set x,10",
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 02700269c..64d603ba4 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -5,9 +5,10 @@
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join; 7use embassy_futures::join::join;
8use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::program::pio_asm;
9use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; 11use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
10use embassy_rp::{bind_interrupts, Peripheral};
11use fixed::traits::ToFixed; 12use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8; 13use fixed_macro::types::U56F8;
13use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -32,7 +33,7 @@ async fn main(_spawner: Spawner) {
32 .. 33 ..
33 } = Pio::new(pio, Irqs); 34 } = Pio::new(pio, Irqs);
34 35
35 let prg = pio_proc::pio_asm!( 36 let prg = pio_asm!(
36 ".origin 0", 37 ".origin 0",
37 "set pindirs,1", 38 "set pindirs,1",
38 ".wrap_target", 39 ".wrap_target",
@@ -61,8 +62,8 @@ async fn main(_spawner: Spawner) {
61 sm.set_config(&cfg); 62 sm.set_config(&cfg);
62 sm.set_enable(true); 63 sm.set_enable(true);
63 64
64 let mut dma_out_ref = p.DMA_CH0.into_ref(); 65 let mut dma_out_ref = p.DMA_CH0;
65 let mut dma_in_ref = p.DMA_CH1.into_ref(); 66 let mut dma_in_ref = p.DMA_CH1;
66 let mut dout = [0x12345678u32; 29]; 67 let mut dout = [0x12345678u32; 29];
67 for i in 1..dout.len() { 68 for i in 1..dout.len() {
68 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; 69 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
@@ -71,8 +72,8 @@ async fn main(_spawner: Spawner) {
71 loop { 72 loop {
72 let (rx, tx) = sm.rx_tx(); 73 let (rx, tx) = sm.rx_tx();
73 join( 74 join(
74 tx.dma_push(dma_out_ref.reborrow(), &dout), 75 tx.dma_push(dma_out_ref.reborrow(), &dout, false),
75 rx.dma_pull(dma_in_ref.reborrow(), &mut din), 76 rx.dma_pull(dma_in_ref.reborrow(), &mut din, false),
76 ) 77 )
77 .await; 78 .await;
78 for i in 0..din.len() { 79 for i in 0..din.len() {
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index 6c02630e0..164e6f8d3 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -7,13 +7,11 @@
7use core::fmt::Write; 7use core::fmt::Write;
8 8
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::dma::{AnyChannel, Channel}; 10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0; 11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{ 12use embassy_rp::pio::{InterruptHandler, Pio};
13 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 13use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram};
14};
15use embassy_rp::pwm::{self, Pwm}; 14use embassy_rp::pwm::{self, Pwm};
16use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
17use embassy_time::{Instant, Timer}; 15use embassy_time::{Instant, Timer};
18use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
19 17
@@ -43,8 +41,27 @@ async fn main(_spawner: Spawner) {
43 c 41 c
44 }); 42 });
45 43
46 let mut hd = HD44780::new( 44 let Pio {
47 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, 45 mut common, sm0, irq0, ..
46 } = Pio::new(p.PIO0, Irqs);
47
48 let word_prg = PioHD44780CommandWordProgram::new(&mut common);
49 let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common);
50
51 let mut hd = PioHD44780::new(
52 &mut common,
53 sm0,
54 irq0,
55 p.DMA_CH3,
56 p.PIN_0,
57 p.PIN_1,
58 p.PIN_2,
59 p.PIN_3,
60 p.PIN_4,
61 p.PIN_5,
62 p.PIN_6,
63 &word_prg,
64 &seq_prg,
48 ) 65 )
49 .await; 66 .await;
50 67
@@ -68,173 +85,3 @@ async fn main(_spawner: Spawner) {
68 Timer::after_secs(1).await; 85 Timer::after_secs(1).await;
69 } 86 }
70} 87}
71
72pub struct HD44780<'l> {
73 dma: PeripheralRef<'l, AnyChannel>,
74 sm: StateMachine<'l, PIO0, 0>,
75
76 buf: [u8; 40],
77}
78
79impl<'l> HD44780<'l> {
80 pub async fn new(
81 pio: impl Peripheral<P = PIO0> + 'l,
82 irq: Irqs,
83 dma: impl Peripheral<P = impl Channel> + 'l,
84 rs: impl PioPin,
85 rw: impl PioPin,
86 e: impl PioPin,
87 db4: impl PioPin,
88 db5: impl PioPin,
89 db6: impl PioPin,
90 db7: impl PioPin,
91 ) -> HD44780<'l> {
92 into_ref!(dma);
93
94 let Pio {
95 mut common,
96 mut irq0,
97 mut sm0,
98 ..
99 } = Pio::new(pio, irq);
100
101 // takes command words (<wait:24> <command:4> <0:4>)
102 let prg = pio_proc::pio_asm!(
103 r#"
104 .side_set 1 opt
105 .origin 20
106
107 loop:
108 out x, 24
109 delay:
110 jmp x--, delay
111 out pins, 4 side 1
112 out null, 4 side 0
113 jmp !osre, loop
114 irq 0
115 "#,
116 );
117
118 let rs = common.make_pio_pin(rs);
119 let rw = common.make_pio_pin(rw);
120 let e = common.make_pio_pin(e);
121 let db4 = common.make_pio_pin(db4);
122 let db5 = common.make_pio_pin(db5);
123 let db6 = common.make_pio_pin(db6);
124 let db7 = common.make_pio_pin(db7);
125
126 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
127
128 let mut cfg = Config::default();
129 cfg.use_program(&common.load_program(&prg.program), &[&e]);
130 cfg.clock_divider = 125u8.into();
131 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
132 cfg.shift_out = ShiftConfig {
133 auto_fill: true,
134 direction: ShiftDirection::Left,
135 threshold: 32,
136 };
137 cfg.fifo_join = FifoJoin::TxOnly;
138 sm0.set_config(&cfg);
139
140 sm0.set_enable(true);
141 // init to 8 bit thrice
142 sm0.tx().push((50000 << 8) | 0x30);
143 sm0.tx().push((5000 << 8) | 0x30);
144 sm0.tx().push((200 << 8) | 0x30);
145 // init 4 bit
146 sm0.tx().push((200 << 8) | 0x20);
147 // set font and lines
148 sm0.tx().push((50 << 8) | 0x20);
149 sm0.tx().push(0b1100_0000);
150
151 irq0.wait().await;
152 sm0.set_enable(false);
153
154 // takes command sequences (<rs:1> <count:7>, data...)
155 // many side sets are only there to free up a delay bit!
156 let prg = pio_proc::pio_asm!(
157 r#"
158 .origin 27
159 .side_set 1
160
161 .wrap_target
162 pull side 0
163 out x 1 side 0 ; !rs
164 out y 7 side 0 ; #data - 1
165
166 ; rs/rw to e: >= 60ns
167 ; e high time: >= 500ns
168 ; e low time: >= 500ns
169 ; read data valid after e falling: ~5ns
170 ; write data hold after e falling: ~10ns
171
172 loop:
173 pull side 0
174 jmp !x data side 0
175 command:
176 set pins 0b00 side 0
177 jmp shift side 0
178 data:
179 set pins 0b01 side 0
180 shift:
181 out pins 4 side 1 [9]
182 nop side 0 [9]
183 out pins 4 side 1 [9]
184 mov osr null side 0 [7]
185 out pindirs 4 side 0
186 set pins 0b10 side 0
187 busy:
188 nop side 1 [9]
189 jmp pin more side 0 [9]
190 mov osr ~osr side 1 [9]
191 nop side 0 [4]
192 out pindirs 4 side 0
193 jmp y-- loop side 0
194 .wrap
195 more:
196 nop side 1 [9]
197 jmp busy side 0 [9]
198 "#
199 );
200
201 let mut cfg = Config::default();
202 cfg.use_program(&common.load_program(&prg.program), &[&e]);
203 cfg.clock_divider = 8u8.into(); // ~64ns/insn
204 cfg.set_jmp_pin(&db7);
205 cfg.set_set_pins(&[&rs, &rw]);
206 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
207 cfg.shift_out.direction = ShiftDirection::Left;
208 cfg.fifo_join = FifoJoin::TxOnly;
209 sm0.set_config(&cfg);
210
211 sm0.set_enable(true);
212
213 // display on and cursor on and blinking, reset display
214 sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
215
216 Self {
217 dma: dma.map_into(),
218 sm: sm0,
219 buf: [0x20; 40],
220 }
221 }
222
223 pub async fn add_line(&mut self, s: &[u8]) {
224 // move cursor to 0:0, prepare 16 characters
225 self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
226 // move line 2 up
227 self.buf.copy_within(22..38, 3);
228 // move cursor to 1:0, prepare 16 characters
229 self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
230 // file line 2 with spaces
231 self.buf[22..38].fill(0x20);
232 // copy input line
233 let len = s.len().min(16);
234 self.buf[22..22 + len].copy_from_slice(&s[0..len]);
235 // set cursor to 1:15
236 self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
237
238 self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
239 }
240}
diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs
index cf60e5b30..695a74cc3 100644
--- a/examples/rp/src/bin/pio_i2s.rs
+++ b/examples/rp/src/bin/pio_i2s.rs
@@ -13,10 +13,11 @@
13use core::mem; 13use core::mem;
14 14
15use embassy_executor::Spawner; 15use embassy_executor::Spawner;
16use embassy_rp::bind_interrupts;
17use embassy_rp::bootsel::is_bootsel_pressed;
16use embassy_rp::peripherals::PIO0; 18use embassy_rp::peripherals::PIO0;
17use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; 19use embassy_rp::pio::{InterruptHandler, Pio};
18use embassy_rp::{bind_interrupts, Peripheral}; 20use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram};
19use fixed::traits::ToFixed;
20use static_cell::StaticCell; 21use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
22 23
@@ -25,61 +26,30 @@ bind_interrupts!(struct Irqs {
25}); 26});
26 27
27const SAMPLE_RATE: u32 = 48_000; 28const SAMPLE_RATE: u32 = 48_000;
29const BIT_DEPTH: u32 = 16;
28 30
29#[embassy_executor::main] 31#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 32async fn main(_spawner: Spawner) {
31 let mut p = embassy_rp::init(Default::default()); 33 let mut p = embassy_rp::init(Default::default());
32 34
33 // Setup pio state machine for i2s output 35 // Setup pio state machine for i2s output
34 let mut pio = Pio::new(p.PIO0, Irqs); 36 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
35
36 #[rustfmt::skip]
37 let pio_program = pio_proc::pio_asm!(
38 ".side_set 2",
39 " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock
40 "left_data:",
41 " out pins, 1 side 0b00",
42 " jmp x-- left_data side 0b01",
43 " out pins 1 side 0b10",
44 " set x, 14 side 0b11",
45 "right_data:",
46 " out pins 1 side 0b10",
47 " jmp x-- right_data side 0b11",
48 " out pins 1 side 0b00",
49 );
50 37
51 let bit_clock_pin = p.PIN_18; 38 let bit_clock_pin = p.PIN_18;
52 let left_right_clock_pin = p.PIN_19; 39 let left_right_clock_pin = p.PIN_19;
53 let data_pin = p.PIN_20; 40 let data_pin = p.PIN_20;
54 41
55 let data_pin = pio.common.make_pio_pin(data_pin); 42 let program = PioI2sOutProgram::new(&mut common);
56 let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); 43 let mut i2s = PioI2sOut::new(
57 let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); 44 &mut common,
58 45 sm0,
59 let cfg = { 46 p.DMA_CH0,
60 let mut cfg = Config::default(); 47 data_pin,
61 cfg.use_program( 48 bit_clock_pin,
62 &pio.common.load_program(&pio_program.program), 49 left_right_clock_pin,
63 &[&bit_clock_pin, &left_right_clock_pin], 50 SAMPLE_RATE,
64 ); 51 BIT_DEPTH,
65 cfg.set_out_pins(&[&data_pin]); 52 &program,
66 const BIT_DEPTH: u32 = 16;
67 const CHANNELS: u32 = 2;
68 let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS;
69 cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed();
70 cfg.shift_out = ShiftConfig {
71 threshold: 32,
72 direction: ShiftDirection::Left,
73 auto_fill: true,
74 };
75 // join fifos to have twice the time to start the next dma transfer
76 cfg.fifo_join = FifoJoin::TxOnly;
77 cfg
78 };
79 pio.sm0.set_config(&cfg);
80 pio.sm0.set_pin_dirs(
81 embassy_rp::pio::Direction::Out,
82 &[&data_pin, &left_right_clock_pin, &bit_clock_pin],
83 ); 53 );
84 54
85 // create two audio buffers (back and front) which will take turns being 55 // create two audio buffers (back and front) which will take turns being
@@ -90,20 +60,20 @@ async fn main(_spawner: Spawner) {
90 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); 60 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE);
91 61
92 // start pio state machine 62 // start pio state machine
93 pio.sm0.set_enable(true);
94 let tx = pio.sm0.tx();
95 let mut dma_ref = p.DMA_CH0.into_ref();
96
97 let mut fade_value: i32 = 0; 63 let mut fade_value: i32 = 0;
98 let mut phase: i32 = 0; 64 let mut phase: i32 = 0;
99 65
100 loop { 66 loop {
101 // trigger transfer of front buffer data to the pio fifo 67 // trigger transfer of front buffer data to the pio fifo
102 // but don't await the returned future, yet 68 // but don't await the returned future, yet
103 let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); 69 let dma_future = i2s.write(front_buffer);
104 70
105 // fade in audio when bootsel is pressed 71 // fade in audio when bootsel is pressed
106 let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; 72 let fade_target = if is_bootsel_pressed(p.BOOTSEL.reborrow()) {
73 i32::MAX
74 } else {
75 0
76 };
107 77
108 // fill back buffer with fresh audio samples before awaiting the dma future 78 // fill back buffer with fresh audio samples before awaiting the dma future
109 for s in back_buffer.iter_mut() { 79 for s in back_buffer.iter_mut() {
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
new file mode 100644
index 000000000..379e2b8f9
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -0,0 +1,87 @@
1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
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::{InterruptHandler, Pio};
10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
11use embassy_time::Timer;
12use heapless::Vec;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 PIO0_IRQ_0 => InterruptHandler<PIO0>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_rp::init(Default::default());
22 let mut pio = Pio::new(p.PIO0, Irqs);
23
24 let prg = PioOneWireProgram::new(&mut pio.common);
25 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
26
27 info!("Starting onewire search");
28
29 let mut devices = Vec::<u64, 10>::new();
30 let mut search = PioOneWireSearch::new();
31 for _ in 0..10 {
32 if !search.is_finished() {
33 if let Some(address) = search.next(&mut onewire).await {
34 if crc8(&address.to_le_bytes()) == 0 {
35 info!("Found addres: {:x}", address);
36 let _ = devices.push(address);
37 } else {
38 warn!("Found invalid address: {:x}", address);
39 }
40 }
41 }
42 }
43
44 info!("Search done, found {} devices", devices.len());
45
46 loop {
47 onewire.reset().await;
48 // Skip rom and trigger conversion, we can trigger all devices on the bus immediately
49 onewire.write_bytes(&[0xCC, 0x44]).await;
50
51 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
52
53 // Read all devices one by one
54 for device in &devices {
55 onewire.reset().await;
56 onewire.write_bytes(&[0x55]).await; // Match rom
57 onewire.write_bytes(&device.to_le_bytes()).await;
58 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
59
60 let mut data = [0; 9];
61 onewire.read_bytes(&mut data).await;
62 if crc8(&data) == 0 {
63 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
64 info!("Read device {:x}: {} deg C", device, temp);
65 } else {
66 warn!("Reading device {:x} failed", device);
67 }
68 }
69 Timer::after_secs(1).await;
70 }
71}
72
73fn crc8(data: &[u8]) -> u8 {
74 let mut crc = 0;
75 for b in data {
76 let mut data_byte = *b;
77 for _ in 0..8 {
78 let temp = (crc ^ data_byte) & 0x01;
79 crc >>= 1;
80 if temp != 0 {
81 crc ^= 0x8C;
82 }
83 data_byte >>= 1;
84 }
85 }
86 crc
87}
diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs
index 23d63d435..7eabb2289 100644
--- a/examples/rp/src/bin/pio_pwm.rs
+++ b/examples/rp/src/bin/pio_pwm.rs
@@ -5,12 +5,11 @@
5use core::time::Duration; 5use core::time::Duration;
6 6
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::gpio::Level; 8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; 10use embassy_rp::pio::{InterruptHandler, Pio};
11use embassy_rp::{bind_interrupts, clocks}; 11use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use pio::InstructionOperands;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
16const REFRESH_INTERVAL: u64 = 20000; 15const REFRESH_INTERVAL: u64 = 20000;
@@ -19,93 +18,14 @@ bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>; 18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20}); 19});
21 20
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] 21#[embassy_executor::main]
103async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
104 let p = embassy_rp::init(Default::default()); 23 let p = embassy_rp::init(Default::default());
105 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); 24 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
106 25
107 // Note that PIN_25 is the led pin on the Pico 26 // Note that PIN_25 is the led pin on the Pico
108 let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); 27 let prg = PioPwmProgram::new(&mut common);
28 let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg);
109 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); 29 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL));
110 pwm_pio.start(); 30 pwm_pio.start();
111 31
diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs
index 58bdadbc0..2750f61ae 100644
--- a/examples/rp/src/bin/pio_rotary_encoder.rs
+++ b/examples/rp/src/bin/pio_rotary_encoder.rs
@@ -5,70 +5,30 @@
5 5
6use defmt::info; 6use defmt::info;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::gpio::Pull; 8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::{bind_interrupts, pio}; 10use embassy_rp::pio::{InterruptHandler, Pio};
11use fixed::traits::ToFixed; 11use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram};
12use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine};
13use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
14 13
15bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
16 PIO0_IRQ_0 => InterruptHandler<PIO0>; 15 PIO0_IRQ_0 => InterruptHandler<PIO0>;
17}); 16});
18 17
19pub struct PioEncoder<'d, T: Instance, const SM: usize> { 18#[embassy_executor::task]
20 sm: StateMachine<'d, T, SM>, 19async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) {
21} 20 let mut count = 0;
22 21 loop {
23impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { 22 info!("Count: {}", count);
24 pub fn new( 23 count += match encoder.read().await {
25 pio: &mut Common<'d, T>, 24 Direction::Clockwise => 1,
26 mut sm: StateMachine<'d, T, SM>, 25 Direction::CounterClockwise => -1,
27 pin_a: impl PioPin, 26 };
28 pin_b: impl PioPin,
29 ) -> Self {
30 let mut pin_a = pio.make_pio_pin(pin_a);
31 let mut pin_b = pio.make_pio_pin(pin_b);
32 pin_a.set_pull(Pull::Up);
33 pin_b.set_pull(Pull::Up);
34 sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]);
35
36 let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",);
37
38 let mut cfg = Config::default();
39 cfg.set_in_pins(&[&pin_a, &pin_b]);
40 cfg.fifo_join = FifoJoin::RxOnly;
41 cfg.shift_in.direction = ShiftDirection::Left;
42 cfg.clock_divider = 10_000.to_fixed();
43 cfg.use_program(&pio.load_program(&prg.program), &[]);
44 sm.set_config(&cfg);
45 sm.set_enable(true);
46 Self { sm }
47 }
48
49 pub async fn read(&mut self) -> Direction {
50 loop {
51 match self.sm.rx().wait_pull().await {
52 0 => return Direction::CounterClockwise,
53 1 => return Direction::Clockwise,
54 _ => {}
55 }
56 }
57 } 27 }
58} 28}
59 29
60pub enum Direction { 30#[embassy_executor::task]
61 Clockwise, 31async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) {
62 CounterClockwise,
63}
64
65#[embassy_executor::main]
66async fn main(_spawner: Spawner) {
67 let p = embassy_rp::init(Default::default());
68 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
69
70 let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5);
71
72 let mut count = 0; 32 let mut count = 0;
73 loop { 33 loop {
74 info!("Count: {}", count); 34 info!("Count: {}", count);
@@ -78,3 +38,18 @@ async fn main(_spawner: Spawner) {
78 }; 38 };
79 } 39 }
80} 40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let Pio {
46 mut common, sm0, sm1, ..
47 } = Pio::new(p.PIO0, Irqs);
48
49 let prg = PioEncoderProgram::new(&mut common);
50 let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg);
51 let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg);
52
53 spawner.must_spawn(encoder_0(encoder0));
54 spawner.must_spawn(encoder_1(encoder1));
55}
diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs
index a79540479..c52ee7492 100644
--- a/examples/rp/src/bin/pio_servo.rs
+++ b/examples/rp/src/bin/pio_servo.rs
@@ -5,12 +5,11 @@
5use core::time::Duration; 5use core::time::Duration;
6 6
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::gpio::Level; 8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; 10use embassy_rp::pio::{Instance, InterruptHandler, Pio};
11use embassy_rp::{bind_interrupts, clocks}; 11use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use pio::InstructionOperands;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
16const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo 15const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo
@@ -22,88 +21,8 @@ bind_interrupts!(struct Irqs {
22 PIO0_IRQ_0 => InterruptHandler<PIO0>; 21 PIO0_IRQ_0 => InterruptHandler<PIO0>;
23}); 22});
24 23
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> { 24pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
106 pwm: PwmPio<'d, T, SM>, 25 pwm: PioPwm<'d, T, SM>,
107 period: Duration, 26 period: Duration,
108 min_pulse_width: Duration, 27 min_pulse_width: Duration,
109 max_pulse_width: Duration, 28 max_pulse_width: Duration,
@@ -111,7 +30,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
111} 30}
112 31
113impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { 32impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
114 pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { 33 pub fn new(pwm: PioPwm<'d, T, SM>) -> Self {
115 Self { 34 Self {
116 pwm, 35 pwm,
117 period: Duration::from_micros(REFRESH_INTERVAL), 36 period: Duration::from_micros(REFRESH_INTERVAL),
@@ -153,7 +72,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
153} 72}
154 73
155pub struct Servo<'d, T: Instance, const SM: usize> { 74pub struct Servo<'d, T: Instance, const SM: usize> {
156 pwm: PwmPio<'d, T, SM>, 75 pwm: PioPwm<'d, T, SM>,
157 min_pulse_width: Duration, 76 min_pulse_width: Duration,
158 max_pulse_width: Duration, 77 max_pulse_width: Duration,
159 max_degree_rotation: u64, 78 max_degree_rotation: u64,
@@ -190,7 +109,8 @@ async fn main(_spawner: Spawner) {
190 let p = embassy_rp::init(Default::default()); 109 let p = embassy_rp::init(Default::default());
191 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); 110 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
192 111
193 let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); 112 let prg = PioPwmProgram::new(&mut common);
113 let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg);
194 let mut servo = ServoBuilder::new(pwm_pio) 114 let mut servo = ServoBuilder::new(pwm_pio)
195 .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo 115 .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. 116 .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment.
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs
index 4952f4fbd..3862c248b 100644
--- a/examples/rp/src/bin/pio_stepper.rs
+++ b/examples/rp/src/bin/pio_stepper.rs
@@ -3,143 +3,20 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6use core::mem::{self, MaybeUninit};
7 6
8use defmt::info; 7use defmt::info;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; 11use embassy_rp::pio::{InterruptHandler, Pio};
12use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram};
13use embassy_time::{with_timeout, Duration, Timer}; 13use embassy_time::{with_timeout, Duration, Timer};
14use fixed::traits::ToFixed;
15use fixed::types::extra::U8;
16use fixed::FixedU32;
17use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
18 15
19bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
20 PIO0_IRQ_0 => InterruptHandler<PIO0>; 17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
21}); 18});
22 19
23pub struct PioStepper<'d, T: Instance, const SM: usize> {
24 irq: Irq<'d, T, SM>,
25 sm: StateMachine<'d, T, SM>,
26}
27
28impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
29 pub fn new(
30 pio: &mut Common<'d, T>,
31 mut sm: StateMachine<'d, T, SM>,
32 irq: Irq<'d, T, SM>,
33 pin0: impl PioPin,
34 pin1: impl PioPin,
35 pin2: impl PioPin,
36 pin3: impl PioPin,
37 ) -> Self {
38 let prg = pio_proc::pio_asm!(
39 "pull block",
40 "mov x, osr",
41 "pull block",
42 "mov y, osr",
43 "jmp !x end",
44 "loop:",
45 "jmp !osre step",
46 "mov osr, y",
47 "step:",
48 "out pins, 4 [31]"
49 "jmp x-- loop",
50 "end:",
51 "irq 0 rel"
52 );
53 let pin0 = pio.make_pio_pin(pin0);
54 let pin1 = pio.make_pio_pin(pin1);
55 let pin2 = pio.make_pio_pin(pin2);
56 let pin3 = pio.make_pio_pin(pin3);
57 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
58 let mut cfg = Config::default();
59 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
60 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
61 cfg.use_program(&pio.load_program(&prg.program), &[]);
62 sm.set_config(&cfg);
63 sm.set_enable(true);
64 Self { irq, sm }
65 }
66
67 // Set pulse frequency
68 pub fn set_frequency(&mut self, freq: u32) {
69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
71 assert!(clock_divider >= 1, "clkdiv must be >= 1");
72 self.sm.set_clock_divider(clock_divider);
73 self.sm.clkdiv_restart();
74 }
75
76 // Full step, one phase
77 pub async fn step(&mut self, steps: i32) {
78 if steps > 0 {
79 self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await
80 } else {
81 self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await
82 }
83 }
84
85 // Full step, two phase
86 pub async fn step2(&mut self, steps: i32) {
87 if steps > 0 {
88 self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await
89 } else {
90 self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await
91 }
92 }
93
94 // Half step
95 pub async fn step_half(&mut self, steps: i32) {
96 if steps > 0 {
97 self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await
98 } else {
99 self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await
100 }
101 }
102
103 async fn run(&mut self, steps: i32, pattern: u32) {
104 self.sm.tx().wait_push(steps as u32).await;
105 self.sm.tx().wait_push(pattern).await;
106 let drop = OnDrop::new(|| {
107 self.sm.clear_fifos();
108 unsafe {
109 self.sm.exec_instr(
110 pio::InstructionOperands::JMP {
111 address: 0,
112 condition: pio::JmpCondition::Always,
113 }
114 .encode(),
115 );
116 }
117 });
118 self.irq.wait().await;
119 drop.defuse();
120 }
121}
122
123struct OnDrop<F: FnOnce()> {
124 f: MaybeUninit<F>,
125}
126
127impl<F: FnOnce()> OnDrop<F> {
128 pub fn new(f: F) -> Self {
129 Self { f: MaybeUninit::new(f) }
130 }
131
132 pub fn defuse(self) {
133 mem::forget(self)
134 }
135}
136
137impl<F: FnOnce()> Drop for OnDrop<F> {
138 fn drop(&mut self) {
139 unsafe { self.f.as_ptr().read()() }
140 }
141}
142
143#[embassy_executor::main] 20#[embassy_executor::main]
144async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
145 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
@@ -147,14 +24,18 @@ async fn main(_spawner: Spawner) {
147 mut common, irq0, sm0, .. 24 mut common, irq0, sm0, ..
148 } = Pio::new(p.PIO0, Irqs); 25 } = Pio::new(p.PIO0, Irqs);
149 26
150 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); 27 let prg = PioStepperProgram::new(&mut common);
28 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg);
151 stepper.set_frequency(120); 29 stepper.set_frequency(120);
152 loop { 30 loop {
153 info!("CW full steps"); 31 info!("CW full steps");
154 stepper.step(1000).await; 32 stepper.step(1000).await;
155 33
156 info!("CCW full steps, drop after 1 sec"); 34 info!("CCW full steps, drop after 1 sec");
157 if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { 35 if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX))
36 .await
37 .is_err()
38 {
158 info!("Time's up!"); 39 info!("Time's up!");
159 Timer::after(Duration::from_secs(1)).await; 40 Timer::after(Duration::from_secs(1)).await;
160 } 41 }
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index 53b696309..485c65204 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -13,10 +13,10 @@
13use defmt::{info, panic, trace}; 13use defmt::{info, panic, trace};
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_futures::join::{join, join3}; 15use embassy_futures::join::{join, join3};
16use embassy_rp::bind_interrupts;
17use embassy_rp::peripherals::{PIO0, USB}; 16use embassy_rp::peripherals::{PIO0, USB};
18use embassy_rp::pio::InterruptHandler as PioInterruptHandler; 17use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram};
19use embassy_rp::usb::{Driver, Instance, InterruptHandler}; 18use embassy_rp::usb::{Driver, Instance, InterruptHandler};
19use embassy_rp::{bind_interrupts, pio};
20use embassy_sync::blocking_mutex::raw::NoopRawMutex; 20use embassy_sync::blocking_mutex::raw::NoopRawMutex;
21use embassy_sync::pipe::Pipe; 21use embassy_sync::pipe::Pipe;
22use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; 22use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State};
@@ -25,13 +25,11 @@ use embassy_usb::{Builder, Config};
25use embedded_io_async::{Read, Write}; 25use embedded_io_async::{Read, Write};
26use {defmt_rtt as _, panic_probe as _}; 26use {defmt_rtt as _, panic_probe as _};
27 27
28use crate::uart::PioUart; 28//use crate::uart::PioUart;
29use crate::uart_rx::PioUartRx;
30use crate::uart_tx::PioUartTx;
31 29
32bind_interrupts!(struct Irqs { 30bind_interrupts!(struct Irqs {
33 USBCTRL_IRQ => InterruptHandler<USB>; 31 USBCTRL_IRQ => InterruptHandler<USB>;
34 PIO0_IRQ_0 => PioInterruptHandler<PIO0>; 32 PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
35}); 33});
36 34
37#[embassy_executor::main] 35#[embassy_executor::main]
@@ -51,13 +49,6 @@ async fn main(_spawner: Spawner) {
51 config.max_power = 100; 49 config.max_power = 100;
52 config.max_packet_size_0 = 64; 50 config.max_packet_size_0 = 64;
53 51
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 = 0xEF;
57 config.device_sub_class = 0x02;
58 config.device_protocol = 0x01;
59 config.composite_with_iads = true;
60
61 // Create embassy-usb DeviceBuilder using the driver and config. 52 // Create embassy-usb DeviceBuilder using the driver and config.
62 // It needs some buffers for building the descriptors. 53 // It needs some buffers for building the descriptors.
63 let mut config_descriptor = [0; 256]; 54 let mut config_descriptor = [0; 256];
@@ -85,8 +76,15 @@ async fn main(_spawner: Spawner) {
85 let usb_fut = usb.run(); 76 let usb_fut = usb.run();
86 77
87 // PIO UART setup 78 // PIO UART setup
88 let uart = PioUart::new(9600, p.PIO0, p.PIN_4, p.PIN_5); 79 let pio::Pio {
89 let (mut uart_tx, mut uart_rx) = uart.split(); 80 mut common, sm0, sm1, ..
81 } = pio::Pio::new(p.PIO0, Irqs);
82
83 let tx_program = PioUartTxProgram::new(&mut common);
84 let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program);
85
86 let rx_program = PioUartRxProgram::new(&mut common);
87 let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program);
90 88
91 // Pipe setup 89 // Pipe setup
92 let mut usb_pipe: Pipe<NoopRawMutex, 20> = Pipe::new(); 90 let mut usb_pipe: Pipe<NoopRawMutex, 20> = Pipe::new();
@@ -163,8 +161,8 @@ async fn usb_write<'d, T: Instance + 'd>(
163} 161}
164 162
165/// Read from the UART and write it to the USB TX pipe 163/// Read from the UART and write it to the USB TX pipe
166async fn uart_read( 164async fn uart_read<PIO: pio::Instance, const SM: usize>(
167 uart_rx: &mut PioUartRx<'_>, 165 uart_rx: &mut PioUartRx<'_, PIO, SM>,
168 usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, 166 usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>,
169) -> ! { 167) -> ! {
170 let mut buf = [0; 64]; 168 let mut buf = [0; 64];
@@ -180,8 +178,8 @@ async fn uart_read(
180} 178}
181 179
182/// Read from the UART TX pipe and write it to the UART 180/// Read from the UART TX pipe and write it to the UART
183async fn uart_write( 181async fn uart_write<PIO: pio::Instance, const SM: usize>(
184 uart_tx: &mut PioUartTx<'_>, 182 uart_tx: &mut PioUartTx<'_, PIO, SM>,
185 uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, 183 uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>,
186) -> ! { 184) -> ! {
187 let mut buf = [0; 64]; 185 let mut buf = [0; 64];
@@ -192,197 +190,3 @@ async fn uart_write(
192 let _ = uart_tx.write(&data).await; 190 let _ = uart_tx.write(&data).await;
193 } 191 }
194} 192}
195
196mod uart {
197 use embassy_rp::peripherals::PIO0;
198 use embassy_rp::pio::{Pio, PioPin};
199 use embassy_rp::Peripheral;
200
201 use crate::uart_rx::PioUartRx;
202 use crate::uart_tx::PioUartTx;
203 use crate::Irqs;
204
205 pub struct PioUart<'a> {
206 tx: PioUartTx<'a>,
207 rx: PioUartRx<'a>,
208 }
209
210 impl<'a> PioUart<'a> {
211 pub fn new(
212 baud: u64,
213 pio: impl Peripheral<P = PIO0> + 'a,
214 tx_pin: impl PioPin,
215 rx_pin: impl PioPin,
216 ) -> PioUart<'a> {
217 let Pio {
218 mut common, sm0, sm1, ..
219 } = Pio::new(pio, Irqs);
220
221 let tx = PioUartTx::new(&mut common, sm0, tx_pin, baud);
222 let rx = PioUartRx::new(&mut common, sm1, rx_pin, baud);
223
224 PioUart { tx, rx }
225 }
226
227 pub fn split(self) -> (PioUartTx<'a>, PioUartRx<'a>) {
228 (self.tx, self.rx)
229 }
230 }
231}
232
233mod uart_tx {
234 use core::convert::Infallible;
235
236 use embassy_rp::gpio::Level;
237 use embassy_rp::peripherals::PIO0;
238 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
239 use embedded_io_async::{ErrorType, Write};
240 use fixed::traits::ToFixed;
241 use fixed_macro::types::U56F8;
242
243 pub struct PioUartTx<'a> {
244 sm_tx: StateMachine<'a, PIO0, 0>,
245 }
246
247 impl<'a> PioUartTx<'a> {
248 pub fn new(
249 common: &mut Common<'a, PIO0>,
250 mut sm_tx: StateMachine<'a, PIO0, 0>,
251 tx_pin: impl PioPin,
252 baud: u64,
253 ) -> Self {
254 let prg = pio_proc::pio_asm!(
255 r#"
256 .side_set 1 opt
257
258 ; An 8n1 UART transmit program.
259 ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
260
261 pull side 1 [7] ; Assert stop bit, or stall with line in idle state
262 set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks
263 bitloop: ; This loop will run 8 times (8n1 UART)
264 out pins, 1 ; Shift 1 bit from OSR to the first OUT pin
265 jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
266 "#
267 );
268 let tx_pin = common.make_pio_pin(tx_pin);
269 sm_tx.set_pins(Level::High, &[&tx_pin]);
270 sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]);
271
272 let mut cfg = Config::default();
273
274 cfg.set_out_pins(&[&tx_pin]);
275 cfg.use_program(&common.load_program(&prg.program), &[&tx_pin]);
276 cfg.shift_out.auto_fill = false;
277 cfg.shift_out.direction = ShiftDirection::Right;
278 cfg.fifo_join = FifoJoin::TxOnly;
279 cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed();
280 sm_tx.set_config(&cfg);
281 sm_tx.set_enable(true);
282
283 Self { sm_tx }
284 }
285
286 pub async fn write_u8(&mut self, data: u8) {
287 self.sm_tx.tx().wait_push(data as u32).await;
288 }
289 }
290
291 impl ErrorType for PioUartTx<'_> {
292 type Error = Infallible;
293 }
294
295 impl Write for PioUartTx<'_> {
296 async fn write(&mut self, buf: &[u8]) -> Result<usize, Infallible> {
297 for byte in buf {
298 self.write_u8(*byte).await;
299 }
300 Ok(buf.len())
301 }
302 }
303}
304
305mod uart_rx {
306 use core::convert::Infallible;
307
308 use embassy_rp::gpio::Level;
309 use embassy_rp::peripherals::PIO0;
310 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
311 use embedded_io_async::{ErrorType, Read};
312 use fixed::traits::ToFixed;
313 use fixed_macro::types::U56F8;
314
315 pub struct PioUartRx<'a> {
316 sm_rx: StateMachine<'a, PIO0, 1>,
317 }
318
319 impl<'a> PioUartRx<'a> {
320 pub fn new(
321 common: &mut Common<'a, PIO0>,
322 mut sm_rx: StateMachine<'a, PIO0, 1>,
323 rx_pin: impl PioPin,
324 baud: u64,
325 ) -> Self {
326 let prg = pio_proc::pio_asm!(
327 r#"
328 ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
329 ; break conditions more gracefully.
330 ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
331
332 start:
333 wait 0 pin 0 ; Stall until start bit is asserted
334 set x, 7 [10] ; Preload bit counter, then delay until halfway through
335 rx_bitloop: ; the first data bit (12 cycles incl wait, set).
336 in pins, 1 ; Shift data bit into ISR
337 jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
338 jmp pin good_rx_stop ; Check stop bit (should be high)
339
340 irq 4 rel ; Either a framing error or a break. Set a sticky flag,
341 wait 1 pin 0 ; and wait for line to return to idle state.
342 jmp start ; Don't push data if we didn't see good framing.
343
344 good_rx_stop: ; No delay before returning to start; a little slack is
345 in null 24
346 push ; important in case the TX clock is slightly too fast.
347 "#
348 );
349 let mut cfg = Config::default();
350 cfg.use_program(&common.load_program(&prg.program), &[]);
351
352 let rx_pin = common.make_pio_pin(rx_pin);
353 sm_rx.set_pins(Level::High, &[&rx_pin]);
354 cfg.set_in_pins(&[&rx_pin]);
355 cfg.set_jmp_pin(&rx_pin);
356 sm_rx.set_pin_dirs(Direction::In, &[&rx_pin]);
357
358 cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed();
359 cfg.shift_in.auto_fill = false;
360 cfg.shift_in.direction = ShiftDirection::Right;
361 cfg.shift_in.threshold = 32;
362 cfg.fifo_join = FifoJoin::RxOnly;
363 sm_rx.set_config(&cfg);
364 sm_rx.set_enable(true);
365
366 Self { sm_rx }
367 }
368
369 pub async fn read_u8(&mut self) -> u8 {
370 self.sm_rx.rx().wait_pull().await as u8
371 }
372 }
373
374 impl ErrorType for PioUartRx<'_> {
375 type Error = Infallible;
376 }
377
378 impl Read for PioUartRx<'_> {
379 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Infallible> {
380 let mut i = 0;
381 while i < buf.len() {
382 buf[i] = self.read_u8().await;
383 i += 1;
384 }
385 Ok(i)
386 }
387 }
388}
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index ac145933c..d1fcfc471 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -6,15 +6,11 @@
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::dma::{AnyChannel, Channel}; 9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{ 11use embassy_rp::pio::{InterruptHandler, Pio};
12 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 12use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program};
13}; 13use embassy_time::{Duration, Ticker};
14use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
15use embassy_time::{Duration, Ticker, Timer};
16use fixed::types::U24F8;
17use fixed_macro::fixed;
18use smart_leds::RGB8; 14use smart_leds::RGB8;
19use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
20 16
@@ -22,96 +18,6 @@ bind_interrupts!(struct Irqs {
22 PIO0_IRQ_0 => InterruptHandler<PIO0>; 18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
23}); 19});
24 20
25pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
26 dma: PeripheralRef<'d, AnyChannel>,
27 sm: StateMachine<'d, P, S>,
28}
29
30impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
31 pub fn new(
32 pio: &mut Common<'d, P>,
33 mut sm: StateMachine<'d, P, S>,
34 dma: impl Peripheral<P = impl Channel> + 'd,
35 pin: impl PioPin,
36 ) -> Self {
37 into_ref!(dma);
38
39 // Setup sm0
40
41 // prepare the PIO program
42 let side_set = pio::SideSet::new(false, 1, false);
43 let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
44
45 const T1: u8 = 2; // start bit
46 const T2: u8 = 5; // data bit
47 const T3: u8 = 3; // stop bit
48 const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
49
50 let mut wrap_target = a.label();
51 let mut wrap_source = a.label();
52 let mut do_zero = a.label();
53 a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
54 a.bind(&mut wrap_target);
55 // Do stop bit
56 a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
57 // Do start bit
58 a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
59 // Do data bit = 1
60 a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
61 a.bind(&mut do_zero);
62 // Do data bit = 0
63 a.nop_with_delay_and_side_set(T2 - 1, 0);
64 a.bind(&mut wrap_source);
65
66 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
67 let mut cfg = Config::default();
68
69 // Pin config
70 let out_pin = pio.make_pio_pin(pin);
71 cfg.set_out_pins(&[&out_pin]);
72 cfg.set_set_pins(&[&out_pin]);
73
74 cfg.use_program(&pio.load_program(&prg), &[&out_pin]);
75
76 // Clock config, measured in kHz to avoid overflows
77 // TODO CLOCK_FREQ should come from embassy_rp
78 let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
79 let ws2812_freq = fixed!(800: U24F8);
80 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
81 cfg.clock_divider = clock_freq / bit_freq;
82
83 // FIFO config
84 cfg.fifo_join = FifoJoin::TxOnly;
85 cfg.shift_out = ShiftConfig {
86 auto_fill: true,
87 threshold: 24,
88 direction: ShiftDirection::Left,
89 };
90
91 sm.set_config(&cfg);
92 sm.set_enable(true);
93
94 Self {
95 dma: dma.map_into(),
96 sm,
97 }
98 }
99
100 pub async fn write(&mut self, colors: &[RGB8; N]) {
101 // Precompute the word bytes from the colors
102 let mut words = [0u32; N];
103 for i in 0..N {
104 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
105 words[i] = word;
106 }
107
108 // DMA transfer
109 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
110
111 Timer::after_micros(55).await;
112 }
113}
114
115/// Input a value 0 to 255 to get a color value 21/// Input a value 0 to 255 to get a color value
116/// The colours are a transition r - g - b - back to r. 22/// The colours are a transition r - g - b - back to r.
117fn wheel(mut wheel_pos: u8) -> RGB8 { 23fn wheel(mut wheel_pos: u8) -> RGB8 {
@@ -142,7 +48,8 @@ async fn main(_spawner: Spawner) {
142 // Common neopixel pins: 48 // Common neopixel pins:
143 // Thing plus: 8 49 // Thing plus: 8
144 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 50 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4
145 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); 51 let program = PioWs2812Program::new(&mut common);
52 let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program);
146 53
147 // Loop forever making RGB values and pushing them out to the WS2812. 54 // Loop forever making RGB values and pushing them out to the WS2812.
148 let mut ticker = Ticker::every(Duration::from_millis(10)); 55 let mut ticker = Ticker::every(Duration::from_millis(10));
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
index 26e233260..04374323d 100644
--- a/examples/rp/src/bin/pwm.rs
+++ b/examples/rp/src/bin/pwm.rs
@@ -1,24 +1,37 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. 1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip.
2//! 2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. 3//! We demonstrate two ways of using PWM:
4//! 1. Via config
5//! 2. Via setting a duty cycle
4 6
5#![no_std] 7#![no_std]
6#![no_main] 8#![no_main]
7 9
8use defmt::*; 10use defmt::*;
9use embassy_executor::Spawner; 11use embassy_executor::Spawner;
10use embassy_rp::pwm::{Config, Pwm}; 12use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4};
13use embassy_rp::pwm::{Config, Pwm, SetDutyCycle};
14use embassy_rp::Peri;
11use embassy_time::Timer; 15use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
13 17
14#[embassy_executor::main] 18#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 19async fn main(spawner: Spawner) {
16 let p = embassy_rp::init(Default::default()); 20 let p = embassy_rp::init(Default::default());
21 spawner.spawn(pwm_set_config(p.PWM_SLICE4, p.PIN_25)).unwrap();
22 spawner.spawn(pwm_set_dutycycle(p.PWM_SLICE2, p.PIN_4)).unwrap();
23}
17 24
18 let mut c: Config = Default::default(); 25/// Demonstrate PWM by modifying & applying the config
19 c.top = 0x8000; 26///
27/// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant)
28/// you must use another slice & pin and an appropriate resistor.
29#[embassy_executor::task]
30async fn pwm_set_config(slice4: Peri<'static, PWM_SLICE4>, pin25: Peri<'static, PIN_25>) {
31 let mut c = Config::default();
32 c.top = 32_768;
20 c.compare_b = 8; 33 c.compare_b = 8;
21 let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); 34 let mut pwm = Pwm::new_output_b(slice4, pin25, c.clone());
22 35
23 loop { 36 loop {
24 info!("current LED duty cycle: {}/32768", c.compare_b); 37 info!("current LED duty cycle: {}/32768", c.compare_b);
@@ -27,3 +40,41 @@ async fn main(_spawner: Spawner) {
27 pwm.set_config(&c); 40 pwm.set_config(&c);
28 } 41 }
29} 42}
43
44/// Demonstrate PWM by setting duty cycle
45///
46/// Using GP4 in Slice2, make sure to use an appropriate resistor.
47#[embassy_executor::task]
48async fn pwm_set_dutycycle(slice2: Peri<'static, PWM_SLICE2>, pin4: Peri<'static, PIN_4>) {
49 // If we aim for a specific frequency, here is how we can calculate the top value.
50 // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0.
51 // Every such wraparound is one PWM cycle. So here is how we get 25KHz:
52 let desired_freq_hz = 25_000;
53 let clock_freq_hz = embassy_rp::clocks::clk_sys_freq();
54 let divider = 16u8;
55 let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1;
56
57 let mut c = Config::default();
58 c.top = period;
59 c.divider = divider.into();
60
61 let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone());
62
63 loop {
64 // 100% duty cycle, fully on
65 pwm.set_duty_cycle_fully_on().unwrap();
66 Timer::after_secs(1).await;
67
68 // 66% duty cycle. Expressed as simple percentage.
69 pwm.set_duty_cycle_percent(66).unwrap();
70 Timer::after_secs(1).await;
71
72 // 25% duty cycle. Expressed as 32768/4 = 8192.
73 pwm.set_duty_cycle(c.top / 4).unwrap();
74 Timer::after_secs(1).await;
75
76 // 0% duty cycle, fully off.
77 pwm.set_duty_cycle_fully_off().unwrap();
78 Timer::after_secs(1).await;
79 }
80}
diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs
index c6cb5d64c..9267dfccb 100644
--- a/examples/rp/src/bin/shared_bus.rs
+++ b/examples/rp/src/bin/shared_bus.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; 8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{AnyPin, Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::i2c::{self, I2c, InterruptHandler}; 12use embassy_rp::i2c::{self, I2c, InterruptHandler};
13use embassy_rp::peripherals::{I2C1, SPI1}; 13use embassy_rp::peripherals::{I2C1, SPI1};
14use embassy_rp::spi::{self, Spi}; 14use embassy_rp::spi::{self, Spi};
@@ -45,8 +45,8 @@ async fn main(spawner: Spawner) {
45 let spi_bus = SPI_BUS.init(Mutex::new(spi)); 45 let spi_bus = SPI_BUS.init(Mutex::new(spi));
46 46
47 // Chip select pins for the SPI devices 47 // Chip select pins for the SPI devices
48 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); 48 let cs_a = Output::new(p.PIN_0, Level::High);
49 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); 49 let cs_b = Output::new(p.PIN_1, Level::High);
50 50
51 spawner.must_spawn(spi_task_a(spi_bus, cs_a)); 51 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
52 spawner.must_spawn(spi_task_b(spi_bus, cs_b)); 52 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs
index 5416e20ce..856be6ace 100644
--- a/examples/rp/src/bin/sharing.rs
+++ b/examples/rp/src/bin/sharing.rs
@@ -27,11 +27,10 @@ use embassy_rp::{bind_interrupts, interrupt};
27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
28use embassy_sync::{blocking_mutex, mutex}; 28use embassy_sync::{blocking_mutex, mutex};
29use embassy_time::{Duration, Ticker}; 29use embassy_time::{Duration, Ticker};
30use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell}; 30use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _}; 31use {defmt_rtt as _, panic_probe as _};
33 32
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; 33type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
35 34
36struct MyType { 35struct MyType {
37 inner: u32, 36 inner: u32,
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index e937b9d0a..dd114a4ae 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -9,11 +9,12 @@
9use core::cell::RefCell; 9use core::cell::RefCell;
10 10
11use defmt::*; 11use defmt::*;
12use display_interface_spi::SPIInterface;
12use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; 13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
13use embassy_executor::Spawner; 14use embassy_executor::Spawner;
14use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
15use embassy_rp::spi; 16use embassy_rp::spi;
16use embassy_rp::spi::{Blocking, Spi}; 17use embassy_rp::spi::Spi;
17use embassy_sync::blocking_mutex::raw::NoopRawMutex; 18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
18use embassy_sync::blocking_mutex::Mutex; 19use embassy_sync::blocking_mutex::Mutex;
19use embassy_time::Delay; 20use embassy_time::Delay;
@@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565;
24use embedded_graphics::prelude::*; 25use embedded_graphics::prelude::*;
25use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; 26use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
26use embedded_graphics::text::Text; 27use embedded_graphics::text::Text;
27use st7789::{Orientation, ST7789}; 28use mipidsi::models::ST7789;
29use mipidsi::options::{Orientation, Rotation};
30use mipidsi::Builder;
28use {defmt_rtt as _, panic_probe as _}; 31use {defmt_rtt as _, panic_probe as _};
29 32
30use crate::my_display_interface::SPIDeviceInterface;
31use crate::touch::Touch; 33use crate::touch::Touch;
32 34
33const DISPLAY_FREQ: u32 = 64_000_000; 35const DISPLAY_FREQ: u32 = 64_000_000;
@@ -58,7 +60,7 @@ async fn main(_spawner: Spawner) {
58 touch_config.phase = spi::Phase::CaptureOnSecondTransition; 60 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
59 touch_config.polarity = spi::Polarity::IdleHigh; 61 touch_config.polarity = spi::Polarity::IdleHigh;
60 62
61 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); 63 let spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
62 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi)); 64 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
63 65
64 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); 66 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
@@ -74,17 +76,15 @@ async fn main(_spawner: Spawner) {
74 let _bl = Output::new(bl, Level::High); 76 let _bl = Output::new(bl, Level::High);
75 77
76 // display interface abstraction from SPI and DC 78 // display interface abstraction from SPI and DC
77 let di = SPIDeviceInterface::new(display_spi, dcx); 79 let di = SPIInterface::new(display_spi, dcx);
78 80
79 // create driver 81 // Define the display from the display interface and initialize it
80 let mut display = ST7789::new(di, rst, 240, 320); 82 let mut display = Builder::new(ST7789, di)
81 83 .display_size(240, 320)
82 // initialize 84 .reset_pin(rst)
83 display.init(&mut Delay).unwrap(); 85 .orientation(Orientation::new().rotate(Rotation::Deg90))
84 86 .init(&mut Delay)
85 // set default orientation 87 .unwrap();
86 display.set_orientation(Orientation::Landscape).unwrap();
87
88 display.clear(Rgb565::BLACK).unwrap(); 88 display.clear(Rgb565::BLACK).unwrap();
89 89
90 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); 90 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
@@ -175,138 +175,3 @@ mod touch {
175 } 175 }
176 } 176 }
177} 177}
178
179mod my_display_interface {
180 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
181 use embedded_hal_1::digital::OutputPin;
182 use embedded_hal_1::spi::SpiDevice;
183
184 /// SPI display interface.
185 ///
186 /// This combines the SPI peripheral and a data/command pin
187 pub struct SPIDeviceInterface<SPI, DC> {
188 spi: SPI,
189 dc: DC,
190 }
191
192 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
193 where
194 SPI: SpiDevice,
195 DC: OutputPin,
196 {
197 /// Create new SPI interface for communciation with a display driver
198 pub fn new(spi: SPI, dc: DC) -> Self {
199 Self { spi, dc }
200 }
201 }
202
203 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
204 where
205 SPI: SpiDevice,
206 DC: OutputPin,
207 {
208 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
209 // 1 = data, 0 = command
210 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
211
212 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
213 Ok(())
214 }
215
216 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
217 // 1 = data, 0 = command
218 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
219
220 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
221 Ok(())
222 }
223 }
224
225 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
226 match words {
227 DataFormat::U8(slice) => spi.write(slice),
228 DataFormat::U16(slice) => {
229 use byte_slice_cast::*;
230 spi.write(slice.as_byte_slice())
231 }
232 DataFormat::U16LE(slice) => {
233 use byte_slice_cast::*;
234 for v in slice.as_mut() {
235 *v = v.to_le();
236 }
237 spi.write(slice.as_byte_slice())
238 }
239 DataFormat::U16BE(slice) => {
240 use byte_slice_cast::*;
241 for v in slice.as_mut() {
242 *v = v.to_be();
243 }
244 spi.write(slice.as_byte_slice())
245 }
246 DataFormat::U8Iter(iter) => {
247 let mut buf = [0; 32];
248 let mut i = 0;
249
250 for v in iter.into_iter() {
251 buf[i] = v;
252 i += 1;
253
254 if i == buf.len() {
255 spi.write(&buf)?;
256 i = 0;
257 }
258 }
259
260 if i > 0 {
261 spi.write(&buf[..i])?;
262 }
263
264 Ok(())
265 }
266 DataFormat::U16LEIter(iter) => {
267 use byte_slice_cast::*;
268 let mut buf = [0; 32];
269 let mut i = 0;
270
271 for v in iter.map(u16::to_le) {
272 buf[i] = v;
273 i += 1;
274
275 if i == buf.len() {
276 spi.write(&buf.as_byte_slice())?;
277 i = 0;
278 }
279 }
280
281 if i > 0 {
282 spi.write(&buf[..i].as_byte_slice())?;
283 }
284
285 Ok(())
286 }
287 DataFormat::U16BEIter(iter) => {
288 use byte_slice_cast::*;
289 let mut buf = [0; 64];
290 let mut i = 0;
291 let len = buf.len();
292
293 for v in iter.map(u16::to_be) {
294 buf[i] = v;
295 i += 1;
296
297 if i == len {
298 spi.write(&buf.as_byte_slice())?;
299 i = 0;
300 }
301 }
302
303 if i > 0 {
304 spi.write(&buf[..i].as_byte_slice())?;
305 }
306
307 Ok(())
308 }
309 _ => unimplemented!(),
310 }
311 }
312}
diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs
new file mode 100644
index 000000000..fdef09d4b
--- /dev/null
+++ b/examples/rp/src/bin/spi_gc9a01.rs
@@ -0,0 +1,125 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example written for a display using the GC9A01 chip. Possibly the Waveshare RP2040-LCD-1.28
4//! (https://www.waveshare.com/wiki/RP2040-LCD-1.28)
5
6#![no_std]
7#![no_main]
8
9use core::cell::RefCell;
10
11use defmt::*;
12use display_interface_spi::SPIInterface;
13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
14use embassy_executor::Spawner;
15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Level, Output};
17use embassy_rp::spi;
18use embassy_rp::spi::{Blocking, Spi};
19use embassy_sync::blocking_mutex::raw::NoopRawMutex;
20use embassy_sync::blocking_mutex::Mutex;
21use embassy_time::{Delay, Duration, Timer};
22use embedded_graphics::image::{Image, ImageRawLE};
23use embedded_graphics::pixelcolor::Rgb565;
24use embedded_graphics::prelude::*;
25use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
26use mipidsi::models::GC9A01;
27use mipidsi::options::{ColorInversion, ColorOrder};
28use mipidsi::Builder;
29use {defmt_rtt as _, panic_probe as _};
30
31const DISPLAY_FREQ: u32 = 64_000_000;
32const LCD_X_RES: i32 = 240;
33const LCD_Y_RES: i32 = 240;
34const FERRIS_WIDTH: u32 = 86;
35const FERRIS_HEIGHT: u32 = 64;
36
37#[embassy_executor::main]
38async fn main(_spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 let mut rng = RoscRng;
41
42 info!("Hello World!");
43
44 let bl = p.PIN_25;
45 let rst = p.PIN_12;
46 let display_cs = p.PIN_9;
47 let dcx = p.PIN_8;
48 let mosi = p.PIN_11;
49 let clk = p.PIN_10;
50
51 // create SPI
52 let mut display_config = spi::Config::default();
53 display_config.frequency = DISPLAY_FREQ;
54 display_config.phase = spi::Phase::CaptureOnSecondTransition;
55 display_config.polarity = spi::Polarity::IdleHigh;
56
57 let spi: Spi<'_, _, Blocking> = Spi::new_blocking_txonly(p.SPI1, clk, mosi, display_config.clone());
58 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
59
60 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
61 let dcx = Output::new(dcx, Level::Low);
62 let rst = Output::new(rst, Level::Low);
63 // dcx: 0 = command, 1 = data
64
65 // Enable LCD backlight
66 let _bl = Output::new(bl, Level::High);
67
68 // display interface abstraction from SPI and DC
69 let di = SPIInterface::new(display_spi, dcx);
70
71 // Define the display from the display interface and initialize it
72 let mut display = Builder::new(GC9A01, di)
73 .display_size(240, 240)
74 .reset_pin(rst)
75 .color_order(ColorOrder::Bgr)
76 .invert_colors(ColorInversion::Inverted)
77 .init(&mut Delay)
78 .unwrap();
79 display.clear(Rgb565::BLACK).unwrap();
80
81 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), FERRIS_WIDTH);
82 let mut ferris = Image::new(&raw_image_data, Point::zero());
83
84 let r = rng.next_u32();
85 let mut delta = Point {
86 x: ((r % 10) + 5) as i32,
87 y: (((r >> 8) % 10) + 5) as i32,
88 };
89 loop {
90 // Move Ferris
91 let bb = ferris.bounding_box();
92 let tl = bb.top_left;
93 let br = bb.bottom_right().unwrap();
94 if tl.x < 0 || br.x > LCD_X_RES {
95 delta.x = -delta.x;
96 }
97 if tl.y < 0 || br.y > LCD_Y_RES {
98 delta.y = -delta.y;
99 }
100
101 // Erase ghosting
102 let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLACK).build();
103 let mut off = Point { x: 0, y: 0 };
104 if delta.x < 0 {
105 off.x = FERRIS_WIDTH as i32;
106 }
107 Rectangle::new(tl + off, Size::new(delta.x as u32, FERRIS_HEIGHT))
108 .into_styled(style)
109 .draw(&mut display)
110 .unwrap();
111 off = Point { x: 0, y: 0 };
112 if delta.y < 0 {
113 off.y = FERRIS_HEIGHT as i32;
114 }
115 Rectangle::new(tl + off, Size::new(FERRIS_WIDTH, delta.y as u32))
116 .into_styled(style)
117 .draw(&mut display)
118 .unwrap();
119 // Translate Ferris
120 ferris.translate_mut(delta);
121 // Display the image
122 ferris.draw(&mut display).unwrap();
123 Timer::after(Duration::from_millis(50)).await;
124 }
125}
diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs
index 4cbc82f7b..4e3c2f199 100644
--- a/examples/rp/src/bin/spi_sdmmc.rs
+++ b/examples/rp/src/bin/spi_sdmmc.rs
@@ -7,7 +7,6 @@
7#![no_main] 7#![no_main]
8 8
9use defmt::*; 9use defmt::*;
10use embassy_embedded_hal::SetConfig;
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
12use embassy_rp::spi::Spi; 11use embassy_rp::spi::Spi;
13use embassy_rp::{gpio, spi}; 12use embassy_rp::{gpio, spi};
@@ -33,7 +32,6 @@ impl embedded_sdmmc::TimeSource for DummyTimesource {
33 32
34#[embassy_executor::main] 33#[embassy_executor::main]
35async fn main(_spawner: Spawner) { 34async fn main(_spawner: Spawner) {
36 embassy_rp::pac::SIO.spinlock(31).write_value(1);
37 let p = embassy_rp::init(Default::default()); 35 let p = embassy_rp::init(Default::default());
38 36
39 // SPI clock needs to be running at <= 400kHz during initialization 37 // SPI clock needs to be running at <= 400kHz during initialization
@@ -51,7 +49,7 @@ async fn main(_spawner: Spawner) {
51 // Now that the card is initialized, the SPI clock can go faster 49 // Now that the card is initialized, the SPI clock can go faster
52 let mut config = spi::Config::default(); 50 let mut config = spi::Config::default();
53 config.frequency = 16_000_000; 51 config.frequency = 16_000_000;
54 sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); 52 sdcard.spi(|dev| dev.bus_mut().set_config(&config));
55 53
56 // Now let's look for volumes (also known as partitions) on our block device. 54 // 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. 55 // To do this we need a Volume Manager. It will take ownership of the block device.
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index 468d2b61a..3adbc18ab 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -30,7 +30,7 @@ async fn main(spawner: Spawner) {
30 let tx_buf = &mut TX_BUF.init([0; 16])[..]; 30 let tx_buf = &mut TX_BUF.init([0; 16])[..];
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, tx_pin, rx_pin, Irqs, tx_buf, rx_buf, Config::default());
34 let (mut tx, rx) = uart.split(); 34 let (mut tx, rx) = uart.split();
35 35
36 unwrap!(spawner.spawn(reader(rx))); 36 unwrap!(spawner.spawn(reader(rx)));
@@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
52 info!("Reading..."); 52 info!("Reading...");
53 loop { 53 loop {
54 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
index a45f40756..c2c8dfad8 100644
--- a/examples/rp/src/bin/uart_unidir.rs
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
43 info!("Reading..."); 43 info!("Reading...");
44 loop { 44 loop {
45 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 03c510f37..171f21a75 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -8,7 +8,7 @@
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::clocks::RoscRng;
13use embassy_rp::peripherals::USB; 13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, InterruptHandler}; 14use embassy_rp::usb::{Driver, InterruptHandler};
@@ -17,7 +17,6 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
18use embassy_usb::{Builder, Config, UsbDevice}; 18use embassy_usb::{Builder, Config, UsbDevice};
19use embedded_io_async::Write; 19use embedded_io_async::Write;
20use rand::RngCore;
21use static_cell::StaticCell; 20use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
23 22
@@ -40,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
40} 39}
41 40
42#[embassy_executor::task] 41#[embassy_executor::task]
43async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 42async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
44 stack.run().await 43 runner.run().await
45} 44}
46 45
47#[embassy_executor::main] 46#[embassy_executor::main]
@@ -60,12 +59,6 @@ async fn main(spawner: Spawner) {
60 config.max_power = 100; 59 config.max_power = 100;
61 config.max_packet_size_0 = 64; 60 config.max_packet_size_0 = 64;
62 61
63 // Required for Windows support.
64 config.composite_with_iads = true;
65 config.device_class = 0xEF;
66 config.device_sub_class = 0x02;
67 config.device_protocol = 0x01;
68
69 // Create embassy-usb DeviceBuilder using the driver and config. 62 // Create embassy-usb DeviceBuilder using the driver and config.
70 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 63 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
71 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 64 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
@@ -108,11 +101,10 @@ async fn main(spawner: Spawner) {
108 let seed = rng.next_u64(); 101 let seed = rng.next_u64();
109 102
110 // Init network stack 103 // Init network stack
111 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
112 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 104 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
113 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 105 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
114 106
115 unwrap!(spawner.spawn(net_task(stack))); 107 unwrap!(spawner.spawn(net_task(runner)));
116 108
117 // And now we can use it! 109 // And now we can use it!
118 110
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
index cce344fb0..4454c593c 100644..100755
--- a/examples/rp/src/bin/usb_hid_mouse.rs
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -8,7 +8,6 @@ use embassy_executor::Spawner;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
10use embassy_rp::clocks::RoscRng; 10use embassy_rp::clocks::RoscRng;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_time::Timer; 13use embassy_time::Timer;
@@ -75,12 +74,6 @@ async fn main(_spawner: Spawner) {
75 // Run the USB device. 74 // Run the USB device.
76 let usb_fut = usb.run(); 75 let usb_fut = usb.run();
77 76
78 // Set up the signal pin that will be used to trigger the keyboard.
79 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
80
81 // Enable the schmitt trigger to slightly debounce.
82 signal_pin.set_schmitt(true);
83
84 let (reader, mut writer) = hid.split(); 77 let (reader, mut writer) = hid.split();
85 78
86 // Do stuff with the class! 79 // Do stuff with the class!
@@ -92,8 +85,8 @@ async fn main(_spawner: Spawner) {
92 _ = Timer::after_secs(1).await; 85 _ = Timer::after_secs(1).await;
93 let report = MouseReport { 86 let report = MouseReport {
94 buttons: 0, 87 buttons: 0,
95 x: rng.gen_range(-100..100), // random small x movement 88 x: rng.random_range(-100..100), // random small x movement
96 y: rng.gen_range(-100..100), // random small y movement 89 y: rng.random_range(-100..100), // random small y movement
97 wheel: 0, 90 wheel: 0,
98 pan: 0, 91 pan: 0,
99 }; 92 };
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs
index 11db1b2e1..3b7910f8b 100644
--- a/examples/rp/src/bin/usb_midi.rs
+++ b/examples/rp/src/bin/usb_midi.rs
@@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) {
37 config.max_power = 100; 37 config.max_power = 100;
38 config.max_packet_size_0 = 64; 38 config.max_packet_size_0 = 64;
39 39
40 // Required for windows compatibility.
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
42 config.device_class = 0xEF;
43 config.device_sub_class = 0x02;
44 config.device_protocol = 0x01;
45 config.composite_with_iads = true;
46
47 // Create embassy-usb DeviceBuilder using the driver and config. 40 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 41 // It needs some buffers for building the descriptors.
49 let mut config_descriptor = [0; 256]; 42 let mut config_descriptor = [0; 256];
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs
index 97e7e0244..5974c04c0 100644
--- a/examples/rp/src/bin/usb_raw.rs
+++ b/examples/rp/src/bin/usb_raw.rs
@@ -84,13 +84,6 @@ async fn main(_spawner: Spawner) {
84 config.max_power = 100; 84 config.max_power = 100;
85 config.max_packet_size_0 = 64; 85 config.max_packet_size_0 = 64;
86 86
87 // // Required for windows compatibility.
88 // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
89 config.device_class = 0xEF;
90 config.device_sub_class = 0x02;
91 config.device_protocol = 0x01;
92 config.composite_with_iads = true;
93
94 // Create embassy-usb DeviceBuilder using the driver and config. 87 // Create embassy-usb DeviceBuilder using the driver and config.
95 // It needs some buffers for building the descriptors. 88 // It needs some buffers for building the descriptors.
96 let mut config_descriptor = [0; 256]; 89 let mut config_descriptor = [0; 256];
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs
index 331c3da4c..103269791 100644
--- a/examples/rp/src/bin/usb_raw_bulk.rs
+++ b/examples/rp/src/bin/usb_raw_bulk.rs
@@ -62,13 +62,6 @@ async fn main(_spawner: Spawner) {
62 config.max_power = 100; 62 config.max_power = 100;
63 config.max_packet_size_0 = 64; 63 config.max_packet_size_0 = 64;
64 64
65 // // Required for windows compatibility.
66 // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
67 config.device_class = 0xEF;
68 config.device_sub_class = 0x02;
69 config.device_protocol = 0x01;
70 config.composite_with_iads = true;
71
72 // Create embassy-usb DeviceBuilder using the driver and config. 65 // Create embassy-usb DeviceBuilder using the driver and config.
73 // It needs some buffers for building the descriptors. 66 // It needs some buffers for building the descriptors.
74 let mut config_descriptor = [0; 256]; 67 let mut config_descriptor = [0; 256];
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index 4a802994a..5e3f0f378 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -37,13 +37,6 @@ async fn main(spawner: Spawner) {
37 config.serial_number = Some("12345678"); 37 config.serial_number = Some("12345678");
38 config.max_power = 100; 38 config.max_power = 100;
39 config.max_packet_size_0 = 64; 39 config.max_packet_size_0 = 64;
40
41 // Required for windows compatibility.
42 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
43 config.device_class = 0xEF;
44 config.device_sub_class = 0x02;
45 config.device_protocol = 0x01;
46 config.composite_with_iads = true;
47 config 40 config
48 }; 41 };
49 42
diff --git a/examples/rp/src/bin/usb_serial_with_handler.rs b/examples/rp/src/bin/usb_serial_with_handler.rs
new file mode 100644
index 000000000..a9e65be70
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial_with_handler.rs
@@ -0,0 +1,64 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates the possibility to send log::info/warn/error/debug! to USB serial port.
4
5#![no_std]
6#![no_main]
7
8use core::str;
9
10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts;
12use embassy_rp::peripherals::USB;
13use embassy_rp::rom_data::reset_to_usb_boot;
14use embassy_rp::usb::{Driver, InterruptHandler};
15use embassy_time::Timer;
16use embassy_usb_logger::ReceiverHandler;
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>;
21});
22
23struct Handler;
24
25impl ReceiverHandler for Handler {
26 async fn handle_data(&self, data: &[u8]) {
27 if let Ok(data) = str::from_utf8(data) {
28 let data = data.trim();
29
30 // If you are using elf2uf2-term with the '-t' flag, then when closing the serial monitor,
31 // this will automatically put the pico into boot mode
32 if data == "q" || data == "elf2uf2-term" {
33 reset_to_usb_boot(0, 0); // Restart the chip
34 } else if data.eq_ignore_ascii_case("hello") {
35 log::info!("World!");
36 } else {
37 log::info!("Recieved: {:?}", data);
38 }
39 }
40 }
41
42 fn new() -> Self {
43 Self
44 }
45}
46
47#[embassy_executor::task]
48async fn logger_task(driver: Driver<'static, USB>) {
49 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver, Handler);
50}
51
52#[embassy_executor::main]
53async fn main(spawner: Spawner) {
54 let p = embassy_rp::init(Default::default());
55 let driver = Driver::new(p.USB, Irqs);
56 spawner.spawn(logger_task(driver)).unwrap();
57
58 let mut counter = 0;
59 loop {
60 counter += 1;
61 log::info!("Tick {}", counter);
62 Timer::after_secs(1).await;
63 }
64}
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs
index f9cfdef94..ea13a1e27 100644
--- a/examples/rp/src/bin/usb_serial_with_logger.rs
+++ b/examples/rp/src/bin/usb_serial_with_logger.rs
@@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) {
37 config.max_power = 100; 37 config.max_power = 100;
38 config.max_packet_size_0 = 64; 38 config.max_packet_size_0 = 64;
39 39
40 // Required for windows compatibility.
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
42 config.device_class = 0xEF;
43 config.device_sub_class = 0x02;
44 config.device_protocol = 0x01;
45 config.composite_with_iads = true;
46
47 // Create embassy-usb DeviceBuilder using the driver and config. 40 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors. 41 // It needs some buffers for building the descriptors.
49 let mut config_descriptor = [0; 256]; 42 let mut config_descriptor = [0; 256];
diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs
index e73938ac9..a5dc94d5b 100644
--- a/examples/rp/src/bin/usb_webusb.rs
+++ b/examples/rp/src/bin/usb_webusb.rs
@@ -51,12 +51,6 @@ async fn main(_spawner: Spawner) {
51 config.max_power = 100; 51 config.max_power = 100;
52 config.max_packet_size_0 = 64; 52 config.max_packet_size_0 = 64;
53 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. 54 // Create embassy-usb DeviceBuilder using the driver and config.
61 // It needs some buffers for building the descriptors. 55 // It needs some buffers for building the descriptors.
62 let mut config_descriptor = [0; 256]; 56 let mut config_descriptor = [0; 256];
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 00f404a9b..856838a8c 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -7,11 +7,11 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43_pio::PioSpi; 10use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
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::clocks::RoscRng;
17use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
@@ -19,7 +19,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio}; 19use embassy_rp::pio::{InterruptHandler, Pio};
20use embassy_time::Duration; 20use embassy_time::Duration;
21use embedded_io_async::Write; 21use embedded_io_async::Write;
22use rand::RngCore;
23use static_cell::StaticCell; 22use static_cell::StaticCell;
24use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
25 24
@@ -33,8 +32,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
33} 32}
34 33
35#[embassy_executor::task] 34#[embassy_executor::task]
36async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 35async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
37 stack.run().await 36 runner.run().await
38} 37}
39 38
40#[embassy_executor::main] 39#[embassy_executor::main]
@@ -57,7 +56,16 @@ async fn main(spawner: Spawner) {
57 let pwr = Output::new(p.PIN_23, Level::Low); 56 let pwr = Output::new(p.PIN_23, Level::Low);
58 let cs = Output::new(p.PIN_25, Level::High); 57 let cs = Output::new(p.PIN_25, Level::High);
59 let mut pio = Pio::new(p.PIO0, Irqs); 58 let mut pio = Pio::new(p.PIO0, Irqs);
60 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 59 let spi = PioSpi::new(
60 &mut pio.common,
61 pio.sm0,
62 DEFAULT_CLOCK_DIVIDER,
63 pio.irq0,
64 cs,
65 p.PIN_24,
66 p.PIN_29,
67 p.DMA_CH0,
68 );
61 69
62 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 70 static STATE: StaticCell<cyw43::State> = StaticCell::new();
63 let state = STATE.init(cyw43::State::new()); 71 let state = STATE.init(cyw43::State::new());
@@ -80,16 +88,10 @@ async fn main(spawner: Spawner) {
80 let seed = rng.next_u64(); 88 let seed = rng.next_u64();
81 89
82 // Init network stack 90 // Init network stack
83 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
84 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 91 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
85 let stack = &*STACK.init(Stack::new( 92 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
86 net_device, 93
87 config, 94 unwrap!(spawner.spawn(net_task(runner)));
88 RESOURCES.init(StackResources::new()),
89 seed,
90 ));
91
92 unwrap!(spawner.spawn(net_task(stack)));
93 95
94 //control.start_ap_open("cyw43", 5).await; 96 //control.start_ap_open("cyw43", 5).await;
95 control.start_ap_wpa2("cyw43", "password", 5).await; 97 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 04a61bbd5..6e91ce167 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -5,7 +5,7 @@
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7 7
8use cyw43_pio::PioSpi; 8use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts; 11use embassy_rp::bind_interrupts;
@@ -33,15 +33,24 @@ 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 --binary-format bin --chip RP2040 --base-address 0x10100000 36 // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
37 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 37 // probe-rs download ../../cyw43-firmware/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
41 let pwr = Output::new(p.PIN_23, Level::Low); 41 let pwr = Output::new(p.PIN_23, Level::Low);
42 let cs = Output::new(p.PIN_25, Level::High); 42 let cs = Output::new(p.PIN_25, Level::High);
43 let mut pio = Pio::new(p.PIO0, Irqs); 43 let mut pio = Pio::new(p.PIO0, Irqs);
44 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 44 let spi = PioSpi::new(
45 &mut pio.common,
46 pio.sm0,
47 DEFAULT_CLOCK_DIVIDER,
48 pio.irq0,
49 cs,
50 p.PIN_24,
51 p.PIN_29,
52 p.DMA_CH0,
53 );
45 54
46 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 55 static STATE: StaticCell<cyw43::State> = StaticCell::new();
47 let state = STATE.init(cyw43::State::new()); 56 let state = STATE.init(cyw43::State::new());
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index ab3529112..fe9c363d9 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -7,10 +7,9 @@
7 7
8use core::str; 8use core::str;
9 9
10use cyw43_pio::PioSpi; 10use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
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};
@@ -27,11 +26,6 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
27 runner.run().await 26 runner.run().await
28} 27}
29 28
30#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
32 stack.run().await
33}
34
35#[embassy_executor::main] 29#[embassy_executor::main]
36async fn main(spawner: Spawner) { 30async fn main(spawner: Spawner) {
37 info!("Hello World!"); 31 info!("Hello World!");
@@ -51,7 +45,16 @@ async fn main(spawner: Spawner) {
51 let pwr = Output::new(p.PIN_23, Level::Low); 45 let pwr = Output::new(p.PIN_23, Level::Low);
52 let cs = Output::new(p.PIN_25, Level::High); 46 let cs = Output::new(p.PIN_25, Level::High);
53 let mut pio = Pio::new(p.PIO0, Irqs); 47 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); 48 let spi = PioSpi::new(
49 &mut pio.common,
50 pio.sm0,
51 DEFAULT_CLOCK_DIVIDER,
52 pio.irq0,
53 cs,
54 p.PIN_24,
55 p.PIN_29,
56 p.DMA_CH0,
57 );
55 58
56 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 59 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new()); 60 let state = STATE.init(cyw43::State::new());
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index 61eeb82f7..fbc957e0e 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -7,11 +7,12 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43_pio::PioSpi; 10use cyw43::JoinOptions;
11use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
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;
16use embassy_rp::clocks::RoscRng; 17use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Level, Output}; 18use embassy_rp::gpio::{Level, Output};
@@ -19,7 +20,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio}; 20use embassy_rp::pio::{InterruptHandler, Pio};
20use embassy_time::{Duration, Timer}; 21use embassy_time::{Duration, Timer};
21use embedded_io_async::Write; 22use embedded_io_async::Write;
22use rand::RngCore;
23use static_cell::StaticCell; 23use static_cell::StaticCell;
24use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
25 25
@@ -27,8 +27,8 @@ bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>; 27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28}); 28});
29 29
30const WIFI_NETWORK: &str = "LadronDeWifi"; 30const WIFI_NETWORK: &str = "ssid"; // change to your network SSID
31const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; 31const WIFI_PASSWORD: &str = "pwd"; // change to your network password
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 34async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
@@ -36,8 +36,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -60,7 +60,16 @@ async fn main(spawner: Spawner) {
60 let pwr = Output::new(p.PIN_23, Level::Low); 60 let pwr = Output::new(p.PIN_23, Level::Low);
61 let cs = Output::new(p.PIN_25, Level::High); 61 let cs = Output::new(p.PIN_25, Level::High);
62 let mut pio = Pio::new(p.PIO0, Irqs); 62 let mut pio = Pio::new(p.PIO0, Irqs);
63 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 63 let spi = PioSpi::new(
64 &mut pio.common,
65 pio.sm0,
66 DEFAULT_CLOCK_DIVIDER,
67 pio.irq0,
68 cs,
69 p.PIN_24,
70 p.PIN_29,
71 p.DMA_CH0,
72 );
64 73
65 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 74 static STATE: StaticCell<cyw43::State> = StaticCell::new();
66 let state = STATE.init(cyw43::State::new()); 75 let state = STATE.init(cyw43::State::new());
@@ -83,20 +92,16 @@ async fn main(spawner: Spawner) {
83 let seed = rng.next_u64(); 92 let seed = rng.next_u64();
84 93
85 // Init network stack 94 // Init network stack
86 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
87 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
88 let stack = &*STACK.init(Stack::new( 96 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
89 net_device,
90 config,
91 RESOURCES.init(StackResources::new()),
92 seed,
93 ));
94 97
95 unwrap!(spawner.spawn(net_task(stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
96 99
97 loop { 100 loop {
98 //control.join_open(WIFI_NETWORK).await; 101 match control
99 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 102 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
103 .await
104 {
100 Ok(_) => break, 105 Ok(_) => break,
101 Err(err) => { 106 Err(err) => {
102 info!("join failed with status={}", err.status); 107 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
index 889371241..1efd1cd28 100644
--- a/examples/rp/src/bin/wifi_webrequest.rs
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -7,19 +7,19 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43_pio::PioSpi; 10use cyw43::JoinOptions;
11use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
11use defmt::*; 12use defmt::*;
12use embassy_executor::Spawner; 13use embassy_executor::Spawner;
13use embassy_net::dns::DnsSocket; 14use embassy_net::dns::DnsSocket;
14use embassy_net::tcp::client::{TcpClient, TcpClientState}; 15use embassy_net::tcp::client::{TcpClient, TcpClientState};
15use embassy_net::{Config, Stack, StackResources}; 16use embassy_net::{Config, StackResources};
16use embassy_rp::bind_interrupts; 17use embassy_rp::bind_interrupts;
17use embassy_rp::clocks::RoscRng; 18use embassy_rp::clocks::RoscRng;
18use embassy_rp::gpio::{Level, Output}; 19use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{DMA_CH0, PIO0}; 20use embassy_rp::peripherals::{DMA_CH0, PIO0};
20use embassy_rp::pio::{InterruptHandler, Pio}; 21use embassy_rp::pio::{InterruptHandler, Pio};
21use embassy_time::{Duration, Timer}; 22use embassy_time::{Duration, Timer};
22use rand::RngCore;
23use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; 23use reqwless::client::{HttpClient, TlsConfig, TlsVerify};
24use reqwless::request::Method; 24use reqwless::request::Method;
25use serde::Deserialize; 25use serde::Deserialize;
@@ -39,8 +39,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 42async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
43 stack.run().await 43 runner.run().await
44} 44}
45 45
46#[embassy_executor::main] 46#[embassy_executor::main]
@@ -62,7 +62,16 @@ async fn main(spawner: Spawner) {
62 let pwr = Output::new(p.PIN_23, Level::Low); 62 let pwr = Output::new(p.PIN_23, Level::Low);
63 let cs = Output::new(p.PIN_25, Level::High); 63 let cs = Output::new(p.PIN_25, Level::High);
64 let mut pio = Pio::new(p.PIO0, Irqs); 64 let mut pio = Pio::new(p.PIO0, Irqs);
65 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 65 let spi = PioSpi::new(
66 &mut pio.common,
67 pio.sm0,
68 DEFAULT_CLOCK_DIVIDER,
69 pio.irq0,
70 cs,
71 p.PIN_24,
72 p.PIN_29,
73 p.DMA_CH0,
74 );
66 75
67 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 76 static STATE: StaticCell<cyw43::State> = StaticCell::new();
68 let state = STATE.init(cyw43::State::new()); 77 let state = STATE.init(cyw43::State::new());
@@ -86,20 +95,16 @@ async fn main(spawner: Spawner) {
86 let seed = rng.next_u64(); 95 let seed = rng.next_u64();
87 96
88 // Init network stack 97 // Init network stack
89 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
90 static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new(); 98 static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new();
91 let stack = &*STACK.init(Stack::new( 99 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
92 net_device,
93 config,
94 RESOURCES.init(StackResources::new()),
95 seed,
96 ));
97 100
98 unwrap!(spawner.spawn(net_task(stack))); 101 unwrap!(spawner.spawn(net_task(runner)));
99 102
100 loop { 103 loop {
101 //match control.join_open(WIFI_NETWORK).await { // for open networks 104 match control
102 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 105 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
106 .await
107 {
103 Ok(_) => break, 108 Ok(_) => break,
104 Err(err) => { 109 Err(err) => {
105 info!("join failed with status={}", err.status); 110 info!("join failed with status={}", err.status);
diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
index 39f03c8e4..d1fb0eb00 100644
--- a/examples/rp/src/bin/zerocopy.rs
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -9,9 +9,9 @@ use core::sync::atomic::{AtomicU16, Ordering};
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; 11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::Pull; 12use embassy_rp::gpio::Pull;
14use embassy_rp::peripherals::DMA_CH0; 13use embassy_rp::peripherals::DMA_CH0;
14use embassy_rp::{bind_interrupts, Peri};
15use embassy_sync::blocking_mutex::raw::NoopRawMutex; 15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; 16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
17use embassy_time::{Duration, Ticker, Timer}; 17use embassy_time::{Duration, Ticker, Timer};
@@ -31,7 +31,7 @@ static MAX: AtomicU16 = AtomicU16::new(0);
31struct AdcParts { 31struct AdcParts {
32 adc: Adc<'static, Async>, 32 adc: Adc<'static, Async>,
33 pin: adc::Channel<'static>, 33 pin: adc::Channel<'static>,
34 dma: DMA_CH0, 34 dma: Peri<'static, DMA_CH0>,
35} 35}
36 36
37#[embassy_executor::main] 37#[embassy_executor::main]
@@ -70,7 +70,10 @@ async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut a
70 let buf = sender.send().await; 70 let buf = sender.send().await;
71 71
72 // Fill it with data 72 // Fill it with data
73 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); 73 adc.adc
74 .read_many(&mut adc.pin, buf, 1, adc.dma.reborrow())
75 .await
76 .unwrap();
74 77
75 // Notify the channel that the buffer is now ready to be received 78 // Notify the channel that the buffer is now ready to be received
76 sender.send_done(); 79 sender.send_done();
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
deleted file mode 100644
index 8f8d6ff10..000000000
--- a/examples/rp23/Cargo.toml
+++ /dev/null
@@ -1,80 +0,0 @@
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" }
74bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" }
75embassy-executor = { path = "../../embassy-executor" }
76embassy-sync = { path = "../../embassy-sync" }
77embassy-futures = { path = "../../embassy-futures" }
78embassy-time = { path = "../../embassy-time" }
79embassy-time-driver = { path = "../../embassy-time-driver" }
80embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs
deleted file mode 100644
index fc658267d..000000000
--- a/examples/rp23/src/bin/pio_hd44780.rs
+++ /dev/null
@@ -1,255 +0,0 @@
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_cargo_bin_name!(),
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
deleted file mode 100644
index 5a3bde759..000000000
--- a/examples/rp23/src/bin/pio_i2s.rs
+++ /dev/null
@@ -1,140 +0,0 @@
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_cargo_bin_name!(),
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
deleted file mode 100644
index 7c5eefc45..000000000
--- a/examples/rp23/src/bin/pio_pwm.rs
+++ /dev/null
@@ -1,133 +0,0 @@
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_cargo_bin_name!(),
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_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs
deleted file mode 100644
index 8b52dc37a..000000000
--- a/examples/rp23/src/bin/pio_stepper.rs
+++ /dev/null
@@ -1,183 +0,0 @@
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_cargo_bin_name!(),
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
deleted file mode 100644
index 99d9cf7e6..000000000
--- a/examples/rp23/src/bin/pio_ws2812.rs
+++ /dev/null
@@ -1,176 +0,0 @@
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_cargo_bin_name!(),
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
deleted file mode 100644
index 4cd3b3eb4..000000000
--- a/examples/rp23/src/bin/pwm.rs
+++ /dev/null
@@ -1,44 +0,0 @@
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_cargo_bin_name!(),
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/spi_display.rs b/examples/rp23/src/bin/spi_display.rs
deleted file mode 100644
index 2441b1186..000000000
--- a/examples/rp23/src/bin/spi_display.rs
+++ /dev/null
@@ -1,327 +0,0 @@
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_cargo_bin_name!(),
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/rp235x/.cargo/config.toml b/examples/rp235x/.cargo/config.toml
new file mode 100644
index 000000000..40f245785
--- /dev/null
+++ b/examples/rp235x/.cargo/config.toml
@@ -0,0 +1,10 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip RP235x"
3#runner = "elf2uf2-rs -d"
4#runner = "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/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml
new file mode 100644
index 000000000..c81b79ae1
--- /dev/null
+++ b/examples/rp235x/Cargo.toml
@@ -0,0 +1,65 @@
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.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] }
14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
20cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] }
21
22defmt = "1.0.1"
23defmt-rtt = "1.0.0"
24fixed = "1.23.1"
25fixed-macro = "1.2"
26
27serde = { version = "1.0.203", default-features = false, features = ["derive"] }
28serde-json-core = "0.5.1"
29
30# for assign resources example
31assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "bd22cb7a92031fb16f74a5da42469d466c33383e" }
32
33# for TB6612FNG example
34tb6612fng = "1.0.0"
35
36#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
37cortex-m = { version = "0.7.6", features = ["inline-asm"] }
38cortex-m-rt = "0.7.0"
39critical-section = "1.1"
40panic-probe = { version = "1.0.0", features = ["print-defmt"] }
41display-interface-spi = "0.5.0"
42embedded-graphics = "0.8.1"
43mipidsi = "0.8.0"
44display-interface = "0.5.0"
45byte-slice-cast = { version = "1.2.0", default-features = false }
46smart-leds = "0.3.0"
47heapless = "0.8"
48usbd-hid = "0.8.1"
49
50embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
51embedded-hal-async = "1.0"
52embedded-hal-bus = { version = "0.1", features = ["async"] }
53embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
54embedded-storage = { version = "0.3" }
55static_cell = "2.1"
56portable-atomic = { version = "1.5", features = ["critical-section"] }
57log = "0.4"
58embedded-sdmmc = "0.7.0"
59
60[profile.release]
61debug = 2
62
63[profile.dev]
64lto = true
65opt-level = "z"
diff --git a/examples/rp23/assets/ferris.raw b/examples/rp235x/assets/ferris.raw
index 9733889c5..9733889c5 100644
--- a/examples/rp23/assets/ferris.raw
+++ b/examples/rp235x/assets/ferris.raw
Binary files differ
diff --git a/examples/rp235x/build.rs b/examples/rp235x/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/rp235x/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/rp235x/memory.x
index 777492062..c803896f6 100644
--- a/examples/rp23/memory.x
+++ b/examples/rp235x/memory.x
@@ -31,6 +31,7 @@ SECTIONS {
31 { 31 {
32 __start_block_addr = .; 32 __start_block_addr = .;
33 KEEP(*(.start_block)); 33 KEEP(*(.start_block));
34 KEEP(*(.boot_info));
34 } > FLASH 35 } > FLASH
35 36
36} INSERT AFTER .vector_table; 37} INSERT AFTER .vector_table;
diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp235x/src/bin/adc.rs
index 19872607e..5c4135268 100644
--- a/examples/rp23/src/bin/adc.rs
+++ b/examples/rp235x/src/bin/adc.rs
@@ -1,4 +1,4 @@
1//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28. 1//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28.
2//! It also reads the temperature sensor in the chip. 2//! It also reads the temperature sensor in the chip.
3 3
4#![no_std] 4#![no_std]
@@ -8,25 +8,10 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; 9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull; 11use embassy_rp::gpio::Pull;
13use embassy_time::Timer; 12use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
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_cargo_bin_name!(),
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 { 15bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler; 16 ADC_IRQ_FIFO => InterruptHandler;
32}); 17});
@@ -55,7 +40,7 @@ async fn main(_spawner: Spawner) {
55} 40}
56 41
57fn convert_to_celsius(raw_temp: u16) -> f32 { 42fn convert_to_celsius(raw_temp: u16) -> f32 {
58 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet 43 // According to chapter 12.4.6 Temperature Sensor in RP235x datasheet
59 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721; 44 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 }; 45 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; 46 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp235x/src/bin/adc_dma.rs
index d538ddaa2..4003cc078 100644
--- a/examples/rp23/src/bin/adc_dma.rs
+++ b/examples/rp235x/src/bin/adc_dma.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads. 1//! This example shows how to use the RP235x ADC with DMA, both single- and multichannel reads.
2//! For multichannel, the samples are interleaved in the buffer: 2//! For multichannel, the samples are interleaved in the buffer:
3//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]` 3//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]`
4#![no_std] 4#![no_std]
@@ -8,25 +8,10 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; 9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull; 11use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Ticker}; 12use embassy_time::{Duration, Ticker};
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
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_cargo_bin_name!(),
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 { 15bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler; 16 ADC_IRQ_FIFO => InterruptHandler;
32}); 17});
@@ -53,13 +38,13 @@ async fn main(_spawner: Spawner) {
53 // Read 100 samples from a single channel 38 // Read 100 samples from a single channel
54 let mut buf = [0_u16; BLOCK_SIZE]; 39 let mut buf = [0_u16; BLOCK_SIZE];
55 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) 40 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1)
56 adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); 41 adc.read_many(&mut pin, &mut buf, div, dma.reborrow()).await.unwrap();
57 info!("single: {:?} ...etc", buf[..8]); 42 info!("single: {:?} ...etc", buf[..8]);
58 43
59 // Read 100 samples from 4 channels interleaved 44 // Read 100 samples from 4 channels interleaved
60 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; 45 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }];
61 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) 46 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1)
62 adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) 47 adc.read_many_multichannel(&mut pins, &mut buf, div, dma.reborrow())
63 .await 48 .await
64 .unwrap(); 49 .unwrap();
65 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); 50 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]);
diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp235x/src/bin/assign_resources.rs
index 923c13514..341f54d22 100644
--- a/examples/rp23/src/bin/assign_resources.rs
+++ b/examples/rp235x/src/bin/assign_resources.rs
@@ -14,26 +14,12 @@
14use assign_resources::assign_resources; 14use assign_resources::assign_resources;
15use defmt::*; 15use defmt::*;
16use embassy_executor::Spawner; 16use embassy_executor::Spawner;
17use embassy_rp::block::ImageDef;
18use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{self, PIN_20, PIN_21}; 18use embassy_rp::peripherals::{self, PIN_20, PIN_21};
19use embassy_rp::Peri;
20use embassy_time::Timer; 20use embassy_time::Timer;
21use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 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_cargo_bin_name!(),
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] 23#[embassy_executor::main]
38async fn main(spawner: Spawner) { 24async fn main(spawner: Spawner) {
39 // initialize the peripherals 25 // initialize the peripherals
@@ -53,7 +39,11 @@ async fn main(spawner: Spawner) {
53 39
54// 1) Assigning a resource to a task by passing parts of the peripherals. 40// 1) Assigning a resource to a task by passing parts of the peripherals.
55#[embassy_executor::task] 41#[embassy_executor::task]
56async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { 42async fn double_blinky_manually_assigned(
43 _spawner: Spawner,
44 pin_20: Peri<'static, PIN_20>,
45 pin_21: Peri<'static, PIN_21>,
46) {
57 let mut led_20 = Output::new(pin_20, Level::Low); 47 let mut led_20 = Output::new(pin_20, Level::Low);
58 let mut led_21 = Output::new(pin_21, Level::High); 48 let mut led_21 = Output::new(pin_21, Level::High);
59 49
diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp235x/src/bin/blinky.rs
index 02bdf9b3d..8a2464fbb 100644
--- a/examples/rp23/src/bin/blinky.rs
+++ b/examples/rp235x/src/bin/blinky.rs
@@ -1,36 +1,34 @@
1//! This example test the RP Pico on board LED. 1//! This example test the RP Pico on board LED.
2//! 2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs. 3//! It does not work with the RP Pico W board. See `blinky_wifi.rs`.
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio; 10use embassy_rp::gpio;
12use embassy_time::Timer; 11use embassy_time::Timer;
13use gpio::{Level, Output}; 12use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
16#[link_section = ".start_block"] 15// Program metadata for `picotool info`.
17#[used] 16// This isn't needed, but it's recomended to have these minimal entries.
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); 17#[unsafe(link_section = ".bi_entries")]
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used] 18#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 19pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info_rp_cargo_bin_name!(), 20 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"),
25 embassy_rp::binary_info_rp_cargo_version!(), 21 embassy_rp::binary_info::rp_program_description!(
26 embassy_rp::binary_info_rp_program_description!(c"Blinky"), 22 c"This example tests the RP Pico on board LED, connected to gpio 25"
27 embassy_rp::binary_info_rp_program_build_attribute!(), 23 ),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
28]; 26];
29 27
30#[embassy_executor::main] 28#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 29async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default()); 30 let p = embassy_rp::init(Default::default());
33 let mut led = Output::new(p.PIN_2, Level::Low); 31 let mut led = Output::new(p.PIN_25, Level::Low);
34 32
35 loop { 33 loop {
36 info!("led on!"); 34 info!("led on!");
diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp235x/src/bin/blinky_two_channels.rs
index 4d7dc89fa..51e139e94 100644
--- a/examples/rp23/src/bin/blinky_two_channels.rs
+++ b/examples/rp235x/src/bin/blinky_two_channels.rs
@@ -7,28 +7,13 @@
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) 7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio; 10use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::channel::{Channel, Sender}; 12use embassy_sync::channel::{Channel, Sender};
14use embassy_time::{Duration, Ticker}; 13use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output}; 14use gpio::{Level, Output};
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
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_cargo_bin_name!(),
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 { 17enum LedState {
33 Toggle, 18 Toggle,
34} 19}
@@ -37,7 +22,7 @@ static CHANNEL: Channel<ThreadModeRawMutex, LedState, 64> = Channel::new();
37#[embassy_executor::main] 22#[embassy_executor::main]
38async fn main(spawner: Spawner) { 23async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default()); 24 let p = embassy_rp::init(Default::default());
40 let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); 25 let mut led = Output::new(p.PIN_25, Level::High);
41 26
42 let dt = 100 * 1_000_000; 27 let dt = 100 * 1_000_000;
43 let k = 1.003; 28 let k = 1.003;
diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp235x/src/bin/blinky_two_tasks.rs
index 24b960242..67a9108c0 100644
--- a/examples/rp23/src/bin/blinky_two_tasks.rs
+++ b/examples/rp235x/src/bin/blinky_two_tasks.rs
@@ -7,28 +7,13 @@
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) 7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio; 10use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
14use embassy_time::{Duration, Ticker}; 13use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output}; 14use gpio::{Level, Output};
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
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_cargo_bin_name!(),
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>>>; 17type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>;
33static LED: LedType = Mutex::new(None); 18static LED: LedType = Mutex::new(None);
34 19
@@ -36,7 +21,7 @@ static LED: LedType = Mutex::new(None);
36async fn main(spawner: Spawner) { 21async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
38 // set the content of the global LED reference to the real LED pin 23 // 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); 24 let led = Output::new(p.PIN_25, Level::High);
40 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the 25 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the
41 // Mutex is released 26 // Mutex is released
42 { 27 {
diff --git a/examples/rp235x/src/bin/blinky_wifi.rs b/examples/rp235x/src/bin/blinky_wifi.rs
new file mode 100644
index 000000000..8c352ebc4
--- /dev/null
+++ b/examples/rp235x/src/bin/blinky_wifi.rs
@@ -0,0 +1,89 @@
1//! This example tests the RP Pico 2 W onboard LED.
2//!
3//! It does not work with the RP Pico 2 board. See `blinky.rs`.
4
5#![no_std]
6#![no_main]
7
8use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::{Level, Output};
13use embassy_rp::peripherals::{DMA_CH0, PIO0};
14use embassy_rp::pio::{InterruptHandler, Pio};
15use embassy_time::{Duration, Timer};
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _};
18
19// Program metadata for `picotool info`.
20// This isn't needed, but it's recommended to have these minimal entries.
21#[unsafe(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"Blinky Example"),
25 embassy_rp::binary_info::rp_program_description!(
26 c"This example tests the RP Pico 2 W's onboard LED, connected to GPIO 0 of the cyw43 \
27 (WiFi chip) via PIO 0 over the SPI bus."
28 ),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_build_attribute!(),
31];
32
33bind_interrupts!(struct Irqs {
34 PIO0_IRQ_0 => InterruptHandler<PIO0>;
35});
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::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
46 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
47
48 // To make flashing faster for development, you may want to flash the firmwares independently
49 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
50 // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP235x --base-address 0x10100000
51 // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP235x --base-address 0x10140000
52 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
53 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
54
55 let pwr = Output::new(p.PIN_23, Level::Low);
56 let cs = Output::new(p.PIN_25, Level::High);
57 let mut pio = Pio::new(p.PIO0, Irqs);
58 let spi = PioSpi::new(
59 &mut pio.common,
60 pio.sm0,
61 DEFAULT_CLOCK_DIVIDER,
62 pio.irq0,
63 cs,
64 p.PIN_24,
65 p.PIN_29,
66 p.DMA_CH0,
67 );
68
69 static STATE: StaticCell<cyw43::State> = StaticCell::new();
70 let state = STATE.init(cyw43::State::new());
71 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
72 unwrap!(spawner.spawn(cyw43_task(runner)));
73
74 control.init(clm).await;
75 control
76 .set_power_management(cyw43::PowerManagementMode::PowerSave)
77 .await;
78
79 let delay = Duration::from_millis(250);
80 loop {
81 info!("led on!");
82 control.gpio_set(0, true).await;
83 Timer::after(delay).await;
84
85 info!("led off!");
86 control.gpio_set(0, false).await;
87 Timer::after(delay).await;
88 }
89}
diff --git a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs
new file mode 100644
index 000000000..0a5bccfb3
--- /dev/null
+++ b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs
@@ -0,0 +1,88 @@
1//! This example test the Pimoroni Pico Plus 2 on board LED.
2//!
3//! It does not work with the RP Pico 2 board. See `blinky.rs`.
4
5#![no_std]
6#![no_main]
7
8use cyw43_pio::{PioSpi, RM2_CLOCK_DIVIDER};
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::peripherals::{DMA_CH0, PIO0};
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::{bind_interrupts, gpio};
14use embassy_time::{Duration, Timer};
15use gpio::{Level, Output};
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _};
18
19// Program metadata for `picotool info`.
20// This isn't needed, but it's recomended to have these minimal entries.
21#[unsafe(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"Blinky Example"),
25 embassy_rp::binary_info::rp_program_description!(
26 c"This example tests the RP Pico on board LED, connected to gpio 25"
27 ),
28 embassy_rp::binary_info::rp_cargo_version!(),
29 embassy_rp::binary_info::rp_program_build_attribute!(),
30];
31
32bind_interrupts!(struct Irqs {
33 PIO0_IRQ_0 => InterruptHandler<PIO0>;
34});
35
36#[embassy_executor::task]
37async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
38 runner.run().await
39}
40
41#[embassy_executor::main]
42async fn main(spawner: Spawner) {
43 let p = embassy_rp::init(Default::default());
44 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
45 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
46
47 // 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!`:
49 // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP235x --base-address 0x10100000
50 // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP235x --base-address 0x10140000
51 //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) };
53
54 let pwr = Output::new(p.PIN_23, Level::Low);
55 let cs = Output::new(p.PIN_25, Level::High);
56 let mut pio = Pio::new(p.PIO0, Irqs);
57 let spi = PioSpi::new(
58 &mut pio.common,
59 pio.sm0,
60 RM2_CLOCK_DIVIDER,
61 pio.irq0,
62 cs,
63 p.PIN_24,
64 p.PIN_29,
65 p.DMA_CH0,
66 );
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 delay = Duration::from_secs(1);
79 loop {
80 info!("led on!");
81 control.gpio_set(0, true).await;
82 Timer::after(delay).await;
83
84 info!("led off!");
85 control.gpio_set(0, false).await;
86 Timer::after(delay).await;
87 }
88}
diff --git a/examples/rp23/src/bin/button.rs b/examples/rp235x/src/bin/button.rs
index 0a0559397..4ad2ca3b7 100644
--- a/examples/rp23/src/bin/button.rs
+++ b/examples/rp235x/src/bin/button.rs
@@ -6,24 +6,9 @@
6#![no_main] 6#![no_main]
7 7
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Output, Pull}; 9use embassy_rp::gpio::{Input, Level, Output, Pull};
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
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_cargo_bin_name!(),
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] 12#[embassy_executor::main]
28async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default()); 14 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp235x/src/bin/debounce.rs
index e82e71f61..0077f19fc 100644
--- a/examples/rp23/src/bin/debounce.rs
+++ b/examples/rp235x/src/bin/debounce.rs
@@ -6,25 +6,10 @@
6 6
7use defmt::info; 7use defmt::info;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Pull}; 9use embassy_rp::gpio::{Input, Level, Pull};
11use embassy_time::{with_deadline, Duration, Instant, Timer}; 10use embassy_time::{with_deadline, Duration, Instant, Timer};
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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> { 13pub struct Debouncer<'a> {
29 input: Input<'a>, 14 input: Input<'a>,
30 debounce: Duration, 15 debounce: Duration,
diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp235x/src/bin/flash.rs
index 2917dda0b..31ad4aafc 100644
--- a/examples/rp23/src/bin/flash.rs
+++ b/examples/rp235x/src/bin/flash.rs
@@ -1,30 +1,15 @@
1//! This example test the flash connected to the RP2040 chip. 1//! This example test the flash connected to the RP2350 chip.
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE}; 8use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH; 9use embassy_rp::peripherals::FLASH;
11use embassy_time::Timer; 10use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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
28const ADDR_OFFSET: u32 = 0x100000; 13const ADDR_OFFSET: u32 = 0x100000;
29const FLASH_SIZE: usize = 2 * 1024 * 1024; 14const FLASH_SIZE: usize = 2 * 1024 * 1024;
30 15
@@ -41,22 +26,13 @@ async fn main(_spawner: Spawner) {
41 26
42 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); 27 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
43 28
44 // Get JEDEC id
45 let jedec = flash.blocking_jedec_id().unwrap();
46 info!("jedec id: 0x{:x}", jedec);
47
48 // Get unique id
49 let mut uid = [0; 8];
50 flash.blocking_unique_id(&mut uid).unwrap();
51 info!("unique id: {:?}", uid);
52
53 erase_write_sector(&mut flash, 0x00); 29 erase_write_sector(&mut flash, 0x00);
54 30
55 multiwrite_bytes(&mut flash, ERASE_SIZE as u32); 31 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
56 32
57 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; 33 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await;
58 34
59 loop {} 35 info!("Flash Works!");
60} 36}
61 37
62fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { 38fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
@@ -82,7 +58,7 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH
82 58
83 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); 59 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
84 info!("Contents after write starts with {=[u8]}", read_buf[0..4]); 60 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
85 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { 61 if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] {
86 defmt::panic!("unexpected"); 62 defmt::panic!("unexpected");
87 } 63 }
88} 64}
diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp235x/src/bin/gpio_async.rs
index 1618f7c8b..3be8569bc 100644
--- a/examples/rp23/src/bin/gpio_async.rs
+++ b/examples/rp235x/src/bin/gpio_async.rs
@@ -1,4 +1,4 @@
1//! This example shows how async gpio can be used with a RP2040. 1//! This example shows how async gpio can be used with a RP235x.
2//! 2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. 3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4 4
@@ -7,26 +7,11 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio; 10use embassy_rp::gpio;
12use embassy_time::Timer; 11use embassy_time::Timer;
13use gpio::{Input, Level, Output, Pull}; 12use gpio::{Input, Level, Output, Pull};
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
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_cargo_bin_name!(),
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 15/// 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 16/// 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. 17/// button so that it is possible to toggle the signal from low to high.
diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp235x/src/bin/gpout.rs
index b15963f02..011359253 100644
--- a/examples/rp23/src/bin/gpout.rs
+++ b/examples/rp235x/src/bin/gpout.rs
@@ -7,25 +7,10 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::clocks; 10use embassy_rp::clocks;
12use embassy_time::Timer; 11use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
14 13
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_cargo_bin_name!(),
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] 14#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default()); 16 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp235x/src/bin/i2c_async.rs
index 2528fe1d2..e31cc894c 100644
--- a/examples/rp23/src/bin/i2c_async.rs
+++ b/examples/rp235x/src/bin/i2c_async.rs
@@ -9,27 +9,12 @@
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts; 11use embassy_rp::bind_interrupts;
12use embassy_rp::block::ImageDef;
13use embassy_rp::i2c::{self, Config, InterruptHandler}; 12use embassy_rp::i2c::{self, Config, InterruptHandler};
14use embassy_rp::peripherals::I2C1; 13use embassy_rp::peripherals::I2C1;
15use embassy_time::Timer; 14use embassy_time::Timer;
16use embedded_hal_async::i2c::I2c; 15use embedded_hal_async::i2c::I2c;
17use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
18 17
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_cargo_bin_name!(),
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 { 18bind_interrupts!(struct Irqs {
34 I2C1_IRQ => InterruptHandler<I2C1>; 19 I2C1_IRQ => InterruptHandler<I2C1>;
35}); 20});
diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp235x/src/bin/i2c_async_embassy.rs
index 461b1d171..a65b71b9f 100644
--- a/examples/rp23/src/bin/i2c_async_embassy.rs
+++ b/examples/rp235x/src/bin/i2c_async_embassy.rs
@@ -7,24 +7,9 @@
7#![no_main] 7#![no_main]
8 8
9use defmt::*; 9use defmt::*;
10use embassy_rp::block::ImageDef;
11use embassy_rp::i2c::InterruptHandler; 10use embassy_rp::i2c::InterruptHandler;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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: 13// 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 14// 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, 15// It requires no configuration or calibration, works with all i2c bus speeds,
diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp235x/src/bin/i2c_blocking.rs
index 6d36d1890..c9c8a2760 100644
--- a/examples/rp23/src/bin/i2c_blocking.rs
+++ b/examples/rp235x/src/bin/i2c_blocking.rs
@@ -8,26 +8,11 @@
8 8
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::i2c::{self, Config}; 11use embassy_rp::i2c::{self, Config};
13use embassy_time::Timer; 12use embassy_time::Timer;
14use embedded_hal_1::i2c::I2c; 13use embedded_hal_1::i2c::I2c;
15use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
16 15
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_cargo_bin_name!(),
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)] 16#[allow(dead_code)]
32mod mcp23017 { 17mod mcp23017 {
33 pub const ADDR: u8 = 0x20; // default addr 18 pub const ADDR: u8 = 0x20; // default addr
diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp235x/src/bin/i2c_slave.rs
index 1f3408cf3..9fffb4646 100644
--- a/examples/rp23/src/bin/i2c_slave.rs
+++ b/examples/rp235x/src/bin/i2c_slave.rs
@@ -4,27 +4,12 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::{I2C0, I2C1}; 7use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave}; 8use embassy_rp::{bind_interrupts, i2c, i2c_slave};
10use embassy_time::Timer; 9use embassy_time::Timer;
11use embedded_hal_async::i2c::I2c; 10use embedded_hal_async::i2c::I2c;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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 { 13bind_interrupts!(struct Irqs {
29 I2C0_IRQ => i2c::InterruptHandler<I2C0>; 14 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
30 I2C1_IRQ => i2c::InterruptHandler<I2C1>; 15 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp235x/src/bin/interrupt.rs
index 6184b1bd7..e9ac76486 100644
--- a/examples/rp23/src/bin/interrupt.rs
+++ b/examples/rp235x/src/bin/interrupt.rs
@@ -13,7 +13,6 @@ use core::cell::{Cell, RefCell};
13use defmt::*; 13use defmt::*;
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking}; 15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::block::ImageDef;
17use embassy_rp::gpio::Pull; 16use embassy_rp::gpio::Pull;
18use embassy_rp::interrupt; 17use embassy_rp::interrupt;
19use embassy_rp::pwm::{Config, Pwm}; 18use embassy_rp::pwm::{Config, Pwm};
@@ -25,20 +24,6 @@ use portable_atomic::{AtomicU32, Ordering};
25use static_cell::StaticCell; 24use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
27 26
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_cargo_bin_name!(),
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); 27static COUNTER: AtomicU32 = AtomicU32::new(0);
43static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None)); 28static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
44static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> = 29static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
@@ -47,7 +32,6 @@ static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
47 32
48#[embassy_executor::main] 33#[embassy_executor::main]
49async fn main(spawner: Spawner) { 34async fn main(spawner: Spawner) {
50 embassy_rp::pac::SIO.spinlock(31).write_value(1);
51 let p = embassy_rp::init(Default::default()); 35 let p = embassy_rp::init(Default::default());
52 36
53 let adc = Adc::new_blocking(p.ADC, Default::default()); 37 let adc = Adc::new_blocking(p.ADC, Default::default());
diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp235x/src/bin/multicore.rs
index 8649143e1..f02dc3876 100644
--- a/examples/rp23/src/bin/multicore.rs
+++ b/examples/rp235x/src/bin/multicore.rs
@@ -1,4 +1,4 @@
1//! This example shows how to send messages between the two cores in the RP2040 chip. 1//! This example shows how to send messages between the two cores in the RP235x chip.
2//! 2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. 3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4 4
@@ -7,7 +7,6 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
12use embassy_rp::multicore::{spawn_core1, Stack}; 11use embassy_rp::multicore::{spawn_core1, Stack};
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 12use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@@ -16,20 +15,6 @@ use embassy_time::Timer;
16use static_cell::StaticCell; 15use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
18 17
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_cargo_bin_name!(),
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(); 18static mut CORE1_STACK: Stack<4096> = Stack::new();
34static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); 19static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
35static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); 20static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp235x/src/bin/multiprio.rs
index 7590fb431..2b397f97d 100644
--- a/examples/rp23/src/bin/multiprio.rs
+++ b/examples/rp235x/src/bin/multiprio.rs
@@ -59,27 +59,12 @@
59use cortex_m_rt::entry; 59use cortex_m_rt::entry;
60use defmt::{info, unwrap}; 60use defmt::{info, unwrap};
61use embassy_executor::{Executor, InterruptExecutor}; 61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_rp::block::ImageDef;
63use embassy_rp::interrupt; 62use embassy_rp::interrupt;
64use embassy_rp::interrupt::{InterruptExt, Priority}; 63use embassy_rp::interrupt::{InterruptExt, Priority};
65use embassy_time::{Instant, Timer, TICK_HZ}; 64use embassy_time::{Instant, Timer, TICK_HZ};
66use static_cell::StaticCell; 65use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 66use {defmt_rtt as _, panic_probe as _};
68 67
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_cargo_bin_name!(),
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] 68#[embassy_executor::task]
84async fn run_high() { 69async fn run_high() {
85 loop { 70 loop {
diff --git a/examples/rp235x/src/bin/otp.rs b/examples/rp235x/src/bin/otp.rs
new file mode 100644
index 000000000..5ffbb7610
--- /dev/null
+++ b/examples/rp235x/src/bin/otp.rs
@@ -0,0 +1,31 @@
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::otp;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let _ = embassy_rp::init(Default::default());
15 //
16 // add some delay to give an attached debug probe time to parse the
17 // defmt RTT header. Reading that header might touch flash memory, which
18 // interferes with flash write operations.
19 // https://github.com/knurling-rs/defmt/pull/683
20 Timer::after_millis(10).await;
21
22 let chip_id = unwrap!(otp::get_chipid());
23 info!("Unique id:{:X}", chip_id);
24
25 let private_rand = unwrap!(otp::get_private_random_number());
26 info!("Private Rand:{:X}", private_rand);
27
28 loop {
29 Timer::after_secs(1).await;
30 }
31}
diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs
new file mode 100644
index 000000000..5fd97ef97
--- /dev/null
+++ b/examples/rp235x/src/bin/overclock.rs
@@ -0,0 +1,74 @@
1//! # Overclocking the RP2350 to 200 MHz
2//!
3//! This example demonstrates how to configure the RP2350 to run at 200 MHz instead of the default 150 MHz.
4//!
5//! ## Note
6//!
7//! As of yet there is no official support for running the RP235x at higher clock frequencies and/or other core voltages than the default.
8//! Doing so may cause unexpected behavior and/or damage the chip.
9
10#![no_std]
11#![no_main]
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage};
16use embassy_rp::config::Config;
17use embassy_rp::gpio::{Level, Output};
18use embassy_time::{Duration, Instant, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21const COUNT_TO: i64 = 10_000_000;
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) -> ! {
25 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
26 let mut config = Config::new(ClockConfig::system_freq(200_000_000).unwrap());
27
28 // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us.
29 // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on
30 // what we know about the RP2040. This is not guaranteed to be correct.
31 config.clocks.core_voltage = CoreVoltage::V1_15;
32
33 // Initialize the peripherals
34 let p = embassy_rp::init(config);
35
36 // Show CPU frequency for verification
37 let sys_freq = clk_sys_freq();
38 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
39 // Show core voltage for verification
40 let core_voltage = core_voltage().unwrap();
41 info!("Core voltage: {}", core_voltage);
42
43 // LED to indicate the system is running
44 let mut led = Output::new(p.PIN_25, Level::Low);
45
46 loop {
47 // Reset the counter at the start of measurement period
48 let mut counter = 0;
49
50 // Turn LED on while counting
51 led.set_high();
52
53 let start = Instant::now();
54
55 // This is a busy loop that will take some time to complete
56 while counter < COUNT_TO {
57 counter += 1;
58 }
59
60 let elapsed = Instant::now() - start;
61
62 // Report the elapsed time
63 led.set_low();
64 info!(
65 "At {}Mhz: Elapsed time to count to {}: {}ms",
66 sys_freq / 1_000_000,
67 counter,
68 elapsed.as_millis()
69 );
70
71 // Wait 2 seconds before starting the next measurement
72 Timer::after(Duration::from_secs(2)).await;
73 }
74}
diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs
index 005708bc2..a519b8a50 100644
--- a/examples/rp23/src/bin/pio_async.rs
+++ b/examples/rp235x/src/bin/pio_async.rs
@@ -1,40 +1,26 @@
1//! This example shows powerful PIO module in the RP2040 chip. 1//! This example shows powerful PIO module in the RP235x chip.
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::block::ImageDef;
9use embassy_rp::peripherals::PIO0; 7use embassy_rp::peripherals::PIO0;
8use embassy_rp::pio::program::pio_asm;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; 9use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
10use embassy_rp::{bind_interrupts, Peri};
11use fixed::traits::ToFixed; 11use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8; 12use fixed_macro::types::U56F8;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 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_cargo_bin_name!(),
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 { 15bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => InterruptHandler<PIO0>; 16 PIO0_IRQ_0 => InterruptHandler<PIO0>;
31}); 17});
32 18
33fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { 19fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: Peri<'a, impl PioPin>) {
34 // Setup sm0 20 // Setup sm0
35 21
36 // Send data serially to pin 22 // Send data serially to pin
37 let prg = pio_proc::pio_asm!( 23 let prg = pio_asm!(
38 ".origin 16", 24 ".origin 16",
39 "set pindirs, 1", 25 "set pindirs, 1",
40 ".wrap_target", 26 ".wrap_target",
@@ -68,7 +54,7 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
68 // Setupm sm1 54 // Setupm sm1
69 55
70 // Read 0b10101 repeatedly until ISR is full 56 // Read 0b10101 repeatedly until ISR is full
71 let prg = pio_proc::pio_asm!( 57 let prg = pio_asm!(
72 // 58 //
73 ".origin 8", 59 ".origin 8",
74 "set x, 0x15", 60 "set x, 0x15",
@@ -98,7 +84,7 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
98 // Setup sm2 84 // Setup sm2
99 85
100 // Repeatedly trigger IRQ 3 86 // Repeatedly trigger IRQ 3
101 let prg = pio_proc::pio_asm!( 87 let prg = pio_asm!(
102 ".origin 0", 88 ".origin 0",
103 ".wrap_target", 89 ".wrap_target",
104 "set x,10", 90 "set x,10",
diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp235x/src/bin/pio_dma.rs
index 48fd9123f..17332a238 100644
--- a/examples/rp23/src/bin/pio_dma.rs
+++ b/examples/rp235x/src/bin/pio_dma.rs
@@ -1,32 +1,18 @@
1//! This example shows powerful PIO module in the RP2040 chip. 1//! This example shows powerful PIO module in the RP235x chip.
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join; 7use embassy_futures::join::join;
8use embassy_rp::block::ImageDef; 8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::program::pio_asm;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; 11use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::{bind_interrupts, Peripheral};
12use fixed::traits::ToFixed; 12use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8; 13use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 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_cargo_bin_name!(),
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 { 16bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>; 17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32}); 18});
@@ -47,7 +33,7 @@ async fn main(_spawner: Spawner) {
47 .. 33 ..
48 } = Pio::new(pio, Irqs); 34 } = Pio::new(pio, Irqs);
49 35
50 let prg = pio_proc::pio_asm!( 36 let prg = pio_asm!(
51 ".origin 0", 37 ".origin 0",
52 "set pindirs,1", 38 "set pindirs,1",
53 ".wrap_target", 39 ".wrap_target",
@@ -76,8 +62,8 @@ async fn main(_spawner: Spawner) {
76 sm.set_config(&cfg); 62 sm.set_config(&cfg);
77 sm.set_enable(true); 63 sm.set_enable(true);
78 64
79 let mut dma_out_ref = p.DMA_CH0.into_ref(); 65 let mut dma_out_ref = p.DMA_CH0;
80 let mut dma_in_ref = p.DMA_CH1.into_ref(); 66 let mut dma_in_ref = p.DMA_CH1;
81 let mut dout = [0x12345678u32; 29]; 67 let mut dout = [0x12345678u32; 29];
82 for i in 1..dout.len() { 68 for i in 1..dout.len() {
83 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; 69 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
@@ -86,8 +72,8 @@ async fn main(_spawner: Spawner) {
86 loop { 72 loop {
87 let (rx, tx) = sm.rx_tx(); 73 let (rx, tx) = sm.rx_tx();
88 join( 74 join(
89 tx.dma_push(dma_out_ref.reborrow(), &dout), 75 tx.dma_push(dma_out_ref.reborrow(), &dout, false),
90 rx.dma_pull(dma_in_ref.reborrow(), &mut din), 76 rx.dma_pull(dma_in_ref.reborrow(), &mut din, false),
91 ) 77 )
92 .await; 78 .await;
93 for i in 0..din.len() { 79 for i in 0..din.len() {
diff --git a/examples/rp235x/src/bin/pio_hd44780.rs b/examples/rp235x/src/bin/pio_hd44780.rs
new file mode 100644
index 000000000..06d989505
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_hd44780.rs
@@ -0,0 +1,87 @@
1//! This example shows powerful PIO module in the RP235x 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::bind_interrupts;
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram};
14use embassy_rp::pwm::{self, Pwm};
15use embassy_time::{Instant, Timer};
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(pub struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 // this test assumes a 2x16 HD44780 display attached as follow:
25 // rs = PIN0
26 // rw = PIN1
27 // e = PIN2
28 // db4 = PIN3
29 // db5 = PIN4
30 // db6 = PIN5
31 // db7 = PIN6
32 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
33 // allowing direct connection of the display to the RP235x without level shifters.
34 let p = embassy_rp::init(Default::default());
35
36 let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, {
37 let mut c = pwm::Config::default();
38 c.divider = 125.into();
39 c.top = 100;
40 c.compare_b = 50;
41 c
42 });
43
44 let Pio {
45 mut common, sm0, irq0, ..
46 } = Pio::new(p.PIO0, Irqs);
47
48 let word_prg = PioHD44780CommandWordProgram::new(&mut common);
49 let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common);
50
51 let mut hd = PioHD44780::new(
52 &mut common,
53 sm0,
54 irq0,
55 p.DMA_CH3,
56 p.PIN_0,
57 p.PIN_1,
58 p.PIN_2,
59 p.PIN_3,
60 p.PIN_4,
61 p.PIN_5,
62 p.PIN_6,
63 &word_prg,
64 &seq_prg,
65 )
66 .await;
67
68 loop {
69 struct Buf<const N: usize>([u8; N], usize);
70 impl<const N: usize> Write for Buf<N> {
71 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
72 for b in s.as_bytes() {
73 if self.1 >= N {
74 return Err(core::fmt::Error);
75 }
76 self.0[self.1] = *b;
77 self.1 += 1;
78 }
79 Ok(())
80 }
81 }
82 let mut buf = Buf([0; 16], 0);
83 write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
84 hd.add_line(&buf.0[0..buf.1]).await;
85 Timer::after_secs(1).await;
86 }
87}
diff --git a/examples/rp235x/src/bin/pio_i2s.rs b/examples/rp235x/src/bin/pio_i2s.rs
new file mode 100644
index 000000000..cfcb0221d
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_i2s.rs
@@ -0,0 +1,93 @@
1//! This example shows generating audio and sending it to a connected i2s DAC using the PIO
2//! module of the RP235x.
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::bind_interrupts;
17use embassy_rp::gpio::{Input, Pull};
18use embassy_rp::peripherals::PIO0;
19use embassy_rp::pio::{InterruptHandler, Pio};
20use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram};
21use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _};
23
24bind_interrupts!(struct Irqs {
25 PIO0_IRQ_0 => InterruptHandler<PIO0>;
26});
27
28const SAMPLE_RATE: u32 = 48_000;
29const BIT_DEPTH: u32 = 16;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34
35 // Setup pio state machine for i2s output
36 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
37
38 let bit_clock_pin = p.PIN_18;
39 let left_right_clock_pin = p.PIN_19;
40 let data_pin = p.PIN_20;
41
42 let program = PioI2sOutProgram::new(&mut common);
43 let mut i2s = PioI2sOut::new(
44 &mut common,
45 sm0,
46 p.DMA_CH0,
47 data_pin,
48 bit_clock_pin,
49 left_right_clock_pin,
50 SAMPLE_RATE,
51 BIT_DEPTH,
52 &program,
53 );
54
55 let fade_input = Input::new(p.PIN_0, Pull::Up);
56
57 // create two audio buffers (back and front) which will take turns being
58 // filled with new audio data and being sent to the pio fifo using dma
59 const BUFFER_SIZE: usize = 960;
60 static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new();
61 let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]);
62 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE);
63
64 // start pio state machine
65 let mut fade_value: i32 = 0;
66 let mut phase: i32 = 0;
67
68 loop {
69 // trigger transfer of front buffer data to the pio fifo
70 // but don't await the returned future, yet
71 let dma_future = i2s.write(front_buffer);
72
73 // fade in audio when bootsel is pressed
74 let fade_target = if fade_input.is_low() { i32::MAX } else { 0 };
75
76 // fill back buffer with fresh audio samples before awaiting the dma future
77 for s in back_buffer.iter_mut() {
78 // exponential approach of fade_value => fade_target
79 fade_value += (fade_target - fade_value) >> 14;
80 // generate triangle wave with amplitude and frequency based on fade value
81 phase = (phase + (fade_value >> 22)) & 0xffff;
82 let triangle_sample = (phase as i16 as i32).abs() - 16384;
83 let sample = (triangle_sample * (fade_value >> 15)) >> 16;
84 // duplicate mono sample into lower and upper half of dma word
85 *s = (sample as u16 as u32) * 0x10001;
86 }
87
88 // now await the dma future. once the dma finishes, the next buffer needs to be queued
89 // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us
90 dma_future.await;
91 mem::swap(&mut back_buffer, &mut front_buffer);
92 }
93}
diff --git a/examples/rp235x/src/bin/pio_onewire.rs b/examples/rp235x/src/bin/pio_onewire.rs
new file mode 100644
index 000000000..991510851
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_onewire.rs
@@ -0,0 +1,83 @@
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, InterruptHandler, Pio};
10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 PIO0_IRQ_0 => InterruptHandler<PIO0>;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_rp::init(Default::default());
21 let mut pio = Pio::new(p.PIO0, Irqs);
22
23 let prg = PioOneWireProgram::new(&mut pio.common);
24 let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
25
26 let mut sensor = Ds18b20::new(onewire);
27
28 loop {
29 sensor.start().await; // Start a new measurement
30 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
31 match sensor.temperature().await {
32 Ok(temp) => info!("temp = {:?} deg C", temp),
33 _ => error!("sensor error"),
34 }
35 Timer::after_secs(1).await;
36 }
37}
38
39/// DS18B20 temperature sensor driver
40pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
41 wire: PioOneWire<'d, PIO, SM>,
42}
43
44impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> {
45 pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self {
46 Self { wire }
47 }
48
49 /// Calculate CRC8 of the data
50 fn crc8(data: &[u8]) -> u8 {
51 let mut temp;
52 let mut data_byte;
53 let mut crc = 0;
54 for b in data {
55 data_byte = *b;
56 for _ in 0..8 {
57 temp = (crc ^ data_byte) & 0x01;
58 crc >>= 1;
59 if temp != 0 {
60 crc ^= 0x8C;
61 }
62 data_byte >>= 1;
63 }
64 }
65 crc
66 }
67
68 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
69 pub async fn start(&mut self) {
70 self.wire.write_bytes(&[0xCC, 0x44]).await;
71 }
72
73 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
74 pub async fn temperature(&mut self) -> Result<f32, ()> {
75 self.wire.write_bytes(&[0xCC, 0xBE]).await;
76 let mut data = [0; 9];
77 self.wire.read_bytes(&mut data).await;
78 match Self::crc8(&data) == 0 {
79 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.),
80 false => Err(()),
81 }
82 }
83}
diff --git a/examples/rp235x/src/bin/pio_pwm.rs b/examples/rp235x/src/bin/pio_pwm.rs
new file mode 100644
index 000000000..5712b5b91
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_pwm.rs
@@ -0,0 +1,38 @@
1//! This example shows how to create a pwm using the PIO module in the RP235x chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{InterruptHandler, Pio};
11use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15const REFRESH_INTERVAL: u64 = 20000;
16
17bind_interrupts!(struct Irqs {
18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let p = embassy_rp::init(Default::default());
24 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
25
26 // Note that PIN_25 is the led pin on the Pico
27 let prg = PioPwmProgram::new(&mut common);
28 let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg);
29 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL));
30 pwm_pio.start();
31
32 let mut duration = 0;
33 loop {
34 duration = (duration + 1) % 1000;
35 pwm_pio.write(Duration::from_micros(duration));
36 Timer::after_millis(1).await;
37 }
38}
diff --git a/examples/rp235x/src/bin/pio_rotary_encoder.rs b/examples/rp235x/src/bin/pio_rotary_encoder.rs
new file mode 100644
index 000000000..e820d316d
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_rotary_encoder.rs
@@ -0,0 +1,55 @@
1//! This example shows how to use the PIO module in the RP235x to read a quadrature rotary encoder.
2
3#![no_std]
4#![no_main]
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{InterruptHandler, Pio};
11use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram};
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 PIO0_IRQ_0 => InterruptHandler<PIO0>;
16});
17
18#[embassy_executor::task]
19async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) {
20 let mut count = 0;
21 loop {
22 info!("Count: {}", count);
23 count += match encoder.read().await {
24 Direction::Clockwise => 1,
25 Direction::CounterClockwise => -1,
26 };
27 }
28}
29
30#[embassy_executor::task]
31async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) {
32 let mut count = 0;
33 loop {
34 info!("Count: {}", count);
35 count += match encoder.read().await {
36 Direction::Clockwise => 1,
37 Direction::CounterClockwise => -1,
38 };
39 }
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let Pio {
46 mut common, sm0, sm1, ..
47 } = Pio::new(p.PIO0, Irqs);
48
49 let prg = PioEncoderProgram::new(&mut common);
50 let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg);
51 let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg);
52
53 spawner.must_spawn(encoder_0(encoder0));
54 spawner.must_spawn(encoder_1(encoder1));
55}
diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs
index 287992a83..61af94560 100644
--- a/examples/rp23/src/bin/pio_rotary_encoder.rs
+++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs
@@ -1,30 +1,28 @@
1//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder. 1//! This example shows how to use the PIO module in the RP235x to read a quadrature rotary encoder.
2//! It differs from the other example in that it uses the RX FIFO as a status register
2 3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
5 6
6use defmt::info; 7use defmt::info;
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull; 9use embassy_rp::gpio::Pull;
10use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
11use embassy_rp::{bind_interrupts, pio}; 11use embassy_rp::pio::program::pio_asm;
12use embassy_rp::{bind_interrupts, pio, Peri};
13use embassy_time::Timer;
12use fixed::traits::ToFixed; 14use fixed::traits::ToFixed;
13use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; 15use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine};
14use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
15 17
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info` 18// Program metadata for `picotool info`
21#[link_section = ".bi_entries"] 19#[unsafe(link_section = ".bi_entries")]
22#[used] 20#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info_rp_cargo_bin_name!(), 22 embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"),
25 embassy_rp::binary_info_rp_cargo_version!(), 23 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info_rp_program_description!(c"Blinky"), 24 embassy_rp::binary_info::rp_program_description!(c"Rotary encoder (RXF)"),
27 embassy_rp::binary_info_rp_program_build_attribute!(), 25 embassy_rp::binary_info::rp_program_build_attribute!(),
28]; 26];
29 27
30bind_interrupts!(struct Irqs { 28bind_interrupts!(struct Irqs {
@@ -39,36 +37,59 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
39 pub fn new( 37 pub fn new(
40 pio: &mut Common<'d, T>, 38 pio: &mut Common<'d, T>,
41 mut sm: StateMachine<'d, T, SM>, 39 mut sm: StateMachine<'d, T, SM>,
42 pin_a: impl PioPin, 40 pin_a: Peri<'d, impl PioPin>,
43 pin_b: impl PioPin, 41 pin_b: Peri<'d, impl PioPin>,
44 ) -> Self { 42 ) -> Self {
45 let mut pin_a = pio.make_pio_pin(pin_a); 43 let mut pin_a = pio.make_pio_pin(pin_a);
46 let mut pin_b = pio.make_pio_pin(pin_b); 44 let mut pin_b = pio.make_pio_pin(pin_b);
47 pin_a.set_pull(Pull::Up); 45 pin_a.set_pull(Pull::Up);
48 pin_b.set_pull(Pull::Up); 46 pin_b.set_pull(Pull::Up);
47
49 sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); 48 sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]);
50 49
51 let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); 50 let prg = pio_asm!(
51 "start:"
52 // encoder count is stored in X
53 "mov isr, x"
54 // and then moved to the RX FIFO register
55 "mov rxfifo[0], isr"
56
57 // wait for encoder transition
58 "wait 1 pin 1"
59 "wait 0 pin 1"
60
61 "set y, 0"
62 "mov y, pins[1]"
63
64 // update X depending on pin 1
65 "jmp !y decr"
66
67 // this is just a clever way of doing x++
68 "mov x, ~x"
69 "jmp x--, incr"
70 "incr:"
71 "mov x, ~x"
72 "jmp start"
73
74 // and this is x--
75 "decr:"
76 "jmp x--, start"
77 );
52 78
53 let mut cfg = Config::default(); 79 let mut cfg = Config::default();
54 cfg.set_in_pins(&[&pin_a, &pin_b]); 80 cfg.set_in_pins(&[&pin_a, &pin_b]);
55 cfg.fifo_join = FifoJoin::RxOnly; 81 cfg.fifo_join = FifoJoin::RxAsStatus;
56 cfg.shift_in.direction = ShiftDirection::Left; 82 cfg.shift_in.direction = ShiftDirection::Left;
57 cfg.clock_divider = 10_000.to_fixed(); 83 cfg.clock_divider = 10_000.to_fixed();
58 cfg.use_program(&pio.load_program(&prg.program), &[]); 84 cfg.use_program(&pio.load_program(&prg.program), &[]);
59 sm.set_config(&cfg); 85 sm.set_config(&cfg);
86
60 sm.set_enable(true); 87 sm.set_enable(true);
61 Self { sm } 88 Self { sm }
62 } 89 }
63 90
64 pub async fn read(&mut self) -> Direction { 91 pub async fn read(&mut self) -> i32 {
65 loop { 92 self.sm.get_rxf_entry(0) as i32
66 match self.sm.rx().wait_pull().await {
67 0 => return Direction::CounterClockwise,
68 1 => return Direction::Clockwise,
69 _ => {}
70 }
71 }
72 } 93 }
73} 94}
74 95
@@ -84,12 +105,8 @@ async fn main(_spawner: Spawner) {
84 105
85 let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); 106 let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5);
86 107
87 let mut count = 0;
88 loop { 108 loop {
89 info!("Count: {}", count); 109 info!("Count: {}", encoder.read().await);
90 count += match encoder.read().await { 110 Timer::after_millis(1000).await;
91 Direction::Clockwise => 1,
92 Direction::CounterClockwise => -1,
93 };
94 } 111 }
95} 112}
diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp235x/src/bin/pio_servo.rs
index 1dec86927..086b02f03 100644
--- a/examples/rp23/src/bin/pio_servo.rs
+++ b/examples/rp235x/src/bin/pio_servo.rs
@@ -1,33 +1,17 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip. 1//! This example shows how to create a pwm using the PIO module in the RP235x chip.
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5use core::time::Duration; 5use core::time::Duration;
6 6
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef; 8use embassy_rp::bind_interrupts;
9use embassy_rp::gpio::Level;
10use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; 10use embassy_rp::pio::{Instance, InterruptHandler, Pio};
12use embassy_rp::{bind_interrupts, clocks}; 11use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram};
13use embassy_time::Timer; 12use embassy_time::Timer;
14use pio::InstructionOperands;
15use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
16 14
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_cargo_bin_name!(),
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 15const 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 16const 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 17const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical
@@ -37,88 +21,8 @@ bind_interrupts!(struct Irqs {
37 PIO0_IRQ_0 => InterruptHandler<PIO0>; 21 PIO0_IRQ_0 => InterruptHandler<PIO0>;
38}); 22});
39 23
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> { 24pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
121 pwm: PwmPio<'d, T, SM>, 25 pwm: PioPwm<'d, T, SM>,
122 period: Duration, 26 period: Duration,
123 min_pulse_width: Duration, 27 min_pulse_width: Duration,
124 max_pulse_width: Duration, 28 max_pulse_width: Duration,
@@ -126,7 +30,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
126} 30}
127 31
128impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { 32impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
129 pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { 33 pub fn new(pwm: PioPwm<'d, T, SM>) -> Self {
130 Self { 34 Self {
131 pwm, 35 pwm,
132 period: Duration::from_micros(REFRESH_INTERVAL), 36 period: Duration::from_micros(REFRESH_INTERVAL),
@@ -168,7 +72,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
168} 72}
169 73
170pub struct Servo<'d, T: Instance, const SM: usize> { 74pub struct Servo<'d, T: Instance, const SM: usize> {
171 pwm: PwmPio<'d, T, SM>, 75 pwm: PioPwm<'d, T, SM>,
172 min_pulse_width: Duration, 76 min_pulse_width: Duration,
173 max_pulse_width: Duration, 77 max_pulse_width: Duration,
174 max_degree_rotation: u64, 78 max_degree_rotation: u64,
@@ -205,7 +109,8 @@ async fn main(_spawner: Spawner) {
205 let p = embassy_rp::init(Default::default()); 109 let p = embassy_rp::init(Default::default());
206 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); 110 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
207 111
208 let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); 112 let prg = PioPwmProgram::new(&mut common);
113 let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg);
209 let mut servo = ServoBuilder::new(pwm_pio) 114 let mut servo = ServoBuilder::new(pwm_pio)
210 .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo 115 .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. 116 .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment.
diff --git a/examples/rp235x/src/bin/pio_stepper.rs b/examples/rp235x/src/bin/pio_stepper.rs
new file mode 100644
index 000000000..931adbeda
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_stepper.rs
@@ -0,0 +1,49 @@
1//! This example shows how to use the PIO module in the RP235x 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]
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{InterruptHandler, Pio};
12use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram};
13use embassy_time::{with_timeout, Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = embassy_rp::init(Default::default());
23 let Pio {
24 mut common, irq0, sm0, ..
25 } = Pio::new(p.PIO0, Irqs);
26
27 let prg = PioStepperProgram::new(&mut common);
28 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg);
29 stepper.set_frequency(120);
30 loop {
31 info!("CW full steps");
32 stepper.step(1000).await;
33
34 info!("CCW full steps, drop after 1 sec");
35 if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX))
36 .await
37 .is_err()
38 {
39 info!("Time's up!");
40 Timer::after(Duration::from_secs(1)).await;
41 }
42
43 info!("CW half steps");
44 stepper.step_half(1000).await;
45
46 info!("CCW half steps");
47 stepper.step_half(-1000).await;
48 }
49}
diff --git a/examples/rp235x/src/bin/pio_uart.rs b/examples/rp235x/src/bin/pio_uart.rs
new file mode 100644
index 000000000..d92e33feb
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_uart.rs
@@ -0,0 +1,190 @@
1//! This example shows how to use the PIO module in the RP235x chip to implement a duplex UART.
2//! The PIO module is a very powerful peripheral that can be used to implement many different
3//! protocols. It is a very flexible state machine that can be programmed to do almost anything.
4//!
5//! This example opens up a USB device that implements a CDC ACM serial port. It then uses the
6//! PIO module to implement a UART that is connected to the USB serial port. This allows you to
7//! communicate with a device connected to the RP235x over USB serial.
8
9#![no_std]
10#![no_main]
11#![allow(async_fn_in_trait)]
12
13use defmt::{info, panic, trace};
14use embassy_executor::Spawner;
15use embassy_futures::join::{join, join3};
16use embassy_rp::peripherals::{PIO0, USB};
17use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram};
18use embassy_rp::usb::{Driver, Instance, InterruptHandler};
19use embassy_rp::{bind_interrupts, pio};
20use embassy_sync::blocking_mutex::raw::NoopRawMutex;
21use embassy_sync::pipe::Pipe;
22use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State};
23use embassy_usb::driver::EndpointError;
24use embassy_usb::{Builder, Config};
25use embedded_io_async::{Read, Write};
26use {defmt_rtt as _, panic_probe as _};
27
28bind_interrupts!(struct Irqs {
29 USBCTRL_IRQ => InterruptHandler<USB>;
30 PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
31});
32
33#[embassy_executor::main]
34async fn main(_spawner: Spawner) {
35 info!("Hello there!");
36
37 let p = embassy_rp::init(Default::default());
38
39 // Create the driver, from the HAL.
40 let driver = Driver::new(p.USB, Irqs);
41
42 // Create embassy-usb Config
43 let mut config = Config::new(0xc0de, 0xcafe);
44 config.manufacturer = Some("Embassy");
45 config.product = Some("PIO UART example");
46 config.serial_number = Some("12345678");
47 config.max_power = 100;
48 config.max_packet_size_0 = 64;
49
50 // Create embassy-usb DeviceBuilder using the driver and config.
51 // It needs some buffers for building the descriptors.
52 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 64];
55
56 let mut state = State::new();
57
58 let mut builder = Builder::new(
59 driver,
60 config,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut [], // no msos descriptors
64 &mut control_buf,
65 );
66
67 // Create classes on the builder.
68 let class = CdcAcmClass::new(&mut builder, &mut state, 64);
69
70 // Build the builder.
71 let mut usb = builder.build();
72
73 // Run the USB device.
74 let usb_fut = usb.run();
75
76 // PIO UART setup
77 let pio::Pio {
78 mut common, sm0, sm1, ..
79 } = pio::Pio::new(p.PIO0, Irqs);
80
81 let tx_program = PioUartTxProgram::new(&mut common);
82 let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program);
83
84 let rx_program = PioUartRxProgram::new(&mut common);
85 let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program);
86
87 // Pipe setup
88 let mut usb_pipe: Pipe<NoopRawMutex, 20> = Pipe::new();
89 let (mut usb_pipe_reader, mut usb_pipe_writer) = usb_pipe.split();
90
91 let mut uart_pipe: Pipe<NoopRawMutex, 20> = Pipe::new();
92 let (mut uart_pipe_reader, mut uart_pipe_writer) = uart_pipe.split();
93
94 let (mut usb_tx, mut usb_rx) = class.split();
95
96 // Read + write from USB
97 let usb_future = async {
98 loop {
99 info!("Wait for USB connection");
100 usb_rx.wait_connection().await;
101 info!("Connected");
102 let _ = join(
103 usb_read(&mut usb_rx, &mut uart_pipe_writer),
104 usb_write(&mut usb_tx, &mut usb_pipe_reader),
105 )
106 .await;
107 info!("Disconnected");
108 }
109 };
110
111 // Read + write from UART
112 let uart_future = join(
113 uart_read(&mut uart_rx, &mut usb_pipe_writer),
114 uart_write(&mut uart_tx, &mut uart_pipe_reader),
115 );
116
117 // Run everything concurrently.
118 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
119 join3(usb_fut, usb_future, uart_future).await;
120}
121
122struct Disconnected {}
123
124impl From<EndpointError> for Disconnected {
125 fn from(val: EndpointError) -> Self {
126 match val {
127 EndpointError::BufferOverflow => panic!("Buffer overflow"),
128 EndpointError::Disabled => Disconnected {},
129 }
130 }
131}
132
133/// Read from the USB and write it to the UART TX pipe
134async fn usb_read<'d, T: Instance + 'd>(
135 usb_rx: &mut Receiver<'d, Driver<'d, T>>,
136 uart_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>,
137) -> Result<(), Disconnected> {
138 let mut buf = [0; 64];
139 loop {
140 let n = usb_rx.read_packet(&mut buf).await?;
141 let data = &buf[..n];
142 trace!("USB IN: {:x}", data);
143 (*uart_pipe_writer).write(data).await;
144 }
145}
146
147/// Read from the USB TX pipe and write it to the USB
148async fn usb_write<'d, T: Instance + 'd>(
149 usb_tx: &mut Sender<'d, Driver<'d, T>>,
150 usb_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>,
151) -> Result<(), Disconnected> {
152 let mut buf = [0; 64];
153 loop {
154 let n = (*usb_pipe_reader).read(&mut buf).await;
155 let data = &buf[..n];
156 trace!("USB OUT: {:x}", data);
157 usb_tx.write_packet(&data).await?;
158 }
159}
160
161/// Read from the UART and write it to the USB TX pipe
162async fn uart_read<PIO: pio::Instance, const SM: usize>(
163 uart_rx: &mut PioUartRx<'_, PIO, SM>,
164 usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>,
165) -> ! {
166 let mut buf = [0; 64];
167 loop {
168 let n = uart_rx.read(&mut buf).await.expect("UART read error");
169 if n == 0 {
170 continue;
171 }
172 let data = &buf[..n];
173 trace!("UART IN: {:x}", buf);
174 (*usb_pipe_writer).write(data).await;
175 }
176}
177
178/// Read from the UART TX pipe and write it to the UART
179async fn uart_write<PIO: pio::Instance, const SM: usize>(
180 uart_tx: &mut PioUartTx<'_, PIO, SM>,
181 uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>,
182) -> ! {
183 let mut buf = [0; 64];
184 loop {
185 let n = (*uart_pipe_reader).read(&mut buf).await;
186 let data = &buf[..n];
187 trace!("UART OUT: {:x}", data);
188 let _ = uart_tx.write(&data).await;
189 }
190}
diff --git a/examples/rp235x/src/bin/pio_ws2812.rs b/examples/rp235x/src/bin/pio_ws2812.rs
new file mode 100644
index 000000000..42694c527
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_ws2812.rs
@@ -0,0 +1,68 @@
1//! This example shows powerful PIO module in the RP235x 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::bind_interrupts;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{InterruptHandler, Pio};
12use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program};
13use embassy_time::{Duration, Ticker};
14use smart_leds::RGB8;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
19});
20
21/// Input a value 0 to 255 to get a color value
22/// The colours are a transition r - g - b - back to r.
23fn wheel(mut wheel_pos: u8) -> RGB8 {
24 wheel_pos = 255 - wheel_pos;
25 if wheel_pos < 85 {
26 return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
27 }
28 if wheel_pos < 170 {
29 wheel_pos -= 85;
30 return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
31 }
32 wheel_pos -= 170;
33 (wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
34}
35
36#[embassy_executor::main]
37async fn main(_spawner: Spawner) {
38 info!("Start");
39 let p = embassy_rp::init(Default::default());
40
41 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
42
43 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
44 // feather boards for the 2040 both have one built in.
45 const NUM_LEDS: usize = 1;
46 let mut data = [RGB8::default(); NUM_LEDS];
47
48 // Common neopixel pins:
49 // Thing plus: 8
50 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4
51 let program = PioWs2812Program::new(&mut common);
52 let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program);
53
54 // Loop forever making RGB values and pushing them out to the WS2812.
55 let mut ticker = Ticker::every(Duration::from_millis(10));
56 loop {
57 for j in 0..(256 * 5) {
58 debug!("New Colors:");
59 for i in 0..NUM_LEDS {
60 data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
61 debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
62 }
63 ws2812.write(&data).await;
64
65 ticker.next().await;
66 }
67 }
68}
diff --git a/examples/rp235x/src/bin/pwm.rs b/examples/rp235x/src/bin/pwm.rs
new file mode 100644
index 000000000..da1acc18a
--- /dev/null
+++ b/examples/rp235x/src/bin/pwm.rs
@@ -0,0 +1,80 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP235x chip.
2//!
3//! We demonstrate two ways of using PWM:
4//! 1. Via config
5//! 2. Via setting a duty cycle
6
7#![no_std]
8#![no_main]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4};
13use embassy_rp::pwm::{Config, Pwm, SetDutyCycle};
14use embassy_rp::Peri;
15use embassy_time::Timer;
16use {defmt_rtt as _, panic_probe as _};
17
18#[embassy_executor::main]
19async fn main(spawner: Spawner) {
20 let p = embassy_rp::init(Default::default());
21 spawner.spawn(pwm_set_config(p.PWM_SLICE4, p.PIN_25)).unwrap();
22 spawner.spawn(pwm_set_dutycycle(p.PWM_SLICE2, p.PIN_4)).unwrap();
23}
24
25/// Demonstrate PWM by modifying & applying the config
26///
27/// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant)
28/// you must use another slice & pin and an appropriate resistor.
29#[embassy_executor::task]
30async fn pwm_set_config(slice4: Peri<'static, PWM_SLICE4>, pin25: Peri<'static, PIN_25>) {
31 let mut c = Config::default();
32 c.top = 32_768;
33 c.compare_b = 8;
34 let mut pwm = Pwm::new_output_b(slice4, pin25, c.clone());
35
36 loop {
37 info!("current LED duty cycle: {}/32768", c.compare_b);
38 Timer::after_secs(1).await;
39 c.compare_b = c.compare_b.rotate_left(4);
40 pwm.set_config(&c);
41 }
42}
43
44/// Demonstrate PWM by setting duty cycle
45///
46/// Using GP4 in Slice2, make sure to use an appropriate resistor.
47#[embassy_executor::task]
48async fn pwm_set_dutycycle(slice2: Peri<'static, PWM_SLICE2>, pin4: Peri<'static, PIN_4>) {
49 // If we aim for a specific frequency, here is how we can calculate the top value.
50 // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0.
51 // Every such wraparound is one PWM cycle. So here is how we get 25KHz:
52 let desired_freq_hz = 25_000;
53 let clock_freq_hz = embassy_rp::clocks::clk_sys_freq();
54 let divider = 16u8;
55 let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1;
56
57 let mut c = Config::default();
58 c.top = period;
59 c.divider = divider.into();
60
61 let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone());
62
63 loop {
64 // 100% duty cycle, fully on
65 pwm.set_duty_cycle_fully_on().unwrap();
66 Timer::after_secs(1).await;
67
68 // 66% duty cycle. Expressed as simple percentage.
69 pwm.set_duty_cycle_percent(66).unwrap();
70 Timer::after_secs(1).await;
71
72 // 25% duty cycle. Expressed as 32768/4 = 8192.
73 pwm.set_duty_cycle(c.top / 4).unwrap();
74 Timer::after_secs(1).await;
75
76 // 0% duty cycle, fully off.
77 pwm.set_duty_cycle_fully_off().unwrap();
78 Timer::after_secs(1).await;
79 }
80}
diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp235x/src/bin/pwm_input.rs
index b75d04963..bf454a936 100644
--- a/examples/rp23/src/bin/pwm_input.rs
+++ b/examples/rp235x/src/bin/pwm_input.rs
@@ -5,26 +5,11 @@
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull; 8use embassy_rp::gpio::Pull;
10use embassy_rp::pwm::{Config, InputMode, Pwm}; 9use embassy_rp::pwm::{Config, InputMode, Pwm};
11use embassy_time::{Duration, Ticker}; 10use embassy_time::{Duration, Ticker};
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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] 13#[embassy_executor::main]
29async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs
new file mode 100644
index 000000000..2cfb2038d
--- /dev/null
+++ b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs
@@ -0,0 +1,105 @@
1//! # PWM TB6612FNG motor driver
2//!
3//! This example shows the use of a TB6612FNG motor driver. The driver is built on top of embedded_hal and the example demonstrates how embassy_rp can be used to interact with ist.
4
5#![no_std]
6#![no_main]
7
8use assign_resources::assign_resources;
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::config::Config;
12use embassy_rp::gpio::Output;
13use embassy_rp::{gpio, peripherals, pwm, Peri};
14use embassy_time::{Duration, Timer};
15use tb6612fng::{DriveCommand, Motor, Tb6612fng};
16use {defmt_rtt as _, panic_probe as _};
17
18assign_resources! {
19 motor: MotorResources {
20 standby_pin: PIN_22,
21 left_slice: PWM_SLICE6,
22 left_pwm_pin: PIN_28,
23 left_forward_pin: PIN_21,
24 left_backward_pin: PIN_20,
25 right_slice: PWM_SLICE5,
26 right_pwm_pin: PIN_27,
27 right_forward_pin: PIN_19,
28 right_backward_pin: PIN_18,
29 },
30}
31
32#[embassy_executor::main]
33async fn main(_spawner: Spawner) {
34 let p = embassy_rp::init(Config::default());
35 let s = split_resources!(p);
36 let r = s.motor;
37
38 // we want a PWM frequency of 10KHz, especially cheaper motors do not respond well to higher frequencies
39 let desired_freq_hz = 10_000;
40 let clock_freq_hz = embassy_rp::clocks::clk_sys_freq();
41 let divider = 16u8;
42 let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1;
43
44 // we need a standby output and two motors to construct a full TB6612FNG
45
46 // standby pin
47 let stby = Output::new(r.standby_pin, gpio::Level::Low);
48
49 // motor A, here defined to be the left motor
50 let left_fwd = gpio::Output::new(r.left_forward_pin, gpio::Level::Low);
51 let left_bckw = gpio::Output::new(r.left_backward_pin, gpio::Level::Low);
52 let mut left_speed = pwm::Config::default();
53 left_speed.top = period;
54 left_speed.divider = divider.into();
55 let left_pwm = pwm::Pwm::new_output_a(r.left_slice, r.left_pwm_pin, left_speed);
56 let left_motor = Motor::new(left_fwd, left_bckw, left_pwm).unwrap();
57
58 // motor B, here defined to be the right motor
59 let right_fwd = gpio::Output::new(r.right_forward_pin, gpio::Level::Low);
60 let right_bckw = gpio::Output::new(r.right_backward_pin, gpio::Level::Low);
61 let mut right_speed = pwm::Config::default();
62 right_speed.top = period;
63 right_speed.divider = divider.into();
64 let right_pwm = pwm::Pwm::new_output_b(r.right_slice, r.right_pwm_pin, right_speed);
65 let right_motor = Motor::new(right_fwd, right_bckw, right_pwm).unwrap();
66
67 // construct the motor driver
68 let mut control = Tb6612fng::new(left_motor, right_motor, stby).unwrap();
69
70 loop {
71 // wake up the motor driver
72 info!("end standby");
73 control.disable_standby().unwrap();
74 Timer::after(Duration::from_millis(100)).await;
75
76 // drive a straight line forward at 20% speed for 5s
77 info!("drive straight");
78 control.motor_a.drive(DriveCommand::Forward(80)).unwrap();
79 control.motor_b.drive(DriveCommand::Forward(80)).unwrap();
80 Timer::after(Duration::from_secs(5)).await;
81
82 // coast for 2s
83 info!("coast");
84 control.motor_a.drive(DriveCommand::Stop).unwrap();
85 control.motor_b.drive(DriveCommand::Stop).unwrap();
86 Timer::after(Duration::from_secs(2)).await;
87
88 // actively brake
89 info!("brake");
90 control.motor_a.drive(DriveCommand::Brake).unwrap();
91 control.motor_b.drive(DriveCommand::Brake).unwrap();
92 Timer::after(Duration::from_secs(1)).await;
93
94 // slowly turn for 3s
95 info!("turn");
96 control.motor_a.drive(DriveCommand::Backward(50)).unwrap();
97 control.motor_b.drive(DriveCommand::Forward(50)).unwrap();
98 Timer::after(Duration::from_secs(3)).await;
99
100 // and put the driver in standby mode and wait for 5s
101 info!("standby");
102 control.enable_standby().unwrap();
103 Timer::after(Duration::from_secs(5)).await;
104 }
105}
diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp235x/src/bin/rosc.rs
index 28c778f51..942b72319 100644
--- a/examples/rp23/src/bin/rosc.rs
+++ b/examples/rp235x/src/bin/rosc.rs
@@ -7,26 +7,11 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::{clocks, gpio}; 10use embassy_rp::{clocks, gpio};
12use embassy_time::Timer; 11use embassy_time::Timer;
13use gpio::{Level, Output}; 12use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
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_cargo_bin_name!(),
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] 15#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
32 let mut config = embassy_rp::config::Config::default(); 17 let mut config = embassy_rp::config::Config::default();
diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp235x/src/bin/shared_bus.rs
index 00e65f80d..9267dfccb 100644
--- a/examples/rp23/src/bin/shared_bus.rs
+++ b/examples/rp235x/src/bin/shared_bus.rs
@@ -8,8 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; 8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::gpio::{AnyPin, Level, Output};
13use embassy_rp::i2c::{self, I2c, InterruptHandler}; 12use embassy_rp::i2c::{self, I2c, InterruptHandler};
14use embassy_rp::peripherals::{I2C1, SPI1}; 13use embassy_rp::peripherals::{I2C1, SPI1};
15use embassy_rp::spi::{self, Spi}; 14use embassy_rp::spi::{self, Spi};
@@ -19,20 +18,6 @@ use embassy_time::Timer;
19use static_cell::StaticCell; 18use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
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_cargo_bin_name!(),
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>>; 21type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>;
37type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>; 22type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>;
38 23
@@ -60,8 +45,8 @@ async fn main(spawner: Spawner) {
60 let spi_bus = SPI_BUS.init(Mutex::new(spi)); 45 let spi_bus = SPI_BUS.init(Mutex::new(spi));
61 46
62 // Chip select pins for the SPI devices 47 // Chip select pins for the SPI devices
63 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); 48 let cs_a = Output::new(p.PIN_0, Level::High);
64 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); 49 let cs_b = Output::new(p.PIN_1, Level::High);
65 50
66 spawner.must_spawn(spi_task_a(spi_bus, cs_a)); 51 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
67 spawner.must_spawn(spi_task_b(spi_bus, cs_b)); 52 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs
index b5ef08147..856be6ace 100644
--- a/examples/rp23/src/bin/sharing.rs
+++ b/examples/rp235x/src/bin/sharing.rs
@@ -19,7 +19,6 @@ use core::sync::atomic::{AtomicU32, Ordering};
19use cortex_m_rt::entry; 19use cortex_m_rt::entry;
20use defmt::info; 20use defmt::info;
21use embassy_executor::{Executor, InterruptExecutor}; 21use embassy_executor::{Executor, InterruptExecutor};
22use embassy_rp::block::ImageDef;
23use embassy_rp::clocks::RoscRng; 22use embassy_rp::clocks::RoscRng;
24use embassy_rp::interrupt::{InterruptExt, Priority}; 23use embassy_rp::interrupt::{InterruptExt, Priority};
25use embassy_rp::peripherals::UART0; 24use embassy_rp::peripherals::UART0;
@@ -28,25 +27,10 @@ use embassy_rp::{bind_interrupts, interrupt};
28use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
29use embassy_sync::{blocking_mutex, mutex}; 28use embassy_sync::{blocking_mutex, mutex};
30use embassy_time::{Duration, Ticker}; 29use embassy_time::{Duration, Ticker};
31use rand::RngCore;
32use static_cell::{ConstStaticCell, StaticCell}; 30use static_cell::{ConstStaticCell, StaticCell};
33use {defmt_rtt as _, panic_probe as _}; 31use {defmt_rtt as _, panic_probe as _};
34 32
35#[link_section = ".start_block"] 33type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
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_cargo_bin_name!(),
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 34
51struct MyType { 35struct MyType {
52 inner: u32, 36 inner: u32,
diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp235x/src/bin/spi.rs
index 98aa7622c..308f05c01 100644
--- a/examples/rp23/src/bin/spi.rs
+++ b/examples/rp235x/src/bin/spi.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. 1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP235x chip.
2//! 2//!
3//! Example for resistive touch sensor in Waveshare Pico-ResTouch 3//! Example for resistive touch sensor in Waveshare Pico-ResTouch
4 4
@@ -7,26 +7,11 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::spi::Spi; 10use embassy_rp::spi::Spi;
12use embassy_rp::{gpio, spi}; 11use embassy_rp::{gpio, spi};
13use gpio::{Level, Output}; 12use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
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_cargo_bin_name!(),
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] 15#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default()); 17 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp235x/src/bin/spi_async.rs
index 71eaa5c05..62bedc68a 100644
--- a/examples/rp23/src/bin/spi_async.rs
+++ b/examples/rp235x/src/bin/spi_async.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. 1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP235x chip.
2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back. 2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back.
3 3
4#![no_std] 4#![no_std]
@@ -6,25 +6,10 @@
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::spi::{Config, Spi}; 9use embassy_rp::spi::{Config, Spi};
11use embassy_time::Timer; 10use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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] 13#[embassy_executor::main]
29async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp235x/src/bin/spi_display.rs b/examples/rp235x/src/bin/spi_display.rs
new file mode 100644
index 000000000..9967abefd
--- /dev/null
+++ b/examples/rp235x/src/bin/spi_display.rs
@@ -0,0 +1,177 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2350 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 display_interface_spi::SPIInterface;
13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
14use embassy_executor::Spawner;
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 mipidsi::models::ST7789;
29use mipidsi::options::{Orientation, Rotation};
30use mipidsi::Builder;
31use {defmt_rtt as _, panic_probe as _};
32
33use crate::touch::Touch;
34
35const DISPLAY_FREQ: u32 = 64_000_000;
36const TOUCH_FREQ: u32 = 200_000;
37
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) {
40 let p = embassy_rp::init(Default::default());
41 info!("Hello World!");
42
43 let bl = p.PIN_13;
44 let rst = p.PIN_15;
45 let display_cs = p.PIN_9;
46 let dcx = p.PIN_8;
47 let miso = p.PIN_12;
48 let mosi = p.PIN_11;
49 let clk = p.PIN_10;
50 let touch_cs = p.PIN_16;
51 //let touch_irq = p.PIN_17;
52
53 // create SPI
54 let mut display_config = spi::Config::default();
55 display_config.frequency = DISPLAY_FREQ;
56 display_config.phase = spi::Phase::CaptureOnSecondTransition;
57 display_config.polarity = spi::Polarity::IdleHigh;
58 let mut touch_config = spi::Config::default();
59 touch_config.frequency = TOUCH_FREQ;
60 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
61 touch_config.polarity = spi::Polarity::IdleHigh;
62
63 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
64 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
65
66 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
67 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
68
69 let mut touch = Touch::new(touch_spi);
70
71 let dcx = Output::new(dcx, Level::Low);
72 let rst = Output::new(rst, Level::Low);
73 // dcx: 0 = command, 1 = data
74
75 // Enable LCD backlight
76 let _bl = Output::new(bl, Level::High);
77
78 // display interface abstraction from SPI and DC
79 let di = SPIInterface::new(display_spi, dcx);
80
81 // Define the display from the display interface and initialize it
82 let mut display = Builder::new(ST7789, di)
83 .display_size(240, 320)
84 .reset_pin(rst)
85 .orientation(Orientation::new().rotate(Rotation::Deg90))
86 .init(&mut Delay)
87 .unwrap();
88 display.clear(Rgb565::BLACK).unwrap();
89
90 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
91 let ferris = Image::new(&raw_image_data, Point::new(34, 68));
92
93 // Display the image
94 ferris.draw(&mut display).unwrap();
95
96 let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
97 Text::new(
98 "Hello embedded_graphics \n + embassy + RP235x!",
99 Point::new(20, 200),
100 style,
101 )
102 .draw(&mut display)
103 .unwrap();
104
105 loop {
106 if let Some((x, y)) = touch.read() {
107 let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build();
108
109 Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
110 .into_styled(style)
111 .draw(&mut display)
112 .unwrap();
113 }
114 }
115}
116
117/// Driver for the XPT2046 resistive touchscreen sensor
118mod touch {
119 use embedded_hal_1::spi::{Operation, SpiDevice};
120
121 struct Calibration {
122 x1: i32,
123 x2: i32,
124 y1: i32,
125 y2: i32,
126 sx: i32,
127 sy: i32,
128 }
129
130 const CALIBRATION: Calibration = Calibration {
131 x1: 3880,
132 x2: 340,
133 y1: 262,
134 y2: 3850,
135 sx: 320,
136 sy: 240,
137 };
138
139 pub struct Touch<SPI: SpiDevice> {
140 spi: SPI,
141 }
142
143 impl<SPI> Touch<SPI>
144 where
145 SPI: SpiDevice,
146 {
147 pub fn new(spi: SPI) -> Self {
148 Self { spi }
149 }
150
151 pub fn read(&mut self) -> Option<(i32, i32)> {
152 let mut x = [0; 2];
153 let mut y = [0; 2];
154 self.spi
155 .transaction(&mut [
156 Operation::Write(&[0x90]),
157 Operation::Read(&mut x),
158 Operation::Write(&[0xd0]),
159 Operation::Read(&mut y),
160 ])
161 .unwrap();
162
163 let x = (u16::from_be_bytes(x) >> 3) as i32;
164 let y = (u16::from_be_bytes(y) >> 3) as i32;
165
166 let cal = &CALIBRATION;
167
168 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
169 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
170 if x == 0 && y == 0 {
171 None
172 } else {
173 Some((x, y))
174 }
175 }
176 }
177}
diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp235x/src/bin/spi_sdmmc.rs
index d7af77a30..e14a62c31 100644
--- a/examples/rp23/src/bin/spi_sdmmc.rs
+++ b/examples/rp235x/src/bin/spi_sdmmc.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. 1//! This example shows how to use `embedded-sdmmc` with the RP235x chip, over SPI.
2//! 2//!
3//! The example will attempt to read a file `MY_FILE.TXT` from the root directory 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. 4//! of the SD card and print its contents.
@@ -9,7 +9,6 @@
9use defmt::*; 9use defmt::*;
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_rp::block::ImageDef;
13use embassy_rp::spi::Spi; 12use embassy_rp::spi::Spi;
14use embassy_rp::{gpio, spi}; 13use embassy_rp::{gpio, spi};
15use embedded_hal_bus::spi::ExclusiveDevice; 14use embedded_hal_bus::spi::ExclusiveDevice;
@@ -17,20 +16,6 @@ use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
17use gpio::{Level, Output}; 16use gpio::{Level, Output};
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
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_cargo_bin_name!(),
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(); 19struct DummyTimesource();
35 20
36impl embedded_sdmmc::TimeSource for DummyTimesource { 21impl embedded_sdmmc::TimeSource for DummyTimesource {
@@ -48,7 +33,6 @@ impl embedded_sdmmc::TimeSource for DummyTimesource {
48 33
49#[embassy_executor::main] 34#[embassy_executor::main]
50async fn main(_spawner: Spawner) { 35async fn main(_spawner: Spawner) {
51 embassy_rp::pac::SIO.spinlock(31).write_value(1);
52 let p = embassy_rp::init(Default::default()); 36 let p = embassy_rp::init(Default::default());
53 37
54 // SPI clock needs to be running at <= 400kHz during initialization 38 // SPI clock needs to be running at <= 400kHz during initialization
@@ -66,7 +50,7 @@ async fn main(_spawner: Spawner) {
66 // Now that the card is initialized, the SPI clock can go faster 50 // Now that the card is initialized, the SPI clock can go faster
67 let mut config = spi::Config::default(); 51 let mut config = spi::Config::default();
68 config.frequency = 16_000_000; 52 config.frequency = 16_000_000;
69 sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); 53 sdcard.spi(|dev| SetConfig::set_config(dev.bus_mut(), &config)).ok();
70 54
71 // Now let's look for volumes (also known as partitions) on our block device. 55 // 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. 56 // To do this we need a Volume Manager. It will take ownership of the block device.
diff --git a/examples/rp235x/src/bin/trng.rs b/examples/rp235x/src/bin/trng.rs
new file mode 100644
index 000000000..100d6b104
--- /dev/null
+++ b/examples/rp235x/src/bin/trng.rs
@@ -0,0 +1,48 @@
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::gpio::{Level, Output};
10use embassy_rp::peripherals::TRNG;
11use embassy_rp::trng::Trng;
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let peripherals = embassy_rp::init(Default::default());
22
23 // Initialize the TRNG with default configuration
24 let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default());
25 // A buffer to collect random bytes in.
26 let mut randomness = [0u8; 58];
27
28 let mut led = Output::new(peripherals.PIN_25, Level::Low);
29
30 loop {
31 trng.fill_bytes(&mut randomness).await;
32 info!("Random bytes async {}", &randomness);
33 trng.blocking_fill_bytes(&mut randomness);
34 info!("Random bytes blocking {}", &randomness);
35 let random_u32 = trng.blocking_next_u32();
36 let random_u64 = trng.blocking_next_u64();
37 info!("Random u32 {} u64 {}", random_u32, random_u64);
38 // Random number of blinks between 0 and 31
39 let blinks = random_u32 % 32;
40 for _ in 0..blinks {
41 led.set_high();
42 Timer::after_millis(20).await;
43 led.set_low();
44 Timer::after_millis(20).await;
45 }
46 Timer::after_millis(1000).await;
47 }
48}
diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp235x/src/bin/uart.rs
index ae00f36dc..ed912b959 100644
--- a/examples/rp23/src/bin/uart.rs
+++ b/examples/rp235x/src/bin/uart.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. 1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip.
2//! 2//!
3//! No specific hardware is specified in this example. Only output on pin 0 is tested. 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 4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
@@ -8,24 +8,9 @@
8#![no_main] 8#![no_main]
9 9
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::uart; 11use embassy_rp::uart;
13use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
14 13
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_cargo_bin_name!(),
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] 14#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default()); 16 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs
index 2b14520d5..7cad09f9b 100644
--- a/examples/rp23/src/bin/uart_buffered_split.rs
+++ b/examples/rp235x/src/bin/uart_buffered_split.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. 1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip.
2//! 2//!
3//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back. 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 4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
@@ -10,7 +10,6 @@
10use defmt::*; 10use defmt::*;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts; 12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::peripherals::UART0; 13use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; 14use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::Timer; 15use embassy_time::Timer;
@@ -18,20 +17,6 @@ use embedded_io_async::{Read, Write};
18use static_cell::StaticCell; 17use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
20 19
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_cargo_bin_name!(),
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 { 20bind_interrupts!(struct Irqs {
36 UART0_IRQ => BufferedInterruptHandler<UART0>; 21 UART0_IRQ => BufferedInterruptHandler<UART0>;
37}); 22});
@@ -45,7 +30,7 @@ async fn main(spawner: Spawner) {
45 let tx_buf = &mut TX_BUF.init([0; 16])[..]; 30 let tx_buf = &mut TX_BUF.init([0; 16])[..];
46 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); 31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
47 let rx_buf = &mut RX_BUF.init([0; 16])[..]; 32 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()); 33 let uart = BufferedUart::new(uart, tx_pin, rx_pin, Irqs, tx_buf, rx_buf, Config::default());
49 let (mut tx, rx) = uart.split(); 34 let (mut tx, rx) = uart.split();
50 35
51 unwrap!(spawner.spawn(reader(rx))); 36 unwrap!(spawner.spawn(reader(rx)));
@@ -63,7 +48,7 @@ async fn main(spawner: Spawner) {
63} 48}
64 49
65#[embassy_executor::task] 50#[embassy_executor::task]
66async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
67 info!("Reading..."); 52 info!("Reading...");
68 loop { 53 loop {
69 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp235x/src/bin/uart_r503.rs
index 39a17d305..085be280b 100644
--- a/examples/rp23/src/bin/uart_r503.rs
+++ b/examples/rp235x/src/bin/uart_r503.rs
@@ -4,27 +4,12 @@
4use defmt::{debug, error, info}; 4use defmt::{debug, error, info};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_rp::bind_interrupts; 6use embassy_rp::bind_interrupts;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::UART0; 7use embassy_rp::peripherals::UART0;
9use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; 8use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart};
10use embassy_time::{with_timeout, Duration, Timer}; 9use embassy_time::{with_timeout, Duration, Timer};
11use heapless::Vec; 10use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
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_cargo_bin_name!(),
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 { 13bind_interrupts!(pub struct Irqs {
29 UART0_IRQ => UARTInterruptHandler<UART0>; 14 UART0_IRQ => UARTInterruptHandler<UART0>;
30}); 15});
diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs
index 38210a8d0..45c9c8407 100644
--- a/examples/rp23/src/bin/uart_unidir.rs
+++ b/examples/rp235x/src/bin/uart_unidir.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. 1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip.
2//! 2//!
3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for 3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for
4//! this to work 4//! this to work
@@ -11,26 +11,11 @@
11use defmt::*; 11use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_rp::bind_interrupts; 13use embassy_rp::bind_interrupts;
14use embassy_rp::block::ImageDef;
15use embassy_rp::peripherals::UART1; 14use embassy_rp::peripherals::UART1;
16use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx}; 15use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
17use embassy_time::Timer; 16use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
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_cargo_bin_name!(),
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 { 19bind_interrupts!(struct Irqs {
35 UART1_IRQ => InterruptHandler<UART1>; 20 UART1_IRQ => InterruptHandler<UART1>;
36}); 21});
@@ -54,7 +39,7 @@ async fn main(spawner: Spawner) {
54} 39}
55 40
56#[embassy_executor::task] 41#[embassy_executor::task]
57async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
58 info!("Reading..."); 43 info!("Reading...");
59 loop { 44 loop {
60 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..6f496e23a
--- /dev/null
+++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,188 @@
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::gpio::{Input, Pull};
11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState};
14use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config, Handler};
16use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>;
21});
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let p = embassy_rp::init(Default::default());
26 // Create the driver, from the HAL.
27 let driver = UsbDriver::new(p.USB, Irqs);
28
29 // Create embassy-usb Config
30 let mut config = Config::new(0xc0de, 0xcafe);
31 config.manufacturer = Some("Embassy");
32 config.product = Some("HID keyboard example");
33 config.serial_number = Some("12345678");
34 config.max_power = 100;
35 config.max_packet_size_0 = 64;
36
37 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors.
39 let mut config_descriptor = [0; 256];
40 let mut bos_descriptor = [0; 256];
41 // You can also add a Microsoft OS descriptor.
42 let mut msos_descriptor = [0; 256];
43 let mut control_buf = [0; 64];
44 let mut request_handler = MyRequestHandler {};
45 let mut device_handler = MyDeviceHandler::new();
46
47 let mut state = HidState::new();
48
49 let mut builder = Builder::new(
50 driver,
51 config,
52 &mut config_descriptor,
53 &mut bos_descriptor,
54 &mut msos_descriptor,
55 &mut control_buf,
56 );
57
58 builder.handler(&mut device_handler);
59
60 // Create classes on the builder.
61 let config = embassy_usb::class::hid::Config {
62 report_descriptor: KeyboardReport::desc(),
63 request_handler: None,
64 poll_ms: 60,
65 max_packet_size: 64,
66 };
67 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
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 // Set up the signal pin that will be used to trigger the keyboard.
76 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
77
78 // Enable the schmitt trigger to slightly debounce.
79 signal_pin.set_schmitt(true);
80
81 let (reader, mut writer) = hid.split();
82
83 // Do stuff with the class!
84 let in_fut = async {
85 loop {
86 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier)
90 let report = KeyboardReport {
91 keycodes: [4, 0, 0, 0, 0, 0],
92 leds: 0,
93 modifier: 0,
94 reserved: 0,
95 };
96 // Send the report.
97 match writer.write_serialize(&report).await {
98 Ok(()) => {}
99 Err(e) => warn!("Failed to send report: {:?}", e),
100 };
101 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED");
103 let report = KeyboardReport {
104 keycodes: [0, 0, 0, 0, 0, 0],
105 leds: 0,
106 modifier: 0,
107 reserved: 0,
108 };
109 match writer.write_serialize(&report).await {
110 Ok(()) => {}
111 Err(e) => warn!("Failed to send report: {:?}", e),
112 };
113 }
114 };
115
116 let out_fut = async {
117 reader.run(false, &mut request_handler).await;
118 };
119
120 // Run everything concurrently.
121 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
122 join(usb_fut, join(in_fut, out_fut)).await;
123}
124
125struct MyRequestHandler {}
126
127impl RequestHandler for MyRequestHandler {
128 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
129 info!("Get report for {:?}", id);
130 None
131 }
132
133 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
134 info!("Set report for {:?}: {=[u8]}", id, data);
135 OutResponse::Accepted
136 }
137
138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur);
140 }
141
142 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
143 info!("Get idle rate for {:?}", id);
144 None
145 }
146}
147
148struct MyDeviceHandler {
149 configured: AtomicBool,
150}
151
152impl MyDeviceHandler {
153 fn new() -> Self {
154 MyDeviceHandler {
155 configured: AtomicBool::new(false),
156 }
157 }
158}
159
160impl Handler for MyDeviceHandler {
161 fn enabled(&mut self, enabled: bool) {
162 self.configured.store(false, Ordering::Relaxed);
163 if enabled {
164 info!("Device enabled");
165 } else {
166 info!("Device disabled");
167 }
168 }
169
170 fn reset(&mut self) {
171 self.configured.store(false, Ordering::Relaxed);
172 info!("Bus reset, the Vbus current limit is 100mA");
173 }
174
175 fn addressed(&mut self, addr: u8) {
176 self.configured.store(false, Ordering::Relaxed);
177 info!("USB address set to: {}", addr);
178 }
179
180 fn configured(&mut self, configured: bool) {
181 self.configured.store(configured, Ordering::Relaxed);
182 if configured {
183 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
184 } else {
185 info!("Device is no longer configured, the Vbus current limit is 100mA.");
186 }
187 }
188}
diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp235x/src/bin/usb_webusb.rs
index f4ecde30e..75d28c853 100644
--- a/examples/rp23/src/bin/usb_webusb.rs
+++ b/examples/rp235x/src/bin/usb_webusb.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. 1//! This example shows how to use USB (Universal Serial Bus) in the RP235x chip.
2//! 2//!
3//! This creates a WebUSB capable device that echoes data back to the host. 3//! This creates a WebUSB capable device that echoes data back to the host.
4//! 4//!
@@ -21,7 +21,6 @@ use defmt::info;
21use embassy_executor::Spawner; 21use embassy_executor::Spawner;
22use embassy_futures::join::join; 22use embassy_futures::join::join;
23use embassy_rp::bind_interrupts; 23use embassy_rp::bind_interrupts;
24use embassy_rp::block::ImageDef;
25use embassy_rp::peripherals::USB; 24use embassy_rp::peripherals::USB;
26use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; 25use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
27use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; 26use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb};
@@ -30,20 +29,6 @@ use embassy_usb::msos::{self, windows_version};
30use embassy_usb::{Builder, Config}; 29use embassy_usb::{Builder, Config};
31use {defmt_rtt as _, panic_probe as _}; 30use {defmt_rtt as _, panic_probe as _};
32 31
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_cargo_bin_name!(),
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 { 32bind_interrupts!(struct Irqs {
48 USBCTRL_IRQ => InterruptHandler<USB>; 33 USBCTRL_IRQ => InterruptHandler<USB>;
49}); 34});
@@ -66,12 +51,6 @@ async fn main(_spawner: Spawner) {
66 config.max_power = 100; 51 config.max_power = 100;
67 config.max_packet_size_0 = 64; 52 config.max_packet_size_0 = 64;
68 53
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. 54 // Create embassy-usb DeviceBuilder using the driver and config.
76 // It needs some buffers for building the descriptors. 55 // It needs some buffers for building the descriptors.
77 let mut config_descriptor = [0; 256]; 56 let mut config_descriptor = [0; 256];
diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp235x/src/bin/watchdog.rs
index 3ac457219..a54ec493a 100644
--- a/examples/rp23/src/bin/watchdog.rs
+++ b/examples/rp235x/src/bin/watchdog.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use Watchdog in the RP2040 chip. 1//! This example shows how to use Watchdog in the RP235x chip.
2//! 2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor. 3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor.
4 4
@@ -7,27 +7,12 @@
7 7
8use defmt::info; 8use defmt::info;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio; 10use embassy_rp::gpio;
12use embassy_rp::watchdog::*; 11use embassy_rp::watchdog::*;
13use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
14use gpio::{Level, Output}; 13use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
16 15
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_cargo_bin_name!(),
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] 16#[embassy_executor::main]
32async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default()); 18 let p = embassy_rp::init(Default::default());
diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs
index d04e1bf2a..086c86cac 100644
--- a/examples/rp23/src/bin/zerocopy.rs
+++ b/examples/rp235x/src/bin/zerocopy.rs
@@ -1,6 +1,6 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for 1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying. 2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA. 3//! The example also shows how to use the RP235x ADC with DMA.
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6 6
@@ -9,30 +9,15 @@ use core::sync::atomic::{AtomicU16, Ordering};
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; 11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::gpio::Pull; 12use embassy_rp::gpio::Pull;
15use embassy_rp::peripherals::DMA_CH0; 13use embassy_rp::peripherals::DMA_CH0;
14use embassy_rp::{bind_interrupts, Peri};
16use embassy_sync::blocking_mutex::raw::NoopRawMutex; 15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; 16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
18use embassy_time::{Duration, Ticker, Timer}; 17use embassy_time::{Duration, Ticker, Timer};
19use static_cell::StaticCell; 18use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
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_cargo_bin_name!(),
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]; 21type SampleBuffer = [u16; 512];
37 22
38bind_interrupts!(struct Irqs { 23bind_interrupts!(struct Irqs {
@@ -46,7 +31,7 @@ static MAX: AtomicU16 = AtomicU16::new(0);
46struct AdcParts { 31struct AdcParts {
47 adc: Adc<'static, Async>, 32 adc: Adc<'static, Async>,
48 pin: adc::Channel<'static>, 33 pin: adc::Channel<'static>,
49 dma: DMA_CH0, 34 dma: Peri<'static, DMA_CH0>,
50} 35}
51 36
52#[embassy_executor::main] 37#[embassy_executor::main]
@@ -85,7 +70,10 @@ async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut a
85 let buf = sender.send().await; 70 let buf = sender.send().await;
86 71
87 // Fill it with data 72 // Fill it with data
88 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); 73 adc.adc
74 .read_many(&mut adc.pin, buf, 1, adc.dma.reborrow())
75 .await
76 .unwrap();
89 77
90 // Notify the channel that the buffer is now ready to be received 78 // Notify the channel that the buffer is now ready to be received
91 sender.send_done(); 79 sender.send_done();
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 87491b1d2..63740963d 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/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.6.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } 10embassy-time = { version = "0.4.0", 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.7.0", path = "../../embassy-net", features=[ "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.2.0", path = "../../embassy-net-ppp", features = ["log"]}
14embedded-io-async = { version = "0.6.1" } 14embedded-io-async = { version = "0.6.1" }
15embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] } 15embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] }
16critical-section = { version = "1.1", features = ["std"] } 16critical-section = { version = "1.1", features = ["std"] }
@@ -21,7 +21,7 @@ futures = { version = "0.3.17" }
21log = "0.4.14" 21log = "0.4.14"
22nix = "0.26.2" 22nix = "0.26.2"
23clap = { version = "3.0.0-beta.5", features = ["derive"] } 23clap = { version = "3.0.0-beta.5", features = ["derive"] }
24rand_core = { version = "0.6.3", features = ["std"] } 24rand_core = { version = "0.9.1", features = ["std", "os_rng"] }
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26static_cell = "2" 26static_cell = "2"
27 27
diff --git a/examples/std/README.md b/examples/std/README.md
index e3a59d6ea..ac2c2a1a6 100644
--- a/examples/std/README.md
+++ b/examples/std/README.md
@@ -1,23 +1,128 @@
1 1
2## Running the `embassy-net` examples 2## Running the `embassy-net` examples
3 3
4First, create the tap0 interface. You only need to do this once. 4To run `net`, `tcp_accept`, `net_udp` and `net_dns` examples you will need a tap interface. Before running these examples, create the tap99 interface. (The number was chosen to
5hopefully not collide with anything.) You only need to do this once every time you reboot your computer.
5 6
6```sh 7```sh
7sudo ip tuntap add name tap0 mode tap user $USER 8cd $EMBASSY_ROOT/examples/std/
8sudo ip link set tap0 up 9sudo sh tap.sh
9sudo ip addr add 192.168.69.100/24 dev tap0
10sudo ip -6 addr add fe80::100/64 dev tap0
11sudo ip -6 addr add fdaa::100/64 dev tap0
12sudo ip -6 route add fe80::/64 dev tap0
13sudo ip -6 route add fdaa::/64 dev tap0
14``` 10```
15 11
16Second, have something listening there. For example `nc -lp 8000` 12The example `net_ppp` requires different steps that are detailed in its section.
13
14### `net` example
15
16For this example, you need to have something listening in the correct port. For example `nc -lp 8000`.
17 17
18Then run the example located in the `examples` folder: 18Then run the example located in the `examples` folder:
19 19
20```sh 20```sh
21cd $EMBASSY_ROOT/examples/std/ 21cd $EMBASSY_ROOT/examples/std/
22cargo run --bin net -- --static-ip 22cargo run --bin net -- --tap tap99 --static-ip
23```
24### `tcp_accept` example
25
26This example listen for a tcp connection.
27
28First run the example located in the `examples` folder:
29
30```sh
31cd $EMBASSY_ROOT/examples/std/
32cargo run --bin tcp_accept -- --tap tap99 --static-ip
33```
34
35Then open a connection to the port. For example `nc 192.168.69.2 9999`.
36
37### `net_udp` example
38
39This example listen for a udp connection.
40
41First run the example located in the `examples` folder:
42
43```sh
44cd $EMBASSY_ROOT/examples/std/
45cargo run --bin net_udp -- --tap tap99 --static-ip
46```
47
48Then open a connection to the port. For example `nc -u 192.168.69.2 9400`.
49
50### `net_dns` example
51
52This example queries a `DNS` for the IP address of `www.example.com`.
53
54In order to achieve this, the `tap99` interface requires configuring tap99 as a gateway device temporarily.
55
56For example, in Ubuntu you can do this by:
57
581. Identifying your default route device. In the next example `eth0`
59
60```sh
61ip r | grep "default"
62default via 192.168.2.1 dev eth0 proto kernel metric 35
63```
64
652. Enabling temporarily IP Forwarding:
66
67```sh
68sudo sysctl -w net.ipv4.ip_forward=1
69```
70
713. Configuring NAT to mascarade traffic from `tap99` to `eth0`
72
73```sh
74sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
75sudo iptables -A FORWARD -i tap99 -j ACCEPT
76sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
77```
78
794. Then you can run the example located in the `examples` folder:
80
81```sh
82cd $EMBASSY_ROOT/examples/std/
83cargo run --bin net_dns -- --tap tap99 --static-ip
84```
85
86### `net_ppp` example
87
88This example establish a Point-to-Point Protocol (PPP) connection that can be used, for example, for connecting to internet through a 4G modem via a serial channel.
89
90The example creates a PPP bridge over a virtual serial channel between `pty1` and `pty2` for the example code and a PPP server running on the same computer.
91
92To run this example you will need:
93- ppp (pppd server)
94- socat (socket CAT)
95
96To run the examples you may follow the next steps:
97
981. Save the PPP server configuration:
99```sh
100sudo sh -c 'echo "myuser $(hostname) mypass 192.168.7.10" >> /etc/ppp/pap-secrets'
101```
102
1032. Create a files `pty1` and `pty2` and link them
104```sh
105cd $EMBASSY_ROOT/examples/std/
106socat -v -x PTY,link=pty1,rawer PTY,link=pty2,rawer
107```
108
1093. open a second terminal and start the PPP server:
110```sh
111cd $EMBASSY_ROOT/examples/std/
112sudo pppd $PWD/pty1 115200 192.168.7.1: ms-dns 8.8.4.4 ms-dns 8.8.8.8 nodetach debug local persist silent
113```
114
1154. Open a third terminal and run the example
116```sh
117cd $EMBASSY_ROOT/examples/std/
118RUST_LOG=trace cargo run --bin net_ppp -- --device pty2
119```
1205. Observe the output in the second and third terminal
1216. Open one last terminal to interact with `net_ppp` example through the PPP connection
122```sh
123# ping the net_ppp client
124ping 192.168.7.10
125# open an tcp connection
126nc 192.168.7.10 1234
127# Type anything and observe the output in the different terminals
23``` 128```
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 310e7264d..232cf494b 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,13 +1,15 @@
1use core::fmt::Write as _;
2
1use clap::Parser; 3use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 4use embassy_executor::{Executor, Spawner};
3use embassy_net::tcp::TcpSocket; 5use embassy_net::tcp::TcpSocket;
4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
5use embassy_net_tuntap::TunTapDevice; 7use embassy_net_tuntap::TunTapDevice;
6use embassy_time::Duration; 8use embassy_time::Duration;
7use embedded_io_async::Write; 9use embedded_io_async::Write;
8use heapless::Vec; 10use heapless::Vec;
9use log::*; 11use log::*;
10use rand_core::{OsRng, RngCore}; 12use rand_core::{OsRng, TryRngCore};
11use static_cell::StaticCell; 13use static_cell::StaticCell;
12 14
13#[derive(Parser)] 15#[derive(Parser)]
@@ -22,8 +24,8 @@ struct Opts {
22} 24}
23 25
24#[embassy_executor::task] 26#[embassy_executor::task]
25async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
26 stack.run().await 28 runner.run().await
27} 29}
28 30
29#[embassy_executor::task] 31#[embassy_executor::task]
@@ -46,16 +48,15 @@ async fn main_task(spawner: Spawner) {
46 48
47 // Generate random seed 49 // Generate random seed
48 let mut seed = [0; 8]; 50 let mut seed = [0; 8];
49 OsRng.fill_bytes(&mut seed); 51 OsRng.try_fill_bytes(&mut seed).unwrap();
50 let seed = u64::from_le_bytes(seed); 52 let seed = u64::from_le_bytes(seed);
51 53
52 // Init network stack 54 // Init network stack
53 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
54 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 55 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
55 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 56 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
56 57
57 // Launch network task 58 // Launch network task
58 spawner.spawn(net_task(stack)).unwrap(); 59 spawner.spawn(net_task(runner)).unwrap();
59 60
60 // Then we can use it! 61 // Then we can use it!
61 let mut rx_buffer = [0; 4096]; 62 let mut rx_buffer = [0; 4096];
@@ -72,8 +73,10 @@ async fn main_task(spawner: Spawner) {
72 return; 73 return;
73 } 74 }
74 info!("connected!"); 75 info!("connected!");
75 loop { 76 for i in 0.. {
76 let r = socket.write_all(b"Hello!\n").await; 77 let mut buf = heapless::String::<100>::new();
78 write!(buf, "Hello! ({})\r\n", i).unwrap();
79 let r = socket.write_all(buf.as_bytes()).await;
77 if let Err(e) = r { 80 if let Err(e) = r {
78 warn!("write error: {:?}", e); 81 warn!("write error: {:?}", e);
79 return; 82 return;
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index c9615ef35..cf90731dd 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -1,11 +1,11 @@
1use clap::Parser; 1use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
3use embassy_net::dns::DnsQueryType; 3use embassy_net::dns::DnsQueryType;
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::*;
8use rand_core::{OsRng, RngCore}; 8use rand_core::{OsRng, TryRngCore};
9use static_cell::StaticCell; 9use static_cell::StaticCell;
10 10
11#[derive(Parser)] 11#[derive(Parser)]
@@ -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]
@@ -45,16 +45,15 @@ async fn main_task(spawner: Spawner) {
45 45
46 // Generate random seed 46 // Generate random seed
47 let mut seed = [0; 8]; 47 let mut seed = [0; 8];
48 OsRng.fill_bytes(&mut seed); 48 OsRng.try_fill_bytes(&mut seed).unwrap();
49 let seed = u64::from_le_bytes(seed); 49 let seed = u64::from_le_bytes(seed);
50 50
51 // Init network stack 51 // Init network stack
52 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
54 let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 53 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
55 54
56 // Launch network task 55 // Launch network task
57 spawner.spawn(net_task(stack)).unwrap(); 56 spawner.spawn(net_task(runner)).unwrap();
58 57
59 let host = "example.com"; 58 let host = "example.com";
60 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 c5c27c4a3..ac3aea6ff 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -16,14 +16,14 @@ use async_io::Async;
16use clap::Parser; 16use clap::Parser;
17use embassy_executor::{Executor, Spawner}; 17use embassy_executor::{Executor, Spawner};
18use embassy_net::tcp::TcpSocket; 18use embassy_net::tcp::TcpSocket;
19use embassy_net::{Config, ConfigV4, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 19use embassy_net::{Config, ConfigV4, Ipv4Cidr, Stack, StackResources};
20use embassy_net_ppp::Runner; 20use embassy_net_ppp::Runner;
21use embedded_io_async::Write; 21use embedded_io_async::Write;
22use futures::io::BufReader; 22use futures::io::BufReader;
23use heapless::Vec; 23use heapless::Vec;
24use log::*; 24use log::*;
25use nix::sys::termios; 25use nix::sys::termios;
26use rand_core::{OsRng, RngCore}; 26use rand_core::{OsRng, TryRngCore};
27use static_cell::StaticCell; 27use static_cell::StaticCell;
28 28
29use crate::serial_port::SerialPort; 29use crate::serial_port::SerialPort;
@@ -37,19 +37,15 @@ 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 = embedded_io_adapters::futures_03::FromFutures::new(port);
53 49
54 let config = embassy_net_ppp::Config { 50 let config = embassy_net_ppp::Config {
55 username: b"myuser", 51 username: b"myuser",
@@ -64,10 +60,10 @@ async fn ppp_task(
64 }; 60 };
65 let mut dns_servers = Vec::new(); 61 let mut dns_servers = Vec::new();
66 for s in ipv4.dns_servers.iter().flatten() { 62 for s in ipv4.dns_servers.iter().flatten() {
67 let _ = dns_servers.push(Ipv4Address::from_bytes(&s.0)); 63 let _ = dns_servers.push(*s);
68 } 64 }
69 let config = ConfigV4::Static(embassy_net::StaticConfigV4 { 65 let config = ConfigV4::Static(embassy_net::StaticConfigV4 {
70 address: Ipv4Cidr::new(Ipv4Address::from_bytes(&addr.0), 0), 66 address: Ipv4Cidr::new(addr, 0),
71 gateway: None, 67 gateway: None,
72 dns_servers, 68 dns_servers,
73 }); 69 });
@@ -93,21 +89,20 @@ async fn main_task(spawner: Spawner) {
93 89
94 // Generate random seed 90 // Generate random seed
95 let mut seed = [0; 8]; 91 let mut seed = [0; 8];
96 OsRng.fill_bytes(&mut seed); 92 OsRng.try_fill_bytes(&mut seed).unwrap();
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::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!
@@ -168,53 +163,3 @@ fn main() {
168 spawner.spawn(main_task(spawner)).unwrap(); 163 spawner.spawn(main_task(spawner)).unwrap();
169 }); 164 });
170} 165}
171
172mod adapter {
173 use core::future::poll_fn;
174 use core::pin::Pin;
175
176 use futures::AsyncBufReadExt;
177
178 /// Adapter from `futures::io` traits.
179 #[derive(Clone)]
180 pub struct FromFutures<T: ?Sized> {
181 inner: T,
182 }
183
184 impl<T> FromFutures<T> {
185 /// Create a new adapter.
186 pub fn new(inner: T) -> Self {
187 Self { inner }
188 }
189 }
190
191 impl<T: ?Sized> embedded_io_async::ErrorType for FromFutures<T> {
192 type Error = std::io::Error;
193 }
194
195 impl<T: futures::io::AsyncRead + Unpin + ?Sized> embedded_io_async::Read for FromFutures<T> {
196 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
197 poll_fn(|cx| Pin::new(&mut self.inner).poll_read(cx, buf)).await
198 }
199 }
200
201 impl<T: futures::io::AsyncBufRead + Unpin + ?Sized> embedded_io_async::BufRead for FromFutures<T> {
202 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
203 self.inner.fill_buf().await
204 }
205
206 fn consume(&mut self, amt: usize) {
207 Pin::new(&mut self.inner).consume(amt)
208 }
209 }
210
211 impl<T: futures::io::AsyncWrite + Unpin + ?Sized> embedded_io_async::Write for FromFutures<T> {
212 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
213 poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await
214 }
215
216 async fn flush(&mut self) -> Result<(), Self::Error> {
217 poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await
218 }
219 }
220}
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index b2ba4915a..53632a5b4 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -1,11 +1,11 @@
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::*;
8use rand_core::{OsRng, RngCore}; 8use rand_core::{OsRng, TryRngCore};
9use static_cell::StaticCell; 9use static_cell::StaticCell;
10 10
11#[derive(Parser)] 11#[derive(Parser)]
@@ -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]
@@ -44,16 +44,15 @@ async fn main_task(spawner: Spawner) {
44 44
45 // Generate random seed 45 // Generate random seed
46 let mut seed = [0; 8]; 46 let mut seed = [0; 8];
47 OsRng.fill_bytes(&mut seed); 47 OsRng.try_fill_bytes(&mut seed).unwrap();
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(device, config, RESOURCES.init(StackResources::new()), seed)); 52 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
54 53
55 // Launch network task 54 // Launch network task
56 spawner.spawn(net_task(stack)).unwrap(); 55 spawner.spawn(net_task(runner)).unwrap();
57 56
58 // Then we can use it! 57 // Then we can use it!
59 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 39b29a449..961c20e2d 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -1,15 +1,13 @@
1use core::fmt::Write as _;
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, Timer}; 6use embassy_time::{Duration, Timer};
9use embedded_io_async::Write as _; 7use embedded_io_async::Write as _;
10use heapless::Vec; 8use heapless::Vec;
11use log::*; 9use log::*;
12use rand_core::{OsRng, RngCore}; 10use rand_core::{OsRng, TryRngCore};
13use static_cell::StaticCell; 11use static_cell::StaticCell;
14 12
15#[derive(Parser)] 13#[derive(Parser)]
@@ -24,18 +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}
30
31#[derive(Default)]
32struct StrWrite(pub heapless::Vec<u8, 30>);
33
34impl core::fmt::Write for StrWrite {
35 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
36 self.0.extend_from_slice(s.as_bytes()).unwrap();
37 Ok(())
38 }
39} 27}
40 28
41#[embassy_executor::task] 29#[embassy_executor::task]
@@ -58,16 +46,15 @@ async fn main_task(spawner: Spawner) {
58 46
59 // Generate random seed 47 // Generate random seed
60 let mut seed = [0; 8]; 48 let mut seed = [0; 8];
61 OsRng.fill_bytes(&mut seed); 49 OsRng.try_fill_bytes(&mut seed).unwrap();
62 let seed = u64::from_le_bytes(seed); 50 let seed = u64::from_le_bytes(seed);
63 51
64 // Init network stack 52 // Init network stack
65 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
66 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
67 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 54 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
68 55
69 // Launch network task 56 // Launch network task
70 spawner.spawn(net_task(stack)).unwrap(); 57 spawner.spawn(net_task(runner)).unwrap();
71 58
72 // Then we can use it! 59 // Then we can use it!
73 let mut rx_buffer = [0; 4096]; 60 let mut rx_buffer = [0; 4096];
@@ -86,9 +73,8 @@ async fn main_task(spawner: Spawner) {
86 73
87 // Write some quick output 74 // Write some quick output
88 for i in 1..=5 { 75 for i in 1..=5 {
89 let mut w = StrWrite::default(); 76 let s = format!("{}! ", i);
90 write!(w, "{}! ", i).unwrap(); 77 let r = socket.write_all(s.as_bytes()).await;
91 let r = socket.write_all(&w.0).await;
92 if let Err(e) = r { 78 if let Err(e) = r {
93 warn!("write error: {:?}", e); 79 warn!("write error: {:?}", e);
94 return; 80 return;
diff --git a/examples/std/tap.sh b/examples/std/tap.sh
new file mode 100644
index 000000000..fb89d2381
--- /dev/null
+++ b/examples/std/tap.sh
@@ -0,0 +1,7 @@
1ip tuntap add name tap99 mode tap user $SUDO_USER
2ip link set tap99 up
3ip addr add 192.168.69.100/24 dev tap99
4ip -6 addr add fe80::100/64 dev tap99
5ip -6 addr add fdaa::100/64 dev tap99
6ip -6 route add fe80::/64 dev tap99
7ip -6 route add fdaa::/64 dev tap99
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 9102467eb..4cf07cef4 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -6,18 +6,18 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "1.0.1"
15defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
16 16
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-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 = "1.0.0", features = ["print-defmt"] }
21heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
22 22
23[profile.release] 23[profile.release]
diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs
new file mode 100644
index 000000000..1f54b0b18
--- /dev/null
+++ b/examples/stm32c0/src/bin/adc.rs
@@ -0,0 +1,58 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::vals::Scandir;
7use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime};
8use embassy_stm32::peripherals::ADC1;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let config = Default::default();
15 let p = embassy_stm32::init(config);
16
17 info!("ADC STM32C0 example.");
18
19 // We need to set certain sample time to be able to read temp sensor.
20 let mut adc = Adc::new(p.ADC1, SampleTime::CYCLES12_5, Resolution::BITS12);
21 let mut temp = adc.enable_temperature().degrade_adc();
22 let mut vref = adc.enable_vrefint().degrade_adc();
23 let mut pin0 = p.PA0.degrade_adc();
24
25 let mut dma = p.DMA1_CH1;
26 let mut read_buffer: [u16; 3] = [0; 3];
27
28 loop {
29 info!("============================");
30 let blocking_temp = adc.blocking_read(&mut temp);
31 let blocking_vref = adc.blocking_read(&mut vref);
32 let blocing_pin0 = adc.blocking_read(&mut pin0);
33 info!(
34 "Blocking ADC read: vref = {}, temp = {}, pin0 = {}.",
35 blocking_vref, blocking_temp, blocing_pin0
36 );
37
38 let channels_seqence: [&mut AnyAdcChannel<ADC1>; 3] = [&mut vref, &mut temp, &mut pin0];
39 adc.read(dma.reborrow(), channels_seqence.into_iter(), &mut read_buffer)
40 .await;
41 // Values are ordered according to hardware ADC channel number!
42 info!(
43 "DMA ADC read in set: vref = {}, temp = {}, pin0 = {}.",
44 read_buffer[0], read_buffer[1], read_buffer[2]
45 );
46
47 let hw_channel_selection: u32 =
48 (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel());
49 adc.read_in_hw_order(dma.reborrow(), hw_channel_selection, Scandir::UP, &mut read_buffer)
50 .await;
51 info!(
52 "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.",
53 read_buffer[2], read_buffer[1], read_buffer[0]
54 );
55
56 Timer::after_millis(2000).await;
57 }
58}
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 724efdaff..400e6b94c 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -6,15 +6,15 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f091rc to your chip name, if necessary. 8# Change stm32f091rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-tim2", "exti", "unstable-pac"] }
10cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 10cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
11cortex-m-rt = "0.7.0" 11cortex-m-rt = "0.7.0"
12defmt = "0.3" 12defmt = "1.0.1"
13defmt-rtt = "0.4" 13defmt-rtt = "1.0.0"
14panic-probe = { version = "0.3", features = ["print-defmt"] } 14panic-probe = { version = "1.0.0", features = ["print-defmt"] }
15embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
17embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18static_cell = "2" 18static_cell = "2"
19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
20 20
diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs
index 4465483d9..744df3e3b 100644
--- a/examples/stm32f0/src/bin/button_controlled_blink.rs
+++ b/examples/stm32f0/src/bin/button_controlled_blink.rs
@@ -8,14 +8,15 @@ use core::sync::atomic::{AtomicU32, Ordering};
8use defmt::info; 8use defmt::info;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Pull, Speed}; 11use embassy_stm32::gpio::{AnyPin, Level, Output, Pull, Speed};
12use embassy_stm32::Peri;
12use embassy_time::Timer; 13use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
14 15
15static BLINK_MS: AtomicU32 = AtomicU32::new(0); 16static BLINK_MS: AtomicU32 = AtomicU32::new(0);
16 17
17#[embassy_executor::task] 18#[embassy_executor::task]
18async fn led_task(led: AnyPin) { 19async fn led_task(led: Peri<'static, AnyPin>) {
19 // Configure the LED pin as a push pull output and obtain handler. 20 // Configure the LED pin as a push pull output and obtain handler.
20 // On the Nucleo F091RC there's an on-board LED connected to pin PA5. 21 // On the Nucleo F091RC there's an on-board LED connected to pin PA5.
21 let mut led = Output::new(led, Level::Low, Speed::Low); 22 let mut led = Output::new(led, Level::Low, Speed::Low);
@@ -45,7 +46,7 @@ async fn main(spawner: Spawner) {
45 BLINK_MS.store(del_var, Ordering::Relaxed); 46 BLINK_MS.store(del_var, Ordering::Relaxed);
46 47
47 // Spawn LED blinking task 48 // Spawn LED blinking task
48 spawner.spawn(led_task(p.PA5.degrade())).unwrap(); 49 spawner.spawn(led_task(p.PA5.into())).unwrap();
49 50
50 loop { 51 loop {
51 // Check if button got pressed 52 // Check if button got pressed
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 0084651a3..261733305 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.4.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 = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24nb = "1.0.0" 24nb = "1.0.0"
25static_cell = "2.0.0" 25static_cell = "2.0.0"
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs
index 5e2dab9e6..6fe8e0b50 100644
--- a/examples/stm32f1/src/bin/input_capture.rs
+++ b/examples/stm32f1/src/bin/input_capture.rs
@@ -7,14 +7,14 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel}; 9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals}; 10use embassy_stm32::{bind_interrupts, peripherals, Peri};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14/// Connect PA2 and PC13 with a 1k Ohm resistor 14/// Connect PA2 and PC13 with a 1k Ohm resistor
15 15
16#[embassy_executor::task] 16#[embassy_executor::task]
17async fn blinky(led: peripherals::PC13) { 17async fn blinky(led: Peri<'static, peripherals::PC13>) {
18 let mut led = Output::new(led, Level::High, Speed::Low); 18 let mut led = Output::new(led, Level::High, Speed::Low);
19 19
20 loop { 20 loop {
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs
index f74853d4e..afbef3edb 100644
--- a/examples/stm32f1/src/bin/pwm_input.rs
+++ b/examples/stm32f1/src/bin/pwm_input.rs
@@ -6,14 +6,14 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput; 8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer}; 9use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13/// Connect PA0 and PC13 with a 1k Ohm resistor 13/// Connect PA0 and PC13 with a 1k Ohm resistor
14 14
15#[embassy_executor::task] 15#[embassy_executor::task]
16async fn blinky(led: peripherals::PC13) { 16async fn blinky(led: Peri<'static, peripherals::PC13>) {
17 let mut led = Output::new(led, Level::High, Speed::Low); 17 let mut led = Output::new(led, Level::High, Speed::Low);
18 18
19 loop { 19 loop {
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index ee99acf41..77ec307b9 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) {
47 // Pull the D+ pin down to send a RESET condition to the USB bus. 47 // Pull the D+ pin down to send a RESET condition to the USB bus.
48 // This forced reset is needed only for development, without it host 48 // This forced reset is needed only for development, without it host
49 // will not reset your device when you upload new firmware. 49 // will not reset your device when you upload new firmware.
50 let _dp = Output::new(&mut p.PA12, Level::Low, Speed::Low); 50 let _dp = Output::new(p.PA12.reborrow(), Level::Low, Speed::Low);
51 Timer::after_millis(10).await; 51 Timer::after_millis(10).await;
52 } 52 }
53 53
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 60eb0eb93..905cffff0 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -6,18 +6,18 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "1.0.1"
15defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
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"] }
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 = "1.0.0", features = ["print-defmt"] }
21heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
22nb = "1.0.0" 22nb = "1.0.0"
23 23
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 7fda410d9..f675b0be1 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.4.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 = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24nb = "1.0.0" 24nb = "1.0.0"
25embedded-storage = "0.3.1" 25embedded-storage = "0.3.1"
diff --git a/examples/stm32f3/README.md b/examples/stm32f3/README.md
new file mode 100644
index 000000000..0a85c4858
--- /dev/null
+++ b/examples/stm32f3/README.md
@@ -0,0 +1,24 @@
1# Examples for STM32F3 family
2Run individual examples with
3```
4cargo run --bin <module-name>
5```
6for example
7```
8cargo run --bin blinky
9```
10
11## Checklist before running examples
12You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
13
14* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for F303ZE it should be `probe-rs run --chip STM32F303ZETx`. (use `probe-rs chip list` to find your chip)
15* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for F303ZE it should be `stm32f303ze`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
16* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
17* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
18
19If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
20
21* Which example you are trying to run
22* Which chip and board you are using
23
24Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs
deleted file mode 100644
index 5c8dac94f..000000000
--- a/examples/stm32f3/src/bin/blocking-tsc.rs
+++ /dev/null
@@ -1,98 +0,0 @@
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/tsc_blocking.rs b/examples/stm32f3/src/bin/tsc_blocking.rs
new file mode 100644
index 000000000..2c33838e5
--- /dev/null
+++ b/examples/stm32f3/src/bin/tsc_blocking.rs
@@ -0,0 +1,138 @@
1// Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// This example demonstrates:
4// 1. Configuring a single TSC channel pin
5// 2. Using the blocking TSC interface with polling
6// 3. Waiting for acquisition completion using `poll_for_acquisition`
7// 4. Reading touch values and controlling an LED based on the results
8//
9// Suggested physical setup on STM32F303ZE Nucleo board:
10// - Connect a 1000pF capacitor between pin PA10 and GND. This is your sampling capacitor.
11// - Connect one end of a 1K resistor to pin PA9 and leave the other end loose.
12// The loose end will act as the touch sensor which will register your touch.
13//
14// The example uses two pins from Group 4 of the TSC:
15// - PA10 as the sampling capacitor, TSC group 4 IO2 (D68 on the STM32F303ZE nucleo-board)
16// - PA9 as the channel pin, TSC group 4 IO1 (D69 on the STM32F303ZE nucleo-board)
17//
18// The program continuously reads the touch sensor value:
19// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value.
20// - The LED is turned on when touch is detected (sensor value < 40).
21// - Touch values are logged to the console.
22//
23// Troubleshooting:
24// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value.
25// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
26// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
27//
28// Note: Configuration values and sampling capacitor value have been determined experimentally.
29// Optimal values may vary based on your specific hardware setup.
30// Pins have been chosen for their convenient locations on the STM32F303ZE board. Refer to the
31// official relevant STM32 datasheets and user nucleo-board user manuals to find suitable
32// alternative pins.
33
34#![no_std]
35#![no_main]
36
37use defmt::*;
38use embassy_stm32::gpio::{Level, Output, Speed};
39use embassy_stm32::tsc::{self, *};
40use embassy_stm32::{mode, peripherals};
41use embassy_time::Timer;
42use {defmt_rtt as _, panic_probe as _};
43
44const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup
45
46#[embassy_executor::main]
47async fn main(_spawner: embassy_executor::Spawner) {
48 let device_config = embassy_stm32::Config::default();
49 let context = embassy_stm32::init(device_config);
50
51 let tsc_conf = Config {
52 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
53 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
54 spread_spectrum: false,
55 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
56 spread_spectrum_prescaler: false,
57 pulse_generator_prescaler: PGPrescalerDivider::_16,
58 max_count_value: MaxCount::_255,
59 io_default_mode: false,
60 synchro_pin_polarity: false,
61 acquisition_mode: false,
62 max_count_interrupt: false,
63 };
64
65 let mut g: PinGroupWithRoles<peripherals::TSC, G4> = PinGroupWithRoles::default();
66 // D68 on the STM32F303ZE nucleo-board
67 g.set_io2::<tsc::pin_roles::Sample>(context.PA10);
68 // D69 on the STM32F303ZE nucleo-board
69 let tsc_sensor = g.set_io1::<tsc::pin_roles::Channel>(context.PA9);
70
71 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
72 g4: Some(g.pin_group),
73 ..Default::default()
74 };
75
76 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap();
77
78 // Check if TSC is ready
79 if touch_controller.get_state() != State::Ready {
80 crate::panic!("TSC not ready!");
81 }
82 info!("TSC initialized successfully");
83
84 // LED2 on the STM32F303ZE nucleo-board
85 let mut led = Output::new(context.PB7, Level::High, Speed::Low);
86
87 // smaller sample capacitor discharge faster and can be used with shorter delay.
88 let discharge_delay = 5; // ms
89
90 // the interval at which the loop polls for new touch sensor values
91 let polling_interval = 100; // ms
92
93 info!("polling for touch");
94 loop {
95 touch_controller.set_active_channels_mask(tsc_sensor.pin.into());
96 touch_controller.start();
97 touch_controller.poll_for_acquisition();
98 touch_controller.discharge_io(true);
99 Timer::after_millis(discharge_delay).await;
100
101 match read_touch_value(&mut touch_controller, tsc_sensor.pin).await {
102 Some(v) => {
103 info!("sensor value {}", v);
104 if v < SENSOR_THRESHOLD {
105 led.set_high();
106 } else {
107 led.set_low();
108 }
109 }
110 None => led.set_low(),
111 }
112
113 Timer::after_millis(polling_interval).await;
114 }
115}
116
117const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10;
118
119// attempt to read group status and delay when still ongoing
120async fn read_touch_value(
121 touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>,
122 sensor_pin: tsc::IOPin,
123) -> Option<u16> {
124 for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS {
125 match touch_controller.group_get_status(sensor_pin.group()) {
126 GroupStatus::Complete => {
127 return Some(touch_controller.group_get_value(sensor_pin.group()));
128 }
129 GroupStatus::Ongoing => {
130 // if you end up here a lot, then you prob need to increase discharge_delay
131 // or consider changing the code to adjust the discharge_delay dynamically
132 info!("Acquisition still ongoing");
133 Timer::after_millis(1).await;
134 }
135 }
136 }
137 None
138}
diff --git a/examples/stm32f3/src/bin/tsc_multipin.rs b/examples/stm32f3/src/bin/tsc_multipin.rs
new file mode 100644
index 000000000..c524c3760
--- /dev/null
+++ b/examples/stm32f3/src/bin/tsc_multipin.rs
@@ -0,0 +1,204 @@
1// Example of TSC (Touch Sensing Controller) using multiple pins from the same tsc-group.
2//
3// What is special about using multiple TSC pins as sensor channels from the same TSC group,
4// is that only one TSC pin for each TSC group can be acquired and read at the time.
5// To control which channel pins are acquired and read, we must write a mask before initiating an
6// acquisition. To help manage and abstract all this business away, we can organize our channel
7// pins into acquisition banks. Each acquisition bank can contain exactly one channel pin per TSC
8// group and it will contain the relevant mask.
9//
10// This example demonstrates how to:
11// 1. Configure multiple channel pins within a single TSC group
12// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks)
13// 3. Read and interpret touch values from multiple channels in the same group
14//
15// Suggested physical setup on STM32F303ZE Nucleo board:
16// - Connect a 1000pF capacitor between pin PA10 and GND. This is the sampling capacitor for TSC
17// group 4.
18// - Connect one end of a 1K resistor to pin PA9 and leave the other end loose.
19// The loose end will act as a touch sensor.
20//
21// - Connect a 1000pF capacitor between pin PA7 and GND. This is the sampling capacitor for TSC
22// group 2.
23// - Connect one end of another 1K resistor to pin PA6 and leave the other end loose.
24// The loose end will act as a touch sensor.
25// - Connect one end of another 1K resistor to pin PA5 and leave the other end loose.
26// The loose end will act as a touch sensor.
27//
28// The example uses pins from two TSC groups.
29// - PA10 as sampling capacitor, TSC group 4 IO2
30// - PA9 as channel, TSC group 4 IO1
31// - PA7 as sampling capacitor, TSC group 2 IO4
32// - PA6 as channel, TSC group 2 IO3
33// - PA5 as channel, TSC group 2 IO2
34//
35// The pins have been chosen to make it easy to simply add capacitors directly onto the board and
36// connect one leg to GND, and to easily add resistors to the board with no special connectors,
37// breadboards, special wires or soldering required. All you need is the capacitors and resistors.
38//
39// The program reads the designated channel pins and adjusts the LED blinking
40// pattern based on which sensor(s) are touched:
41// - No touch: LED off
42// - one sensor touched: Slow blinking
43// - two sensors touched: Fast blinking
44// - three sensors touched: LED constantly on
45//
46// ## Troubleshooting:
47//
48// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20).
49// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
50// - Be aware that for some boards there will be overlapping concerns between some pins, for
51// example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will
52// be emitted if you try to use such a pin for TSC, but you will get strange sensor readings.
53//
54// Note: Configuration values and sampling capacitor values have been determined experimentally. Optimal values may vary based on your specific hardware setup. Refer to the official STM32 datasheet and user manuals for more information on pin configurations and TSC functionality.
55
56#![no_std]
57#![no_main]
58
59use defmt::*;
60use embassy_stm32::gpio::{Level, Output, Speed};
61use embassy_stm32::tsc::{self, *};
62use embassy_stm32::{mode, peripherals};
63use embassy_time::Timer;
64use {defmt_rtt as _, panic_probe as _};
65
66const SENSOR_THRESHOLD: u16 = 10;
67
68async fn acquire_sensors(
69 touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Blocking>,
70 tsc_acquisition_bank: &AcquisitionBank,
71) {
72 touch_controller.set_active_channels_bank(tsc_acquisition_bank);
73 touch_controller.start();
74 touch_controller.poll_for_acquisition();
75 touch_controller.discharge_io(true);
76 let discharge_delay = 5; // ms
77 Timer::after_millis(discharge_delay).await;
78}
79
80#[embassy_executor::main]
81async fn main(_spawner: embassy_executor::Spawner) {
82 let device_config = embassy_stm32::Config::default();
83 let context = embassy_stm32::init(device_config);
84
85 // ---------- initial configuration of TSC ----------
86 //
87 let mut pin_group4: PinGroupWithRoles<peripherals::TSC, G4> = PinGroupWithRoles::default();
88 // D68 on the STM32F303ZE nucleo-board
89 pin_group4.set_io2::<tsc::pin_roles::Sample>(context.PA10);
90 // D69 on the STM32F303ZE nucleo-board
91 let tsc_sensor0 = pin_group4.set_io1(context.PA9);
92
93 let mut pin_group2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
94 // D11 on the STM32F303ZE nucleo-board
95 pin_group2.set_io4::<tsc::pin_roles::Sample>(context.PA7);
96 // D12 on the STM32F303ZE nucleo-board
97 let tsc_sensor1 = pin_group2.set_io3(context.PA6);
98 // D13 on the STM32F303ZE nucleo-board
99 let tsc_sensor2 = pin_group2.set_io2(context.PA5);
100
101 let config = Config {
102 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
103 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
104 spread_spectrum: false,
105 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
106 spread_spectrum_prescaler: false,
107 pulse_generator_prescaler: PGPrescalerDivider::_16,
108 max_count_value: MaxCount::_255,
109 io_default_mode: false,
110 synchro_pin_polarity: false,
111 acquisition_mode: false,
112 max_count_interrupt: false,
113 };
114
115 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
116 g4: Some(pin_group4.pin_group),
117 g2: Some(pin_group2.pin_group),
118 ..Default::default()
119 };
120
121 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, config).unwrap();
122
123 // ---------- setting up acquisition banks ----------
124 // sensor0 and sensor1 in this example belong to different TSC-groups,
125 // therefore we can acquire and read them both in one go.
126 let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
127 g4_pin: Some(tsc_sensor0),
128 g2_pin: Some(tsc_sensor1),
129 ..Default::default()
130 });
131 // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to
132 // acquire them one at the time. Therefore, we organize them into different acquisition banks.
133 let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
134 g2_pin: Some(tsc_sensor2),
135 ..Default::default()
136 });
137
138 // Check if TSC is ready
139 if touch_controller.get_state() != State::Ready {
140 crate::panic!("TSC not ready!");
141 }
142
143 info!("TSC initialized successfully");
144
145 // LED2 on the STM32F303ZE nucleo-board
146 let mut led = Output::new(context.PB7, Level::High, Speed::Low);
147
148 let mut led_state = false;
149
150 loop {
151 acquire_sensors(&mut touch_controller, &bank1).await;
152 let readings1 = touch_controller.get_acquisition_bank_values(&bank1);
153 acquire_sensors(&mut touch_controller, &bank2).await;
154 let readings2 = touch_controller.get_acquisition_bank_values(&bank2);
155
156 let mut touched_sensors_count = 0;
157 for reading in readings1.iter() {
158 info!("{}", reading);
159 if reading.sensor_value < SENSOR_THRESHOLD {
160 touched_sensors_count += 1;
161 }
162 }
163 for reading in readings2.iter() {
164 info!("{}", reading);
165 if reading.sensor_value < SENSOR_THRESHOLD {
166 touched_sensors_count += 1;
167 }
168 }
169
170 match touched_sensors_count {
171 0 => {
172 // No sensors touched, turn off the LED
173 led.set_low();
174 led_state = false;
175 }
176 1 => {
177 // One sensor touched, blink slowly
178 led_state = !led_state;
179 if led_state {
180 led.set_high();
181 } else {
182 led.set_low();
183 }
184 Timer::after_millis(200).await;
185 }
186 2 => {
187 // Two sensors touched, blink faster
188 led_state = !led_state;
189 if led_state {
190 led.set_high();
191 } else {
192 led.set_low();
193 }
194 Timer::after_millis(50).await;
195 }
196 3 => {
197 // All three sensors touched, LED constantly on
198 led.set_high();
199 led_state = true;
200 }
201 _ => crate::unreachable!(), // This case should never occur with 3 sensors
202 }
203 }
204}
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 1cc0a97da..b47a81e1b 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -5,20 +5,20 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.4.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 = "1.0.1"
16defmt-rtt = "0.4" 16defmt-rtt = "1.0.0"
17 17
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"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
22heapless = { version = "0.8", default-features = false } 22heapless = { version = "0.8", default-features = false }
23nb = "1.0.0" 23nb = "1.0.0"
24embedded-storage = "0.3.1" 24embedded-storage = "0.3.1"
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index 2dbf1bdab..c344935d7 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -4,7 +4,7 @@
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::opamp::{OpAmp, OpAmpGain}; 7use embassy_stm32::opamp::OpAmp;
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};
@@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) -> ! {
48 48
49 let mut vrefint = adc.enable_vref(); 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(p.PA7.reborrow(), p.PA6.reborrow());
52 52
53 loop { 53 loop {
54 let vref = adc.read(&mut vrefint).await; 54 let vref = adc.read(&mut vrefint).await;
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index e6d1a6c02..2b0686121 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -57,14 +57,14 @@ async fn main(_spawner: Spawner) {
57 // embassy_stm32::pac::HRTIM1 57 // embassy_stm32::pac::HRTIM1
58 // .tim(0) 58 // .tim(0)
59 // .setr(0) 59 // .setr(0)
60 // .modify(|w| w.set_sst(Activeeffect::SETACTIVE)); 60 // .modify(|w| w.set_sst(true));
61 // 61 //
62 // Timer::after_millis(500).await; 62 // Timer::after_millis(500).await;
63 // 63 //
64 // embassy_stm32::pac::HRTIM1 64 // embassy_stm32::pac::HRTIM1
65 // .tim(0) 65 // .tim(0)
66 // .rstr(0) 66 // .rstr(0)
67 // .modify(|w| w.set_srt(Inactiveeffect::SETINACTIVE)); 67 // .modify(|w| w.set_srt(true));
68 68
69 let max_duty = buck_converter.get_max_compare_value(); 69 let max_duty = buck_converter.get_max_compare_value();
70 70
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index b85361596..edab9ea00 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,17 +6,17 @@ 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.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } 13embassy-usb = { version = "0.4.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.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
15embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 15embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
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"
@@ -24,9 +24,10 @@ embedded-hal = "0.2.6"
24embedded-hal-bus = { version = "0.2", features = ["async"] } 24embedded-hal-bus = { version = "0.2", features = ["async"] }
25embedded-io = { version = "0.6.0" } 25embedded-io = { version = "0.6.0" }
26embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.6.1" }
27panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "1.0.0", features = ["print-defmt"] }
28futures-util = { version = "0.3.30", default-features = false } 28futures-util = { version = "0.3.30", default-features = false }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30critical-section = "1.1"
30nb = "1.0.0" 31nb = "1.0.0"
31embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
32micromath = "2.0.0" 33micromath = "2.0.0"
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index 8e3beee24..fd90e0d6d 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 // To synchronise to the bus the RX input needs to see a high level. 30 // To synchronise to the bus the RX input needs to see a high level.
31 // Use `mem::forget()` to release the borrow on the pin but keep the 31 // Use `mem::forget()` to release the borrow on the pin but keep the
32 // pull-up resistor enabled. 32 // pull-up resistor enabled.
33 let rx_pin = Input::new(&mut p.PA11, Pull::Up); 33 let rx_pin = Input::new(p.PA11.reborrow(), Pull::Up);
34 core::mem::forget(rx_pin); 34 core::mem::forget(rx_pin);
35 35
36 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);
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index dd2a45718..68fe6cabd 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dac::{DacCh1, Value}; 6use embassy_stm32::dac::{DacCh1, Value};
7use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
9 8
10#[embassy_executor::main] 9#[embassy_executor::main]
@@ -12,7 +11,7 @@ async fn main(_spawner: Spawner) -> ! {
12 let p = embassy_stm32::init(Default::default()); 11 let p = embassy_stm32::init(Default::default());
13 info!("Hello World, dude!"); 12 info!("Hello World, dude!");
14 13
15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 14 let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
16 15
17 loop { 16 loop {
18 for v in 0..=255 { 17 for v in 0..=255 {
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 9388c64bf..634d8e2c6 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -4,9 +4,8 @@
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::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 9use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
12use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
@@ -21,11 +20,11 @@ bind_interrupts!(struct Irqs {
21 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 20 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
22}); 21});
23 22
24type Device = Ethernet<'static, ETH, GenericSMI>; 23type Device = Ethernet<'static, ETH, GenericPhy>;
25 24
26#[embassy_executor::task] 25#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 26async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 27 runner.run().await
29} 28}
30 29
31#[embassy_executor::main] 30#[embassy_executor::main]
@@ -76,7 +75,7 @@ async fn main(spawner: Spawner) -> ! {
76 p.PG13, 75 p.PG13,
77 p.PB13, 76 p.PB13,
78 p.PG11, 77 p.PG11,
79 GenericSMI::new(0), 78 GenericPhy::new_auto(),
80 mac_addr, 79 mac_addr,
81 ); 80 );
82 81
@@ -88,12 +87,11 @@ async fn main(spawner: Spawner) -> ! {
88 //}); 87 //});
89 88
90 // Init network stack 89 // Init network stack
91 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 90 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 91 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 92
95 // Launch network task 93 // Launch network task
96 unwrap!(spawner.spawn(net_task(stack))); 94 unwrap!(spawner.spawn(net_task(runner)));
97 95
98 // Ensure DHCP configuration is up before trying connect 96 // Ensure DHCP configuration is up before trying connect
99 stack.wait_config_up().await; 97 stack.wait_config_up().await;
@@ -105,7 +103,7 @@ async fn main(spawner: Spawner) -> ! {
105 let mut tx_buffer = [0; 4096]; 103 let mut tx_buffer = [0; 4096];
106 104
107 loop { 105 loop {
108 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 106 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
109 107
110 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 108 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
111 109
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..52f9d57f6
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth_compliance_test.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement};
7use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
9use embassy_time::Timer;
10use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 ETH => eth::InterruptHandler;
15 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 let mut config = Config::default();
21 {
22 use embassy_stm32::rcc::*;
23 config.rcc.hse = Some(Hse {
24 freq: Hertz(8_000_000),
25 mode: HseMode::Bypass,
26 });
27 config.rcc.pll_src = PllSource::HSE;
28 config.rcc.pll = Some(Pll {
29 prediv: PllPreDiv::DIV4,
30 mul: PllMul::MUL180,
31 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
32 divq: None,
33 divr: None,
34 });
35 config.rcc.ahb_pre = AHBPrescaler::DIV1;
36 config.rcc.apb1_pre = APBPrescaler::DIV4;
37 config.rcc.apb2_pre = APBPrescaler::DIV2;
38 config.rcc.sys = Sysclk::PLL1_P;
39 }
40 let p = embassy_stm32::init(config);
41
42 info!("Hello Compliance World!");
43
44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
45
46 const PHY_ADDR: u8 = 0;
47 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
48 let mut device = Ethernet::new(
49 PACKETS.init(PacketQueue::<4, 4>::new()),
50 p.ETH,
51 Irqs,
52 p.PA1,
53 p.PA2,
54 p.PC1,
55 p.PA7,
56 p.PC4,
57 p.PC5,
58 p.PG13,
59 p.PB13,
60 p.PG11,
61 GenericPhy::new(PHY_ADDR),
62 mac_addr,
63 );
64
65 let sm = device.station_management();
66
67 // Just an example. Exact register settings depend on the specific PHY and test.
68 sm.smi_write(PHY_ADDR, 0, 0x2100);
69 sm.smi_write(PHY_ADDR, 11, 0xA000);
70
71 // NB: Remember to reset the PHY after testing before starting the networking stack
72
73 loop {
74 Timer::after_secs(1).await;
75 }
76}
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index 5c3c6c3ba..6e6bef08c 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.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_net_wiznet::chip::W5500; 8use embassy_net_wiznet::chip::W5500;
9use embassy_net_wiznet::{Device, Runner, State}; 9use embassy_net_wiznet::{Device, Runner, State};
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
@@ -31,8 +31,8 @@ async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'st
31} 31}
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 34async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
35 stack.run().await 35 runner.run().await
36} 36}
37 37
38#[embassy_executor::main] 38#[embassy_executor::main]
@@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! {
92 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 92 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
93 //}); 93 //});
94 94
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 96 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
98 97
99 // Launch network task 98 // Launch network task
100 unwrap!(spawner.spawn(net_task(stack))); 99 unwrap!(spawner.spawn(net_task(runner)));
101 100
102 // Ensure DHCP configuration is up before trying connect 101 // Ensure DHCP configuration is up before trying connect
103 stack.wait_config_up().await; 102 stack.wait_config_up().await;
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
index 493a536f3..755713542 100644
--- a/examples/stm32f4/src/bin/flash_async.rs
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -3,9 +3,9 @@
3 3
4use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::bind_interrupts;
7use embassy_stm32::flash::{Flash, InterruptHandler}; 6use embassy_stm32::flash::{Flash, InterruptHandler};
8use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed}; 7use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
8use embassy_stm32::{bind_interrupts, Peri};
9use embassy_time::Timer; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -21,14 +21,14 @@ async fn main(spawner: Spawner) {
21 let mut f = Flash::new(p.FLASH, Irqs); 21 let mut f = Flash::new(p.FLASH, Irqs);
22 22
23 // Led should blink uninterrupted during ~2sec erase operation 23 // Led should blink uninterrupted during ~2sec erase operation
24 spawner.spawn(blinky(p.PB7.degrade())).unwrap(); 24 spawner.spawn(blinky(p.PB7.into())).unwrap();
25 25
26 // Test on bank 2 in order not to stall CPU. 26 // Test on bank 2 in order not to stall CPU.
27 test_flash(&mut f, 1024 * 1024, 128 * 1024).await; 27 test_flash(&mut f, 1024 * 1024, 128 * 1024).await;
28} 28}
29 29
30#[embassy_executor::task] 30#[embassy_executor::task]
31async fn blinky(p: AnyPin) { 31async fn blinky(p: Peri<'static, AnyPin>) {
32 let mut led = Output::new(p, Level::High, Speed::Low); 32 let mut led = Output::new(p, Level::High, Speed::Low);
33 33
34 loop { 34 loop {
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs
index 27b165f1b..db5103d0f 100644
--- a/examples/stm32f4/src/bin/i2s_dma.rs
+++ b/examples/stm32f4/src/bin/i2s_dma.rs
@@ -1,34 +1,83 @@
1// This example is written for an STM32F411 chip communicating with an external
2// PCM5102a DAC. Remap pins, change clock speeds, etc. as necessary for your own
3// hardware.
4//
5// NOTE: This example outputs potentially loud audio. Please run responsibly.
6
1#![no_std] 7#![no_std]
2#![no_main] 8#![no_main]
3 9
4use core::fmt::Write;
5
6use defmt::*;
7use embassy_executor::Spawner; 10use embassy_executor::Spawner;
8use embassy_stm32::i2s::{Config, I2S}; 11use embassy_stm32::i2s::{Config, Format, I2S};
9use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
10use heapless::String;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
13#[embassy_executor::main] 15#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 17 let config = {
16 info!("Hello World!"); 18 use embassy_stm32::rcc::*;
17 19
18 let mut i2s = I2S::new_txonly( 20 let mut config = embassy_stm32::Config::default();
19 p.SPI2, 21 config.rcc.hse = Some(Hse {
20 p.PC3, // sd 22 freq: Hertz::mhz(25),
21 p.PB12, // ws 23 mode: HseMode::Oscillator,
22 p.PB10, // ck 24 });
23 p.PC6, // mck 25 config.rcc.pll_src = PllSource::HSE;
24 p.DMA1_CH4, 26 config.rcc.pll = Some(Pll {
25 Hertz(1_000_000), 27 prediv: PllPreDiv::DIV25,
26 Config::default(), 28 mul: PllMul::MUL192,
29 divp: Some(PllPDiv::DIV2),
30 divq: Some(PllQDiv::DIV4),
31 divr: None,
32 });
33 config.rcc.sys = Sysclk::PLL1_P;
34
35 config.rcc.ahb_pre = AHBPrescaler::DIV1;
36 config.rcc.apb1_pre = APBPrescaler::DIV2;
37 config.rcc.apb2_pre = APBPrescaler::DIV1;
38
39 // reference your chip's manual for proper clock settings; this config
40 // is recommended for a 32 bit frame at 48 kHz sample rate
41 config.rcc.plli2s = Some(Pll {
42 prediv: PllPreDiv::DIV25,
43 mul: PllMul::MUL384,
44 divp: None,
45 divq: None,
46 divr: Some(PllRDiv::DIV5),
47 });
48 config.enable_debug_during_sleep = true;
49
50 config
51 };
52
53 let p = embassy_stm32::init(config);
54
55 // stereo wavetable generation
56 let mut wavetable = [0u16; 1200];
57 for (i, frame) in wavetable.chunks_mut(2).enumerate() {
58 frame[0] = ((((i / 150) % 2) * 2048) as i16 - 1024) as u16; // 160 Hz square wave in left channel
59 frame[1] = ((((i / 100) % 2) * 2048) as i16 - 1024) as u16; // 240 Hz square wave in right channel
60 }
61
62 // i2s configuration
63 let mut dma_buffer = [0u16; 2400];
64
65 let mut i2s_config = Config::default();
66 i2s_config.format = Format::Data16Channel32;
67 i2s_config.master_clock = false;
68 let mut i2s = I2S::new_txonly_nomck(
69 p.SPI3,
70 p.PB5, // sd
71 p.PA15, // ws
72 p.PB3, // ck
73 p.DMA1_CH7,
74 &mut dma_buffer,
75 Hertz(48_000),
76 i2s_config,
27 ); 77 );
78 i2s.start();
28 79
29 for n in 0u32.. { 80 loop {
30 let mut write: String<128> = String::new(); 81 i2s.write(&wavetable).await.ok();
31 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
32 i2s.write(&mut write.as_bytes()).await.ok();
33 } 82 }
34} 83}
diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs
index 49de33d2b..fe5e2bdfc 100644
--- a/examples/stm32f4/src/bin/input_capture.rs
+++ b/examples/stm32f4/src/bin/input_capture.rs
@@ -7,14 +7,14 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel}; 9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals}; 10use embassy_stm32::{bind_interrupts, peripherals, Peri};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14/// Connect PB2 and PB10 with a 1k Ohm resistor 14/// Connect PB2 and PB10 with a 1k Ohm resistor
15 15
16#[embassy_executor::task] 16#[embassy_executor::task]
17async fn blinky(led: peripherals::PB2) { 17async fn blinky(led: Peri<'static, peripherals::PB2>) {
18 let mut led = Output::new(led, Level::High, Speed::Low); 18 let mut led = Output::new(led, Level::High, Speed::Low);
19 19
20 loop { 20 loop {
diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs
index 8844a9f0e..04811162b 100644
--- a/examples/stm32f4/src/bin/pwm.rs
+++ b/examples/stm32f4/src/bin/pwm.rs
@@ -6,7 +6,6 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
9use embassy_stm32::timer::Channel;
10use embassy_time::Timer; 9use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -15,22 +14,22 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 15 info!("Hello World!");
17 16
18 let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); 17 let ch1_pin = PwmPin::new_ch1(p.PE9, OutputType::PushPull);
19 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); 18 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default());
20 let max = pwm.get_max_duty(); 19 let mut ch1 = pwm.ch1();
21 pwm.enable(Channel::Ch1); 20 ch1.enable();
22 21
23 info!("PWM initialized"); 22 info!("PWM initialized");
24 info!("PWM max duty {}", max); 23 info!("PWM max duty {}", ch1.max_duty_cycle());
25 24
26 loop { 25 loop {
27 pwm.set_duty(Channel::Ch1, 0); 26 ch1.set_duty_cycle_fully_off();
28 Timer::after_millis(300).await; 27 Timer::after_millis(300).await;
29 pwm.set_duty(Channel::Ch1, max / 4); 28 ch1.set_duty_cycle_fraction(1, 4);
30 Timer::after_millis(300).await; 29 Timer::after_millis(300).await;
31 pwm.set_duty(Channel::Ch1, max / 2); 30 ch1.set_duty_cycle_fraction(1, 2);
32 Timer::after_millis(300).await; 31 Timer::after_millis(300).await;
33 pwm.set_duty(Channel::Ch1, max - 1); 32 ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
34 Timer::after_millis(300).await; 33 Timer::after_millis(300).await;
35 } 34 }
36} 35}
diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs
index ce200549d..465cbe4f5 100644
--- a/examples/stm32f4/src/bin/pwm_input.rs
+++ b/examples/stm32f4/src/bin/pwm_input.rs
@@ -6,14 +6,14 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput; 8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer}; 9use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13/// Connect PB2 and PA6 with a 1k Ohm resistor 13/// Connect PB2 and PA6 with a 1k Ohm resistor
14 14
15#[embassy_executor::task] 15#[embassy_executor::task]
16async fn blinky(led: peripherals::PB2) { 16async fn blinky(led: Peri<'static, peripherals::PB2>) {
17 let mut led = Output::new(led, Level::High, Speed::Low); 17 let mut led = Output::new(led, Level::High, Speed::Low);
18 18
19 loop { 19 loop {
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index 66e4e527c..e97b63925 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) {
59 59
60 let mut err = None; 60 let mut err = None;
61 loop { 61 loop {
62 match sdmmc.init_card(mhz(24)).await { 62 match sdmmc.init_sd_card(mhz(24)).await {
63 Ok(_) => break, 63 Ok(_) => break,
64 Err(e) => { 64 Err(e) => {
65 if err != Some(e) { 65 if err != Some(e) {
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs
index c99807f11..3b6cdad8d 100644
--- a/examples/stm32f4/src/bin/usart_buffered.rs
+++ b/examples/stm32f4/src/bin/usart_buffered.rs
@@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) {
21 21
22 let mut tx_buf = [0u8; 32]; 22 let mut tx_buf = [0u8; 32];
23 let mut rx_buf = [0u8; 32]; 23 let mut rx_buf = [0u8; 32];
24 let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config).unwrap(); 24 let mut buf_usart = BufferedUart::new(p.USART3, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap();
25 25
26 loop { 26 loop {
27 let buf = buf_usart.fill_buf().await.unwrap(); 27 let buf = buf_usart.fill_buf().await.unwrap();
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 94e51c338..322cb90c7 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.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_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
9use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::Driver; 10use embassy_stm32::usb::Driver;
@@ -31,8 +31,8 @@ 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 {
@@ -93,12 +93,6 @@ async fn main(spawner: Spawner) {
93 config.max_power = 100; 93 config.max_power = 100;
94 config.max_packet_size_0 = 64; 94 config.max_packet_size_0 = 64;
95 95
96 // Required for Windows support.
97 config.composite_with_iads = true;
98 config.device_class = 0xEF;
99 config.device_sub_class = 0x02;
100 config.device_protocol = 0x01;
101
102 // Create embassy-usb DeviceBuilder using the driver and config. 96 // Create embassy-usb DeviceBuilder using the driver and config.
103 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 97 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
104 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 98 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
@@ -144,11 +138,10 @@ async fn main(spawner: Spawner) {
144 let seed = u64::from_le_bytes(seed); 138 let seed = u64::from_le_bytes(seed);
145 139
146 // Init network stack 140 // Init network stack
147 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
148 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 141 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
149 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 142 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
150 143
151 unwrap!(spawner.spawn(net_task(stack))); 144 unwrap!(spawner.spawn(net_task(runner)));
152 145
153 // And now we can use it! 146 // And now we can use it!
154 147
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index 1270995c4..d6b4a9bc9 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -71,13 +71,6 @@ async fn main(_spawner: Spawner) {
71 config.max_power = 100; 71 config.max_power = 100;
72 config.max_packet_size_0 = 64; 72 config.max_packet_size_0 = 64;
73 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. 74 // Create embassy-usb DeviceBuilder using the driver and config.
82 // It needs some buffers for building the descriptors. 75 // It needs some buffers for building the descriptors.
83 let mut config_descriptor = [0; 256]; 76 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index 45136f965..badb65e98 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) {
66 config.product = Some("HID mouse example"); 66 config.product = Some("HID mouse example");
67 config.serial_number = Some("12345678"); 67 config.serial_number = Some("12345678");
68 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. 69 // Create embassy-usb DeviceBuilder using the driver and config.
77 // It needs some buffers for building the descriptors. 70 // It needs some buffers for building the descriptors.
78 let mut config_descriptor = [0; 256]; 71 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index b2d706208..bbbcc082b 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -119,13 +119,6 @@ async fn main(_spawner: Spawner) {
119 config.product = Some("USB-raw example"); 119 config.product = Some("USB-raw example");
120 config.serial_number = Some("12345678"); 120 config.serial_number = Some("12345678");
121 121
122 // Required for windows compatibility.
123 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
124 config.device_class = 0xEF;
125 config.device_sub_class = 0x02;
126 config.device_protocol = 0x01;
127 config.composite_with_iads = true;
128
129 // Create embassy-usb DeviceBuilder using the driver and config. 122 // Create embassy-usb DeviceBuilder using the driver and config.
130 // It needs some buffers for building the descriptors. 123 // It needs some buffers for building the descriptors.
131 let mut config_descriptor = [0; 256]; 124 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 328b5effe..e62b2d8d6 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) {
66 config.product = Some("USB-serial example"); 66 config.product = Some("USB-serial example");
67 config.serial_number = Some("12345678"); 67 config.serial_number = Some("12345678");
68 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. 69 // Create embassy-usb DeviceBuilder using the driver and config.
77 // It needs some buffers for building the descriptors. 70 // It needs some buffers for building the descriptors.
78 let mut config_descriptor = [0; 256]; 71 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs
new file mode 100644
index 000000000..654bec498
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs
@@ -0,0 +1,383 @@
1#![no_std]
2#![no_main]
3
4use core::cell::{Cell, RefCell};
5
6use defmt::{panic, *};
7use embassy_executor::Spawner;
8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config};
10use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
11use embassy_sync::blocking_mutex::Mutex;
12use embassy_sync::signal::Signal;
13use embassy_sync::zerocopy_channel;
14use embassy_usb::class::uac1;
15use embassy_usb::class::uac1::speaker::{self, Speaker};
16use embassy_usb::driver::EndpointError;
17use heapless::Vec;
18use micromath::F32Ext;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
24});
25
26static TIMER: Mutex<CriticalSectionRawMutex, RefCell<Option<timer::low_level::Timer<peripherals::TIM2>>>> =
27 Mutex::new(RefCell::new(None));
28
29// A counter signal that is written by the feedback timer, once every `FEEDBACK_REFRESH_PERIOD`.
30// At that point, a feedback value is sent to the host.
31pub static FEEDBACK_SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
32
33// Stereo input
34pub const INPUT_CHANNEL_COUNT: usize = 2;
35
36// This example uses a fixed sample rate of 48 kHz.
37pub const SAMPLE_RATE_HZ: u32 = 48_000;
38pub const FEEDBACK_COUNTER_TICK_RATE: u32 = 42_000_000;
39
40// Use 32 bit samples, which allow for a lot of (software) volume adjustment without degradation of quality.
41pub const SAMPLE_WIDTH: uac1::SampleWidth = uac1::SampleWidth::Width4Byte;
42pub const SAMPLE_WIDTH_BIT: usize = SAMPLE_WIDTH.in_bit();
43pub const SAMPLE_SIZE: usize = SAMPLE_WIDTH as usize;
44pub const SAMPLE_SIZE_PER_S: usize = (SAMPLE_RATE_HZ as usize) * INPUT_CHANNEL_COUNT * SAMPLE_SIZE;
45
46// Size of audio samples per 1 ms - for the full-speed USB frame period of 1 ms.
47pub const USB_FRAME_SIZE: usize = SAMPLE_SIZE_PER_S.div_ceil(1000);
48
49// Select front left and right audio channels.
50pub const AUDIO_CHANNELS: [uac1::Channel; INPUT_CHANNEL_COUNT] = [uac1::Channel::LeftFront, uac1::Channel::RightFront];
51
52// Factor of two as a margin for feedback (this is an excessive amount)
53pub const USB_MAX_PACKET_SIZE: usize = 2 * USB_FRAME_SIZE;
54pub const USB_MAX_SAMPLE_COUNT: usize = USB_MAX_PACKET_SIZE / SAMPLE_SIZE;
55
56// The data type that is exchanged via the zero-copy channel (a sample vector).
57pub type SampleBlock = Vec<u32, USB_MAX_SAMPLE_COUNT>;
58
59// Feedback is provided in 10.14 format for full-speed endpoints.
60pub const FEEDBACK_REFRESH_PERIOD: uac1::FeedbackRefresh = uac1::FeedbackRefresh::Period8Frames;
61const FEEDBACK_SHIFT: usize = 14;
62
63const TICKS_PER_SAMPLE: f32 = (FEEDBACK_COUNTER_TICK_RATE as f32) / (SAMPLE_RATE_HZ as f32);
64
65struct Disconnected {}
66
67impl From<EndpointError> for Disconnected {
68 fn from(val: EndpointError) -> Self {
69 match val {
70 EndpointError::BufferOverflow => panic!("Buffer overflow"),
71 EndpointError::Disabled => Disconnected {},
72 }
73 }
74}
75
76/// Sends feedback messages to the host.
77async fn feedback_handler<'d, T: usb::Instance + 'd>(
78 feedback: &mut speaker::Feedback<'d, usb::Driver<'d, T>>,
79 feedback_factor: f32,
80) -> Result<(), Disconnected> {
81 let mut packet: Vec<u8, 4> = Vec::new();
82
83 // Collects the fractional component of the feedback value that is lost by rounding.
84 let mut rest = 0.0_f32;
85
86 loop {
87 let counter = FEEDBACK_SIGNAL.wait().await;
88
89 packet.clear();
90
91 let raw_value = counter as f32 * feedback_factor + rest;
92 let value = raw_value.round();
93 rest = raw_value - value;
94
95 let value = value as u32;
96 packet.push(value as u8).unwrap();
97 packet.push((value >> 8) as u8).unwrap();
98 packet.push((value >> 16) as u8).unwrap();
99
100 feedback.write_packet(&packet).await?;
101 }
102}
103
104/// Handles streaming of audio data from the host.
105async fn stream_handler<'d, T: usb::Instance + 'd>(
106 stream: &mut speaker::Stream<'d, usb::Driver<'d, T>>,
107 sender: &mut zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>,
108) -> Result<(), Disconnected> {
109 loop {
110 let mut usb_data = [0u8; USB_MAX_PACKET_SIZE];
111 let data_size = stream.read_packet(&mut usb_data).await?;
112
113 let word_count = data_size / SAMPLE_SIZE;
114
115 if word_count * SAMPLE_SIZE == data_size {
116 // Obtain a buffer from the channel
117 let samples = sender.send().await;
118 samples.clear();
119
120 for w in 0..word_count {
121 let byte_offset = w * SAMPLE_SIZE;
122 let sample = u32::from_le_bytes(usb_data[byte_offset..byte_offset + SAMPLE_SIZE].try_into().unwrap());
123
124 // Fill the sample buffer with data.
125 samples.push(sample).unwrap();
126 }
127
128 sender.send_done();
129 } else {
130 debug!("Invalid USB buffer size of {}, skipped.", data_size);
131 }
132 }
133}
134
135/// Receives audio samples from the USB streaming task and can play them back.
136#[embassy_executor::task]
137async fn audio_receiver_task(mut usb_audio_receiver: zerocopy_channel::Receiver<'static, NoopRawMutex, SampleBlock>) {
138 loop {
139 let _samples = usb_audio_receiver.receive().await;
140 // Use the samples, for example play back via the SAI peripheral.
141
142 // Notify the channel that the buffer is now ready to be reused
143 usb_audio_receiver.receive_done();
144 }
145}
146
147/// Receives audio samples from the host.
148#[embassy_executor::task]
149async fn usb_streaming_task(
150 mut stream: speaker::Stream<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>,
151 mut sender: zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>,
152) {
153 loop {
154 stream.wait_connection().await;
155 _ = stream_handler(&mut stream, &mut sender).await;
156 }
157}
158
159/// Sends sample rate feedback to the host.
160///
161/// The `feedback_factor` scales the feedback timer's counter value so that the result is the number of samples that
162/// this device played back or "consumed" during one SOF period (1 ms) - in 10.14 format.
163///
164/// Ideally, the `feedback_factor` that is calculated below would be an integer for avoiding numerical errors.
165/// This is achieved by having `TICKS_PER_SAMPLE` be a power of two. For audio applications at a sample rate of 48 kHz,
166/// 24.576 MHz would be one such option.
167///
168/// A good choice for the STM32F4, which also has to generate a 48 MHz clock from its HSE (e.g. running at 8 MHz)
169/// for USB, is to clock the feedback timer from the MCLK output of the SAI peripheral. The SAI peripheral then uses an
170/// external clock. In that case, wiring the MCLK output to the timer clock input is required.
171///
172/// This simple example just uses the internal clocks for supplying the feedback timer,
173/// and does not even set up a SAI peripheral.
174#[embassy_executor::task]
175async fn usb_feedback_task(mut feedback: speaker::Feedback<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>) {
176 let feedback_factor =
177 ((1 << FEEDBACK_SHIFT) as f32 / TICKS_PER_SAMPLE) / FEEDBACK_REFRESH_PERIOD.frame_count() as f32;
178
179 // Should be 2.3405714285714287...
180 info!("Using a feedback factor of {}.", feedback_factor);
181
182 loop {
183 feedback.wait_connection().await;
184 _ = feedback_handler(&mut feedback, feedback_factor).await;
185 }
186}
187
188#[embassy_executor::task]
189async fn usb_task(mut usb_device: embassy_usb::UsbDevice<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>) {
190 usb_device.run().await;
191}
192
193/// Checks for changes on the control monitor of the class.
194///
195/// In this case, monitor changes of volume or mute state.
196#[embassy_executor::task]
197async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) {
198 loop {
199 control_monitor.changed().await;
200
201 for channel in AUDIO_CHANNELS {
202 let volume = control_monitor.volume(channel).unwrap();
203 info!("Volume changed to {} on channel {}.", volume, channel);
204 }
205 }
206}
207
208/// Feedback value measurement and calculation
209///
210/// Used for measuring/calculating the number of samples that were received from the host during the
211/// `FEEDBACK_REFRESH_PERIOD`.
212///
213/// Configured in this example with
214/// - a refresh period of 8 ms, and
215/// - a tick rate of 42 MHz.
216///
217/// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`.
218#[interrupt]
219fn TIM2() {
220 static LAST_TICKS: Mutex<CriticalSectionRawMutex, Cell<u32>> = Mutex::new(Cell::new(0));
221 static FRAME_COUNT: Mutex<CriticalSectionRawMutex, Cell<usize>> = Mutex::new(Cell::new(0));
222
223 critical_section::with(|cs| {
224 // Read timer counter.
225 let timer = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32();
226
227 let status = timer.sr().read();
228
229 const CHANNEL_INDEX: usize = 0;
230 if status.ccif(CHANNEL_INDEX) {
231 let ticks = timer.ccr(CHANNEL_INDEX).read();
232
233 let frame_count = FRAME_COUNT.borrow(cs);
234 let last_ticks = LAST_TICKS.borrow(cs);
235
236 frame_count.set(frame_count.get() + 1);
237 if frame_count.get() >= FEEDBACK_REFRESH_PERIOD.frame_count() {
238 frame_count.set(0);
239 FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(last_ticks.get()));
240 last_ticks.set(ticks);
241 }
242 };
243
244 // Clear trigger interrupt flag.
245 timer.sr().modify(|r| r.set_tif(false));
246 });
247}
248
249// If you are trying this and your USB device doesn't connect, the most
250// common issues are the RCC config and vbus_detection
251//
252// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
253// for more information.
254#[embassy_executor::main]
255async fn main(spawner: Spawner) {
256 info!("Hello World!");
257
258 let mut config = Config::default();
259 {
260 use embassy_stm32::rcc::*;
261 config.rcc.hse = Some(Hse {
262 freq: Hertz(8_000_000),
263 mode: HseMode::Bypass,
264 });
265 config.rcc.pll_src = PllSource::HSE;
266 config.rcc.pll = Some(Pll {
267 prediv: PllPreDiv::DIV4,
268 mul: PllMul::MUL168,
269 divp: Some(PllPDiv::DIV2), // ((8 MHz / 4) * 168) / 2 = 168 Mhz.
270 divq: Some(PllQDiv::DIV7), // ((8 MHz / 4) * 168) / 7 = 48 Mhz.
271 divr: None,
272 });
273 config.rcc.ahb_pre = AHBPrescaler::DIV1;
274 config.rcc.apb1_pre = APBPrescaler::DIV4;
275 config.rcc.apb2_pre = APBPrescaler::DIV2;
276 config.rcc.sys = Sysclk::PLL1_P;
277 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
278 }
279 let p = embassy_stm32::init(config);
280
281 // Configure all required buffers in a static way.
282 debug!("USB packet size is {} byte", USB_MAX_PACKET_SIZE);
283 static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
284 let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]);
285
286 static BOS_DESCRIPTOR: StaticCell<[u8; 32]> = StaticCell::new();
287 let bos_descriptor = BOS_DESCRIPTOR.init([0; 32]);
288
289 const CONTROL_BUF_SIZE: usize = 64;
290 static CONTROL_BUF: StaticCell<[u8; CONTROL_BUF_SIZE]> = StaticCell::new();
291 let control_buf = CONTROL_BUF.init([0; CONTROL_BUF_SIZE]);
292
293 const FEEDBACK_BUF_SIZE: usize = 4;
294 static EP_OUT_BUFFER: StaticCell<[u8; FEEDBACK_BUF_SIZE + CONTROL_BUF_SIZE + USB_MAX_PACKET_SIZE]> =
295 StaticCell::new();
296 let ep_out_buffer = EP_OUT_BUFFER.init([0u8; FEEDBACK_BUF_SIZE + CONTROL_BUF_SIZE + USB_MAX_PACKET_SIZE]);
297
298 static STATE: StaticCell<speaker::State> = StaticCell::new();
299 let state = STATE.init(speaker::State::new());
300
301 // Create the driver, from the HAL.
302 let mut usb_config = usb::Config::default();
303
304 // Do not enable vbus_detection. This is a safe default that works in all boards.
305 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
306 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
307 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
308 usb_config.vbus_detection = false;
309
310 let usb_driver = usb::Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, usb_config);
311
312 // Basic USB device configuration
313 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
314 config.manufacturer = Some("Embassy");
315 config.product = Some("USB-audio-speaker example");
316 config.serial_number = Some("12345678");
317
318 let mut builder = embassy_usb::Builder::new(
319 usb_driver,
320 config,
321 config_descriptor,
322 bos_descriptor,
323 &mut [], // no msos descriptors
324 control_buf,
325 );
326
327 // Create the UAC1 Speaker class components
328 let (stream, feedback, control_monitor) = Speaker::new(
329 &mut builder,
330 state,
331 USB_MAX_PACKET_SIZE as u16,
332 uac1::SampleWidth::Width4Byte,
333 &[SAMPLE_RATE_HZ],
334 &AUDIO_CHANNELS,
335 FEEDBACK_REFRESH_PERIOD,
336 );
337
338 // Create the USB device
339 let usb_device = builder.build();
340
341 // Establish a zero-copy channel for transferring received audio samples between tasks
342 static SAMPLE_BLOCKS: StaticCell<[SampleBlock; 2]> = StaticCell::new();
343 let sample_blocks = SAMPLE_BLOCKS.init([Vec::new(), Vec::new()]);
344
345 static CHANNEL: StaticCell<zerocopy_channel::Channel<'_, NoopRawMutex, SampleBlock>> = StaticCell::new();
346 let channel = CHANNEL.init(zerocopy_channel::Channel::new(sample_blocks));
347 let (sender, receiver) = channel.split();
348
349 // Run a timer for counting between SOF interrupts.
350 let mut tim2 = timer::low_level::Timer::new(p.TIM2);
351 tim2.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE));
352 tim2.set_trigger_source(timer::low_level::TriggerSource::ITR1); // The USB SOF signal.
353
354 const TIMER_CHANNEL: timer::Channel = timer::Channel::Ch1;
355 tim2.set_input_ti_selection(TIMER_CHANNEL, timer::low_level::InputTISelection::TRC);
356 tim2.set_input_capture_prescaler(TIMER_CHANNEL, 0);
357 tim2.set_input_capture_filter(TIMER_CHANNEL, timer::low_level::FilterValue::FCK_INT_N2);
358
359 // Reset all interrupt flags.
360 tim2.regs_gp32().sr().write(|r| r.0 = 0);
361
362 // Enable routing of SOF to the timer.
363 tim2.regs_gp32().or().write(|r| *r = 0b10 << 10);
364
365 tim2.enable_channel(TIMER_CHANNEL, true);
366 tim2.enable_input_interrupt(TIMER_CHANNEL, true);
367
368 tim2.start();
369
370 TIMER.lock(|p| p.borrow_mut().replace(tim2));
371
372 // Unmask the TIM2 interrupt.
373 unsafe {
374 cortex_m::peripheral::NVIC::unmask(interrupt::TIM2);
375 }
376
377 // Launch USB audio tasks.
378 unwrap!(spawner.spawn(usb_control_task(control_monitor)));
379 unwrap!(spawner.spawn(usb_streaming_task(stream, sender)));
380 unwrap!(spawner.spawn(usb_feedback_task(feedback)));
381 unwrap!(spawner.spawn(usb_task(usb_device)));
382 unwrap!(spawner.spawn(audio_receiver_task(receiver)));
383}
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index cbaff75fc..ca924e181 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) {
61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit 61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
62 // 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
63 63
64 let max_duty = ws2812_pwm.get_max_duty() as u16; 64 let max_duty = ws2812_pwm.max_duty_cycle();
65 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
66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing 66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing
67 67
@@ -84,7 +84,7 @@ async fn main(_spawner: Spawner) {
84 let pwm_channel = Channel::Ch1; 84 let pwm_channel = Channel::Ch1;
85 85
86 // make sure PWM output keep low on first start 86 // make sure PWM output keep low on first start
87 ws2812_pwm.set_duty(pwm_channel, 0); 87 ws2812_pwm.channel(pwm_channel).set_duty_cycle(0);
88 88
89 // flip color at 2 Hz 89 // flip color at 2 Hz
90 let mut ticker = Ticker::every(Duration::from_millis(500)); 90 let mut ticker = Ticker::every(Duration::from_millis(500));
@@ -92,7 +92,7 @@ async fn main(_spawner: Spawner) {
92 loop { 92 loop {
93 for &color in color_list { 93 for &color in color_list {
94 // with &mut, we can easily reuse same DMA channel multiple times 94 // with &mut, we can easily reuse same DMA channel multiple times
95 ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await; 95 ws2812_pwm.waveform_up(dp.DMA1_CH2.reborrow(), pwm_channel, color).await;
96 // ws2812 need at least 50 us low level input to confirm the input data and change it's state 96 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
97 Timer::after_micros(50).await; 97 Timer::after_micros(50).await;
98 // wait until ticker tick 98 // wait until ticker tick
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml
index 6a5bd0b29..87a3b8f75 100644
--- a/examples/stm32f469/Cargo.toml
+++ b/examples/stm32f469/Cargo.toml
@@ -6,17 +6,17 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Specific examples only for stm32f469 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"] } 9embassy-stm32 = { version = "0.2.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"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12 12
13defmt = "0.3" 13defmt = "1.0.1"
14defmt-rtt = "0.4" 14defmt-rtt = "1.0.0"
15 15
16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
18embedded-hal = "1.0.0" 18embedded-hal = "1.0.0"
19panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "1.0.0", features = ["print-defmt"] }
20 20
21[profile.release] 21[profile.release]
22debug = 2 22debug = 2
diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs
index e4e9e9c01..3a24d5dcf 100644
--- a/examples/stm32f469/src/bin/dsi_bsp.rs
+++ b/examples/stm32f469/src/bin/dsi_bsp.rs
@@ -363,20 +363,20 @@ async fn main(_spawner: Spawner) {
363 const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0 363 const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0
364 364
365 const LTDC_DE_POLARITY: Depol = if !DE_POLARITY { 365 const LTDC_DE_POLARITY: Depol = if !DE_POLARITY {
366 Depol::ACTIVELOW 366 Depol::ACTIVE_LOW
367 } else { 367 } else {
368 Depol::ACTIVEHIGH 368 Depol::ACTIVE_HIGH
369 }; 369 };
370 const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY { 370 const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY {
371 Vspol::ACTIVEHIGH 371 Vspol::ACTIVE_HIGH
372 } else { 372 } else {
373 Vspol::ACTIVELOW 373 Vspol::ACTIVE_LOW
374 }; 374 };
375 375
376 const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY { 376 const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY {
377 Hspol::ACTIVEHIGH 377 Hspol::ACTIVE_HIGH
378 } else { 378 } else {
379 Hspol::ACTIVELOW 379 Hspol::ACTIVE_LOW
380 }; 380 };
381 381
382 /* Timing Configuration */ 382 /* Timing Configuration */
@@ -397,7 +397,7 @@ async fn main(_spawner: Spawner) {
397 w.set_hspol(LTDC_HS_POLARITY); 397 w.set_hspol(LTDC_HS_POLARITY);
398 w.set_vspol(LTDC_VS_POLARITY); 398 w.set_vspol(LTDC_VS_POLARITY);
399 w.set_depol(LTDC_DE_POLARITY); 399 w.set_depol(LTDC_DE_POLARITY);
400 w.set_pcpol(Pcpol::RISINGEDGE); 400 w.set_pcpol(Pcpol::RISING_EDGE);
401 }); 401 });
402 402
403 // Set Synchronization size 403 // Set Synchronization size
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 8c591ebd2..c5801ea90 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -6,31 +6,30 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti", "single-bank"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", 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.7.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.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
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"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "1.0.0", features = ["print-defmt"] }
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"
28critical-section = "1.1" 27critical-section = "1.1"
29embedded-storage = "0.3.1" 28embedded-storage = "0.3.1"
30static_cell = "2" 29static_cell = "2"
31sha2 = { version = "0.10.8", default-features = false } 30sha2 = { version = "0.10.8", default-features = false }
32hmac = "0.12.1" 31hmac = "0.12.1"
33aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } 32aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
34 33
35[profile.release] 34[profile.release]
36debug = 2 35debug = 2
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index a82e335a9..58ba940a8 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 // To synchronise to the bus the RX input needs to see a high level. 42 // To synchronise to the bus the RX input needs to see a high level.
43 // Use `mem::forget()` to release the borrow on the pin but keep the 43 // Use `mem::forget()` to release the borrow on the pin but keep the
44 // pull-up resistor enabled. 44 // pull-up resistor enabled.
45 let rx_pin = Input::new(&mut p.PA15, Pull::Up); 45 let rx_pin = Input::new(p.PA15.reborrow(), Pull::Up);
46 core::mem::forget(rx_pin); 46 core::mem::forget(rx_pin);
47 47
48 static CAN: StaticCell<Can<'static>> = StaticCell::new(); 48 static CAN: StaticCell<Can<'static>> = StaticCell::new();
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 2fd10c8fb..67a2b34bb 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -4,16 +4,14 @@
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::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 9use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
12use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
14use embassy_time::Timer; 13use embassy_time::Timer;
15use embedded_io_async::Write; 14use embedded_io_async::Write;
16use rand_core::RngCore;
17use static_cell::StaticCell; 15use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
19 17
@@ -22,11 +20,11 @@ bind_interrupts!(struct Irqs {
22 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 20 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
23}); 21});
24 22
25type Device = Ethernet<'static, ETH, GenericSMI>; 23type Device = Ethernet<'static, ETH, GenericPhy>;
26 24
27#[embassy_executor::task] 25#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 26async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 27 runner.run().await
30} 28}
31 29
32#[embassy_executor::main] 30#[embassy_executor::main]
@@ -77,7 +75,7 @@ async fn main(spawner: Spawner) -> ! {
77 p.PG13, 75 p.PG13,
78 p.PB13, 76 p.PB13,
79 p.PG11, 77 p.PG11,
80 GenericSMI::new(0), 78 GenericPhy::new_auto(),
81 mac_addr, 79 mac_addr,
82 ); 80 );
83 81
@@ -89,12 +87,11 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 87 //});
90 88
91 // Init network stack 89 // Init network stack
92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 90 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 91 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
95 92
96 // Launch network task 93 // Launch network task
97 unwrap!(spawner.spawn(net_task(stack))); 94 unwrap!(spawner.spawn(net_task(runner)));
98 95
99 // Ensure DHCP configuration is up before trying connect 96 // Ensure DHCP configuration is up before trying connect
100 stack.wait_config_up().await; 97 stack.wait_config_up().await;
@@ -106,7 +103,7 @@ async fn main(spawner: Spawner) -> ! {
106 let mut tx_buffer = [0; 4096]; 103 let mut tx_buffer = [0; 4096];
107 104
108 loop { 105 loop {
109 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 106 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
110 107
111 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 108 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
112 109
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs
index 90d319b7a..bd3287964 100644
--- a/examples/stm32f7/src/bin/qspi.rs
+++ b/examples/stm32f7/src/bin/qspi.rs
@@ -72,7 +72,7 @@ impl<I: Instance> FlashMemory<I> {
72 address: None, 72 address: None,
73 dummy: DummyCycles::_0, 73 dummy: DummyCycles::_0,
74 }; 74 };
75 self.qspi.command(transaction); 75 self.qspi.blocking_command(transaction);
76 } 76 }
77 77
78 pub fn reset_memory(&mut self) { 78 pub fn reset_memory(&mut self) {
@@ -143,7 +143,7 @@ impl<I: Instance> FlashMemory<I> {
143 dummy: DummyCycles::_0, 143 dummy: DummyCycles::_0,
144 }; 144 };
145 self.enable_write(); 145 self.enable_write();
146 self.qspi.command(transaction); 146 self.qspi.blocking_command(transaction);
147 self.wait_write_finish(); 147 self.wait_write_finish();
148 } 148 }
149 149
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 6d36ef518..787bef25e 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) {
54 // Should print 400kHz for initialization 54 // Should print 400kHz for initialization
55 info!("Configured clock: {}", sdmmc.clock().0); 55 info!("Configured clock: {}", sdmmc.clock().0);
56 56
57 unwrap!(sdmmc.init_card(mhz(25)).await); 57 unwrap!(sdmmc.init_sd_card(mhz(25)).await);
58 58
59 let card = unwrap!(sdmmc.card()); 59 let card = unwrap!(sdmmc.card());
60 60
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 1906b28ed..349012888 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) {
66 config.product = Some("USB-serial example"); 66 config.product = Some("USB-serial example");
67 config.serial_number = Some("12345678"); 67 config.serial_number = Some("12345678");
68 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. 69 // Create embassy-usb DeviceBuilder using the driver and config.
77 // It needs some buffers for building the descriptors. 70 // It needs some buffers for building the descriptors.
78 let mut config_descriptor = [0; 256]; 71 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index a50074ce0..bf1e7250e 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", 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"] } 13embassy-usb = { version = "0.4.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 = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 24portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
25 25
diff --git a/examples/stm32g0/src/bin/adc_dma.rs b/examples/stm32g0/src/bin/adc_dma.rs
index 3713e5a21..d7515933c 100644
--- a/examples/stm32g0/src/bin/adc_dma.rs
+++ b/examples/stm32g0/src/bin/adc_dma.rs
@@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) {
25 25
26 loop { 26 loop {
27 adc.read( 27 adc.read(
28 &mut dma, 28 dma.reborrow(),
29 [ 29 [
30 (&mut vrefint_channel, SampleTime::CYCLES160_5), 30 (&mut vrefint_channel, SampleTime::CYCLES160_5),
31 (&mut pa0, SampleTime::CYCLES160_5), 31 (&mut pa0, SampleTime::CYCLES160_5),
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 3ea06cdee..dfb6e0edc 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -16,7 +16,9 @@ async fn main(_spawner: Spawner) {
16 let mut config = PeripheralConfig::default(); 16 let mut config = PeripheralConfig::default();
17 { 17 {
18 use embassy_stm32::rcc::*; 18 use embassy_stm32::rcc::*;
19 config.rcc.hsi = true; 19 config.rcc.hsi = Some(Hsi {
20 sys_div: HsiSysDiv::DIV1,
21 });
20 config.rcc.pll = Some(Pll { 22 config.rcc.pll = Some(Pll {
21 source: PllSource::HSI, 23 source: PllSource::HSI,
22 prediv: PllPreDiv::DIV1, 24 prediv: PllPreDiv::DIV1,
diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs
index 69fdae96d..08df4e043 100644
--- a/examples/stm32g0/src/bin/input_capture.rs
+++ b/examples/stm32g0/src/bin/input_capture.rs
@@ -16,14 +16,14 @@ use embassy_stm32::time::khz;
16use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 16use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
17use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 17use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
18use embassy_stm32::timer::Channel; 18use embassy_stm32::timer::Channel;
19use embassy_stm32::{bind_interrupts, peripherals, timer}; 19use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
20use embassy_time::Timer; 20use embassy_time::Timer;
21use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 22
23// Connect PB1 and PA6 with a 1k Ohm resistor 23// Connect PB1 and PA6 with a 1k Ohm resistor
24 24
25#[embassy_executor::task] 25#[embassy_executor::task]
26async fn blinky(led: peripherals::PB1) { 26async fn blinky(led: Peri<'static, peripherals::PB1>) {
27 let mut led = Output::new(led, Level::High, Speed::Low); 27 let mut led = Output::new(led, Level::High, Speed::Low);
28 28
29 loop { 29 loop {
@@ -47,10 +47,10 @@ async fn main(spawner: Spawner) {
47 unwrap!(spawner.spawn(blinky(p.PB1))); 47 unwrap!(spawner.spawn(blinky(p.PB1)));
48 48
49 // Connect PB1 and PA8 with a 1k Ohm resistor 49 // Connect PB1 and PA8 with a 1k Ohm resistor
50 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 50 let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
51 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); 51 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default());
52 pwm.enable(Channel::Ch1); 52 pwm.ch1().enable();
53 pwm.set_duty(Channel::Ch1, 50); 53 pwm.ch1().set_duty_cycle(50);
54 54
55 let ch1 = CapturePin::new_ch1(p.PA0, Pull::None); 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()); 56 let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default());
diff --git a/examples/stm32g0/src/bin/onewire_ds18b20.rs b/examples/stm32g0/src/bin/onewire_ds18b20.rs
new file mode 100644
index 000000000..62f8711a6
--- /dev/null
+++ b/examples/stm32g0/src/bin/onewire_ds18b20.rs
@@ -0,0 +1,274 @@
1//! This examples shows how you can use buffered or DMA UART to read a DS18B20 temperature sensor on 1-Wire bus.
2//! Connect 5k pull-up resistor between PA9 and 3.3V.
3#![no_std]
4#![no_main]
5
6use cortex_m::singleton;
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::mode::Async;
10use embassy_stm32::usart::{
11 BufferedUartRx, BufferedUartTx, Config, ConfigError, OutputConfig, RingBufferedUartRx, UartTx,
12};
13use embassy_stm32::{bind_interrupts, peripherals, usart};
14use embassy_time::{Duration, Timer};
15use {defmt_rtt as _, panic_probe as _};
16
17/// Create onewire bus using DMA USART
18fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire<UartTx<'static, Async>, RingBufferedUartRx<'static>> {
19 use embassy_stm32::usart::Uart;
20 bind_interrupts!(struct Irqs {
21 USART1 => usart::InterruptHandler<peripherals::USART1>;
22 });
23
24 let mut config = Config::default();
25 config.tx_config = OutputConfig::OpenDrain;
26
27 let usart = Uart::new_half_duplex(
28 p.USART1,
29 p.PA9,
30 Irqs,
31 p.DMA1_CH1,
32 p.DMA1_CH2,
33 config,
34 // Enable readback so we can read sensor pulling data low while transmission is in progress
35 usart::HalfDuplexReadback::Readback,
36 )
37 .unwrap();
38
39 const BUFFER_SIZE: usize = 16;
40 let (tx, rx) = usart.split();
41 let rx_buf: &mut [u8; BUFFER_SIZE] = singleton!(TX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap();
42 let rx = rx.into_ring_buffered(rx_buf);
43 OneWire::new(tx, rx)
44}
45
46/*
47/// Create onewire bus using buffered USART
48fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire<BufferedUartTx<'static>, BufferedUartRx<'static>> {
49 use embassy_stm32::usart::BufferedUart;
50 bind_interrupts!(struct Irqs {
51 USART1 => usart::BufferedInterruptHandler<peripherals::USART1>;
52 });
53
54 const BUFFER_SIZE: usize = 16;
55 let mut config = Confi::default();
56 config.tx_config = OutputConfig::OpenDrain;
57 let tx_buf: &mut [u8; BUFFER_SIZE] = singleton!(TX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap();
58 let rx_buf: &mut [u8; BUFFER_SIZE] = singleton!(RX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap();
59 let usart = BufferedUart::new_half_duplex(
60 p.USART1,
61 p.PA9,
62 Irqs,
63 tx_buf,
64 rx_buf,
65 config,
66 // Enable readback so we can read sensor pulling data low while transmission is in progress
67 usart::HalfDuplexReadback::Readback,
68 )
69 .unwrap();
70 let (tx, rx) = usart.split();
71 OneWire::new(tx, rx)
72}
73*/
74
75#[embassy_executor::main]
76async fn main(_spawner: Spawner) {
77 let p = embassy_stm32::init(Default::default());
78
79 let onewire = create_onewire(p);
80 let mut sensor = Ds18b20::new(onewire);
81
82 loop {
83 // Start a new temperature measurement
84 sensor.start().await;
85 // Wait for the measurement to finish
86 Timer::after(Duration::from_secs(1)).await;
87 match sensor.temperature().await {
88 Ok(temp) => info!("temp = {:?} deg C", temp),
89 _ => error!("sensor error"),
90 }
91 Timer::after(Duration::from_secs(1)).await;
92 }
93}
94
95pub trait SetBaudrate {
96 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError>;
97}
98impl SetBaudrate for BufferedUartTx<'_> {
99 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
100 BufferedUartTx::set_baudrate(self, baudrate)
101 }
102}
103impl SetBaudrate for BufferedUartRx<'_> {
104 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
105 BufferedUartRx::set_baudrate(self, baudrate)
106 }
107}
108impl SetBaudrate for RingBufferedUartRx<'_> {
109 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
110 RingBufferedUartRx::set_baudrate(self, baudrate)
111 }
112}
113impl SetBaudrate for UartTx<'_, Async> {
114 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
115 UartTx::set_baudrate(self, baudrate)
116 }
117}
118
119/// Simplified OneWire bus driver
120pub struct OneWire<TX, RX>
121where
122 TX: embedded_io_async::Write + SetBaudrate,
123 RX: embedded_io_async::Read + SetBaudrate,
124{
125 tx: TX,
126 rx: RX,
127}
128
129impl<TX, RX> OneWire<TX, RX>
130where
131 TX: embedded_io_async::Write + SetBaudrate,
132 RX: embedded_io_async::Read + SetBaudrate,
133{
134 // bitrate with one bit taking ~104 us
135 const RESET_BUADRATE: u32 = 9600;
136 // bitrate with one bit taking ~8.7 us
137 const BAUDRATE: u32 = 115200;
138
139 // startbit + 8 low bits = 9 * 1/115200 = 78 us low pulse
140 const LOGIC_1_CHAR: u8 = 0xFF;
141 // startbit only = 1/115200 = 8.7 us low pulse
142 const LOGIC_0_CHAR: u8 = 0x00;
143
144 // Address all devices on the bus
145 const COMMAND_SKIP_ROM: u8 = 0xCC;
146
147 pub fn new(tx: TX, rx: RX) -> Self {
148 Self { tx, rx }
149 }
150
151 fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
152 self.tx.set_baudrate(baudrate)?;
153 self.rx.set_baudrate(baudrate)
154 }
155
156 /// Reset the bus by at least 480 us low pulse.
157 pub async fn reset(&mut self) {
158 // Switch to 9600 baudrate, so one bit takes ~104 us
159 self.set_baudrate(Self::RESET_BUADRATE).expect("set_baudrate failed");
160 // Low USART start bit + 4x low bits = 5 * 104 us = 520 us low pulse
161 self.tx.write(&[0xF0]).await.expect("write failed");
162
163 // Read the value on the bus
164 let mut buffer = [0; 1];
165 self.rx.read_exact(&mut buffer).await.expect("read failed");
166
167 // Switch back to 115200 baudrate, so one bit takes ~8.7 us
168 self.set_baudrate(Self::BAUDRATE).expect("set_baudrate failed");
169
170 // read and expect sensor pulled some high bits to low (device present)
171 if buffer[0] & 0xF != 0 || buffer[0] & 0xF0 == 0xF0 {
172 warn!("No device present");
173 }
174 }
175
176 /// Send byte and read response on the bus.
177 pub async fn write_read_byte(&mut self, byte: u8) -> u8 {
178 // One byte is sent as 8 UART characters
179 let mut tx = [0; 8];
180 for (pos, char) in tx.iter_mut().enumerate() {
181 *char = if (byte >> pos) & 0x1 == 0x1 {
182 Self::LOGIC_1_CHAR
183 } else {
184 Self::LOGIC_0_CHAR
185 };
186 }
187 self.tx.write_all(&tx).await.expect("write failed");
188
189 // Readback the value on the bus, sensors can pull logic 1 to 0
190 let mut rx = [0; 8];
191 self.rx.read_exact(&mut rx).await.expect("read failed");
192 let mut bus_byte = 0;
193 for (pos, char) in rx.iter().enumerate() {
194 // if its 0xFF, sensor didnt pull the bus to low level
195 if *char == 0xFF {
196 bus_byte |= 1 << pos;
197 }
198 }
199
200 bus_byte
201 }
202
203 /// Read a byte from the bus.
204 pub async fn read_byte(&mut self) -> u8 {
205 self.write_read_byte(0xFF).await
206 }
207}
208
209/// DS18B20 temperature sensor driver
210pub struct Ds18b20<TX, RX>
211where
212 TX: embedded_io_async::Write + SetBaudrate,
213 RX: embedded_io_async::Read + SetBaudrate,
214{
215 bus: OneWire<TX, RX>,
216}
217
218impl<TX, RX> Ds18b20<TX, RX>
219where
220 TX: embedded_io_async::Write + SetBaudrate,
221 RX: embedded_io_async::Read + SetBaudrate,
222{
223 /// Start a temperature conversion.
224 const FN_CONVERT_T: u8 = 0x44;
225 /// Read contents of the scratchpad containing the temperature.
226 const FN_READ_SCRATCHPAD: u8 = 0xBE;
227
228 pub fn new(bus: OneWire<TX, RX>) -> Self {
229 Self { bus }
230 }
231
232 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
233 pub async fn start(&mut self) {
234 self.bus.reset().await;
235 self.bus.write_read_byte(OneWire::<TX, RX>::COMMAND_SKIP_ROM).await;
236 self.bus.write_read_byte(Self::FN_CONVERT_T).await;
237 }
238
239 /// Calculate CRC8 of the data
240 fn crc8(data: &[u8]) -> u8 {
241 let mut temp;
242 let mut data_byte;
243 let mut crc = 0;
244 for b in data {
245 data_byte = *b;
246 for _ in 0..8 {
247 temp = (crc ^ data_byte) & 0x01;
248 crc >>= 1;
249 if temp != 0 {
250 crc ^= 0x8C;
251 }
252 data_byte >>= 1;
253 }
254 }
255 crc
256 }
257
258 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
259 pub async fn temperature(&mut self) -> Result<f32, ()> {
260 self.bus.reset().await;
261 self.bus.write_read_byte(OneWire::<TX, RX>::COMMAND_SKIP_ROM).await;
262 self.bus.write_read_byte(Self::FN_READ_SCRATCHPAD).await;
263
264 let mut data = [0; 9];
265 for byte in data.iter_mut() {
266 *byte = self.bus.read_byte().await;
267 }
268
269 match Self::crc8(&data) == 0 {
270 true => Ok(((data[1] as u16) << 8 | data[0] as u16) as f32 / 16.),
271 false => Err(()),
272 }
273 }
274}
diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs
index 152ecda86..9d6b5fe97 100644
--- a/examples/stm32g0/src/bin/pwm_input.rs
+++ b/examples/stm32g0/src/bin/pwm_input.rs
@@ -14,14 +14,13 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed};
14use embassy_stm32::time::khz; 14use embassy_stm32::time::khz;
15use embassy_stm32::timer::pwm_input::PwmInput; 15use embassy_stm32::timer::pwm_input::PwmInput;
16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
17use embassy_stm32::timer::Channel; 17use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
18use embassy_stm32::{bind_interrupts, peripherals, timer};
19use embassy_time::Timer; 18use embassy_time::Timer;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
22// Connect PB1 and PA6 with a 1k Ohm resistor 21// Connect PB1 and PA6 with a 1k Ohm resistor
23#[embassy_executor::task] 22#[embassy_executor::task]
24async fn blinky(led: peripherals::PB1) { 23async fn blinky(led: Peri<'static, peripherals::PB1>) {
25 let mut led = Output::new(led, Level::High, Speed::Low); 24 let mut led = Output::new(led, Level::High, Speed::Low);
26 25
27 loop { 26 loop {
@@ -43,11 +42,10 @@ async fn main(spawner: Spawner) {
43 42
44 unwrap!(spawner.spawn(blinky(p.PB1))); 43 unwrap!(spawner.spawn(blinky(p.PB1)));
45 // Connect PA8 and PA6 with a 1k Ohm resistor 44 // Connect PA8 and PA6 with a 1k Ohm resistor
46 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 45 let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
47 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); 46 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default());
48 let max = pwm.get_max_duty(); 47 pwm.ch1().set_duty_cycle_fraction(1, 4);
49 pwm.set_duty(Channel::Ch1, max / 4); 48 pwm.ch1().enable();
50 pwm.enable(Channel::Ch1);
51 49
52 let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000)); 50 let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000));
53 pwm_input.enable(); 51 pwm_input.enable();
diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs
index c02c1ecd7..50fb6398e 100644
--- a/examples/stm32g0/src/bin/rtc.rs
+++ b/examples/stm32g0/src/bin/rtc.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10); 18 let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0);
19 19
20 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 20 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
21 21
diff --git a/examples/stm32g0/src/bin/usart_buffered.rs b/examples/stm32g0/src/bin/usart_buffered.rs
index c097a0c5a..6d9ec8cb4 100644
--- a/examples/stm32g0/src/bin/usart_buffered.rs
+++ b/examples/stm32g0/src/bin/usart_buffered.rs
@@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) {
21 config.baudrate = 115200; 21 config.baudrate = 115200;
22 let mut tx_buf = [0u8; 256]; 22 let mut tx_buf = [0u8; 256];
23 let mut rx_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(); 24 let mut usart = BufferedUart::new(p.USART1, p.PB7, p.PB6, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap();
25 25
26 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); 26 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
27 info!("wrote Hello, starting echo"); 27 info!("wrote Hello, starting echo");
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 2768147a1..3d2c2aa7d 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -6,22 +6,22 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.4.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.8.1" 15usbd-hid = "0.8.1"
16 16
17defmt = "0.3" 17defmt = "1.0.1"
18defmt-rtt = "0.4" 18defmt-rtt = "1.0.0"
19 19
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" } 23embedded-can = { version = "0.4" }
24panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "1.0.0", features = ["print-defmt"] }
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26static_cell = "2.0.0" 26static_cell = "2.0.0"
27 27
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_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs
new file mode 100644
index 000000000..202704085
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_dma.rs
@@ -0,0 +1,60 @@
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
11static mut DMA_BUF: [u16; 2] = [0; 2];
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let mut read_buffer = unsafe { &mut DMA_BUF[..] };
16
17 let mut config = Config::default();
18 {
19 use embassy_stm32::rcc::*;
20 config.rcc.pll = Some(Pll {
21 source: PllSource::HSI,
22 prediv: PllPreDiv::DIV4,
23 mul: PllMul::MUL85,
24 divp: None,
25 divq: None,
26 // Main system clock at 170 MHz
27 divr: Some(PllRDiv::DIV2),
28 });
29 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
30 config.rcc.sys = Sysclk::PLL1_R;
31 }
32 let p = embassy_stm32::init(config);
33
34 info!("Hello World!");
35
36 let mut adc = Adc::new(p.ADC1);
37
38 let mut dma = p.DMA1_CH1;
39 let mut vrefint_channel = adc.enable_vrefint().degrade_adc();
40 let mut pa0 = p.PA0.degrade_adc();
41
42 loop {
43 adc.read(
44 dma.reborrow(),
45 [
46 (&mut vrefint_channel, SampleTime::CYCLES247_5),
47 (&mut pa0, SampleTime::CYCLES247_5),
48 ]
49 .into_iter(),
50 &mut read_buffer,
51 )
52 .await;
53
54 let vrefint = read_buffer[0];
55 let measured = read_buffer[1];
56 info!("vrefint: {}", vrefint);
57 info!("measured: {}", measured);
58 Timer::after_millis(500).await;
59 }
60}
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/pwm.rs b/examples/stm32g4/src/bin/pwm.rs
index d4809a481..6c965012c 100644
--- a/examples/stm32g4/src/bin/pwm.rs
+++ b/examples/stm32g4/src/bin/pwm.rs
@@ -6,7 +6,6 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
9use embassy_stm32::timer::Channel;
10use embassy_time::Timer; 9use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -15,22 +14,22 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 15 info!("Hello World!");
17 16
18 let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); 17 let ch1_pin = PwmPin::new_ch1(p.PC0, OutputType::PushPull);
19 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); 18 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default());
20 let max = pwm.get_max_duty(); 19 let mut ch1 = pwm.ch1();
21 pwm.enable(Channel::Ch1); 20 ch1.enable();
22 21
23 info!("PWM initialized"); 22 info!("PWM initialized");
24 info!("PWM max duty {}", max); 23 info!("PWM max duty {}", ch1.max_duty_cycle());
25 24
26 loop { 25 loop {
27 pwm.set_duty(Channel::Ch1, 0); 26 ch1.set_duty_cycle_fully_off();
28 Timer::after_millis(300).await; 27 Timer::after_millis(300).await;
29 pwm.set_duty(Channel::Ch1, max / 4); 28 ch1.set_duty_cycle_fraction(1, 4);
30 Timer::after_millis(300).await; 29 Timer::after_millis(300).await;
31 pwm.set_duty(Channel::Ch1, max / 2); 30 ch1.set_duty_cycle_fraction(1, 2);
32 Timer::after_millis(300).await; 31 Timer::after_millis(300).await;
33 pwm.set_duty(Channel::Ch1, max - 1); 32 ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
34 Timer::after_millis(300).await; 33 Timer::after_millis(300).await;
35 } 34 }
36} 35}
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
index 7caea634f..2e87d3931 100644
--- a/examples/stm32g4/src/bin/usb_c_pd.rs
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
55 55
56 info!("Hello World!"); 56 info!("Hello World!");
57 57
58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); 58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default());
59 ucpd.cc_phy().set_pull(CcPull::Sink); 59 ucpd.cc_phy().set_pull(CcPull::Sink);
60 60
61 info!("Waiting for USB connection..."); 61 info!("Waiting for USB connection...");
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index ed2ac7fac..9f66f0c53 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -51,11 +51,6 @@ async fn main(_spawner: Spawner) {
51 config.product = Some("USB-Serial Example"); 51 config.product = Some("USB-Serial Example");
52 config.serial_number = Some("123456"); 52 config.serial_number = Some("123456");
53 53
54 config.device_class = 0xEF;
55 config.device_sub_class = 0x02;
56 config.device_protocol = 0x01;
57 config.composite_with_iads = true;
58
59 let mut config_descriptor = [0; 256]; 54 let mut config_descriptor = [0; 256];
60 let mut bos_descriptor = [0; 256]; 55 let mut bos_descriptor = [0; 256];
61 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 30b1d2be9..f3fda7ff3 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -6,16 +6,16 @@ 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", "low-power"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", 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.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 16
17defmt = "0.3" 17defmt = "1.0.1"
18defmt-rtt = "0.4" 18defmt-rtt = "1.0.0"
19 19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
@@ -23,10 +23,9 @@ embedded-hal = "0.2.6"
23embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 23embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
24embedded-hal-async = { version = "1.0" } 24embedded-hal-async = { version = "1.0" }
25embedded-io-async = { version = "0.6.1" } 25embedded-io-async = { version = "0.6.1" }
26embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = "0.8.0"
27panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "1.0.0", features = ["print-defmt"] }
28heapless = { version = "0.8", default-features = false } 28heapless = { version = "0.8", default-features = false }
29rand_core = "0.6.3"
30critical-section = "1.1" 29critical-section = "1.1"
31micromath = "2.0.0" 30micromath = "2.0.0"
32stm32-fmc = "0.3.0" 31stm32-fmc = "0.3.0"
diff --git a/examples/stm32h5/src/bin/adc.rs b/examples/stm32h5/src/bin/adc.rs
new file mode 100644
index 000000000..c5d508ece
--- /dev/null
+++ b/examples/stm32h5/src/bin/adc.rs
@@ -0,0 +1,59 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime};
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 mut config = Config::default();
14 {
15 use embassy_stm32::rcc::*;
16 config.rcc.hsi = Some(HSIPrescaler::DIV1);
17 config.rcc.csi = true;
18 config.rcc.pll1 = Some(Pll {
19 source: PllSource::HSI,
20 prediv: PllPreDiv::DIV4,
21 mul: PllMul::MUL25,
22 divp: Some(PllDiv::DIV2),
23 divq: Some(PllDiv::DIV4), // SPI1 cksel defaults to pll1_q
24 divr: None,
25 });
26 config.rcc.pll2 = Some(Pll {
27 source: PllSource::HSI,
28 prediv: PllPreDiv::DIV4,
29 mul: PllMul::MUL25,
30 divp: None,
31 divq: None,
32 divr: Some(PllDiv::DIV4), // 100mhz
33 });
34 config.rcc.sys = Sysclk::PLL1_P; // 200 Mhz
35 config.rcc.ahb_pre = AHBPrescaler::DIV1; // 200 Mhz
36 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.voltage_scale = VoltageScale::Scale1;
40 config.rcc.mux.adcdacsel = mux::Adcdacsel::PLL2_R;
41 }
42 let mut p = embassy_stm32::init(config);
43
44 info!("Hello World!");
45
46 let mut adc = Adc::new(p.ADC1);
47
48 adc.set_sample_time(SampleTime::CYCLES24_5);
49
50 let mut vrefint_channel = adc.enable_vrefint();
51
52 loop {
53 let vrefint = adc.blocking_read(&mut vrefint_channel);
54 info!("vrefint: {}", vrefint);
55 let measured = adc.blocking_read(&mut p.PA0);
56 info!("measured: {}", measured);
57 Timer::after_millis(500).await;
58 }
59}
diff --git a/examples/stm32h5/src/bin/cordic.rs b/examples/stm32h5/src/bin/cordic.rs
index 73e873574..cbf854704 100644
--- a/examples/stm32h5/src/bin/cordic.rs
+++ b/examples/stm32h5/src/bin/cordic.rs
@@ -11,7 +11,7 @@ async fn main(_spawner: Spawner) {
11 let mut dp = embassy_stm32::init(Default::default()); 11 let mut dp = embassy_stm32::init(Default::default());
12 12
13 let mut cordic = cordic::Cordic::new( 13 let mut cordic = cordic::Cordic::new(
14 &mut dp.CORDIC, 14 dp.CORDIC.reborrow(),
15 unwrap!(cordic::Config::new( 15 unwrap!(cordic::Config::new(
16 cordic::Function::Sin, 16 cordic::Function::Sin,
17 Default::default(), 17 Default::default(),
@@ -59,8 +59,8 @@ async fn main(_spawner: Spawner) {
59 let cnt1 = unwrap!( 59 let cnt1 = unwrap!(
60 cordic 60 cordic
61 .async_calc_32bit( 61 .async_calc_32bit(
62 &mut dp.GPDMA1_CH0, 62 dp.GPDMA1_CH0.reborrow(),
63 &mut dp.GPDMA1_CH1, 63 dp.GPDMA1_CH1.reborrow(),
64 &input_buf[..arg1.len() - 1], // limit input buf to its actual length 64 &input_buf[..arg1.len() - 1], // limit input buf to its actual length
65 &mut output_u32, 65 &mut output_u32,
66 true, 66 true,
diff --git a/examples/stm32h5/src/bin/dts.rs b/examples/stm32h5/src/bin/dts.rs
new file mode 100644
index 000000000..8c18fafea
--- /dev/null
+++ b/examples/stm32h5/src/bin/dts.rs
@@ -0,0 +1,75 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::dts::{Dts, InterruptHandler, SampleTime};
7use embassy_stm32::peripherals::DTS;
8use embassy_stm32::rcc::frequency;
9use embassy_stm32::{bind_interrupts, dts, Config};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 DTS => InterruptHandler;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut config = Config::default();
20 {
21 use embassy_stm32::rcc::*;
22 config.rcc.hsi = Some(HSIPrescaler::DIV1);
23 config.rcc.csi = true;
24 config.rcc.pll1 = Some(Pll {
25 source: PllSource::HSI,
26 prediv: PllPreDiv::DIV4,
27 mul: PllMul::MUL25,
28 divp: Some(PllDiv::DIV2),
29 divq: Some(PllDiv::DIV4), // SPI1 cksel defaults to pll1_q
30 divr: None,
31 });
32 config.rcc.pll2 = Some(Pll {
33 source: PllSource::HSI,
34 prediv: PllPreDiv::DIV4,
35 mul: PllMul::MUL25,
36 divp: None,
37 divq: None,
38 divr: Some(PllDiv::DIV4), // 100mhz
39 });
40 config.rcc.sys = Sysclk::PLL1_P; // 200 Mhz
41 config.rcc.ahb_pre = AHBPrescaler::DIV1; // 200 Mhz
42 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
45 config.rcc.voltage_scale = VoltageScale::Scale1;
46 config.rcc.mux.adcdacsel = mux::Adcdacsel::PLL2_R;
47 }
48 let p = embassy_stm32::init(config);
49
50 info!("Hello World!");
51
52 let mut config = dts::Config::default();
53 config.sample_time = SampleTime::ClockCycles15;
54 let mut dts = Dts::new(p.DTS, Irqs, config);
55
56 let cal = Dts::factory_calibration();
57 let convert_to_celsius = |raw_temp: u16| {
58 let raw_temp = raw_temp as f32;
59 let sample_time = (config.sample_time as u8) as f32;
60
61 let f = frequency::<DTS>().0 as f32;
62
63 let t0 = cal.t0 as f32;
64 let fmt0 = cal.fmt0.0 as f32;
65 let ramp_coeff = cal.ramp_coeff as f32;
66
67 ((f * sample_time / raw_temp) - fmt0) / ramp_coeff + t0
68 };
69
70 loop {
71 let temp = dts.read().await;
72 info!("Temp: {} degrees", convert_to_celsius(temp));
73 Timer::after_millis(500).await;
74 }
75}
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 65cfad8c9..1d85cc1e7 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -4,9 +4,8 @@
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::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 9use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rcc::{ 10use embassy_stm32::rcc::{
12 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, 11 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
@@ -16,7 +15,6 @@ use embassy_stm32::time::Hertz;
16use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 15use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
17use embassy_time::Timer; 16use embassy_time::Timer;
18use embedded_io_async::Write; 17use embedded_io_async::Write;
19use rand_core::RngCore;
20use static_cell::StaticCell; 18use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
22 20
@@ -25,11 +23,11 @@ bind_interrupts!(struct Irqs {
25 RNG => rng::InterruptHandler<peripherals::RNG>; 23 RNG => rng::InterruptHandler<peripherals::RNG>;
26}); 24});
27 25
28type Device = Ethernet<'static, ETH, GenericSMI>; 26type Device = Ethernet<'static, ETH, GenericPhy>;
29 27
30#[embassy_executor::task] 28#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<Device>) -> ! { 29async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
32 stack.run().await 30 runner.run().await
33} 31}
34 32
35#[embassy_executor::main] 33#[embassy_executor::main]
@@ -80,7 +78,7 @@ async fn main(spawner: Spawner) -> ! {
80 p.PG13, 78 p.PG13,
81 p.PB15, 79 p.PB15,
82 p.PG11, 80 p.PG11,
83 GenericSMI::new(0), 81 GenericPhy::new_auto(),
84 mac_addr, 82 mac_addr,
85 ); 83 );
86 84
@@ -92,12 +90,11 @@ async fn main(spawner: Spawner) -> ! {
92 //}); 90 //});
93 91
94 // Init network stack 92 // Init network stack
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 94 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
98 95
99 // Launch network task 96 // Launch network task
100 unwrap!(spawner.spawn(net_task(&stack))); 97 unwrap!(spawner.spawn(net_task(runner)));
101 98
102 // Ensure DHCP configuration is up before trying connect 99 // Ensure DHCP configuration is up before trying connect
103 stack.wait_config_up().await; 100 stack.wait_config_up().await;
@@ -109,7 +106,7 @@ async fn main(spawner: Spawner) -> ! {
109 let mut tx_buffer = [0; 1024]; 106 let mut tx_buffer = [0; 1024];
110 107
111 loop { 108 loop {
112 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 109 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
113 110
114 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 111 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
115 112
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs
index 0d14c0668..e650791c5 100644
--- a/examples/stm32h5/src/bin/stop.rs
+++ b/examples/stm32h5/src/bin/stop.rs
@@ -10,7 +10,7 @@ use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
10use embassy_stm32::low_power::Executor; 10use embassy_stm32::low_power::Executor;
11use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; 11use embassy_stm32::rcc::{HSIPrescaler, LsConfig};
12use embassy_stm32::rtc::{Rtc, RtcConfig}; 12use embassy_stm32::rtc::{Rtc, RtcConfig};
13use embassy_stm32::Config; 13use embassy_stm32::{Config, Peri};
14use embassy_time::Timer; 14use embassy_time::Timer;
15use static_cell::StaticCell; 15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
@@ -48,7 +48,7 @@ async fn async_main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn blinky(led: AnyPin) { 51async fn blinky(led: Peri<'static, AnyPin>) {
52 let mut led = Output::new(led, Level::Low, Speed::Low); 52 let mut led = Output::new(led, Level::Low, Speed::Low);
53 loop { 53 loop {
54 info!("high"); 54 info!("high");
diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs
new file mode 100644
index 000000000..acb03e498
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_c_pd.rs
@@ -0,0 +1,93 @@
1//! This example targets the NUCLEO-H563ZI platform.
2//! USB-C CC lines are protected by a TCPP01-M12 chipset.
3#![no_std]
4#![no_main]
5
6use defmt::{error, info, Format};
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::Output;
9use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd};
10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_time::{with_timeout, Duration};
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>;
16});
17
18#[derive(Debug, Format)]
19enum CableOrientation {
20 Normal,
21 Flipped,
22 DebugAccessoryMode,
23}
24
25// Returns true when the cable
26async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation {
27 loop {
28 let (cc1, cc2) = cc_phy.vstate();
29 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
30 // Detached, wait until attached by monitoring the CC lines.
31 cc_phy.wait_for_vstate_change().await;
32 continue;
33 }
34
35 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
36 if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change())
37 .await
38 .is_ok()
39 {
40 // State has changed, restart detection procedure.
41 continue;
42 };
43
44 // State was stable for the complete debounce period, check orientation.
45 return match (cc1, cc2) {
46 (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected
47 (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected
48 _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable)
49 };
50 }
51}
52
53#[embassy_executor::main]
54async fn main(_spawner: Spawner) {
55 let config = Config::default();
56 let p = embassy_stm32::init(config);
57
58 info!("Hello World!");
59
60 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB13, p.PB14, Default::default());
61 ucpd.cc_phy().set_pull(CcPull::Sink);
62
63 // This pin controls the dead-battery mode on the attached TCPP01-M12.
64 // If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high.
65 // Must only be set after the CC pull is established.
66 let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low);
67
68 info!("Waiting for USB connection...");
69 let cable_orientation = wait_attached(ucpd.cc_phy()).await;
70 info!("USB cable connected, orientation: {}", cable_orientation);
71
72 let cc_sel = match cable_orientation {
73 CableOrientation::Normal => {
74 info!("Starting PD communication on CC1 pin");
75 CcSel::CC1
76 }
77 CableOrientation::Flipped => {
78 info!("Starting PD communication on CC2 pin");
79 CcSel::CC2
80 }
81 CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"),
82 };
83 let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.GPDMA1_CH0, p.GPDMA1_CH1, cc_sel);
84
85 loop {
86 // Enough space for the longest non-extended data message.
87 let mut buf = [0_u8; 30];
88 match pd_phy.receive(buf.as_mut()).await {
89 Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]),
90 Err(e) => error!("USB PD RX: {}", e),
91 }
92 }
93}
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index fbcbdb5f9..e8f536133 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -56,13 +56,6 @@ async fn main(_spawner: Spawner) {
56 config.product = Some("USB-serial example"); 56 config.product = Some("USB-serial example");
57 config.serial_number = Some("12345678"); 57 config.serial_number = Some("12345678");
58 58
59 // Required for windows compatibility.
60 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
61 config.device_class = 0xEF;
62 config.device_sub_class = 0x02;
63 config.device_protocol = 0x01;
64 config.composite_with_iads = true;
65
66 // Create embassy-usb DeviceBuilder using the driver and config. 59 // Create embassy-usb DeviceBuilder using the driver and config.
67 // It needs some buffers for building the descriptors. 60 // It needs some buffers for building the descriptors.
68 let mut config_descriptor = [0; 256]; 61 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs
new file mode 100644
index 000000000..5d007261c
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs
@@ -0,0 +1,374 @@
1#![no_std]
2#![no_main]
3
4use core::cell::{Cell, RefCell};
5
6use defmt::{panic, *};
7use embassy_executor::Spawner;
8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config};
10use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
11use embassy_sync::blocking_mutex::Mutex;
12use embassy_sync::signal::Signal;
13use embassy_sync::zerocopy_channel;
14use embassy_usb::class::uac1;
15use embassy_usb::class::uac1::speaker::{self, Speaker};
16use embassy_usb::driver::EndpointError;
17use heapless::Vec;
18use micromath::F32Ext;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 USB_DRD_FS => usb::InterruptHandler<peripherals::USB>;
24});
25
26static TIMER: Mutex<CriticalSectionRawMutex, RefCell<Option<timer::low_level::Timer<peripherals::TIM5>>>> =
27 Mutex::new(RefCell::new(None));
28
29// A counter signal that is written by the feedback timer, once every `FEEDBACK_REFRESH_PERIOD`.
30// At that point, a feedback value is sent to the host.
31pub static FEEDBACK_SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
32
33// Stereo input
34pub const INPUT_CHANNEL_COUNT: usize = 2;
35
36// This example uses a fixed sample rate of 48 kHz.
37pub const SAMPLE_RATE_HZ: u32 = 48_000;
38pub const FEEDBACK_COUNTER_TICK_RATE: u32 = 31_250_000;
39
40// Use 32 bit samples, which allow for a lot of (software) volume adjustment without degradation of quality.
41pub const SAMPLE_WIDTH: uac1::SampleWidth = uac1::SampleWidth::Width4Byte;
42pub const SAMPLE_WIDTH_BIT: usize = SAMPLE_WIDTH.in_bit();
43pub const SAMPLE_SIZE: usize = SAMPLE_WIDTH as usize;
44pub const SAMPLE_SIZE_PER_S: usize = (SAMPLE_RATE_HZ as usize) * INPUT_CHANNEL_COUNT * SAMPLE_SIZE;
45
46// Size of audio samples per 1 ms - for the full-speed USB frame period of 1 ms.
47pub const USB_FRAME_SIZE: usize = SAMPLE_SIZE_PER_S.div_ceil(1000);
48
49// Select front left and right audio channels.
50pub const AUDIO_CHANNELS: [uac1::Channel; INPUT_CHANNEL_COUNT] = [uac1::Channel::LeftFront, uac1::Channel::RightFront];
51
52// Factor of two as a margin for feedback (this is an excessive amount)
53pub const USB_MAX_PACKET_SIZE: usize = 2 * USB_FRAME_SIZE;
54pub const USB_MAX_SAMPLE_COUNT: usize = USB_MAX_PACKET_SIZE / SAMPLE_SIZE;
55
56// The data type that is exchanged via the zero-copy channel (a sample vector).
57pub type SampleBlock = Vec<u32, USB_MAX_SAMPLE_COUNT>;
58
59// Feedback is provided in 10.14 format for full-speed endpoints.
60pub const FEEDBACK_REFRESH_PERIOD: uac1::FeedbackRefresh = uac1::FeedbackRefresh::Period8Frames;
61const FEEDBACK_SHIFT: usize = 14;
62
63const TICKS_PER_SAMPLE: f32 = (FEEDBACK_COUNTER_TICK_RATE as f32) / (SAMPLE_RATE_HZ as f32);
64
65struct Disconnected {}
66
67impl From<EndpointError> for Disconnected {
68 fn from(val: EndpointError) -> Self {
69 match val {
70 EndpointError::BufferOverflow => panic!("Buffer overflow"),
71 EndpointError::Disabled => Disconnected {},
72 }
73 }
74}
75
76/// Sends feedback messages to the host.
77async fn feedback_handler<'d, T: usb::Instance + 'd>(
78 feedback: &mut speaker::Feedback<'d, usb::Driver<'d, T>>,
79 feedback_factor: f32,
80) -> Result<(), Disconnected> {
81 let mut packet: Vec<u8, 4> = Vec::new();
82
83 // Collects the fractional component of the feedback value that is lost by rounding.
84 let mut rest = 0.0_f32;
85
86 loop {
87 let counter = FEEDBACK_SIGNAL.wait().await;
88
89 packet.clear();
90
91 let raw_value = counter as f32 * feedback_factor + rest;
92 let value = raw_value.round();
93 rest = raw_value - value;
94
95 let value = value as u32;
96
97 debug!("Feedback value: {}", value);
98
99 packet.push(value as u8).unwrap();
100 packet.push((value >> 8) as u8).unwrap();
101 packet.push((value >> 16) as u8).unwrap();
102
103 feedback.write_packet(&packet).await?;
104 }
105}
106
107/// Handles streaming of audio data from the host.
108async fn stream_handler<'d, T: usb::Instance + 'd>(
109 stream: &mut speaker::Stream<'d, usb::Driver<'d, T>>,
110 sender: &mut zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>,
111) -> Result<(), Disconnected> {
112 loop {
113 let mut usb_data = [0u8; USB_MAX_PACKET_SIZE];
114 let data_size = stream.read_packet(&mut usb_data).await?;
115
116 let word_count = data_size / SAMPLE_SIZE;
117
118 if word_count * SAMPLE_SIZE == data_size {
119 // Obtain a buffer from the channel
120 let samples = sender.send().await;
121 samples.clear();
122
123 for w in 0..word_count {
124 let byte_offset = w * SAMPLE_SIZE;
125 let sample = u32::from_le_bytes(usb_data[byte_offset..byte_offset + SAMPLE_SIZE].try_into().unwrap());
126
127 // Fill the sample buffer with data.
128 samples.push(sample).unwrap();
129 }
130
131 sender.send_done();
132 } else {
133 debug!("Invalid USB buffer size of {}, skipped.", data_size);
134 }
135 }
136}
137
138/// Receives audio samples from the USB streaming task and can play them back.
139#[embassy_executor::task]
140async fn audio_receiver_task(mut usb_audio_receiver: zerocopy_channel::Receiver<'static, NoopRawMutex, SampleBlock>) {
141 loop {
142 let _samples = usb_audio_receiver.receive().await;
143 // Use the samples, for example play back via the SAI peripheral.
144
145 // Notify the channel that the buffer is now ready to be reused
146 usb_audio_receiver.receive_done();
147 }
148}
149
150/// Receives audio samples from the host.
151#[embassy_executor::task]
152async fn usb_streaming_task(
153 mut stream: speaker::Stream<'static, usb::Driver<'static, peripherals::USB>>,
154 mut sender: zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>,
155) {
156 loop {
157 stream.wait_connection().await;
158 info!("USB connected.");
159 _ = stream_handler(&mut stream, &mut sender).await;
160 info!("USB disconnected.");
161 }
162}
163
164/// Sends sample rate feedback to the host.
165///
166/// The `feedback_factor` scales the feedback timer's counter value so that the result is the number of samples that
167/// this device played back or "consumed" during one SOF period (1 ms) - in 10.14 format.
168///
169/// Ideally, the `feedback_factor` that is calculated below would be an integer for avoiding numerical errors.
170/// This is achieved by having `TICKS_PER_SAMPLE` be a power of two. For audio applications at a sample rate of 48 kHz,
171/// 24.576 MHz would be one such option.
172#[embassy_executor::task]
173async fn usb_feedback_task(mut feedback: speaker::Feedback<'static, usb::Driver<'static, peripherals::USB>>) {
174 let feedback_factor =
175 ((1 << FEEDBACK_SHIFT) as f32 / TICKS_PER_SAMPLE) / FEEDBACK_REFRESH_PERIOD.frame_count() as f32;
176
177 loop {
178 feedback.wait_connection().await;
179 _ = feedback_handler(&mut feedback, feedback_factor).await;
180 }
181}
182
183#[embassy_executor::task]
184async fn usb_task(mut usb_device: embassy_usb::UsbDevice<'static, usb::Driver<'static, peripherals::USB>>) {
185 usb_device.run().await;
186}
187
188/// Checks for changes on the control monitor of the class.
189///
190/// In this case, monitor changes of volume or mute state.
191#[embassy_executor::task]
192async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) {
193 loop {
194 control_monitor.changed().await;
195
196 for channel in AUDIO_CHANNELS {
197 let volume = control_monitor.volume(channel).unwrap();
198 info!("Volume changed to {} on channel {}.", volume, channel);
199 }
200 }
201}
202
203/// Feedback value measurement and calculation
204///
205/// Used for measuring/calculating the number of samples that were received from the host during the
206/// `FEEDBACK_REFRESH_PERIOD`.
207///
208/// Configured in this example with
209/// - a refresh period of 8 ms, and
210/// - a tick rate of 42 MHz.
211///
212/// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`.
213#[interrupt]
214fn TIM5() {
215 static LAST_TICKS: Mutex<CriticalSectionRawMutex, Cell<u32>> = Mutex::new(Cell::new(0));
216 static FRAME_COUNT: Mutex<CriticalSectionRawMutex, Cell<usize>> = Mutex::new(Cell::new(0));
217
218 critical_section::with(|cs| {
219 // Read timer counter.
220 let timer = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32();
221
222 let status = timer.sr().read();
223
224 const CHANNEL_INDEX: usize = 0;
225 if status.ccif(CHANNEL_INDEX) {
226 let ticks = timer.ccr(CHANNEL_INDEX).read();
227
228 let frame_count = FRAME_COUNT.borrow(cs);
229 let last_ticks = LAST_TICKS.borrow(cs);
230
231 frame_count.set(frame_count.get() + 1);
232 if frame_count.get() >= FEEDBACK_REFRESH_PERIOD.frame_count() {
233 frame_count.set(0);
234 FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(last_ticks.get()));
235 last_ticks.set(ticks);
236 }
237 };
238
239 // Clear trigger interrupt flag.
240 timer.sr().modify(|r| r.set_tif(false));
241 });
242}
243
244// If you are trying this and your USB device doesn't connect, the most
245// common issues are the RCC config and vbus_detection
246//
247// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
248// for more information.
249#[embassy_executor::main]
250async fn main(spawner: Spawner) {
251 let mut config = Config::default();
252 {
253 use embassy_stm32::rcc::*;
254 config.rcc.hsi = None;
255 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
256 config.rcc.hse = Some(Hse {
257 freq: Hertz(8_000_000),
258 mode: HseMode::BypassDigital,
259 });
260 config.rcc.pll1 = Some(Pll {
261 source: PllSource::HSE,
262 prediv: PllPreDiv::DIV2,
263 mul: PllMul::MUL125,
264 divp: Some(PllDiv::DIV2), // 250 Mhz
265 divq: None,
266 divr: None,
267 });
268 config.rcc.pll2 = Some(Pll {
269 source: PllSource::HSE,
270 prediv: PllPreDiv::DIV4,
271 mul: PllMul::MUL123,
272 divp: Some(PllDiv::DIV20), // 12.3 Mhz, close to 12.288 MHz for 48 kHz audio
273 divq: None,
274 divr: None,
275 });
276 config.rcc.ahb_pre = AHBPrescaler::DIV2;
277 config.rcc.apb1_pre = APBPrescaler::DIV4;
278 config.rcc.apb2_pre = APBPrescaler::DIV2;
279 config.rcc.apb3_pre = APBPrescaler::DIV4;
280 config.rcc.sys = Sysclk::PLL1_P;
281 config.rcc.voltage_scale = VoltageScale::Scale0;
282 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
283 config.rcc.mux.sai2sel = mux::Saisel::PLL2_P;
284 }
285 let p = embassy_stm32::init(config);
286
287 info!("Hello World!");
288
289 // Configure all required buffers in a static way.
290 debug!("USB packet size is {} byte", USB_MAX_PACKET_SIZE);
291 static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
292 let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]);
293
294 static BOS_DESCRIPTOR: StaticCell<[u8; 32]> = StaticCell::new();
295 let bos_descriptor = BOS_DESCRIPTOR.init([0; 32]);
296
297 const CONTROL_BUF_SIZE: usize = 64;
298 static CONTROL_BUF: StaticCell<[u8; CONTROL_BUF_SIZE]> = StaticCell::new();
299 let control_buf = CONTROL_BUF.init([0; CONTROL_BUF_SIZE]);
300
301 static STATE: StaticCell<speaker::State> = StaticCell::new();
302 let state = STATE.init(speaker::State::new());
303
304 let usb_driver = usb::Driver::new(p.USB, Irqs, p.PA12, p.PA11);
305
306 // Basic USB device configuration
307 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
308 config.manufacturer = Some("Embassy");
309 config.product = Some("USB-audio-speaker example");
310 config.serial_number = Some("12345678");
311
312 let mut builder = embassy_usb::Builder::new(
313 usb_driver,
314 config,
315 config_descriptor,
316 bos_descriptor,
317 &mut [], // no msos descriptors
318 control_buf,
319 );
320
321 // Create the UAC1 Speaker class components
322 let (stream, feedback, control_monitor) = Speaker::new(
323 &mut builder,
324 state,
325 USB_MAX_PACKET_SIZE as u16,
326 uac1::SampleWidth::Width4Byte,
327 &[SAMPLE_RATE_HZ],
328 &AUDIO_CHANNELS,
329 FEEDBACK_REFRESH_PERIOD,
330 );
331
332 // Create the USB device
333 let usb_device = builder.build();
334
335 // Establish a zero-copy channel for transferring received audio samples between tasks
336 static SAMPLE_BLOCKS: StaticCell<[SampleBlock; 2]> = StaticCell::new();
337 let sample_blocks = SAMPLE_BLOCKS.init([Vec::new(), Vec::new()]);
338
339 static CHANNEL: StaticCell<zerocopy_channel::Channel<'_, NoopRawMutex, SampleBlock>> = StaticCell::new();
340 let channel = CHANNEL.init(zerocopy_channel::Channel::new(sample_blocks));
341 let (sender, receiver) = channel.split();
342
343 // Run a timer for counting between SOF interrupts.
344 let mut tim5 = timer::low_level::Timer::new(p.TIM5);
345 tim5.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE));
346 tim5.set_trigger_source(timer::low_level::TriggerSource::ITR12); // The USB SOF signal.
347
348 const TIMER_CHANNEL: timer::Channel = timer::Channel::Ch1;
349 tim5.set_input_ti_selection(TIMER_CHANNEL, timer::low_level::InputTISelection::TRC);
350 tim5.set_input_capture_prescaler(TIMER_CHANNEL, 0);
351 tim5.set_input_capture_filter(TIMER_CHANNEL, timer::low_level::FilterValue::FCK_INT_N2);
352
353 // Reset all interrupt flags.
354 tim5.regs_gp32().sr().write(|r| r.0 = 0);
355
356 tim5.enable_channel(TIMER_CHANNEL, true);
357 tim5.enable_input_interrupt(TIMER_CHANNEL, true);
358
359 tim5.start();
360
361 TIMER.lock(|p| p.borrow_mut().replace(tim5));
362
363 // Unmask the TIM5 interrupt.
364 unsafe {
365 cortex_m::peripheral::NVIC::unmask(interrupt::TIM5);
366 }
367
368 // Launch USB audio tasks.
369 unwrap!(spawner.spawn(usb_control_task(control_monitor)));
370 unwrap!(spawner.spawn(usb_streaming_task(stream, sender)));
371 unwrap!(spawner.spawn(usb_feedback_task(feedback)));
372 unwrap!(spawner.spawn(usb_task(usb_device)));
373 unwrap!(spawner.spawn(audio_receiver_task(receiver)));
374}
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 13fce7dc7..27c59d980 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,28 +6,27 @@ 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-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.3.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"] } 12embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.4.0", 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"] } 14embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
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"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = "0.8.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1" 30critical-section = "1.1"
32micromath = "2.0.0" 31micromath = "2.0.0"
33stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs
index 0b905d227..f06b5d06e 100644
--- a/examples/stm32h7/src/bin/adc_dma.rs
+++ b/examples/stm32h7/src/bin/adc_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::Config;
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11#[link_section = ".ram_d3"] 11#[unsafe(link_section = ".ram_d3")]
12static mut DMA_BUF: [u16; 2] = [0; 2]; 12static mut DMA_BUF: [u16; 2] = [0; 2];
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
@@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) {
57 57
58 loop { 58 loop {
59 adc.read( 59 adc.read(
60 &mut dma, 60 dma.reborrow(),
61 [ 61 [
62 (&mut vrefint_channel, SampleTime::CYCLES387_5), 62 (&mut vrefint_channel, SampleTime::CYCLES387_5),
63 (&mut pc0, SampleTime::CYCLES810_5), 63 (&mut pc0, SampleTime::CYCLES810_5),
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a6f969aba..27df80336 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,6 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dac::{DacCh1, Value}; 6use embassy_stm32::dac::{DacCh1, Value};
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
@@ -44,7 +43,7 @@ fn main() -> ! {
44 } 43 }
45 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
46 45
47 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 46 let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
48 47
49 loop { 48 loop {
50 for v in 0..=255 { 49 for v in 0..=255 {
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index 3a9887e3c..8314754bc 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -4,11 +4,13 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::mode::Async;
7use embassy_stm32::pac::timer::vals::Mms; 8use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 9use embassy_stm32::peripherals::{DAC1, TIM6, TIM7};
9use embassy_stm32::rcc::frequency; 10use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Timer; 12use embassy_stm32::timer::low_level::Timer;
13use embassy_stm32::Peri;
12use micromath::F32Ext; 14use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
14 16
@@ -56,7 +58,7 @@ async fn main(spawner: Spawner) {
56} 58}
57 59
58#[embassy_executor::task] 60#[embassy_executor::task]
59async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 61async fn dac_task1(tim: Peri<'static, TIM6>, mut dac: DacCh1<'static, DAC1, Async>) {
60 let data: &[u8; 256] = &calculate_array::<256>(); 62 let data: &[u8; 256] = &calculate_array::<256>();
61 63
62 info!("TIM6 frequency is {}", frequency::<TIM6>()); 64 info!("TIM6 frequency is {}", frequency::<TIM6>());
@@ -99,7 +101,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
99} 101}
100 102
101#[embassy_executor::task] 103#[embassy_executor::task]
102async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 104async fn dac_task2(tim: Peri<'static, TIM7>, mut dac: DacCh2<'static, DAC1, Async>) {
103 let data: &[u8; 256] = &calculate_array::<256>(); 105 let data: &[u8; 256] = &calculate_array::<256>();
104 106
105 info!("TIM7 frequency is {}", frequency::<TIM6>()); 107 info!("TIM7 frequency is {}", frequency::<TIM6>());
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index b2f8ed91e..fc14c1a70 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -4,15 +4,13 @@
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::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 9use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 11use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
13use embassy_time::Timer; 12use embassy_time::Timer;
14use embedded_io_async::Write; 13use embedded_io_async::Write;
15use rand_core::RngCore;
16use static_cell::StaticCell; 14use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
18 16
@@ -21,11 +19,11 @@ bind_interrupts!(struct Irqs {
21 RNG => rng::InterruptHandler<peripherals::RNG>; 19 RNG => rng::InterruptHandler<peripherals::RNG>;
22}); 20});
23 21
24type Device = Ethernet<'static, ETH, GenericSMI>; 22type Device = Ethernet<'static, ETH, GenericPhy>;
25 23
26#[embassy_executor::task] 24#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 25async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 26 runner.run().await
29} 27}
30 28
31#[embassy_executor::main] 29#[embassy_executor::main]
@@ -79,7 +77,7 @@ async fn main(spawner: Spawner) -> ! {
79 p.PG13, // TX_D0: Transmit Bit 0 77 p.PG13, // TX_D0: Transmit Bit 0
80 p.PB13, // TX_D1: Transmit Bit 1 78 p.PB13, // TX_D1: Transmit Bit 1
81 p.PG11, // TX_EN: Transmit Enable 79 p.PG11, // TX_EN: Transmit Enable
82 GenericSMI::new(0), 80 GenericPhy::new_auto(),
83 mac_addr, 81 mac_addr,
84 ); 82 );
85 83
@@ -91,12 +89,11 @@ async fn main(spawner: Spawner) -> ! {
91 //}); 89 //});
92 90
93 // Init network stack 91 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 93 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 94
98 // Launch network task 95 // Launch network task
99 unwrap!(spawner.spawn(net_task(&stack))); 96 unwrap!(spawner.spawn(net_task(runner)));
100 97
101 // Ensure DHCP configuration is up before trying connect 98 // Ensure DHCP configuration is up before trying connect
102 stack.wait_config_up().await; 99 stack.wait_config_up().await;
@@ -108,7 +105,7 @@ async fn main(spawner: Spawner) -> ! {
108 let mut tx_buffer = [0; 1024]; 105 let mut tx_buffer = [0; 1024];
109 106
110 loop { 107 loop {
111 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);
112 109
113 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 110 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
114 111
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 274c24ab1..46301a478 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -1,19 +1,19 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 8use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 10use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
13use embassy_time::Timer; 14use embassy_time::Timer;
14use embedded_io_async::Write; 15use embedded_io_async::Write;
15use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; 16use embedded_nal_async::TcpConnect;
16use rand_core::RngCore;
17use static_cell::StaticCell; 17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
@@ -22,11 +22,11 @@ bind_interrupts!(struct Irqs {
22 RNG => rng::InterruptHandler<peripherals::RNG>; 22 RNG => rng::InterruptHandler<peripherals::RNG>;
23}); 23});
24 24
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericPhy>;
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]
@@ -79,7 +79,7 @@ async fn main(spawner: Spawner) -> ! {
79 p.PG13, 79 p.PG13,
80 p.PB13, 80 p.PB13,
81 p.PG11, 81 p.PG11,
82 GenericSMI::new(0), 82 GenericPhy::new_auto(),
83 mac_addr, 83 mac_addr,
84 ); 84 );
85 85
@@ -91,12 +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(device, config, RESOURCES.init(StackResources::new()), seed)); 95 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 96
98 // Launch network task 97 // Launch network task
99 unwrap!(spawner.spawn(net_task(stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
100 99
101 // Ensure DHCP configuration is up before trying connect 100 // Ensure DHCP configuration is up before trying connect
102 stack.wait_config_up().await; 101 stack.wait_config_up().await;
@@ -104,7 +103,7 @@ async fn main(spawner: Spawner) -> ! {
104 info!("Network task initialized"); 103 info!("Network task initialized");
105 104
106 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 105 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
107 let client = TcpClient::new(&stack, &state); 106 let client = TcpClient::new(stack, &state);
108 107
109 loop { 108 loop {
110 // 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 aa6544f41..99cd1a158 100644
--- a/examples/stm32h7/src/bin/eth_client_mii.rs
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -1,19 +1,19 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 8use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 10use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
13use embassy_time::Timer; 14use embassy_time::Timer;
14use embedded_io_async::Write; 15use embedded_io_async::Write;
15use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; 16use embedded_nal_async::TcpConnect;
16use rand_core::RngCore;
17use static_cell::StaticCell; 17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
@@ -22,11 +22,11 @@ bind_interrupts!(struct Irqs {
22 RNG => rng::InterruptHandler<peripherals::RNG>; 22 RNG => rng::InterruptHandler<peripherals::RNG>;
23}); 23});
24 24
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericPhy>;
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]
@@ -84,7 +84,7 @@ async fn main(spawner: Spawner) -> ! {
84 p.PC2, 84 p.PC2,
85 p.PE2, 85 p.PE2,
86 p.PG11, 86 p.PG11,
87 GenericSMI::new(1), 87 GenericPhy::new_auto(),
88 mac_addr, 88 mac_addr,
89 ); 89 );
90 info!("Device created"); 90 info!("Device created");
@@ -97,12 +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(device, config, RESOURCES.init(StackResources::new()), seed)); 101 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
103 102
104 // Launch network task 103 // Launch network task
105 unwrap!(spawner.spawn(net_task(stack))); 104 unwrap!(spawner.spawn(net_task(runner)));
106 105
107 // Ensure DHCP configuration is up before trying connect 106 // Ensure DHCP configuration is up before trying connect
108 stack.wait_config_up().await; 107 stack.wait_config_up().await;
@@ -110,7 +109,7 @@ async fn main(spawner: Spawner) -> ! {
110 info!("Network task initialized"); 109 info!("Network task initialized");
111 110
112 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 111 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
113 let client = TcpClient::new(&stack, &state); 112 let client = TcpClient::new(stack, &state);
114 113
115 loop { 114 loop {
116 // 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
index 321b35a3e..ec5757284 100644
--- a/examples/stm32h7/src/bin/i2c_shared.rs
+++ b/examples/stm32h7/src/bin/i2c_shared.rs
@@ -10,8 +10,10 @@ use embassy_stm32::i2c::{self, I2c};
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, peripherals}; 12use embassy_stm32::{bind_interrupts, peripherals};
13use embassy_sync::blocking_mutex::raw::NoopRawMutex;
13use embassy_sync::blocking_mutex::NoopMutex; 14use embassy_sync::blocking_mutex::NoopMutex;
14use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_hal_1::i2c::I2c as _;
15use static_cell::StaticCell; 17use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
17 19
@@ -31,7 +33,7 @@ bind_interrupts!(struct Irqs {
31}); 33});
32 34
33#[embassy_executor::task] 35#[embassy_executor::task]
34async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { 36async fn temperature(mut i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>) {
35 let mut data = [0u8; 2]; 37 let mut data = [0u8; 2];
36 38
37 loop { 39 loop {
@@ -48,7 +50,7 @@ async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) {
48} 50}
49 51
50#[embassy_executor::task] 52#[embassy_executor::task]
51async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { 53async fn humidity(mut i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>) {
52 let mut data = [0u8; 6]; 54 let mut data = [0u8; 6];
53 55
54 loop { 56 loop {
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index b796996ea..8de31ea5b 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed};
7use embassy_stm32::time::{khz, Hertz}; 7use embassy_stm32::time::{khz, Hertz};
8use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; 8use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer};
9use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; 9use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel};
10use embassy_stm32::{into_ref, Config, Peripheral}; 10use embassy_stm32::{Config, Peri};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -66,15 +66,13 @@ pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> {
66 66
67impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { 67impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> {
68 pub fn new( 68 pub fn new(
69 tim: impl Peripheral<P = T> + 'd, 69 tim: Peri<'d, T>,
70 ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, 70 ch1: Peri<'d, impl Channel1Pin<T>>,
71 ch2: impl Peripheral<P = impl Channel2Pin<T>> + 'd, 71 ch2: Peri<'d, impl Channel2Pin<T>>,
72 ch3: impl Peripheral<P = impl Channel3Pin<T>> + 'd, 72 ch3: Peri<'d, impl Channel3Pin<T>>,
73 ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, 73 ch4: Peri<'d, impl Channel4Pin<T>>,
74 freq: Hertz, 74 freq: Hertz,
75 ) -> Self { 75 ) -> Self {
76 into_ref!(ch1, ch2, ch3, ch4);
77
78 let af1 = ch1.af_num(); 76 let af1 = ch1.af_num();
79 let af2 = ch2.af_num(); 77 let af2 = ch2.af_num();
80 let af3 = ch3.af_num(); 78 let af3 = ch3.af_num();
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index 1e48ba67b..a1c53fc3f 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -6,7 +6,6 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
9use embassy_stm32::timer::Channel;
10use embassy_stm32::Config; 9use embassy_stm32::Config;
11use embassy_time::Timer; 10use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -37,22 +36,22 @@ async fn main(_spawner: Spawner) {
37 let p = embassy_stm32::init(config); 36 let p = embassy_stm32::init(config);
38 info!("Hello World!"); 37 info!("Hello World!");
39 38
40 let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); 39 let ch1_pin = PwmPin::new_ch1(p.PA6, OutputType::PushPull);
41 let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default()); 40 let mut pwm = SimplePwm::new(p.TIM3, Some(ch1_pin), None, None, None, khz(10), Default::default());
42 let max = pwm.get_max_duty(); 41 let mut ch1 = pwm.ch1();
43 pwm.enable(Channel::Ch1); 42 ch1.enable();
44 43
45 info!("PWM initialized"); 44 info!("PWM initialized");
46 info!("PWM max duty {}", max); 45 info!("PWM max duty {}", ch1.max_duty_cycle());
47 46
48 loop { 47 loop {
49 pwm.set_duty(Channel::Ch1, 0); 48 ch1.set_duty_cycle_fully_off();
50 Timer::after_millis(300).await; 49 Timer::after_millis(300).await;
51 pwm.set_duty(Channel::Ch1, max / 4); 50 ch1.set_duty_cycle_fraction(1, 4);
52 Timer::after_millis(300).await; 51 Timer::after_millis(300).await;
53 pwm.set_duty(Channel::Ch1, max / 2); 52 ch1.set_duty_cycle_fraction(1, 2);
54 Timer::after_millis(300).await; 53 Timer::after_millis(300).await;
55 pwm.set_duty(Channel::Ch1, max - 1); 54 ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
56 Timer::after_millis(300).await; 55 Timer::after_millis(300).await;
57 } 56 }
58} 57}
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
index f6735e235..01937593a 100644
--- a/examples/stm32h7/src/bin/sai.rs
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -16,9 +16,9 @@ const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
16const SAMPLE_RATE: u32 = 48000; 16const SAMPLE_RATE: u32 = 48000;
17 17
18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions 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"] 19#[unsafe(link_section = ".sram1_bss")]
20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
21#[link_section = ".sram1_bss"] 21#[unsafe(link_section = ".sram1_bss")]
22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23 23
24#[embassy_executor::main] 24#[embassy_executor::main]
@@ -81,8 +81,9 @@ async fn main(_spawner: Spawner) {
81 rx_config.sync_output = false; 81 rx_config.sync_output = false;
82 82
83 let tx_buffer: &mut [u32] = unsafe { 83 let tx_buffer: &mut [u32] = unsafe {
84 TX_BUFFER.initialize_all_copied(0); 84 let buf = &mut *core::ptr::addr_of_mut!(TX_BUFFER);
85 let (ptr, len) = TX_BUFFER.get_ptr_len(); 85 buf.initialize_all_copied(0);
86 let (ptr, len) = buf.get_ptr_len();
86 core::slice::from_raw_parts_mut(ptr, len) 87 core::slice::from_raw_parts_mut(ptr, len)
87 }; 88 };
88 89
@@ -98,21 +99,23 @@ async fn main(_spawner: Spawner) {
98 ); 99 );
99 100
100 let rx_buffer: &mut [u32] = unsafe { 101 let rx_buffer: &mut [u32] = unsafe {
101 RX_BUFFER.initialize_all_copied(0); 102 let buf = &mut *core::ptr::addr_of_mut!(RX_BUFFER);
102 let (ptr, len) = RX_BUFFER.get_ptr_len(); 103 buf.initialize_all_copied(0);
104 let (ptr, len) = buf.get_ptr_len();
103 core::slice::from_raw_parts_mut(ptr, len) 105 core::slice::from_raw_parts_mut(ptr, len)
104 }; 106 };
105 107
106 let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config); 108 let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config);
107 109
108 sai_receiver.start(); 110 sai_receiver.start().unwrap();
109 sai_transmitter.start();
110 111
111 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; 112 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
112 113
113 loop { 114 loop {
114 sai_receiver.read(&mut buf).await.unwrap(); 115 // write() must be called before read() to start the master (transmitter)
116 // clock used by the receiver
115 sai_transmitter.write(&buf).await.unwrap(); 117 sai_transmitter.write(&buf).await.unwrap();
118 sai_receiver.read(&mut buf).await.unwrap();
116 } 119 }
117} 120}
118 121
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index abe2d4ba7..96840d8ff 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) -> ! {
53 // Should print 400kHz for initialization 53 // Should print 400kHz for initialization
54 info!("Configured clock: {}", sdmmc.clock().0); 54 info!("Configured clock: {}", sdmmc.clock().0);
55 55
56 unwrap!(sdmmc.init_card(mhz(25)).await); 56 unwrap!(sdmmc.init_sd_card(mhz(25)).await);
57 57
58 let card = unwrap!(sdmmc.card()); 58 let card = unwrap!(sdmmc.card());
59 59
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index 43fb6b41c..5a7dff572 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -16,16 +16,17 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18// Defined in memory.x 18// Defined in memory.x
19#[link_section = ".ram_d3"] 19#[unsafe(link_section = ".ram_d3")]
20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn main_task(mut spi: spi::Spi<'static, Async>) { 23async fn main_task(mut spi: spi::Spi<'static, Async>) {
24 let (read_buffer, write_buffer) = unsafe { 24 let (read_buffer, write_buffer) = unsafe {
25 RAM_D3.initialize_all_copied(0); 25 let ram = &mut *core::ptr::addr_of_mut!(RAM_D3);
26 ram.initialize_all_copied(0);
26 ( 27 (
27 RAM_D3.get_subslice_mut_unchecked(0, 128), 28 ram.get_subslice_mut_unchecked(0, 128),
28 RAM_D3.get_subslice_mut_unchecked(128, 128), 29 ram.get_subslice_mut_unchecked(128, 128),
29 ) 30 )
30 }; 31 };
31 32
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index 65ae597d4..50bb964da 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -67,13 +67,6 @@ async fn main(_spawner: Spawner) {
67 config.product = Some("USB-serial example"); 67 config.product = Some("USB-serial example");
68 config.serial_number = Some("12345678"); 68 config.serial_number = Some("12345678");
69 69
70 // Required for windows compatibility.
71 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
72 config.device_class = 0xEF;
73 config.device_sub_class = 0x02;
74 config.device_protocol = 0x01;
75 config.composite_with_iads = true;
76
77 // Create embassy-usb DeviceBuilder using the driver and config. 70 // Create embassy-usb DeviceBuilder using the driver and config.
78 // It needs some buffers for building the descriptors. 71 // It needs some buffers for building the descriptors.
79 let mut config_descriptor = [0; 256]; 72 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32h723/.cargo/config.toml b/examples/stm32h723/.cargo/config.toml
new file mode 100644
index 000000000..2e53663c5
--- /dev/null
+++ b/examples/stm32h723/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H723ZGTx'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml
new file mode 100644
index 000000000..fb219733f
--- /dev/null
+++ b/examples/stm32h723/Cargo.toml
@@ -0,0 +1,68 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h723-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h723zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
22embedded-hal-async = { version = "1.0" }
23embedded-nal-async = "0.8.0"
24embedded-io-async = { version = "0.6.1" }
25panic-probe = { version = "1.0.0", features = ["print-defmt"] }
26heapless = { version = "0.8", default-features = false }
27critical-section = "1.1"
28static_cell = "2"
29chrono = { version = "^0.4", default-features = false }
30grounded = "0.2.0"
31
32# cargo build/run
33[profile.dev]
34codegen-units = 1
35debug = 2
36debug-assertions = true # <-
37incremental = false
38opt-level = 3 # <-
39overflow-checks = true # <-
40
41# cargo test
42[profile.test]
43codegen-units = 1
44debug = 2
45debug-assertions = true # <-
46incremental = false
47opt-level = 3 # <-
48overflow-checks = true # <-
49
50# cargo build/run --release
51[profile.release]
52codegen-units = 1
53debug = 2
54debug-assertions = false # <-
55incremental = false
56lto = 'fat'
57opt-level = 3 # <-
58overflow-checks = false # <-
59
60# cargo test --release
61[profile.bench]
62codegen-units = 1
63debug = 2
64debug-assertions = false # <-
65incremental = false
66lto = 'fat'
67opt-level = 3 # <-
68overflow-checks = false # <-
diff --git a/examples/stm32h723/build.rs b/examples/stm32h723/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h723/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/stm32h723/memory.x b/examples/stm32h723/memory.x
new file mode 100644
index 000000000..aa4c00505
--- /dev/null
+++ b/examples/stm32h723/memory.x
@@ -0,0 +1,106 @@
1MEMORY
2{
3 /* This file is intended for parts in the STM32H723 family. (RM0468) */
4 /* - FLASH and RAM are mandatory memory sections. */
5 /* - The sum of all non-FLASH sections must add to 564k total device RAM. */
6 /* - The FLASH section size must match your device, see table below. */
7
8 /* FLASH */
9 /* Select the appropriate FLASH size for your device. */
10 /* - STM32H730xB 128K */
11 /* - STM32H723xE/725xE 512K */
12 /* - STM32H723xG/725xG/733xG/735xG 1M */
13 FLASH1 : ORIGIN = 0x08000000, LENGTH = 1M
14
15 /* Data TCM */
16 /* - Two contiguous 64KB RAMs. */
17 /* - Used for interrupt handlers, stacks and general RAM. */
18 /* - Zero wait-states. */
19 /* - The DTCM is taken as the origin of the base ram. (See below.) */
20 /* This is also where the interrupt table and such will live, */
21 /* which is required for deterministic performance. */
22 DTCM : ORIGIN = 0x20000000, LENGTH = 128K
23
24 /* Instruction TCM */
25 /* - More memory can be assigned to ITCM. See AXI SRAM notes, below. */
26 /* - Used for latency-critical interrupt handlers etc. */
27 /* - Zero wait-states. */
28 ITCM : ORIGIN = 0x00000000, LENGTH = 64K + 0K
29
30 /* AXI SRAM */
31 /* - AXISRAM is in D1 and accessible by all system masters except BDMA. */
32 /* - Suitable for application data not stored in DTCM. */
33 /* - Zero wait-states. */
34 /* - The 192k of extra shared RAM is fully allotted to the AXI SRAM by default. */
35 /* As a result: 64k (64k + 0k) for ITCM and 320k (128k + 192k) for AXI SRAM. */
36 /* This can be re-configured via the TCM_AXI_SHARED[1,0] register when more */
37 /* ITCM is required. */
38 AXISRAM : ORIGIN = 0x24000000, LENGTH = 128K + 192K
39
40 /* AHB SRAM */
41 /* - SRAM1-2 are in D2 and accessible by all system masters except BDMA, LTDC */
42 /* and SDMMC1. Suitable for use as DMA buffers. */
43 /* - SRAM4 is in D3 and additionally accessible by the BDMA. Used for BDMA */
44 /* buffers, for storing application data in lower-power modes. */
45 /* - Zero wait-states. */
46 SRAM1 : ORIGIN = 0x30000000, LENGTH = 16K
47 SRAM2 : ORIGIN = 0x30040000, LENGTH = 16K
48 SRAM4 : ORIGIN = 0x38000000, LENGTH = 16K
49
50 /* Backup SRAM */
51 /* Used to store data during low-power sleeps. */
52 BSRAM : ORIGIN = 0x38800000, LENGTH = 4K
53}
54
55/*
56/* Assign the memory regions defined above for use. */
57/*
58
59/* Provide the mandatory FLASH and RAM definitions for cortex-m-rt's linker script. */
60REGION_ALIAS(FLASH, FLASH1);
61REGION_ALIAS(RAM, DTCM);
62
63/* The location of the stack can be overridden using the `_stack_start` symbol. */
64/* - Set the stack location at the end of RAM, using all remaining space. */
65_stack_start = ORIGIN(RAM) + LENGTH(RAM);
66
67/* The location of the .text section can be overridden using the */
68/* `_stext` symbol. By default it will place after .vector_table. */
69/* _stext = ORIGIN(FLASH) + 0x40c; */
70
71/* Define sections for placing symbols into the extra memory regions above. */
72/* This makes them accessible from code. */
73/* - ITCM, DTCM and AXISRAM connect to a 64-bit wide bus -> align to 8 bytes. */
74/* - All other memories connect to a 32-bit wide bus -> align to 4 bytes. */
75SECTIONS {
76 .itcm (NOLOAD) : ALIGN(8) {
77 *(.itcm .itcm.*);
78 . = ALIGN(8);
79 } > ITCM
80
81 .axisram (NOLOAD) : ALIGN(8) {
82 *(.axisram .axisram.*);
83 . = ALIGN(8);
84 } > AXISRAM
85
86 .sram1 (NOLOAD) : ALIGN(4) {
87 *(.sram1 .sram1.*);
88 . = ALIGN(4);
89 } > SRAM1
90
91 .sram2 (NOLOAD) : ALIGN(4) {
92 *(.sram2 .sram2.*);
93 . = ALIGN(4);
94 } > SRAM2
95
96 .sram4 (NOLOAD) : ALIGN(4) {
97 *(.sram4 .sram4.*);
98 . = ALIGN(4);
99 } > SRAM4
100
101 .bsram (NOLOAD) : ALIGN(4) {
102 *(.bsram .bsram.*);
103 . = ALIGN(4);
104 } > BSRAM
105
106};
diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs
new file mode 100644
index 000000000..a04d7cb34
--- /dev/null
+++ b/examples/stm32h723/src/bin/spdifrx.rs
@@ -0,0 +1,175 @@
1//! This example receives inputs on SPDIFRX and outputs on SAI4.
2//!
3//! Only very few controllers connect the SPDIFRX symbol clock to a SAI peripheral's clock input.
4//! However, this is necessary for synchronizing the symbol rates and avoiding glitches.
5#![no_std]
6#![no_main]
7
8use defmt::{info, trace};
9use embassy_executor::Spawner;
10use embassy_futures::select::{self, select, Either};
11use embassy_stm32::spdifrx::{self, Spdifrx};
12use embassy_stm32::{bind_interrupts, peripherals, sai};
13use grounded::uninit::GroundedArrayCell;
14use hal::sai::*;
15use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 SPDIF_RX => spdifrx::GlobalInterruptHandler<peripherals::SPDIFRX1>;
19});
20
21const CHANNEL_COUNT: usize = 2;
22const BLOCK_LENGTH: usize = 64;
23const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * CHANNEL_COUNT;
24const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
25
26// DMA buffers must be in special regions. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
27#[unsafe(link_section = ".sram1")]
28static mut SPDIFRX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
29
30#[unsafe(link_section = ".sram4")]
31static mut SAI_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
32
33#[embassy_executor::main]
34async fn main(_spawner: Spawner) {
35 let mut peripheral_config = embassy_stm32::Config::default();
36 {
37 use embassy_stm32::rcc::*;
38 peripheral_config.rcc.hsi = Some(HSIPrescaler::DIV1);
39 peripheral_config.rcc.pll1 = Some(Pll {
40 source: PllSource::HSI,
41 prediv: PllPreDiv::DIV16,
42 mul: PllMul::MUL200,
43 divp: Some(PllDiv::DIV2), // 400 MHz
44 divq: Some(PllDiv::DIV2),
45 divr: Some(PllDiv::DIV2),
46 });
47 peripheral_config.rcc.sys = Sysclk::PLL1_P;
48 peripheral_config.rcc.ahb_pre = AHBPrescaler::DIV2;
49 peripheral_config.rcc.apb1_pre = APBPrescaler::DIV2;
50 peripheral_config.rcc.apb2_pre = APBPrescaler::DIV2;
51 peripheral_config.rcc.apb3_pre = APBPrescaler::DIV2;
52 peripheral_config.rcc.apb4_pre = APBPrescaler::DIV2;
53
54 peripheral_config.rcc.mux.spdifrxsel = mux::Spdifrxsel::PLL1_Q;
55 }
56 let mut p = embassy_stm32::init(peripheral_config);
57
58 info!("SPDIFRX to SAI4 bridge");
59
60 // Use SPDIFRX clock for SAI.
61 // This ensures equal rates of sample production and consumption.
62 let clk_source = embassy_stm32::pac::rcc::vals::Saiasel::_RESERVED_5;
63 embassy_stm32::pac::RCC.d3ccipr().modify(|w| {
64 w.set_sai4asel(clk_source);
65 });
66
67 let sai_buffer: &mut [u32] = unsafe {
68 SAI_BUFFER.initialize_all_copied(0);
69 let (ptr, len) = SAI_BUFFER.get_ptr_len();
70 core::slice::from_raw_parts_mut(ptr, len)
71 };
72
73 let spdifrx_buffer: &mut [u32] = unsafe {
74 SPDIFRX_BUFFER.initialize_all_copied(0);
75 let (ptr, len) = SPDIFRX_BUFFER.get_ptr_len();
76 core::slice::from_raw_parts_mut(ptr, len)
77 };
78
79 let mut sai_transmitter = new_sai_transmitter(
80 p.SAI4.reborrow(),
81 p.PD13.reborrow(),
82 p.PC1.reborrow(),
83 p.PD12.reborrow(),
84 p.BDMA_CH0.reborrow(),
85 sai_buffer,
86 );
87 let mut spdif_receiver = new_spdif_receiver(
88 p.SPDIFRX1.reborrow(),
89 p.PD7.reborrow(),
90 p.DMA2_CH7.reborrow(),
91 spdifrx_buffer,
92 );
93 spdif_receiver.start();
94
95 let mut renew_sai = false;
96 loop {
97 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
98
99 if renew_sai {
100 renew_sai = false;
101 trace!("Renew SAI.");
102 drop(sai_transmitter);
103 sai_transmitter = new_sai_transmitter(
104 p.SAI4.reborrow(),
105 p.PD13.reborrow(),
106 p.PC1.reborrow(),
107 p.PD12.reborrow(),
108 p.BDMA_CH0.reborrow(),
109 sai_buffer,
110 );
111 }
112
113 match select(spdif_receiver.read(&mut buf), sai_transmitter.wait_write_error()).await {
114 Either::First(spdif_read_result) => match spdif_read_result {
115 Ok(_) => (),
116 Err(spdifrx::Error::RingbufferError(_)) => {
117 trace!("SPDIFRX ringbuffer error. Renew.");
118 drop(spdif_receiver);
119 spdif_receiver = new_spdif_receiver(
120 p.SPDIFRX1.reborrow(),
121 p.PD7.reborrow(),
122 p.DMA2_CH7.reborrow(),
123 spdifrx_buffer,
124 );
125 spdif_receiver.start();
126 continue;
127 }
128 Err(spdifrx::Error::ChannelSyncError) => {
129 trace!("SPDIFRX channel sync (left/right assignment) error.");
130 continue;
131 }
132 },
133 Either::Second(_) => {
134 renew_sai = true;
135 continue;
136 }
137 };
138
139 renew_sai = sai_transmitter.write(&buf).await.is_err();
140 }
141}
142
143/// Creates a new SPDIFRX instance for receiving sample data.
144///
145/// Used (again) after dropping the SPDIFRX instance, in case of errors (e.g. source disconnect).
146fn new_spdif_receiver<'d>(
147 spdifrx: &'d mut peripherals::SPDIFRX1,
148 input_pin: &'d mut peripherals::PD7,
149 dma: &'d mut peripherals::DMA2_CH7,
150 buf: &'d mut [u32],
151) -> Spdifrx<'d, peripherals::SPDIFRX1> {
152 Spdifrx::new(spdifrx, Irqs, spdifrx::Config::default(), input_pin, dma, buf)
153}
154
155/// Creates a new SAI4 instance for transmitting sample data.
156///
157/// Used (again) after dropping the SAI4 instance, in case of errors (e.g. buffer overrun).
158fn new_sai_transmitter<'d>(
159 sai: &'d mut peripherals::SAI4,
160 sck: &'d mut peripherals::PD13,
161 sd: &'d mut peripherals::PC1,
162 fs: &'d mut peripherals::PD12,
163 dma: &'d mut peripherals::BDMA_CH0,
164 buf: &'d mut [u32],
165) -> Sai<'d, peripherals::SAI4, u32> {
166 let mut sai_config = hal::sai::Config::default();
167 sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8);
168 sai_config.slot_enable = 0xFFFF; // All slots
169 sai_config.data_size = sai::DataSize::Data32;
170 sai_config.frame_length = (CHANNEL_COUNT * 32) as u8;
171 sai_config.master_clock_divider = hal::sai::MasterClockDivider::MasterClockDisabled;
172
173 let (sub_block_tx, _) = hal::sai::split_subblocks(sai);
174 Sai::new_asynchronous(sub_block_tx, sck, sd, fs, dma, buf, sai_config)
175}
diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml
index 93e9575b6..8d23c346a 100644
--- a/examples/stm32h735/Cargo.toml
+++ b/examples/stm32h735/Cargo.toml
@@ -5,19 +5,19 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 8embassy-stm32 = { version = "0.2.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"] } 9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 10embassy-embedded-hal = { version = "0.3.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"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "1.0.1"
16defmt-rtt = "0.4" 16defmt-rtt = "1.0.0"
17 17
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 = "1.0.0", features = ["print-defmt"] }
21heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
22embedded-graphics = { version = "0.8.1" } 22embedded-graphics = { version = "0.8.1" }
23tinybmp = { version = "0.5" } 23tinybmp = { version = "0.5" }
diff --git a/examples/stm32h742/.cargo/config.toml b/examples/stm32h742/.cargo/config.toml
new file mode 100644
index 000000000..f30a52a79
--- /dev/null
+++ b/examples/stm32h742/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32H742VITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32H742VITx"
4
5[build]
6target = "thumbv7em-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml
new file mode 100644
index 000000000..31eff4379
--- /dev/null
+++ b/examples/stm32h742/Cargo.toml
@@ -0,0 +1,65 @@
1[package]
2edition = "2021"
3name = "embassy-stm32f7-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [
10 "defmt",
11 "stm32h742vi",
12 "memory-x",
13 "unstable-pac",
14 "time-driver-any",
15 "exti",
16] }
17embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [
18 "defmt",
19] }
20embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [
21 "arch-cortex-m",
22 "executor-thread",
23 "defmt",
24] }
25embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [
26 "defmt",
27 "defmt-timestamp-uptime",
28 "tick-hz-32_768",
29] }
30embassy-net = { version = "0.7.0", path = "../../embassy-net", features = [
31 "defmt",
32 "tcp",
33 "dhcpv4",
34 "medium-ethernet",
35] }
36embedded-io-async = { version = "0.6.1" }
37embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = [
38 "defmt",
39] }
40embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
41
42defmt = "1.0.1"
43defmt-rtt = "1.0.0"
44
45cortex-m = { version = "0.7.6", features = [
46 "inline-asm",
47 "critical-section-single-core",
48] }
49cortex-m-rt = "0.7.0"
50embedded-hal = "0.2.6"
51panic-probe = { version = "1.0.0", features = ["print-defmt"] }
52heapless = { version = "0.8", default-features = false }
53nb = "1.0.0"
54critical-section = "1.1"
55embedded-storage = "0.3.1"
56static_cell = "2"
57sha2 = { version = "0.10.8", default-features = false }
58hmac = "0.12.1"
59aes-gcm = { version = "0.10.3", default-features = false, features = [
60 "aes",
61 "heapless",
62] }
63
64[profile.release]
65debug = 2
diff --git a/examples/stm32h742/build.rs b/examples/stm32h742/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32h742/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/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs
new file mode 100644
index 000000000..aee07f3f2
--- /dev/null
+++ b/examples/stm32h742/src/bin/qspi.rs
@@ -0,0 +1,292 @@
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::Blocking;
8use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *};
9use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig};
10use embassy_stm32::Config as StmCfg;
11use {defmt_rtt as _, panic_probe as _};
12
13const MEMORY_PAGE_SIZE: usize = 256;
14
15const CMD_READ: u8 = 0x03;
16const CMD_HS_READ: u8 = 0x0B;
17const CMD_QUAD_READ: u8 = 0x6B;
18
19const CMD_WRITE_PG: u8 = 0xF2;
20const CMD_QUAD_WRITE_PG: u8 = 0x32;
21
22const CMD_READ_ID: u8 = 0x9F;
23const CMD_READ_UUID: u8 = 0x4B;
24
25const CMD_ENABLE_RESET: u8 = 0x66;
26const CMD_RESET: u8 = 0x99;
27
28const CMD_WRITE_ENABLE: u8 = 0x06;
29const CMD_WRITE_DISABLE: u8 = 0x04;
30
31const CMD_CHIP_ERASE: u8 = 0xC7;
32const CMD_SECTOR_ERASE: u8 = 0x20;
33const CMD_BLOCK_ERASE_32K: u8 = 0x52;
34const CMD_BLOCK_ERASE_64K: u8 = 0xD8;
35
36const CMD_READ_SR: u8 = 0x05;
37const CMD_READ_CR: u8 = 0x35;
38
39const CMD_WRITE_SR: u8 = 0x01;
40const CMD_WRITE_CR: u8 = 0x31;
41const MEMORY_ADDR: u32 = 0x00000001u32;
42
43/// Implementation of access to flash chip.
44/// Chip commands are hardcoded as it depends on used chip.
45/// This implementation is using chip GD25Q64C from Giga Device
46pub struct FlashMemory<I: Instance> {
47 qspi: Qspi<'static, I, Blocking>,
48}
49
50impl<I: Instance> FlashMemory<I> {
51 pub fn new(qspi: Qspi<'static, I, Blocking>) -> Self {
52 let mut memory = Self { qspi };
53
54 memory.reset_memory();
55 memory.enable_quad();
56
57 memory
58 }
59
60 fn enable_quad(&mut self) {
61 let cr = self.read_cr();
62 self.write_cr(cr | 0x02);
63 }
64
65 fn exec_command(&mut self, cmd: u8) {
66 let transaction = TransferConfig {
67 iwidth: QspiWidth::SING,
68 awidth: QspiWidth::NONE,
69 dwidth: QspiWidth::NONE,
70 instruction: cmd,
71 address: None,
72 dummy: DummyCycles::_0,
73 };
74 self.qspi.blocking_command(transaction);
75 }
76
77 pub fn reset_memory(&mut self) {
78 self.exec_command(CMD_ENABLE_RESET);
79 self.exec_command(CMD_RESET);
80 self.wait_write_finish();
81 }
82
83 pub fn enable_write(&mut self) {
84 self.exec_command(CMD_WRITE_ENABLE);
85 }
86
87 pub fn read_id(&mut self) -> [u8; 3] {
88 let mut buffer = [0; 3];
89 let transaction: TransferConfig = TransferConfig {
90 iwidth: QspiWidth::SING,
91 awidth: QspiWidth::NONE,
92 dwidth: QspiWidth::SING,
93 instruction: CMD_READ_ID,
94 address: None,
95 dummy: DummyCycles::_0,
96 };
97 self.qspi.blocking_read(&mut buffer, transaction);
98 buffer
99 }
100
101 pub fn read_uuid(&mut self) -> [u8; 16] {
102 let mut buffer = [0; 16];
103 let transaction: TransferConfig = TransferConfig {
104 iwidth: QspiWidth::SING,
105 awidth: QspiWidth::SING,
106 dwidth: QspiWidth::SING,
107 instruction: CMD_READ_UUID,
108 address: Some(0),
109 dummy: DummyCycles::_8,
110 };
111 self.qspi.blocking_read(&mut buffer, transaction);
112 buffer
113 }
114
115 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8]) {
116 let transaction = TransferConfig {
117 iwidth: QspiWidth::SING,
118 awidth: QspiWidth::SING,
119 dwidth: QspiWidth::QUAD,
120 instruction: CMD_QUAD_READ,
121 address: Some(addr),
122 dummy: DummyCycles::_8,
123 };
124 self.qspi.blocking_read(buffer, transaction);
125 }
126
127 fn wait_write_finish(&mut self) {
128 while (self.read_sr() & 0x01) != 0 {}
129 }
130
131 fn perform_erase(&mut self, addr: u32, cmd: u8) {
132 let transaction = TransferConfig {
133 iwidth: QspiWidth::SING,
134 awidth: QspiWidth::SING,
135 dwidth: QspiWidth::NONE,
136 instruction: cmd,
137 address: Some(addr),
138 dummy: DummyCycles::_0,
139 };
140 self.enable_write();
141 self.qspi.blocking_command(transaction);
142 self.wait_write_finish();
143 }
144
145 pub fn erase_sector(&mut self, addr: u32) {
146 self.perform_erase(addr, CMD_SECTOR_ERASE);
147 }
148
149 pub fn erase_block_32k(&mut self, addr: u32) {
150 self.perform_erase(addr, CMD_BLOCK_ERASE_32K);
151 }
152
153 pub fn erase_block_64k(&mut self, addr: u32) {
154 self.perform_erase(addr, CMD_BLOCK_ERASE_64K);
155 }
156
157 pub fn erase_chip(&mut self) {
158 self.exec_command(CMD_CHIP_ERASE);
159 }
160
161 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize) {
162 assert!(
163 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
164 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
165 len,
166 addr
167 );
168
169 let transaction = TransferConfig {
170 iwidth: QspiWidth::SING,
171 awidth: QspiWidth::SING,
172 dwidth: QspiWidth::QUAD,
173 instruction: CMD_QUAD_WRITE_PG,
174 address: Some(addr),
175 dummy: DummyCycles::_0,
176 };
177 self.enable_write();
178 self.qspi.blocking_write(buffer, transaction);
179 self.wait_write_finish();
180 }
181
182 pub fn write_memory(&mut self, addr: u32, buffer: &[u8]) {
183 let mut left = buffer.len();
184 let mut place = addr;
185 let mut chunk_start = 0;
186
187 while left > 0 {
188 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
189 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
190 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
191 self.write_page(place, chunk, chunk_size);
192 place += chunk_size as u32;
193 left -= chunk_size;
194 chunk_start += chunk_size;
195 }
196 }
197
198 fn read_register(&mut self, cmd: u8) -> u8 {
199 let mut buffer = [0; 1];
200 let transaction: TransferConfig = TransferConfig {
201 iwidth: QspiWidth::SING,
202 awidth: QspiWidth::NONE,
203 dwidth: QspiWidth::SING,
204 instruction: cmd,
205 address: None,
206 dummy: DummyCycles::_0,
207 };
208 self.qspi.blocking_read(&mut buffer, transaction);
209 buffer[0]
210 }
211
212 fn write_register(&mut self, cmd: u8, value: u8) {
213 let buffer = [value; 1];
214 let transaction: TransferConfig = TransferConfig {
215 iwidth: QspiWidth::SING,
216 awidth: QspiWidth::NONE,
217 dwidth: QspiWidth::SING,
218 instruction: cmd,
219 address: None,
220 dummy: DummyCycles::_0,
221 };
222 self.qspi.blocking_write(&buffer, transaction);
223 }
224
225 pub fn read_sr(&mut self) -> u8 {
226 self.read_register(CMD_READ_SR)
227 }
228
229 pub fn read_cr(&mut self) -> u8 {
230 self.read_register(CMD_READ_CR)
231 }
232
233 pub fn write_sr(&mut self, value: u8) {
234 self.write_register(CMD_WRITE_SR, value);
235 }
236
237 pub fn write_cr(&mut self, value: u8) {
238 self.write_register(CMD_WRITE_CR, value);
239 }
240}
241
242#[embassy_executor::main]
243async fn main(_spawner: Spawner) -> ! {
244 let mut config = StmCfg::default();
245 {
246 use embassy_stm32::rcc::*;
247 config.rcc.hsi = Some(HSIPrescaler::DIV1);
248 config.rcc.csi = true;
249 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
250 config.rcc.pll1 = Some(Pll {
251 source: PllSource::HSI,
252 prediv: PllPreDiv::DIV4,
253 mul: PllMul::MUL50,
254 divp: Some(PllDiv::DIV2),
255 divq: None,
256 divr: None,
257 });
258 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
259 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
260 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
261 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
262 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
263 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
264 config.rcc.voltage_scale = VoltageScale::Scale1;
265 }
266 let p = embassy_stm32::init(config);
267 info!("Embassy initialized");
268
269 let config = QspiCfg {
270 memory_size: MemorySize::_8MiB,
271 address_size: AddressSize::_24bit,
272 prescaler: 16,
273 cs_high_time: ChipSelectHighTime::_1Cycle,
274 fifo_threshold: FIFOThresholdLevel::_16Bytes,
275 };
276 let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config);
277 let mut flash = FlashMemory::new(driver);
278 let flash_id = flash.read_id();
279 info!("FLASH ID: {:?}", flash_id);
280 let mut wr_buf = [0u8; 256];
281 for i in 0..256 {
282 wr_buf[i] = i as u8;
283 }
284 let mut rd_buf = [0u8; 256];
285 flash.erase_sector(MEMORY_ADDR);
286 flash.write_memory(MEMORY_ADDR, &wr_buf);
287 flash.read_memory(MEMORY_ADDR, &mut rd_buf);
288 info!("WRITE BUF: {:?}", wr_buf);
289 info!("READ BUF: {:?}", rd_buf);
290 info!("End of Program, proceed to empty endless loop");
291 loop {}
292}
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
index 7a42fbdaa..71bd50d60 100644
--- a/examples/stm32h755cm4/Cargo.toml
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -6,28 +6,27 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32h755zi-cm4 to your chip name, if necessary. 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"] } 9embassy-stm32 = { version = "0.2.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"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.3.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"] } 12embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.4.0", 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"] } 14embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
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"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = "0.8.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1" 30critical-section = "1.1"
32micromath = "2.0.0" 31micromath = "2.0.0"
33stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs
index b5c547839..39112c1f5 100644
--- a/examples/stm32h755cm4/src/bin/blinky.rs
+++ b/examples/stm32h755cm4/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".ram_d3.shared_data"] 13#[unsafe(link_section = ".ram_d3.shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
index 4f0f69c3f..8e960932a 100644
--- a/examples/stm32h755cm7/Cargo.toml
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -6,28 +6,27 @@ 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", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.2.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"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.3.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"] } 12embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.4.0", 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"] } 14embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
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"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" } 26embedded-nal-async = "0.8.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1" 30critical-section = "1.1"
32micromath = "2.0.0" 31micromath = "2.0.0"
33stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs
index 94d2226c0..b30bf4de8 100644
--- a/examples/stm32h755cm7/src/bin/blinky.rs
+++ b/examples/stm32h755cm7/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".ram_d3.shared_data"] 13#[unsafe(link_section = ".ram_d3.shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32h7b0/.cargo/config.toml b/examples/stm32h7b0/.cargo/config.toml
new file mode 100644
index 000000000..870849a27
--- /dev/null
+++ b/examples/stm32h7b0/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H7B0VBTx'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml
new file mode 100644
index 000000000..72f86e0cf
--- /dev/null
+++ b/examples/stm32h7b0/Cargo.toml
@@ -0,0 +1,73 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h7b0-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16
17defmt = "1.0.1"
18defmt-rtt = "1.0.0"
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 = "0.8.0"
26embedded-io-async = { version = "0.6.1" }
27panic-probe = { version = "1.0.0", features = ["print-defmt"] }
28heapless = { version = "0.8", default-features = false }
29critical-section = "1.1"
30micromath = "2.0.0"
31stm32-fmc = "0.3.0"
32embedded-storage = "0.3.1"
33static_cell = "2"
34chrono = { version = "^0.4", default-features = false }
35grounded = "0.2.0"
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/stm32h7b0/build.rs b/examples/stm32h7b0/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h7b0/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/stm32h7b0/memory.x b/examples/stm32h7b0/memory.x
new file mode 100644
index 000000000..6eb1bb7c1
--- /dev/null
+++ b/examples/stm32h7b0/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 128K /* BANK_1 */
4 RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */
5} \ No newline at end of file
diff --git a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs
new file mode 100644
index 000000000..dffb740a9
--- /dev/null
+++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs
@@ -0,0 +1,433 @@
1#![no_main]
2#![no_std]
3
4// Tested on weact stm32h7b0 board + w25q64 spi flash
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::mode::Blocking;
10use embassy_stm32::ospi::{
11 AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, Ospi,
12 OspiWidth, TransferConfig, WrapSize,
13};
14use embassy_stm32::time::Hertz;
15use embassy_stm32::Config;
16use embassy_time::Timer;
17use {defmt_rtt as _, panic_probe as _};
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 // RCC config
22 let mut config = Config::default();
23 info!("START");
24 {
25 use embassy_stm32::rcc::*;
26 config.rcc.hsi = Some(HSIPrescaler::DIV1);
27 config.rcc.csi = true;
28 // Needed for USB
29 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
30 // External oscillator 25MHZ
31 config.rcc.hse = Some(Hse {
32 freq: Hertz(25_000_000),
33 mode: HseMode::Oscillator,
34 });
35 config.rcc.pll1 = Some(Pll {
36 source: PllSource::HSE,
37 prediv: PllPreDiv::DIV5,
38 mul: PllMul::MUL112,
39 divp: Some(PllDiv::DIV2),
40 divq: Some(PllDiv::DIV2),
41 divr: Some(PllDiv::DIV2),
42 });
43 config.rcc.sys = Sysclk::PLL1_P;
44 config.rcc.ahb_pre = AHBPrescaler::DIV2;
45 config.rcc.apb1_pre = APBPrescaler::DIV2;
46 config.rcc.apb2_pre = APBPrescaler::DIV2;
47 config.rcc.apb3_pre = APBPrescaler::DIV2;
48 config.rcc.apb4_pre = APBPrescaler::DIV2;
49 config.rcc.voltage_scale = VoltageScale::Scale0;
50 }
51
52 // Initialize peripherals
53 let p = embassy_stm32::init(config);
54
55 let qspi_config = embassy_stm32::ospi::Config {
56 fifo_threshold: FIFOThresholdLevel::_16Bytes,
57 memory_type: MemoryType::Micron,
58 device_size: MemorySize::_8MiB,
59 chip_select_high_time: ChipSelectHighTime::_1Cycle,
60 free_running_clock: false,
61 clock_mode: false,
62 wrap_size: WrapSize::None,
63 clock_prescaler: 4,
64 sample_shifting: true,
65 delay_hold_quarter_cycle: false,
66 chip_select_boundary: 0,
67 delay_block_bypass: true,
68 max_transfer: 0,
69 refresh: 0,
70 };
71 let ospi = embassy_stm32::ospi::Ospi::new_blocking_quadspi(
72 p.OCTOSPI1,
73 p.PB2,
74 p.PD11,
75 p.PD12,
76 p.PE2,
77 p.PD13,
78 p.PB6,
79 qspi_config,
80 );
81
82 let mut flash = FlashMemory::new(ospi).await;
83
84 let flash_id = flash.read_id();
85 info!("FLASH ID: {=[u8]:x}", flash_id);
86 let mut wr_buf = [0u8; 8];
87 for i in 0..8 {
88 wr_buf[i] = i as u8;
89 }
90 let mut rd_buf = [0u8; 8];
91 flash.erase_sector(0).await;
92 flash.write_memory(0, &wr_buf, true).await;
93 flash.read_memory(0, &mut rd_buf, true);
94 info!("WRITE BUF: {=[u8]:#X}", wr_buf);
95 info!("READ BUF: {=[u8]:#X}", rd_buf);
96 flash.enable_mm().await;
97 info!("Enabled memory mapped mode");
98
99 let first_u32 = unsafe { *(0x90000000 as *const u32) };
100 assert_eq!(first_u32, 0x03020100);
101
102 let second_u32 = unsafe { *(0x90000004 as *const u32) };
103 assert_eq!(second_u32, 0x07060504);
104 flash.disable_mm().await;
105
106 info!("DONE");
107 // Output pin PE3
108 let mut led = Output::new(p.PE3, Level::Low, Speed::Low);
109
110 loop {
111 led.toggle();
112 Timer::after_millis(1000).await;
113 }
114}
115
116const MEMORY_PAGE_SIZE: usize = 8;
117
118const CMD_QUAD_READ: u8 = 0x6B;
119
120const CMD_QUAD_WRITE_PG: u8 = 0x32;
121
122const CMD_READ_ID: u8 = 0x9F;
123
124const CMD_ENABLE_RESET: u8 = 0x66;
125const CMD_RESET: u8 = 0x99;
126
127const CMD_WRITE_ENABLE: u8 = 0x06;
128
129const CMD_CHIP_ERASE: u8 = 0xC7;
130const CMD_SECTOR_ERASE: u8 = 0x20;
131const CMD_BLOCK_ERASE_32K: u8 = 0x52;
132const CMD_BLOCK_ERASE_64K: u8 = 0xD8;
133
134const CMD_READ_SR: u8 = 0x05;
135const CMD_READ_CR: u8 = 0x35;
136
137const CMD_WRITE_SR: u8 = 0x01;
138const CMD_WRITE_CR: u8 = 0x31;
139
140/// Implementation of access to flash chip.
141/// Chip commands are hardcoded as it depends on used chip.
142/// This implementation is using chip GD25Q64C from Giga Device
143pub struct FlashMemory<I: Instance> {
144 ospi: Ospi<'static, I, Blocking>,
145}
146
147impl<I: Instance> FlashMemory<I> {
148 pub async fn new(ospi: Ospi<'static, I, Blocking>) -> Self {
149 let mut memory = Self { ospi };
150
151 memory.reset_memory().await;
152 memory.enable_quad();
153 memory
154 }
155
156 async fn qpi_mode(&mut self) {
157 // Enter qpi mode
158 self.exec_command(0x38).await;
159
160 // Set read param
161 let transaction = TransferConfig {
162 iwidth: OspiWidth::QUAD,
163 dwidth: OspiWidth::QUAD,
164 instruction: Some(0xC0),
165 ..Default::default()
166 };
167 self.enable_write().await;
168 self.ospi.blocking_write(&[0x30_u8], transaction).unwrap();
169 self.wait_write_finish();
170 }
171
172 pub async fn disable_mm(&mut self) {
173 self.ospi.disable_memory_mapped_mode();
174 }
175
176 pub async fn enable_mm(&mut self) {
177 self.qpi_mode().await;
178
179 let read_config = TransferConfig {
180 iwidth: OspiWidth::QUAD,
181 isize: AddressSize::_8Bit,
182 adwidth: OspiWidth::QUAD,
183 adsize: AddressSize::_24bit,
184 dwidth: OspiWidth::QUAD,
185 instruction: Some(0x0B), // Fast read in QPI mode
186 dummy: DummyCycles::_8,
187 ..Default::default()
188 };
189
190 let write_config = TransferConfig {
191 iwidth: OspiWidth::SING,
192 isize: AddressSize::_8Bit,
193 adwidth: OspiWidth::SING,
194 adsize: AddressSize::_24bit,
195 dwidth: OspiWidth::QUAD,
196 instruction: Some(0x32), // Write config
197 dummy: DummyCycles::_0,
198 ..Default::default()
199 };
200 self.ospi.enable_memory_mapped_mode(read_config, write_config).unwrap();
201 }
202
203 fn enable_quad(&mut self) {
204 let cr = self.read_cr();
205 // info!("Read cr: {:x}", cr);
206 self.write_cr(cr | 0x02);
207 // info!("Read cr after writing: {:x}", cr);
208 }
209
210 pub fn disable_quad(&mut self) {
211 let cr = self.read_cr();
212 self.write_cr(cr & (!(0x02)));
213 }
214
215 async fn exec_command_4(&mut self, cmd: u8) {
216 let transaction = TransferConfig {
217 iwidth: OspiWidth::QUAD,
218 adwidth: OspiWidth::NONE,
219 // adsize: AddressSize::_24bit,
220 dwidth: OspiWidth::NONE,
221 instruction: Some(cmd as u32),
222 address: None,
223 dummy: DummyCycles::_0,
224 ..Default::default()
225 };
226 self.ospi.blocking_command(&transaction).unwrap();
227 }
228
229 async fn exec_command(&mut self, cmd: u8) {
230 let transaction = TransferConfig {
231 iwidth: OspiWidth::SING,
232 adwidth: OspiWidth::NONE,
233 // adsize: AddressSize::_24bit,
234 dwidth: OspiWidth::NONE,
235 instruction: Some(cmd as u32),
236 address: None,
237 dummy: DummyCycles::_0,
238 ..Default::default()
239 };
240 // info!("Excuting command: {:x}", transaction.instruction);
241 self.ospi.blocking_command(&transaction).unwrap();
242 }
243
244 pub async fn reset_memory(&mut self) {
245 self.exec_command_4(CMD_ENABLE_RESET).await;
246 self.exec_command_4(CMD_RESET).await;
247 self.exec_command(CMD_ENABLE_RESET).await;
248 self.exec_command(CMD_RESET).await;
249 self.wait_write_finish();
250 }
251
252 pub async fn enable_write(&mut self) {
253 self.exec_command(CMD_WRITE_ENABLE).await;
254 }
255
256 pub fn read_id(&mut self) -> [u8; 3] {
257 let mut buffer = [0; 3];
258 let transaction: TransferConfig = TransferConfig {
259 iwidth: OspiWidth::SING,
260 isize: AddressSize::_8Bit,
261 adwidth: OspiWidth::NONE,
262 // adsize: AddressSize::_24bit,
263 dwidth: OspiWidth::SING,
264 instruction: Some(CMD_READ_ID as u32),
265 ..Default::default()
266 };
267 // info!("Reading id: 0x{:X}", transaction.instruction);
268 self.ospi.blocking_read(&mut buffer, transaction).unwrap();
269 buffer
270 }
271
272 pub fn read_id_4(&mut self) -> [u8; 3] {
273 let mut buffer = [0; 3];
274 let transaction: TransferConfig = TransferConfig {
275 iwidth: OspiWidth::SING,
276 isize: AddressSize::_8Bit,
277 adwidth: OspiWidth::NONE,
278 dwidth: OspiWidth::QUAD,
279 instruction: Some(CMD_READ_ID as u32),
280 ..Default::default()
281 };
282 info!("Reading id: 0x{:X}", transaction.instruction);
283 self.ospi.blocking_read(&mut buffer, transaction).unwrap();
284 buffer
285 }
286
287 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
288 let transaction = TransferConfig {
289 iwidth: OspiWidth::SING,
290 adwidth: OspiWidth::SING,
291 adsize: AddressSize::_24bit,
292 dwidth: OspiWidth::QUAD,
293 instruction: Some(CMD_QUAD_READ as u32),
294 address: Some(addr),
295 dummy: DummyCycles::_8,
296 ..Default::default()
297 };
298 if use_dma {
299 self.ospi.blocking_read(buffer, transaction).unwrap();
300 } else {
301 self.ospi.blocking_read(buffer, transaction).unwrap();
302 }
303 }
304
305 fn wait_write_finish(&mut self) {
306 while (self.read_sr() & 0x01) != 0 {}
307 }
308
309 async fn perform_erase(&mut self, addr: u32, cmd: u8) {
310 let transaction = TransferConfig {
311 iwidth: OspiWidth::SING,
312 adwidth: OspiWidth::SING,
313 adsize: AddressSize::_24bit,
314 dwidth: OspiWidth::NONE,
315 instruction: Some(cmd as u32),
316 address: Some(addr),
317 dummy: DummyCycles::_0,
318 ..Default::default()
319 };
320 self.enable_write().await;
321 self.ospi.blocking_command(&transaction).unwrap();
322 self.wait_write_finish();
323 }
324
325 pub async fn erase_sector(&mut self, addr: u32) {
326 self.perform_erase(addr, CMD_SECTOR_ERASE).await;
327 }
328
329 pub async fn erase_block_32k(&mut self, addr: u32) {
330 self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await;
331 }
332
333 pub async fn erase_block_64k(&mut self, addr: u32) {
334 self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await;
335 }
336
337 pub async fn erase_chip(&mut self) {
338 self.exec_command(CMD_CHIP_ERASE).await;
339 }
340
341 async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
342 assert!(
343 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
344 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
345 len,
346 addr
347 );
348
349 let transaction = TransferConfig {
350 iwidth: OspiWidth::SING,
351 adsize: AddressSize::_24bit,
352 adwidth: OspiWidth::SING,
353 dwidth: OspiWidth::QUAD,
354 instruction: Some(CMD_QUAD_WRITE_PG as u32),
355 address: Some(addr),
356 dummy: DummyCycles::_0,
357 ..Default::default()
358 };
359 self.enable_write().await;
360 if use_dma {
361 self.ospi.blocking_write(buffer, transaction).unwrap();
362 } else {
363 self.ospi.blocking_write(buffer, transaction).unwrap();
364 }
365 self.wait_write_finish();
366 }
367
368 pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
369 let mut left = buffer.len();
370 let mut place = addr;
371 let mut chunk_start = 0;
372
373 while left > 0 {
374 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
375 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
376 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
377 self.write_page(place, chunk, chunk_size, use_dma).await;
378 place += chunk_size as u32;
379 left -= chunk_size;
380 chunk_start += chunk_size;
381 }
382 }
383
384 fn read_register(&mut self, cmd: u8) -> u8 {
385 let mut buffer = [0; 1];
386 let transaction: TransferConfig = TransferConfig {
387 iwidth: OspiWidth::SING,
388 isize: AddressSize::_8Bit,
389 adwidth: OspiWidth::NONE,
390 adsize: AddressSize::_24bit,
391 dwidth: OspiWidth::SING,
392 instruction: Some(cmd as u32),
393 address: None,
394 dummy: DummyCycles::_0,
395 ..Default::default()
396 };
397 self.ospi.blocking_read(&mut buffer, transaction).unwrap();
398 // info!("Read w25q64 register: 0x{:x}", buffer[0]);
399 buffer[0]
400 }
401
402 fn write_register(&mut self, cmd: u8, value: u8) {
403 let buffer = [value; 1];
404 let transaction: TransferConfig = TransferConfig {
405 iwidth: OspiWidth::SING,
406 isize: AddressSize::_8Bit,
407 instruction: Some(cmd as u32),
408 adsize: AddressSize::_24bit,
409 adwidth: OspiWidth::NONE,
410 dwidth: OspiWidth::SING,
411 address: None,
412 dummy: DummyCycles::_0,
413 ..Default::default()
414 };
415 self.ospi.blocking_write(&buffer, transaction).unwrap();
416 }
417
418 pub fn read_sr(&mut self) -> u8 {
419 self.read_register(CMD_READ_SR)
420 }
421
422 pub fn read_cr(&mut self) -> u8 {
423 self.read_register(CMD_READ_CR)
424 }
425
426 pub fn write_sr(&mut self, value: u8) {
427 self.write_register(CMD_WRITE_SR, value);
428 }
429
430 pub fn write_cr(&mut self, value: u8) {
431 self.write_register(CMD_WRITE_CR, value);
432 }
433}
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml
index f97dfd722..5f1ce8dfc 100644
--- a/examples/stm32h7rs/Cargo.toml
+++ b/examples/stm32h7rs/Cargo.toml
@@ -6,27 +6,26 @@ 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", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.2.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"] } 10embassy-sync = { version = "0.7.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"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", 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"] } 13embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ethernet", "medium-ip", "proto-ipv4"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 16
17defmt = "0.3" 17defmt = "1.0.1"
18defmt-rtt = "0.4" 18defmt-rtt = "1.0.0"
19 19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "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-hal-1 = { package = "embedded-hal", version = "1.0" } 23embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
24embedded-hal-async = { version = "1.0" } 24embedded-hal-async = { version = "1.0" }
25embedded-nal-async = { version = "0.7.1" } 25embedded-nal-async = "0.8.0"
26embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.6.1" }
27panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "1.0.0", features = ["print-defmt"] }
28heapless = { version = "0.8", default-features = false } 28heapless = { version = "0.8", default-features = false }
29rand_core = "0.6.3"
30critical-section = "1.1" 29critical-section = "1.1"
31micromath = "2.0.0" 30micromath = "2.0.0"
32stm32-fmc = "0.3.0" 31stm32-fmc = "0.3.0"
diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs
new file mode 100644
index 000000000..6d246bb09
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/eth.rs
@@ -0,0 +1,118 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_net::udp::{PacketMetadata, UdpSocket};
7use embassy_net::{Ipv4Address, Ipv4Cidr, StackResources};
8use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue};
9use embassy_stm32::peripherals::ETH;
10use embassy_stm32::rng::Rng;
11use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
12use embassy_time::Timer;
13use heapless::Vec;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 ETH => eth::InterruptHandler;
19 RNG => rng::InterruptHandler<peripherals::RNG>;
20});
21
22type Device = Ethernet<'static, ETH, GenericPhy>;
23
24#[embassy_executor::task]
25async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
26 runner.run().await
27}
28
29#[embassy_executor::main]
30async fn main(spawner: Spawner) -> ! {
31 let mut config = Config::default();
32 {
33 use embassy_stm32::rcc::*;
34 config.rcc.hsi = Some(HSIPrescaler::DIV1);
35 config.rcc.csi = true;
36 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
37 config.rcc.pll1 = Some(Pll {
38 source: PllSource::HSI,
39 prediv: PllPreDiv::DIV4,
40 mul: PllMul::MUL50,
41 divp: Some(PllDiv::DIV2),
42 divq: None,
43 divr: None,
44 });
45 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
46 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
47 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.apb5_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.voltage_scale = VoltageScale::HIGH;
52 }
53 let p = embassy_stm32::init(config);
54 info!("Hello World!");
55
56 // Generate random seed.
57 let mut rng = Rng::new(p.RNG, Irqs);
58 let mut seed = [0; 8];
59 rng.fill_bytes(&mut seed);
60 let seed = u64::from_le_bytes(seed);
61
62 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
63
64 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
65 let device = Ethernet::new(
66 PACKETS.init(PacketQueue::<4, 4>::new()),
67 p.ETH,
68 Irqs,
69 p.PB6,
70 p.PA2,
71 p.PG6,
72 p.PA7,
73 p.PG4,
74 p.PG5,
75 p.PG13,
76 p.PG12,
77 p.PG11,
78 GenericPhy::new(0),
79 mac_addr,
80 );
81
82 // Have to use UDP w/ static config to fit in internal flash
83 // let config = embassy_net::Config::dhcpv4(Default::default());
84 let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
85 address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
86 dns_servers: Vec::new(),
87 gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
88 });
89
90 // Init network stack
91 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
92 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
93
94 // Launch network task
95 unwrap!(spawner.spawn(net_task(runner)));
96
97 // Ensure DHCP configuration is up before trying connect
98 //stack.wait_config_up().await;
99
100 info!("Network task initialized");
101
102 // Then we can use it!
103 let mut rx_meta = [PacketMetadata::EMPTY; 16];
104 let mut rx_buffer = [0; 1024];
105 let mut tx_meta = [PacketMetadata::EMPTY; 16];
106 let mut tx_buffer = [0; 1024];
107
108 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
109 let socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
110 loop {
111 // You need to start a server on the host machine, for example: `nc -lu 8000`
112 socket
113 .send_to(b"Hello, world", remote_endpoint)
114 .await
115 .expect("Buffer sent");
116 Timer::after_secs(1).await;
117 }
118}
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs
new file mode 100644
index 000000000..56a9884af
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usb_serial.rs
@@ -0,0 +1,134 @@
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
74 // Create embassy-usb DeviceBuilder using the driver and config.
75 // It needs some buffers for building the descriptors.
76 let mut config_descriptor = [0; 256];
77 let mut bos_descriptor = [0; 256];
78 let mut control_buf = [0; 64];
79
80 let mut state = State::new();
81
82 let mut builder = Builder::new(
83 driver,
84 config,
85 &mut config_descriptor,
86 &mut bos_descriptor,
87 &mut [], // no msos descriptors
88 &mut control_buf,
89 );
90
91 // Create classes on the builder.
92 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
93
94 // Build the builder.
95 let mut usb = builder.build();
96
97 // Run the USB device.
98 let usb_fut = usb.run();
99
100 // Do stuff with the class!
101 let echo_fut = async {
102 loop {
103 class.wait_connection().await;
104 info!("Connected");
105 let _ = echo(&mut class).await;
106 info!("Disconnected");
107 }
108 };
109
110 // Run everything concurrently.
111 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
112 join(usb_fut, echo_fut).await;
113}
114
115struct Disconnected {}
116
117impl From<EndpointError> for Disconnected {
118 fn from(val: EndpointError) -> Self {
119 match val {
120 EndpointError::BufferOverflow => panic!("Buffer overflow"),
121 EndpointError::Disabled => Disconnected {},
122 }
123 }
124}
125
126async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
127 let mut buf = [0; 64];
128 loop {
129 let n = class.read_packet(&mut buf).await?;
130 let data = &buf[..n];
131 info!("data: {:x}", data);
132 class.write_packet(data).await?;
133 }
134}
diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
new file mode 100644
index 000000000..88d914180
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
@@ -0,0 +1,448 @@
1#![no_main]
2#![no_std]
3
4//! For Nucleo STM32H7S3L8 MB1737, has MX25UW25645GXDI00
5//!
6//! TODO: Currently this only uses single SPI, pending flash chip documentation for octo SPI.
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_stm32::gpio::{Level, Output, Speed};
11use embassy_stm32::mode::Blocking;
12use embassy_stm32::time::Hertz;
13use embassy_stm32::xspi::{
14 AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, TransferConfig,
15 WrapSize, Xspi, XspiWidth,
16};
17use embassy_stm32::Config;
18use embassy_time::Timer;
19use {defmt_rtt as _, panic_probe as _};
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 // RCC config
24 let mut config = Config::default();
25 {
26 use embassy_stm32::rcc::*;
27 config.rcc.hse = Some(Hse {
28 freq: Hertz(24_000_000),
29 mode: HseMode::Oscillator,
30 });
31 config.rcc.pll1 = Some(Pll {
32 source: PllSource::HSE,
33 prediv: PllPreDiv::DIV3,
34 mul: PllMul::MUL150,
35 divp: Some(PllDiv::DIV2),
36 divq: None,
37 divr: None,
38 });
39 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
40 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
41 config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz
42 config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz
43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz
44 config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz
45 config.rcc.voltage_scale = VoltageScale::HIGH;
46 }
47
48 // Initialize peripherals
49 let p = embassy_stm32::init(config);
50
51 let spi_config = embassy_stm32::xspi::Config {
52 fifo_threshold: FIFOThresholdLevel::_4Bytes,
53 memory_type: MemoryType::Macronix,
54 delay_hold_quarter_cycle: true,
55 // memory_type: MemoryType::Micron,
56 // delay_hold_quarter_cycle: false,
57 device_size: MemorySize::_32MiB,
58 chip_select_high_time: ChipSelectHighTime::_2Cycle,
59 free_running_clock: false,
60 clock_mode: false,
61 wrap_size: WrapSize::None,
62 // 300mhz / (4+1) = 60mhz. Unsure the limit, need to find a MX25UW25645GXDI00 datasheet.
63 clock_prescaler: 3,
64 sample_shifting: false,
65 chip_select_boundary: 0,
66 max_transfer: 0,
67 refresh: 0,
68 };
69
70 let mut cor = cortex_m::Peripherals::take().unwrap();
71
72 // Not necessary, but recommended if using XIP
73 cor.SCB.enable_icache();
74 cor.SCB.enable_dcache(&mut cor.CPUID);
75
76 let xspi = embassy_stm32::xspi::Xspi::new_blocking_xspi(
77 p.XSPI2, p.PN6, p.PN2, p.PN3, p.PN4, p.PN5, p.PN8, p.PN9, p.PN10, p.PN11, p.PN1, spi_config,
78 );
79
80 let mut flash = FlashMemory::new(xspi).await;
81
82 let flash_id = flash.read_id();
83 info!("FLASH ID: {=[u8]:x}", flash_id);
84
85 let mut wr_buf = [0u8; 8];
86 for i in 0..8 {
87 wr_buf[i] = 0x90 + i as u8;
88 }
89 let mut rd_buf = [0u8; 8];
90 flash.erase_sector(0).await;
91 flash.write_memory(0, &wr_buf, true).await;
92 flash.read_memory(0, &mut rd_buf, true);
93 info!("WRITE BUF: {=[u8]:#X}", wr_buf);
94 info!("READ BUF: {=[u8]:#X}", rd_buf);
95 flash.enable_mm().await;
96 info!("Enabled memory mapped mode");
97
98 let first_u32 = unsafe { *(0x70000000 as *const u32) };
99 assert_eq!(first_u32, 0x93929190);
100 info!("first_u32 {:08x}", first_u32);
101
102 let second_u32 = unsafe { *(0x70000004 as *const u32) };
103 assert_eq!(second_u32, 0x97969594);
104 info!("second_u32 {:08x}", first_u32);
105
106 flash.disable_mm().await;
107 info!("Disabled memory mapped mode");
108
109 info!("DONE");
110 // Output pin PE3
111 let mut led = Output::new(p.PE3, Level::Low, Speed::Low);
112
113 loop {
114 led.toggle();
115 Timer::after_millis(1000).await;
116 }
117}
118
119const MEMORY_PAGE_SIZE: usize = 8;
120
121const CMD_READ: u8 = 0x0B;
122const _CMD_QUAD_READ: u8 = 0x6B;
123
124const CMD_WRITE_PG: u8 = 0x02;
125const _CMD_QUAD_WRITE_PG: u8 = 0x32;
126
127const CMD_READ_ID: u8 = 0x9F;
128const CMD_READ_ID_OCTO: u16 = 0x9F60;
129
130const CMD_ENABLE_RESET: u8 = 0x66;
131const CMD_RESET: u8 = 0x99;
132
133const CMD_WRITE_ENABLE: u8 = 0x06;
134
135const CMD_CHIP_ERASE: u8 = 0xC7;
136const CMD_SECTOR_ERASE: u8 = 0x20;
137const CMD_BLOCK_ERASE_32K: u8 = 0x52;
138const CMD_BLOCK_ERASE_64K: u8 = 0xD8;
139
140const CMD_READ_SR: u8 = 0x05;
141const CMD_READ_CR: u8 = 0x35;
142
143const CMD_WRITE_SR: u8 = 0x01;
144const CMD_WRITE_CR: u8 = 0x31;
145
146/// Implementation of access to flash chip.
147///
148/// Chip commands are hardcoded as it depends on used chip.
149/// This targets a MX25UW25645GXDI00.
150pub struct FlashMemory<I: Instance> {
151 xspi: Xspi<'static, I, Blocking>,
152}
153
154impl<I: Instance> FlashMemory<I> {
155 pub async fn new(xspi: Xspi<'static, I, Blocking>) -> Self {
156 let mut memory = Self { xspi };
157
158 memory.reset_memory().await;
159 memory.enable_octo();
160 memory
161 }
162
163 async fn qpi_mode(&mut self) {
164 // Enter qpi mode
165 self.exec_command(0x38).await;
166
167 // Set read param
168 let transaction = TransferConfig {
169 iwidth: XspiWidth::QUAD,
170 dwidth: XspiWidth::QUAD,
171 instruction: Some(0xC0),
172 ..Default::default()
173 };
174 self.enable_write().await;
175 self.xspi.blocking_write(&[0x30_u8], transaction).unwrap();
176 self.wait_write_finish();
177 }
178
179 pub async fn disable_mm(&mut self) {
180 self.xspi.disable_memory_mapped_mode();
181 }
182
183 pub async fn enable_mm(&mut self) {
184 self.qpi_mode().await;
185
186 let read_config = TransferConfig {
187 iwidth: XspiWidth::SING,
188 isize: AddressSize::_8bit,
189 adwidth: XspiWidth::SING,
190 adsize: AddressSize::_24bit,
191 dwidth: XspiWidth::SING,
192 instruction: Some(CMD_READ as u32),
193 dummy: DummyCycles::_8,
194 ..Default::default()
195 };
196
197 let write_config = TransferConfig {
198 iwidth: XspiWidth::SING,
199 isize: AddressSize::_8bit,
200 adwidth: XspiWidth::SING,
201 adsize: AddressSize::_24bit,
202 dwidth: XspiWidth::SING,
203 instruction: Some(CMD_WRITE_PG as u32),
204 dummy: DummyCycles::_0,
205 ..Default::default()
206 };
207 self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap();
208 }
209
210 fn enable_octo(&mut self) {
211 let cr = self.read_cr();
212 // info!("Read cr: {:x}", cr);
213 self.write_cr(cr | 0x02);
214 // info!("Read cr after writing: {:x}", cr);
215 }
216
217 pub fn disable_octo(&mut self) {
218 let cr = self.read_cr();
219 self.write_cr(cr & (!(0x02)));
220 }
221
222 async fn exec_command_4(&mut self, cmd: u8) {
223 let transaction = TransferConfig {
224 iwidth: XspiWidth::QUAD,
225 adwidth: XspiWidth::NONE,
226 // adsize: AddressSize::_24bit,
227 dwidth: XspiWidth::NONE,
228 instruction: Some(cmd as u32),
229 address: None,
230 dummy: DummyCycles::_0,
231 ..Default::default()
232 };
233 self.xspi.blocking_command(&transaction).unwrap();
234 }
235
236 async fn exec_command(&mut self, cmd: u8) {
237 let transaction = TransferConfig {
238 iwidth: XspiWidth::SING,
239 adwidth: XspiWidth::NONE,
240 // adsize: AddressSize::_24bit,
241 dwidth: XspiWidth::NONE,
242 instruction: Some(cmd as u32),
243 address: None,
244 dummy: DummyCycles::_0,
245 ..Default::default()
246 };
247 // info!("Excuting command: {:x}", transaction.instruction);
248 self.xspi.blocking_command(&transaction).unwrap();
249 }
250
251 pub async fn reset_memory(&mut self) {
252 self.exec_command_4(CMD_ENABLE_RESET).await;
253 self.exec_command_4(CMD_RESET).await;
254 self.exec_command(CMD_ENABLE_RESET).await;
255 self.exec_command(CMD_RESET).await;
256 self.wait_write_finish();
257 }
258
259 pub async fn enable_write(&mut self) {
260 self.exec_command(CMD_WRITE_ENABLE).await;
261 }
262
263 pub fn read_id(&mut self) -> [u8; 3] {
264 let mut buffer = [0; 3];
265 let transaction: TransferConfig = TransferConfig {
266 iwidth: XspiWidth::SING,
267 isize: AddressSize::_8bit,
268 adwidth: XspiWidth::NONE,
269 // adsize: AddressSize::_24bit,
270 dwidth: XspiWidth::SING,
271 instruction: Some(CMD_READ_ID as u32),
272 ..Default::default()
273 };
274 // info!("Reading id: 0x{:X}", transaction.instruction);
275 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
276 buffer
277 }
278
279 pub fn read_id_8(&mut self) -> [u8; 3] {
280 let mut buffer = [0; 3];
281 let transaction: TransferConfig = TransferConfig {
282 iwidth: XspiWidth::OCTO,
283 isize: AddressSize::_16bit,
284 adwidth: XspiWidth::OCTO,
285 address: Some(0),
286 adsize: AddressSize::_32bit,
287 dwidth: XspiWidth::OCTO,
288 instruction: Some(CMD_READ_ID_OCTO as u32),
289 dummy: DummyCycles::_4,
290 ..Default::default()
291 };
292 info!("Reading id: {:#X}", transaction.instruction);
293 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
294 buffer
295 }
296
297 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
298 let transaction = TransferConfig {
299 iwidth: XspiWidth::SING,
300 adwidth: XspiWidth::SING,
301 adsize: AddressSize::_24bit,
302 dwidth: XspiWidth::SING,
303 instruction: Some(CMD_READ as u32),
304 dummy: DummyCycles::_8,
305 // dwidth: XspiWidth::QUAD,
306 // instruction: Some(CMD_QUAD_READ as u32),
307 // dummy: DummyCycles::_8,
308 address: Some(addr),
309 ..Default::default()
310 };
311 if use_dma {
312 self.xspi.blocking_read(buffer, transaction).unwrap();
313 } else {
314 self.xspi.blocking_read(buffer, transaction).unwrap();
315 }
316 }
317
318 fn wait_write_finish(&mut self) {
319 while (self.read_sr() & 0x01) != 0 {}
320 }
321
322 async fn perform_erase(&mut self, addr: u32, cmd: u8) {
323 let transaction = TransferConfig {
324 iwidth: XspiWidth::SING,
325 adwidth: XspiWidth::SING,
326 adsize: AddressSize::_24bit,
327 dwidth: XspiWidth::NONE,
328 instruction: Some(cmd as u32),
329 address: Some(addr),
330 dummy: DummyCycles::_0,
331 ..Default::default()
332 };
333 self.enable_write().await;
334 self.xspi.blocking_command(&transaction).unwrap();
335 self.wait_write_finish();
336 }
337
338 pub async fn erase_sector(&mut self, addr: u32) {
339 self.perform_erase(addr, CMD_SECTOR_ERASE).await;
340 }
341
342 pub async fn erase_block_32k(&mut self, addr: u32) {
343 self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await;
344 }
345
346 pub async fn erase_block_64k(&mut self, addr: u32) {
347 self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await;
348 }
349
350 pub async fn erase_chip(&mut self) {
351 self.exec_command(CMD_CHIP_ERASE).await;
352 }
353
354 async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
355 assert!(
356 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
357 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
358 len,
359 addr
360 );
361
362 let transaction = TransferConfig {
363 iwidth: XspiWidth::SING,
364 adsize: AddressSize::_24bit,
365 adwidth: XspiWidth::SING,
366 dwidth: XspiWidth::SING,
367 instruction: Some(CMD_WRITE_PG as u32),
368 // dwidth: XspiWidth::QUAD,
369 // instruction: Some(CMD_QUAD_WRITE_PG as u32),
370 address: Some(addr),
371 dummy: DummyCycles::_0,
372 ..Default::default()
373 };
374 self.enable_write().await;
375 if use_dma {
376 self.xspi.blocking_write(buffer, transaction).unwrap();
377 } else {
378 self.xspi.blocking_write(buffer, transaction).unwrap();
379 }
380 self.wait_write_finish();
381 }
382
383 pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
384 let mut left = buffer.len();
385 let mut place = addr;
386 let mut chunk_start = 0;
387
388 while left > 0 {
389 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
390 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
391 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
392 self.write_page(place, chunk, chunk_size, use_dma).await;
393 place += chunk_size as u32;
394 left -= chunk_size;
395 chunk_start += chunk_size;
396 }
397 }
398
399 fn read_register(&mut self, cmd: u8) -> u8 {
400 let mut buffer = [0; 1];
401 let transaction: TransferConfig = TransferConfig {
402 iwidth: XspiWidth::SING,
403 isize: AddressSize::_8bit,
404 adwidth: XspiWidth::NONE,
405 adsize: AddressSize::_24bit,
406 dwidth: XspiWidth::SING,
407 instruction: Some(cmd as u32),
408 address: None,
409 dummy: DummyCycles::_0,
410 ..Default::default()
411 };
412 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
413 // info!("Read w25q64 register: 0x{:x}", buffer[0]);
414 buffer[0]
415 }
416
417 fn write_register(&mut self, cmd: u8, value: u8) {
418 let buffer = [value; 1];
419 let transaction: TransferConfig = TransferConfig {
420 iwidth: XspiWidth::SING,
421 isize: AddressSize::_8bit,
422 instruction: Some(cmd as u32),
423 adsize: AddressSize::_24bit,
424 adwidth: XspiWidth::NONE,
425 dwidth: XspiWidth::SING,
426 address: None,
427 dummy: DummyCycles::_0,
428 ..Default::default()
429 };
430 self.xspi.blocking_write(&buffer, transaction).unwrap();
431 }
432
433 pub fn read_sr(&mut self) -> u8 {
434 self.read_register(CMD_READ_SR)
435 }
436
437 pub fn read_cr(&mut self) -> u8 {
438 self.read_register(CMD_READ_CR)
439 }
440
441 pub fn write_sr(&mut self, value: u8) {
442 self.write_register(CMD_WRITE_SR, value);
443 }
444
445 pub fn write_cr(&mut self, value: u8) {
446 self.write_register(CMD_WRITE_CR, value);
447 }
448}
diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml
index b050334b2..fed9cf9ce 100644
--- a/examples/stm32l0/.cargo/config.toml
+++ b/examples/stm32l0/.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 your chip as listed in `probe-rs chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32L053R8Tx" 3runner = "probe-rs run --chip STM32L073RZTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 2577f19e0..3101cf7ce 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -6,13 +6,13 @@ 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", "unstable-pac", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "1.0.1"
15defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
16 16
17embedded-storage = "0.3.1" 17embedded-storage = "0.3.1"
18embedded-io = { version = "0.6.0" } 18embedded-io = { version = "0.6.0" }
@@ -20,7 +20,7 @@ embedded-io-async = { version = "0.6.1" }
20 20
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 = "1.0.0", features = ["print-defmt"] }
24heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
25embedded-hal = "0.2.6" 25embedded-hal = "0.2.6"
26static_cell = { version = "2" } 26static_cell = { version = "2" }
diff --git a/examples/stm32l0/README.md b/examples/stm32l0/README.md
new file mode 100644
index 000000000..82d222027
--- /dev/null
+++ b/examples/stm32l0/README.md
@@ -0,0 +1,24 @@
1# Examples for STM32L0 family
2Run individual examples with
3```
4cargo run --bin <module-name>
5```
6for example
7```
8cargo run --bin blinky
9```
10
11## Checklist before running examples
12You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
13
14* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L073RZ it should be `probe-rs run --chip STM32L073RZTx`. (use `probe-rs chip list` to find your chip)
15* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L073RZ it should be `stm32l073rz`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
16* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
17* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
18
19If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
20
21* Which example you are trying to run
22* Which chip and board you are using
23
24Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs
deleted file mode 100644
index c40b86af9..000000000
--- a/examples/stm32l0/src/bin/async-tsc.rs
+++ /dev/null
@@ -1,122 +0,0 @@
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
deleted file mode 100644
index 7e4f40946..000000000
--- a/examples/stm32l0/src/bin/blocking-tsc.rs
+++ /dev/null
@@ -1,116 +0,0 @@
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/eeprom.rs b/examples/stm32l0/src/bin/eeprom.rs
new file mode 100644
index 000000000..370246644
--- /dev/null
+++ b/examples/stm32l0/src/bin/eeprom.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE};
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
13 info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE);
14
15 const ADDR: u32 = 0x0;
16
17 let mut f = Flash::new_blocking(p.FLASH);
18
19 info!("Reading...");
20 let mut buf = [0u8; 8];
21 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
22 info!("Read: {=[u8]:x}", buf);
23
24 info!("Writing...");
25 unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
26
27 info!("Reading...");
28 let mut buf = [0u8; 8];
29 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
30 info!("Read: {=[u8]:x}", buf);
31 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
32}
diff --git a/examples/stm32l0/src/bin/tsc_async.rs b/examples/stm32l0/src/bin/tsc_async.rs
new file mode 100644
index 000000000..dae351c2e
--- /dev/null
+++ b/examples/stm32l0/src/bin/tsc_async.rs
@@ -0,0 +1,116 @@
1// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// This example demonstrates:
4// 1. Configuring a single TSC channel pin
5// 2. Using the blocking TSC interface with polling
6// 3. Waiting for acquisition completion using `poll_for_acquisition`
7// 4. Reading touch values and controlling an LED based on the results
8//
9// Suggested physical setup on STM32L073RZ Nucleo board:
10// - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor.
11// - Connect one end of a 1K resistor to pin PA1 and leave the other end loose.
12// The loose end will act as the touch sensor which will register your touch.
13//
14// The example uses two pins from Group 1 of the TSC on the STM32L073RZ Nucleo board:
15// - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0)
16// - PA1 as the channel pin, TSC group 1 IO2 (label A1)
17//
18// The program continuously reads the touch sensor value:
19// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value.
20// - The LED is turned on when touch is detected (sensor value < 25).
21// - Touch values are logged to the console.
22//
23// Troubleshooting:
24// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value.
25// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
26// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
27//
28// Note: Configuration values and sampling capacitor value have been determined experimentally.
29// Optimal values may vary based on your specific hardware setup.
30// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the
31// official relevant STM32 datasheets and nucleo-board user manuals to find suitable
32// alternative pins.
33//
34// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to
35// the programmer chip. If you try to use these two pins for TSC, you will get strange
36// readings, unless you somehow reconfigure/re-wire your nucleo-board.
37// No errors or warnings will be emitted, they will just silently not work as expected.
38// (see nucleo user manual UM1724, Rev 14, page 25)
39
40#![no_std]
41#![no_main]
42
43use defmt::*;
44use embassy_stm32::gpio::{Level, Output, Speed};
45use embassy_stm32::tsc::{self, *};
46use embassy_stm32::{bind_interrupts, peripherals};
47use embassy_time::Timer;
48use {defmt_rtt as _, panic_probe as _};
49
50bind_interrupts!(struct Irqs {
51 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
52});
53const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup
54
55#[embassy_executor::main]
56async fn main(_spawner: embassy_executor::Spawner) {
57 let device_config = embassy_stm32::Config::default();
58 let context = embassy_stm32::init(device_config);
59
60 let mut pin_group: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default();
61 pin_group.set_io1::<tsc::pin_roles::Sample>(context.PA0);
62 let sensor = pin_group.set_io2::<tsc::pin_roles::Channel>(context.PA1);
63
64 let tsc_conf = Config {
65 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
66 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
67 spread_spectrum: false,
68 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
69 spread_spectrum_prescaler: false,
70 pulse_generator_prescaler: PGPrescalerDivider::_16,
71 max_count_value: MaxCount::_255,
72 io_default_mode: false,
73 synchro_pin_polarity: false,
74 acquisition_mode: false,
75 max_count_interrupt: false,
76 };
77
78 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
79 g1: Some(pin_group.pin_group),
80 ..Default::default()
81 };
82
83 let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap();
84
85 // Check if TSC is ready
86 if touch_controller.get_state() != State::Ready {
87 info!("TSC not ready!");
88 return;
89 }
90 info!("TSC initialized successfully");
91
92 // LED2 on the STM32L073RZ nucleo-board (PA5)
93 let mut led = Output::new(context.PA5, Level::Low, Speed::Low);
94
95 let discharge_delay = 5; // ms
96
97 info!("Starting touch_controller interface");
98 loop {
99 touch_controller.set_active_channels_mask(sensor.pin.into());
100 touch_controller.start();
101 touch_controller.pend_for_acquisition().await;
102 touch_controller.discharge_io(true);
103 Timer::after_millis(discharge_delay).await;
104
105 let group_val = touch_controller.group_get_value(sensor.pin.group());
106 info!("Touch value: {}", group_val);
107
108 if group_val < SENSOR_THRESHOLD {
109 led.set_high();
110 } else {
111 led.set_low();
112 }
113
114 Timer::after_millis(100).await;
115 }
116}
diff --git a/examples/stm32l0/src/bin/tsc_blocking.rs b/examples/stm32l0/src/bin/tsc_blocking.rs
new file mode 100644
index 000000000..e1f24639b
--- /dev/null
+++ b/examples/stm32l0/src/bin/tsc_blocking.rs
@@ -0,0 +1,142 @@
1// Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// This example demonstrates:
4// 1. Configuring a single TSC channel pin
5// 2. Using the blocking TSC interface with polling
6// 3. Waiting for acquisition completion using `poll_for_acquisition`
7// 4. Reading touch values and controlling an LED based on the results
8//
9// Suggested physical setup on STM32L073RZ Nucleo board:
10// - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor.
11// - Connect one end of a 1K resistor to pin PA1 and leave the other end loose.
12// The loose end will act as the touch sensor which will register your touch.
13//
14// The example uses two pins from Group 1 of the TSC on the STM32L073RZ Nucleo board:
15// - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0)
16// - PA1 as the channel pin, TSC group 1 IO2 (label A1)
17//
18// The program continuously reads the touch sensor value:
19// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value.
20// - The LED is turned on when touch is detected (sensor value < 25).
21// - Touch values are logged to the console.
22//
23// Troubleshooting:
24// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value.
25// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
26// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
27//
28// Note: Configuration values and sampling capacitor value have been determined experimentally.
29// Optimal values may vary based on your specific hardware setup.
30// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the
31// official relevant STM32 datasheets and nucleo-board user manuals to find suitable
32// alternative pins.
33//
34// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to
35// the programmer chip. If you try to use these two pins for TSC, you will get strange
36// readings, unless you somehow reconfigure/re-wire your nucleo-board.
37// No errors or warnings will be emitted, they will just silently not work as expected.
38// (see nucleo user manual UM1724, Rev 14, page 25)
39
40#![no_std]
41#![no_main]
42
43use defmt::*;
44use embassy_stm32::gpio::{Level, Output, Speed};
45use embassy_stm32::tsc::{self, *};
46use embassy_stm32::{mode, peripherals};
47use embassy_time::Timer;
48use {defmt_rtt as _, panic_probe as _};
49
50const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup
51
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 tsc_conf = 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 };
70
71 let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default();
72 g1.set_io1::<tsc::pin_roles::Sample>(context.PA0);
73 let tsc_sensor = g1.set_io2::<tsc::pin_roles::Channel>(context.PA1);
74
75 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
76 g1: Some(g1.pin_group),
77 ..Default::default()
78 };
79
80 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap();
81
82 // Check if TSC is ready
83 if touch_controller.get_state() != State::Ready {
84 crate::panic!("TSC not ready!");
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.set_active_channels_mask(tsc_sensor.pin.into());
100 touch_controller.start();
101 touch_controller.poll_for_acquisition();
102 touch_controller.discharge_io(true);
103 Timer::after_millis(discharge_delay).await;
104
105 match read_touch_value(&mut touch_controller, tsc_sensor.pin).await {
106 Some(v) => {
107 info!("sensor value {}", v);
108 if v < SENSOR_THRESHOLD {
109 led.set_high();
110 } else {
111 led.set_low();
112 }
113 }
114 None => led.set_low(),
115 }
116
117 Timer::after_millis(polling_interval).await;
118 }
119}
120
121const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10;
122
123// attempt to read group status and delay when still ongoing
124async fn read_touch_value(
125 touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>,
126 sensor_pin: tsc::IOPin,
127) -> Option<u16> {
128 for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS {
129 match touch_controller.group_get_status(sensor_pin.group()) {
130 GroupStatus::Complete => {
131 return Some(touch_controller.group_get_value(sensor_pin.group()));
132 }
133 GroupStatus::Ongoing => {
134 // if you end up here a lot, then you prob need to increase discharge_delay
135 // or consider changing the code to adjust the discharge_delay dynamically
136 info!("Acquisition still ongoing");
137 Timer::after_millis(1).await;
138 }
139 }
140 }
141 None
142}
diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs
new file mode 100644
index 000000000..6343de141
--- /dev/null
+++ b/examples/stm32l0/src/bin/tsc_multipin.rs
@@ -0,0 +1,209 @@
1// Example of TSC (Touch Sensing Controller) using multiple pins from the same tsc-group.
2//
3// What is special about using multiple TSC pins as sensor channels from the same TSC group,
4// is that only one TSC pin for each TSC group can be acquired and read at the time.
5// To control which channel pins are acquired and read, we must write a mask before initiating an
6// acquisition. To help manage and abstract all this business away, we can organize our channel
7// pins into acquisition banks. Each acquisition bank can contain exactly one channel pin per TSC
8// group and it will contain the relevant mask.
9//
10// This example demonstrates how to:
11// 1. Configure multiple channel pins within a single TSC group
12// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks)
13// 3. Read and interpret touch values from multiple channels in the same group
14//
15// Suggested physical setup on STM32L073RZ Nucleo board:
16// - Connect a 1000pF capacitor between pin PA0 (label A0) and GND. This is the sampling capacitor for TSC
17// group 1.
18// - Connect one end of a 1K resistor to pin PA1 (label A1) and leave the other end loose.
19// The loose end will act as a touch sensor.
20//
21// - Connect a 1000pF capacitor between pin PB3 (label D3) and GND. This is the sampling capacitor for TSC
22// group 5.
23// - Connect one end of another 1K resistor to pin PB4 and leave the other end loose.
24// The loose end will act as a touch sensor.
25// - Connect one end of another 1K resistor to pin PB6 and leave the other end loose.
26// The loose end will act as a touch sensor.
27//
28// The example uses pins from two TSC groups.
29// - PA0 as sampling capacitor, TSC group 1 IO1 (label A0)
30// - PA1 as channel, TSC group 1 IO2 (label A1)
31// - PB3 as sampling capacitor, TSC group 5 IO1 (label D3)
32// - PB4 as channel, TSC group 5 IO2 (label D10)
33// - PB6 as channel, TSC group 5 IO3 (label D5)
34//
35// The pins have been chosen to make it easy to simply add capacitors directly onto the board and
36// connect one leg to GND, and to easily add resistors to the board with no special connectors,
37// breadboards, special wires or soldering required. All you need is the capacitors and resistors.
38//
39// The program reads the designated channel pins and adjusts the LED blinking
40// pattern based on which sensor(s) are touched:
41// - No touch: LED off
42// - one sensor touched: Slow blinking
43// - two sensors touched: Fast blinking
44// - three sensors touched: LED constantly on
45//
46// Troubleshooting:
47// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value.
48// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
49// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
50//
51// Note: Configuration values and sampling capacitor value have been determined experimentally.
52// Optimal values may vary based on your specific hardware setup.
53// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the
54// official relevant STM32 datasheets and nucleo-board user manuals to find suitable
55// alternative pins.
56//
57// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to
58// the programmer chip. If you try to use these two pins for TSC, you will get strange
59// readings, unless you somehow reconfigure/re-wire your nucleo-board.
60// No errors or warnings will be emitted, they will just silently not work as expected.
61// (see nucleo user manual UM1724, Rev 14, page 25)
62
63#![no_std]
64#![no_main]
65
66use defmt::*;
67use embassy_stm32::gpio::{Level, Output, Speed};
68use embassy_stm32::tsc::{self, *};
69use embassy_stm32::{bind_interrupts, mode, peripherals};
70use embassy_time::Timer;
71use {defmt_rtt as _, panic_probe as _};
72
73bind_interrupts!(struct Irqs {
74 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
75});
76
77const SENSOR_THRESHOLD: u16 = 35;
78
79async fn acquire_sensors(
80 touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>,
81 tsc_acquisition_bank: &AcquisitionBank,
82) {
83 touch_controller.set_active_channels_bank(tsc_acquisition_bank);
84 touch_controller.start();
85 touch_controller.pend_for_acquisition().await;
86 touch_controller.discharge_io(true);
87 let discharge_delay = 5; // ms
88 Timer::after_millis(discharge_delay).await;
89}
90
91#[embassy_executor::main]
92async fn main(_spawner: embassy_executor::Spawner) {
93 let device_config = embassy_stm32::Config::default();
94 let context = embassy_stm32::init(device_config);
95
96 // ---------- initial configuration of TSC ----------
97 let mut pin_group1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default();
98 pin_group1.set_io1::<tsc::pin_roles::Sample>(context.PA0);
99 let tsc_sensor0 = pin_group1.set_io2(context.PA1);
100
101 let mut pin_group5: PinGroupWithRoles<peripherals::TSC, G5> = PinGroupWithRoles::default();
102 pin_group5.set_io1::<tsc::pin_roles::Sample>(context.PB3);
103 let tsc_sensor1 = pin_group5.set_io2(context.PB4);
104 let tsc_sensor2 = pin_group5.set_io3(context.PB6);
105
106 let config = tsc::Config {
107 ct_pulse_high_length: ChargeTransferPulseCycle::_16,
108 ct_pulse_low_length: ChargeTransferPulseCycle::_16,
109 spread_spectrum: false,
110 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
111 spread_spectrum_prescaler: false,
112 pulse_generator_prescaler: PGPrescalerDivider::_16,
113 max_count_value: MaxCount::_255,
114 io_default_mode: false,
115 synchro_pin_polarity: false,
116 acquisition_mode: false,
117 max_count_interrupt: false,
118 };
119
120 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
121 g1: Some(pin_group1.pin_group),
122 g5: Some(pin_group5.pin_group),
123 ..Default::default()
124 };
125
126 let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap();
127
128 // ---------- setting up acquisition banks ----------
129 // sensor0 and sensor1 in this example belong to different TSC-groups,
130 // therefore we can acquire and read them both in one go.
131 let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
132 g1_pin: Some(tsc_sensor0),
133 g5_pin: Some(tsc_sensor1),
134 ..Default::default()
135 });
136 // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to
137 // acquire them one at the time. Therefore, we organize them into different acquisition banks.
138 let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
139 g5_pin: Some(tsc_sensor2),
140 ..Default::default()
141 });
142
143 // Check if TSC is ready
144 if touch_controller.get_state() != State::Ready {
145 crate::panic!("TSC not ready!");
146 }
147
148 info!("TSC initialized successfully");
149
150 // LED2 on the STM32L073RZ nucleo-board (PA5)
151 let mut led = Output::new(context.PA5, Level::High, Speed::Low);
152
153 let mut led_state = false;
154
155 loop {
156 acquire_sensors(&mut touch_controller, &bank1).await;
157 let readings1 = touch_controller.get_acquisition_bank_values(&bank1);
158 acquire_sensors(&mut touch_controller, &bank2).await;
159 let readings2 = touch_controller.get_acquisition_bank_values(&bank2);
160
161 let mut touched_sensors_count = 0;
162 for reading in readings1.iter() {
163 info!("{}", reading);
164 if reading.sensor_value < SENSOR_THRESHOLD {
165 touched_sensors_count += 1;
166 }
167 }
168 for reading in readings2.iter() {
169 info!("{}", reading);
170 if reading.sensor_value < SENSOR_THRESHOLD {
171 touched_sensors_count += 1;
172 }
173 }
174
175 match touched_sensors_count {
176 0 => {
177 // No sensors touched, turn off the LED
178 led.set_low();
179 led_state = false;
180 }
181 1 => {
182 // One sensor touched, blink slowly
183 led_state = !led_state;
184 if led_state {
185 led.set_high();
186 } else {
187 led.set_low();
188 }
189 Timer::after_millis(200).await;
190 }
191 2 => {
192 // Two sensors touched, blink faster
193 led_state = !led_state;
194 if led_state {
195 led.set_high();
196 } else {
197 led.set_low();
198 }
199 Timer::after_millis(50).await;
200 }
201 3 => {
202 // All three sensors touched, LED constantly on
203 led.set_high();
204 led_state = true;
205 }
206 _ => crate::unreachable!(), // This case should never occur with 3 sensors
207 }
208 }
209}
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs
index 2c96a8bc2..a51ddbcbb 100644
--- a/examples/stm32l0/src/bin/usart_irq.rs
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) {
21 config.baudrate = 9600; 21 config.baudrate = 9600;
22 let mut tx_buf = [0u8; 256]; 22 let mut tx_buf = [0u8; 256];
23 let mut rx_buf = [0u8; 256]; 23 let mut rx_buf = [0u8; 256];
24 let mut usart = BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, config).unwrap(); 24 let mut usart = BufferedUart::new(p.USART2, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap();
25 25
26 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); 26 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
27 info!("wrote Hello, starting echo"); 27 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 062044f32..a0a7916a7 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -5,20 +5,20 @@ 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.6.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", 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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.4.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 = "1.0.1"
16defmt-rtt = "0.4" 16defmt-rtt = "1.0.0"
17 17
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"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
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/eeprom.rs b/examples/stm32l1/src/bin/eeprom.rs
new file mode 100644
index 000000000..370246644
--- /dev/null
+++ b/examples/stm32l1/src/bin/eeprom.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE};
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
13 info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE);
14
15 const ADDR: u32 = 0x0;
16
17 let mut f = Flash::new_blocking(p.FLASH);
18
19 info!("Reading...");
20 let mut buf = [0u8; 8];
21 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
22 info!("Read: {=[u8]:x}", buf);
23
24 info!("Writing...");
25 unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
26
27 info!("Reading...");
28 let mut buf = [0u8; 8];
29 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
30 info!("Read: {=[u8]:x}", buf);
31 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
32}
diff --git a/examples/stm32l1/src/bin/usart.rs b/examples/stm32l1/src/bin/usart.rs
new file mode 100644
index 000000000..dba79b8b4
--- /dev/null
+++ b/examples/stm32l1/src/bin/usart.rs
@@ -0,0 +1,37 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::entry;
5use defmt::*;
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 USART2 => usart::InterruptHandler<peripherals::USART2>;
12});
13
14#[entry]
15fn main() -> ! {
16 info!("Hello World!");
17
18 let p = embassy_stm32::init(Default::default());
19
20 let config = Config::default();
21 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
22 let desired_baudrate = 9600; // Default is 115200 and 9600 is used as example
23
24 match usart.set_baudrate(desired_baudrate) {
25 Ok(_) => info!("Baud rate set to {}", desired_baudrate),
26 Err(err) => error!("Error setting baudrate to {}: {}", desired_baudrate, err),
27 }
28
29 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
30 info!("wrote Hello, starting echo");
31
32 let mut buf = [0u8; 1];
33 loop {
34 unwrap!(usart.blocking_read(&mut buf));
35 unwrap!(usart.blocking_write(&buf));
36 }
37}
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs
index 837f7fa57..a35f1d7a7 100644
--- a/examples/stm32l1/src/bin/usb_serial.rs
+++ b/examples/stm32l1/src/bin/usb_serial.rs
@@ -41,11 +41,6 @@ async fn main(_spawner: Spawner) {
41 config.product = Some("USB-Serial Example"); 41 config.product = Some("USB-Serial Example");
42 config.serial_number = Some("123456"); 42 config.serial_number = Some("123456");
43 43
44 config.device_class = 0xEF;
45 config.device_sub_class = 0x02;
46 config.device_protocol = 0x01;
47 config.composite_with_iads = true;
48
49 let mut config_descriptor = [0; 256]; 44 let mut config_descriptor = [0; 256];
50 let mut bos_descriptor = [0; 256]; 45 let mut bos_descriptor = [0; 256];
51 let mut control_buf = [0; 64]; 46 let mut control_buf = [0; 64];
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index 83fc6d6f8..d71fb1517 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,8 @@
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-rs run --chip STM32L4S5QI" 5#runner = "probe-rs run --chip STM32L4S5QI"
6runner = "probe-rs run --chip STM32L4R5ZITxP"
6 7
7[build] 8[build]
8target = "thumbv7em-none-eabi" 9target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index c5478b17b..7da09e5b0 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono", "dual-bank"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } 15embassy-net-adin1110 = { version = "0.3.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.7.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" }
18embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 18embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
19embedded-io = { version = "0.6.0", features = ["defmt-03"] } 19embedded-io = { version = "0.6.0", features = ["defmt-03"] }
20 20
21defmt = "0.3" 21defmt = "1.0.1"
22defmt-rtt = "0.4" 22defmt-rtt = "1.0.0"
23 23
24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
@@ -27,10 +27,9 @@ embedded-hal = "0.2.6"
27embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 27embedded-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 = "1.0.0", features = ["print-defmt"] }
31heapless = { version = "0.8", default-features = false } 31heapless = { version = "0.8", default-features = false }
32chrono = { version = "^0.4", default-features = false } 32chrono = { version = "^0.4", default-features = false }
33rand = { version = "0.8.5", default-features = false }
34static_cell = "2" 33static_cell = "2"
35 34
36micromath = "2.0.0" 35micromath = "2.0.0"
diff --git a/examples/stm32l4/README.md b/examples/stm32l4/README.md
new file mode 100644
index 000000000..e463c18a0
--- /dev/null
+++ b/examples/stm32l4/README.md
@@ -0,0 +1,24 @@
1# Examples for STM32L4 family
2Run individual examples with
3```
4cargo run --bin <module-name>
5```
6for example
7```
8cargo run --bin blinky
9```
10
11## Checklist before running examples
12You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
13
14* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L4R5ZI-P it should be `probe-rs run --chip STM32L4R5ZITxP`. (use `probe-rs chip list` to find your chip)
15* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L4R5ZI-P it should be `stm32l4r5zi`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
16* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
17* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
18
19If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
20
21* Which example you are trying to run
22* Which chip and board you are using
23
24Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index fdbf1d374..50db0e082 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dac::{DacCh1, Value}; 5use embassy_stm32::dac::{DacCh1, Value};
6use embassy_stm32::dma::NoDma;
7use {defmt_rtt as _, panic_probe as _}; 6use {defmt_rtt as _, panic_probe as _};
8 7
9#[cortex_m_rt::entry] 8#[cortex_m_rt::entry]
@@ -11,7 +10,7 @@ fn main() -> ! {
11 let p = embassy_stm32::init(Default::default()); 10 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!"); 11 info!("Hello World!");
13 12
14 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 13 let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
15 14
16 loop { 15 loop {
17 for v in 0..=255 { 16 for v in 0..=255 {
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index d01b016c0..cde24f411 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -4,11 +4,13 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::mode::Async;
7use embassy_stm32::pac::timer::vals::Mms; 8use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 9use embassy_stm32::peripherals::{DAC1, TIM6, TIM7};
9use embassy_stm32::rcc::frequency; 10use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Timer; 12use embassy_stm32::timer::low_level::Timer;
13use embassy_stm32::Peri;
12use micromath::F32Ext; 14use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
14 16
@@ -27,7 +29,7 @@ async fn main(spawner: Spawner) {
27} 29}
28 30
29#[embassy_executor::task] 31#[embassy_executor::task]
30async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 32async fn dac_task1(tim: Peri<'static, TIM6>, mut dac: DacCh1<'static, DAC1, Async>) {
31 let data: &[u8; 256] = &calculate_array::<256>(); 33 let data: &[u8; 256] = &calculate_array::<256>();
32 34
33 info!("TIM6 frequency is {}", frequency::<TIM6>()); 35 info!("TIM6 frequency is {}", frequency::<TIM6>());
@@ -70,7 +72,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
70} 72}
71 73
72#[embassy_executor::task] 74#[embassy_executor::task]
73async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 75async fn dac_task2(tim: Peri<'static, TIM7>, mut dac: DacCh2<'static, DAC1, Async>) {
74 let data: &[u8; 256] = &calculate_array::<256>(); 76 let data: &[u8; 256] = &calculate_array::<256>();
75 77
76 info!("TIM7 frequency is {}", frequency::<TIM7>()); 78 info!("TIM7 frequency is {}", frequency::<TIM7>());
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 8f23e4083..dc90a3b85 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -38,7 +38,6 @@ use embedded_io::Write as bWrite;
38use embedded_io_async::Write; 38use embedded_io_async::Write;
39use heapless::Vec; 39use heapless::Vec;
40use panic_probe as _; 40use panic_probe as _;
41use rand::RngCore;
42use static_cell::StaticCell; 41use static_cell::StaticCell;
43 42
44bind_interrupts!(struct Irqs { 43bind_interrupts!(struct Irqs {
@@ -51,7 +50,7 @@ bind_interrupts!(struct Irqs {
51// MAC-address used by the adin1110 50// MAC-address used by the adin1110
52const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; 51const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
53// Static IP settings 52// Static IP settings
54const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); 53const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 5), 24);
55// Listen port for the webserver 54// Listen port for the webserver
56const HTTP_LISTEN_PORT: u16 = 80; 55const HTTP_LISTEN_PORT: u16 = 80;
57 56
@@ -206,12 +205,11 @@ async fn main(spawner: Spawner) {
206 }; 205 };
207 206
208 // Init network stack 207 // Init network stack
209 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
210 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 208 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
211 let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed)); 209 let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed);
212 210
213 // Launch network task 211 // Launch network task
214 unwrap!(spawner.spawn(net_task(stack))); 212 unwrap!(spawner.spawn(net_task(runner)));
215 213
216 let cfg = wait_for_config(stack).await; 214 let cfg = wait_for_config(stack).await;
217 let local_addr = cfg.address.address(); 215 let local_addr = cfg.address.address();
@@ -274,7 +272,7 @@ async fn main(spawner: Spawner) {
274 } 272 }
275} 273}
276 274
277async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 275async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
278 loop { 276 loop {
279 if let Some(config) = stack.config_v4() { 277 if let Some(config) = stack.config_v4() {
280 return config; 278 return config;
@@ -323,8 +321,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! {
323} 321}
324 322
325#[embassy_executor::task] 323#[embassy_executor::task]
326async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 324async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
327 stack.run().await 325 runner.run().await
328} 326}
329 327
330// same panicking *behavior* as `panic-probe` but doesn't print a panic message 328// same panicking *behavior* as `panic-probe` but doesn't print a panic message
diff --git a/examples/stm32l4/src/bin/tsc_async.rs b/examples/stm32l4/src/bin/tsc_async.rs
new file mode 100644
index 000000000..b9a059e2e
--- /dev/null
+++ b/examples/stm32l4/src/bin/tsc_async.rs
@@ -0,0 +1,108 @@
1// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// This example demonstrates:
4// 1. Configuring a single TSC channel pin
5// 2. Using the async TSC interface
6// 3. Waiting for acquisition completion using `pend_for_acquisition`
7// 4. Reading touch values and controlling an LED based on the results
8//
9// Suggested physical setup on STM32L4R5ZI-P board:
10// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor.
11// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose.
12// The loose end will act as the touch sensor which will register your touch.
13//
14// The example uses two pins from Group 2 of the TSC:
15// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1
16// - PB5 (D21) as the channel pin, TSC group 2 IO2
17//
18// The program continuously reads the touch sensor value:
19// - It starts acquisition, waits for completion using `pend_for_acquisition`, and reads the value.
20// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD).
21// - Touch values are logged to the console.
22//
23// Troubleshooting:
24// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value.
25// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
26// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
27//
28// Note: Configuration values and sampling capacitor value have been determined experimentally.
29// Optimal values may vary based on your specific hardware setup.
30
31#![no_std]
32#![no_main]
33
34use defmt::*;
35use embassy_stm32::gpio::{Level, Output, Speed};
36use embassy_stm32::tsc::{self, *};
37use embassy_stm32::{bind_interrupts, peripherals};
38use embassy_time::Timer;
39use {defmt_rtt as _, panic_probe as _};
40
41bind_interrupts!(struct Irqs {
42 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
43});
44const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup
45
46#[embassy_executor::main]
47async fn main(_spawner: embassy_executor::Spawner) {
48 let device_config = embassy_stm32::Config::default();
49 let context = embassy_stm32::init(device_config);
50
51 let mut pin_group: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
52 // D25
53 pin_group.set_io1::<tsc::pin_roles::Sample>(context.PB4);
54 // D21
55 let tsc_sensor = pin_group.set_io2::<tsc::pin_roles::Channel>(context.PB5);
56
57 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
58 g2: Some(pin_group.pin_group),
59 ..Default::default()
60 };
61
62 let tsc_conf = Config {
63 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
64 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
65 spread_spectrum: false,
66 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
67 spread_spectrum_prescaler: false,
68 pulse_generator_prescaler: PGPrescalerDivider::_16,
69 max_count_value: MaxCount::_255,
70 io_default_mode: false,
71 synchro_pin_polarity: false,
72 acquisition_mode: false,
73 max_count_interrupt: false,
74 };
75
76 let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap();
77
78 // Check if TSC is ready
79 if touch_controller.get_state() != State::Ready {
80 info!("TSC not ready!");
81 return;
82 }
83 info!("TSC initialized successfully");
84
85 let mut led = Output::new(context.PB14, Level::High, Speed::Low);
86
87 let discharge_delay = 1; // ms
88
89 info!("Starting touch_controller interface");
90 loop {
91 touch_controller.set_active_channels_mask(tsc_sensor.pin.into());
92 touch_controller.start();
93 touch_controller.pend_for_acquisition().await;
94 touch_controller.discharge_io(true);
95 Timer::after_millis(discharge_delay).await;
96
97 let group_val = touch_controller.group_get_value(tsc_sensor.pin.group());
98 info!("Touch value: {}", group_val);
99
100 if group_val < SENSOR_THRESHOLD {
101 led.set_high();
102 } else {
103 led.set_low();
104 }
105
106 Timer::after_millis(100).await;
107 }
108}
diff --git a/examples/stm32l4/src/bin/tsc_blocking.rs b/examples/stm32l4/src/bin/tsc_blocking.rs
new file mode 100644
index 000000000..12084f8e2
--- /dev/null
+++ b/examples/stm32l4/src/bin/tsc_blocking.rs
@@ -0,0 +1,147 @@
1// # Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected
2//
3// This example demonstrates how to use the Touch Sensing Controller (TSC) in blocking mode on an STM32L4R5ZI-P board.
4//
5// ## This example demonstrates:
6//
7// 1. Configuring a single TSC channel pin
8// 2. Using the blocking TSC interface with polling
9// 3. Waiting for acquisition completion using `poll_for_acquisition`
10// 4. Reading touch values and controlling an LED based on the results
11//
12// ## Suggested physical setup on STM32L4R5ZI-P board:
13//
14// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor.
15// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose.
16// The loose end will act as the touch sensor which will register your touch.
17//
18// ## Pin Configuration:
19//
20// The example uses two pins from Group 2 of the TSC:
21// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1
22// - PB5 (D21) as the channel pin, TSC group 2 IO2
23//
24// ## Program Behavior:
25//
26// The program continuously reads the touch sensor value:
27// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value.
28// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD).
29// - Touch values are logged to the console.
30//
31// ## Troubleshooting:
32//
33// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 25).
34// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length,
35// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
36// - Be aware that for some boards, there might be overlapping concerns between some pins,
37// such as UART connections for the programmer. No errors or warnings will be emitted if you
38// try to use such a pin for TSC, but you may get strange sensor readings.
39//
40// Note: Configuration values and sampling capacitor value have been determined experimentally.
41// Optimal values may vary based on your specific hardware setup. Refer to the official
42// STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality.
43
44#![no_std]
45#![no_main]
46
47use defmt::*;
48use embassy_stm32::gpio::{Level, Output, Speed};
49use embassy_stm32::tsc::{self, *};
50use embassy_stm32::{mode, peripherals};
51use embassy_time::Timer;
52use {defmt_rtt as _, panic_probe as _};
53
54const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup
55
56#[embassy_executor::main]
57async fn main(_spawner: embassy_executor::Spawner) {
58 let device_config = embassy_stm32::Config::default();
59 let context = embassy_stm32::init(device_config);
60
61 let tsc_conf = Config {
62 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
63 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
64 spread_spectrum: false,
65 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
66 spread_spectrum_prescaler: false,
67 pulse_generator_prescaler: PGPrescalerDivider::_16,
68 max_count_value: MaxCount::_255,
69 io_default_mode: false,
70 synchro_pin_polarity: false,
71 acquisition_mode: false,
72 max_count_interrupt: false,
73 };
74
75 let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
76 // D25
77 g2.set_io1::<tsc::pin_roles::Sample>(context.PB4);
78 // D21
79 let tsc_sensor = g2.set_io2::<tsc::pin_roles::Channel>(context.PB5);
80
81 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
82 g2: Some(g2.pin_group),
83 ..Default::default()
84 };
85
86 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap();
87
88 // Check if TSC is ready
89 if touch_controller.get_state() != State::Ready {
90 crate::panic!("TSC not ready!");
91 }
92 info!("TSC initialized successfully");
93
94 let mut led = Output::new(context.PB14, Level::High, Speed::Low);
95
96 // smaller sample capacitor discharge faster and can be used with shorter delay.
97 let discharge_delay = 5; // ms
98
99 // the interval at which the loop polls for new touch sensor values
100 let polling_interval = 100; // ms
101
102 info!("polling for touch");
103 loop {
104 touch_controller.set_active_channels_mask(tsc_sensor.pin.into());
105 touch_controller.start();
106 touch_controller.poll_for_acquisition();
107 touch_controller.discharge_io(true);
108 Timer::after_millis(discharge_delay).await;
109
110 match read_touch_value(&mut touch_controller, tsc_sensor.pin).await {
111 Some(v) => {
112 info!("sensor value {}", v);
113 if v < SENSOR_THRESHOLD {
114 led.set_high();
115 } else {
116 led.set_low();
117 }
118 }
119 None => led.set_low(),
120 }
121
122 Timer::after_millis(polling_interval).await;
123 }
124}
125
126const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10;
127
128// attempt to read group status and delay when still ongoing
129async fn read_touch_value(
130 touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>,
131 sensor_pin: tsc::IOPin,
132) -> Option<u16> {
133 for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS {
134 match touch_controller.group_get_status(sensor_pin.group()) {
135 GroupStatus::Complete => {
136 return Some(touch_controller.group_get_value(sensor_pin.group()));
137 }
138 GroupStatus::Ongoing => {
139 // if you end up here a lot, then you prob need to increase discharge_delay
140 // or consider changing the code to adjust the discharge_delay dynamically
141 info!("Acquisition still ongoing");
142 Timer::after_millis(1).await;
143 }
144 }
145 }
146 None
147}
diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs
new file mode 100644
index 000000000..8fec5ddc4
--- /dev/null
+++ b/examples/stm32l4/src/bin/tsc_multipin.rs
@@ -0,0 +1,198 @@
1// # Example of TSC (Touch Sensing Controller) using multiple pins from the same TSC group
2//
3// This example demonstrates how to use the Touch Sensing Controller (TSC) with multiple pins, including pins from the same TSC group, on an STM32L4R5ZI-P board.
4//
5// ## Key Concepts
6//
7// - Only one TSC pin for each TSC group can be acquired and read at a time.
8// - To control which channel pins are acquired and read, we must write a mask before initiating an acquisition.
9// - We organize channel pins into acquisition banks to manage this process efficiently.
10// - Each acquisition bank can contain exactly one channel pin per TSC group and will contain the relevant mask.
11//
12// ## This example demonstrates how to:
13//
14// 1. Configure multiple channel pins within a single TSC group
15// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks)
16// 3. Read and interpret touch values from multiple channels in the same group
17//
18// ## Suggested physical setup on STM32L4R5ZI-P board:
19//
20// - Connect a 1000pF capacitor between pin PB12 (D19) and GND. This is the sampling capacitor for TSC group 1.
21// - Connect one end of a 1K resistor to pin PB13 (D18) and leave the other end loose. This will act as a touch sensor.
22// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is the sampling capacitor for TSC group 2.
23// - Connect one end of a 1K resistor to pin PB5 (D22) and leave the other end loose. This will act as a touch sensor.
24// - Connect one end of another 1K resistor to pin PB6 (D71) and leave the other end loose. This will act as a touch sensor.
25//
26// ## Pin Configuration:
27//
28// The example uses pins from two TSC groups:
29//
30// - Group 1:
31// - PB12 (D19) as sampling capacitor (TSC group 1 IO1)
32// - PB13 (D18) as channel (TSC group 1 IO2)
33// - Group 2:
34// - PB4 (D25) as sampling capacitor (TSC group 2 IO1)
35// - PB5 (D22) as channel (TSC group 2 IO2)
36// - PB6 (D71) as channel (TSC group 2 IO3)
37//
38// The pins have been chosen for their convenient locations on the STM32L4R5ZI-P board, making it easy to add capacitors and resistors directly to the board without special connectors, breadboards, or soldering.
39//
40// ## Program Behavior:
41//
42// The program reads the designated channel pins and adjusts the LED (connected to PB14) blinking pattern based on which sensor(s) are touched:
43//
44// - No touch: LED off
45// - One sensor touched: Slow blinking
46// - Two sensors touched: Fast blinking
47// - Three sensors touched: LED constantly on
48//
49// ## Troubleshooting:
50//
51// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20).
52// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
53// - Be aware that for some boards there will be overlapping concerns between some pins, for
54// example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will
55// be emitted if you try to use such a pin for TSC, but you will get strange sensor readings.
56//
57// Note: Configuration values and sampling capacitor values have been determined experimentally. Optimal values may vary based on your specific hardware setup. Refer to the official STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality.
58
59#![no_std]
60#![no_main]
61
62use defmt::*;
63use embassy_stm32::gpio::{Level, Output, Speed};
64use embassy_stm32::tsc::{self, *};
65use embassy_stm32::{bind_interrupts, mode, peripherals};
66use embassy_time::Timer;
67use {defmt_rtt as _, panic_probe as _};
68
69bind_interrupts!(struct Irqs {
70 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
71});
72
73const SENSOR_THRESHOLD: u16 = 20;
74
75async fn acquire_sensors(
76 touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>,
77 tsc_acquisition_bank: &AcquisitionBank,
78) {
79 touch_controller.set_active_channels_bank(tsc_acquisition_bank);
80 touch_controller.start();
81 touch_controller.pend_for_acquisition().await;
82 touch_controller.discharge_io(true);
83 let discharge_delay = 1; // ms
84 Timer::after_millis(discharge_delay).await;
85}
86
87#[embassy_executor::main]
88async fn main(_spawner: embassy_executor::Spawner) {
89 let device_config = embassy_stm32::Config::default();
90 let context = embassy_stm32::init(device_config);
91
92 // ---------- initial configuration of TSC ----------
93 let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default();
94 g1.set_io1::<tsc::pin_roles::Sample>(context.PB12);
95 let sensor0 = g1.set_io2::<tsc::pin_roles::Channel>(context.PB13);
96
97 let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
98 g2.set_io1::<tsc::pin_roles::Sample>(context.PB4);
99 let sensor1 = g2.set_io2(context.PB5);
100 let sensor2 = g2.set_io3(context.PB6);
101
102 let config = tsc::Config {
103 ct_pulse_high_length: ChargeTransferPulseCycle::_16,
104 ct_pulse_low_length: ChargeTransferPulseCycle::_16,
105 spread_spectrum: false,
106 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
107 spread_spectrum_prescaler: false,
108 pulse_generator_prescaler: PGPrescalerDivider::_16,
109 max_count_value: MaxCount::_255,
110 io_default_mode: false,
111 synchro_pin_polarity: false,
112 acquisition_mode: false,
113 max_count_interrupt: false,
114 };
115
116 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
117 g1: Some(g1.pin_group),
118 g2: Some(g2.pin_group),
119 ..Default::default()
120 };
121
122 let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap();
123
124 // ---------- setting up acquisition banks ----------
125 // sensor0 and sensor1 belong to different TSC-groups, therefore we can acquire and
126 // read them both in one go.
127 let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
128 g1_pin: Some(sensor0),
129 g2_pin: Some(sensor1),
130 ..Default::default()
131 });
132 // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to
133 // acquire them one at the time. We do this by organizing them into different acquisition banks.
134 let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
135 g2_pin: Some(sensor2),
136 ..Default::default()
137 });
138
139 // Check if TSC is ready
140 if touch_controller.get_state() != State::Ready {
141 crate::panic!("TSC not ready!");
142 }
143
144 info!("TSC initialized successfully");
145
146 let mut led = Output::new(context.PB14, Level::High, Speed::Low);
147
148 let mut led_state = false;
149
150 loop {
151 acquire_sensors(&mut touch_controller, &bank1).await;
152 let readings1 = touch_controller.get_acquisition_bank_values(&bank1);
153 acquire_sensors(&mut touch_controller, &bank2).await;
154 let readings2 = touch_controller.get_acquisition_bank_values(&bank2);
155
156 let mut touched_sensors_count = 0;
157 for reading in readings1.iter().chain(readings2.iter()) {
158 info!("{}", reading);
159 if reading.sensor_value < SENSOR_THRESHOLD {
160 touched_sensors_count += 1;
161 }
162 }
163
164 match touched_sensors_count {
165 0 => {
166 // No sensors touched, turn off the LED
167 led.set_low();
168 led_state = false;
169 }
170 1 => {
171 // One sensor touched, blink slowly
172 led_state = !led_state;
173 if led_state {
174 led.set_high();
175 } else {
176 led.set_low();
177 }
178 Timer::after_millis(200).await;
179 }
180 2 => {
181 // Two sensors touched, blink faster
182 led_state = !led_state;
183 if led_state {
184 led.set_high();
185 } else {
186 led.set_low();
187 }
188 Timer::after_millis(50).await;
189 }
190 3 => {
191 // All three sensors touched, LED constantly on
192 led.set_high();
193 led_state = true;
194 }
195 _ => crate::unreachable!(), // This case should never occur with 3 sensors
196 }
197 }
198}
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index c3b1211d8..af90e297e 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -62,13 +62,6 @@ async fn main(_spawner: Spawner) {
62 config.product = Some("USB-serial example"); 62 config.product = Some("USB-serial example");
63 config.serial_number = Some("12345678"); 63 config.serial_number = Some("12345678");
64 64
65 // Required for windows compatibility.
66 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
67 config.device_class = 0xEF;
68 config.device_sub_class = 0x02;
69 config.device_protocol = 0x01;
70 config.composite_with_iads = true;
71
72 // Create embassy-usb DeviceBuilder using the driver and config. 65 // Create embassy-usb DeviceBuilder using the driver and config.
73 // It needs some buffers for building the descriptors. 66 // It needs some buffers for building the descriptors.
74 let mut config_descriptor = [0; 256]; 67 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32l432/.cargo/config.toml b/examples/stm32l432/.cargo/config.toml
new file mode 100644
index 000000000..0a42c584b
--- /dev/null
+++ b/examples/stm32l432/.cargo/config.toml
@@ -0,0 +1,13 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG"
5#runner = "probe-rs run --chip STM32L4S5QI"
6runner = "probe-rs run --chip STM32L432KCUx --connect-under-reset --speed 3300"
7
8
9[build]
10target = "thumbv7em-none-eabi"
11
12[env]
13DEFMT_LOG = "trace"
diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml
new file mode 100644
index 000000000..c38462355
--- /dev/null
+++ b/examples/stm32l432/Cargo.toml
@@ -0,0 +1,30 @@
1[package]
2edition = "2021"
3name = "embassy-stm32l4-examples"
4version = "0.1.1"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] }
13defmt = "1.0.1"
14defmt-rtt = "1.0.0"
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6"
19embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
20embedded-hal-async = { version = "1.0" }
21embedded-hal-bus = { version = "0.1", features = ["async"] }
22panic-probe = { version = "1.0.0", features = ["print-defmt"] }
23
24[profile.release]
25debug = 2
26
27[[bin]]
28name = "qspi_mmap"
29path = "src/bin/qspi_mmap.rs"
30test = false
diff --git a/examples/stm32l432/README.md b/examples/stm32l432/README.md
new file mode 100644
index 000000000..3dac97f03
--- /dev/null
+++ b/examples/stm32l432/README.md
@@ -0,0 +1,30 @@
1
2# Examples for STM32L432 family
3
4Examples in this repo should work with [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) board.
5
6Run individual examples with
7```
8cargo run --bin <module-name>
9```
10for example
11```
12cargo run --bin blinky
13```
14
15
16
17## Checklist before running examples
18You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
19
20* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L432KCU6 it should be `probe-rs run --chip STM32L432KCUx`. (use `probe-rs chip list` to find your chip)
21* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L432KCU6 it should be `stm32l432kc`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
22* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
23* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
24
25If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
26
27* Which example you are trying to run
28* Which chip and board you are using
29
30Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32l432/build.rs b/examples/stm32l432/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32l432/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/stm32l432/src/bin/qspi_mmap.rs b/examples/stm32l432/src/bin/qspi_mmap.rs
new file mode 100644
index 000000000..86a20eb3d
--- /dev/null
+++ b/examples/stm32l432/src/bin/qspi_mmap.rs
@@ -0,0 +1,274 @@
1#![no_std]
2#![no_main]
3#![allow(dead_code)]
4/// This example demonstrates how to use the QSPI peripheral in both indirect-mode and memory-mapped mode.
5/// If you want to test this example, please pay attention to flash pins and check flash device datasheet
6/// to make sure operations in this example are compatible with your device, especially registers I/O operations.
7use defmt::info;
8use embassy_stm32::mode;
9use embassy_stm32::qspi::enums::{
10 AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, MemorySize, QspiWidth,
11};
12use embassy_stm32::qspi::{self, Instance, TransferConfig};
13pub struct FlashMemory<I: Instance> {
14 qspi: qspi::Qspi<'static, I, mode::Async>,
15}
16use embassy_executor::Spawner;
17use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _};
19
20const MEMORY_PAGE_SIZE: usize = 256;
21const CMD_READ_SR: u8 = 0x05;
22const CMD_READ_CR: u8 = 0x35;
23const CMD_QUAD_READ: u8 = 0x6B;
24const CMD_QUAD_WRITE_PG: u8 = 0x32;
25const CMD_READ_ID: u8 = 0x9F;
26const CMD_READ_MID: u8 = 0x90;
27const CMD_READ_UUID: u8 = 0x4B;
28const CMD_ENABLE_RESET: u8 = 0x66;
29const CMD_RESET: u8 = 0x99;
30const CMD_WRITE_ENABLE: u8 = 0x06;
31const CMD_SECTOR_ERASE: u8 = 0x20;
32
33const CMD_WRITE_SR: u8 = 0x01;
34
35impl<I: Instance> FlashMemory<I> {
36 pub fn new(qspi: qspi::Qspi<'static, I, mode::Async>) -> Self {
37 let mut memory = Self { qspi };
38
39 memory.reset_memory();
40 memory.enable_quad();
41
42 memory
43 }
44 fn enable_quad(&mut self) {
45 let sr = self.read_sr_lsb();
46 let cr = self.read_sr_msb();
47
48 self.write_sr(sr, cr | 0x02);
49 }
50 fn read_register(&mut self, cmd: u8) -> u8 {
51 let mut buffer = [0; 1];
52 let transaction = TransferConfig {
53 iwidth: QspiWidth::SING,
54 awidth: QspiWidth::NONE,
55 dwidth: QspiWidth::SING,
56 instruction: cmd,
57 address: None,
58 dummy: DummyCycles::_0,
59 };
60 self.qspi.blocking_read(&mut buffer, transaction);
61 buffer[0]
62 }
63
64 fn write_register(&mut self, cmd: u8, value: u8) {
65 let buffer = [value; 1];
66 let transaction: TransferConfig = TransferConfig {
67 iwidth: QspiWidth::SING,
68 awidth: QspiWidth::NONE,
69 dwidth: QspiWidth::SING,
70 instruction: cmd,
71 address: None,
72 dummy: DummyCycles::_0,
73 };
74 self.qspi.blocking_write(&buffer, transaction);
75 }
76 pub fn write_sr(&mut self, lsb: u8, msb: u8) {
77 let buffer = [lsb, msb];
78 let transaction: TransferConfig = TransferConfig {
79 iwidth: QspiWidth::SING,
80 awidth: QspiWidth::NONE,
81 dwidth: QspiWidth::SING,
82 instruction: CMD_WRITE_SR,
83 address: None,
84 dummy: DummyCycles::_0,
85 };
86 self.qspi.blocking_write(&buffer, transaction);
87 }
88
89 pub fn read_sr_lsb(&mut self) -> u8 {
90 self.read_register(CMD_READ_SR)
91 }
92 pub fn read_sr_msb(&mut self) -> u8 {
93 self.read_register(CMD_READ_CR)
94 }
95
96 pub fn reset_memory(&mut self) {
97 self.exec_command(CMD_ENABLE_RESET);
98 self.exec_command(CMD_RESET);
99 self.wait_write_finish();
100 }
101 fn exec_command(&mut self, cmd: u8) {
102 let transaction = TransferConfig {
103 iwidth: QspiWidth::SING,
104 awidth: QspiWidth::NONE,
105 dwidth: QspiWidth::NONE,
106 instruction: cmd,
107 address: None,
108 dummy: DummyCycles::_0,
109 };
110 self.qspi.blocking_command(transaction);
111 }
112 fn wait_write_finish(&mut self) {
113 while (self.read_sr_lsb() & 0x01) != 0 {}
114 }
115
116 pub fn read_mid(&mut self) -> [u8; 2] {
117 let mut buffer = [0; 2];
118 let transaction: TransferConfig = TransferConfig {
119 iwidth: QspiWidth::SING,
120 awidth: QspiWidth::SING,
121 dwidth: QspiWidth::SING,
122 instruction: CMD_READ_MID,
123 address: Some(0),
124 dummy: DummyCycles::_0,
125 };
126 self.qspi.blocking_read(&mut buffer, transaction);
127 buffer
128 }
129 pub fn read_uuid(&mut self) -> [u8; 16] {
130 let mut buffer = [0; 16];
131 let transaction: TransferConfig = TransferConfig {
132 iwidth: QspiWidth::SING,
133 awidth: QspiWidth::SING,
134 dwidth: QspiWidth::SING,
135 instruction: CMD_READ_UUID,
136 address: Some(0),
137 dummy: DummyCycles::_8,
138 };
139 self.qspi.blocking_read(&mut buffer, transaction);
140 buffer
141 }
142 pub fn read_id(&mut self) -> [u8; 3] {
143 let mut buffer = [0; 3];
144 let transaction: TransferConfig = TransferConfig {
145 iwidth: QspiWidth::SING,
146 awidth: QspiWidth::NONE,
147 dwidth: QspiWidth::SING,
148 instruction: CMD_READ_ID,
149 address: None,
150 dummy: DummyCycles::_0,
151 };
152 self.qspi.blocking_read(&mut buffer, transaction);
153 buffer
154 }
155
156 pub fn enable_mmap(&mut self) {
157 let transaction: TransferConfig = TransferConfig {
158 iwidth: QspiWidth::SING,
159 awidth: QspiWidth::SING,
160 dwidth: QspiWidth::QUAD,
161 instruction: CMD_QUAD_READ,
162 address: Some(0),
163 dummy: DummyCycles::_8,
164 };
165 self.qspi.enable_memory_map(&transaction);
166 }
167 fn perform_erase(&mut self, addr: u32, cmd: u8) {
168 let transaction = TransferConfig {
169 iwidth: QspiWidth::SING,
170 awidth: QspiWidth::SING,
171 dwidth: QspiWidth::NONE,
172 instruction: cmd,
173 address: Some(addr),
174 dummy: DummyCycles::_0,
175 };
176 self.enable_write();
177 self.qspi.blocking_command(transaction);
178 self.wait_write_finish();
179 }
180 pub fn enable_write(&mut self) {
181 self.exec_command(CMD_WRITE_ENABLE);
182 }
183 pub fn erase_sector(&mut self, addr: u32) {
184 self.perform_erase(addr, CMD_SECTOR_ERASE);
185 }
186 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
187 assert!(
188 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
189 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
190 len,
191 addr
192 );
193
194 let transaction = TransferConfig {
195 iwidth: QspiWidth::SING,
196 awidth: QspiWidth::SING,
197 dwidth: QspiWidth::QUAD,
198 instruction: CMD_QUAD_WRITE_PG,
199 address: Some(addr),
200 dummy: DummyCycles::_0,
201 };
202 self.enable_write();
203 if use_dma {
204 self.qspi.blocking_write_dma(buffer, transaction);
205 } else {
206 self.qspi.blocking_write(buffer, transaction);
207 }
208 self.wait_write_finish();
209 }
210 pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
211 let mut left = buffer.len();
212 let mut place = addr;
213 let mut chunk_start = 0;
214
215 while left > 0 {
216 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
217 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
218 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
219 self.write_page(place, chunk, chunk_size, use_dma);
220 place += chunk_size as u32;
221 left -= chunk_size;
222 chunk_start += chunk_size;
223 }
224 }
225
226 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
227 let transaction = TransferConfig {
228 iwidth: QspiWidth::SING,
229 awidth: QspiWidth::SING,
230 dwidth: QspiWidth::QUAD,
231 instruction: CMD_QUAD_READ,
232 address: Some(addr),
233 dummy: DummyCycles::_8,
234 };
235 if use_dma {
236 self.qspi.blocking_read_dma(buffer, transaction);
237 } else {
238 self.qspi.blocking_read(buffer, transaction);
239 }
240 }
241}
242
243const MEMORY_ADDR: u32 = 0x00000000 as u32;
244
245#[embassy_executor::main]
246async fn main(_spawner: Spawner) {
247 let p = embassy_stm32::init(Default::default());
248
249 let config = qspi::Config {
250 memory_size: MemorySize::_16MiB,
251 address_size: AddressSize::_24bit,
252 prescaler: 200,
253 cs_high_time: ChipSelectHighTime::_1Cycle,
254 fifo_threshold: FIFOThresholdLevel::_16Bytes,
255 };
256 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config);
257 let mut flash = FlashMemory::new(driver);
258 let mut wr_buf = [0u8; 256];
259 for i in 0..32 {
260 wr_buf[i] = i as u8;
261 }
262 let mut rd_buf = [0u8; 32];
263 flash.erase_sector(MEMORY_ADDR);
264 flash.write_memory(MEMORY_ADDR, &wr_buf, false);
265 flash.read_memory(MEMORY_ADDR, &mut rd_buf, false);
266
267 info!("data read from indirect mode: {}", rd_buf);
268 flash.enable_mmap();
269 let qspi_base = unsafe { core::slice::from_raw_parts(0x9000_0000 as *const u8, 32) };
270 info!("data read from mmap: {}", qspi_base);
271 loop {
272 Timer::after_millis(1000).await;
273 }
274}
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 16c184de2..3ea3bcd5c 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -6,24 +6,23 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power", "dual-bank"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.4.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.7.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.8.1" 16usbd-hid = "0.8.1"
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "1.0.0", features = ["print-defmt"] }
21 21
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"
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26rand_core = { version = "0.6.3", default-features = false }
27embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.6.1" }
28static_cell = "2" 27static_cell = "2"
29 28
diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs
index 32a736de8..d7a1efea9 100644
--- a/examples/stm32l5/src/bin/stop.rs
+++ b/examples/stm32l5/src/bin/stop.rs
@@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
7use embassy_stm32::low_power::Executor; 7use embassy_stm32::low_power::Executor;
8use embassy_stm32::rcc::LsConfig; 8use embassy_stm32::rcc::LsConfig;
9use embassy_stm32::rtc::{Rtc, RtcConfig}; 9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::Config; 10use embassy_stm32::{Config, Peri};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use static_cell::StaticCell; 12use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -39,7 +39,7 @@ async fn async_main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn blinky(led: AnyPin) -> ! { 42async fn blinky(led: Peri<'static, AnyPin>) -> ! {
43 let mut led = Output::new(led, Level::Low, Speed::Low); 43 let mut led = Output::new(led, Level::Low, Speed::Low);
44 loop { 44 loop {
45 info!("high"); 45 info!("high");
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index d02bac91d..6c72132c6 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.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_stm32::rng::Rng; 8use embassy_stm32::rng::Rng;
9use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config};
@@ -12,7 +12,6 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
12use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 12use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
13use embassy_usb::{Builder, UsbDevice}; 13use embassy_usb::{Builder, UsbDevice};
14use embedded_io_async::Write; 14use embedded_io_async::Write;
15use rand_core::RngCore;
16use static_cell::StaticCell; 15use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
18 17
@@ -36,8 +35,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
36} 35}
37 36
38#[embassy_executor::task] 37#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 38async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
40 stack.run().await 39 runner.run().await
41} 40}
42 41
43#[embassy_executor::main] 42#[embassy_executor::main]
@@ -72,12 +71,6 @@ async fn main(spawner: Spawner) {
72 config.max_power = 100; 71 config.max_power = 100;
73 config.max_packet_size_0 = 64; 72 config.max_packet_size_0 = 64;
74 73
75 // Required for Windows support.
76 config.composite_with_iads = true;
77 config.device_class = 0xEF;
78 config.device_sub_class = 0x02;
79 config.device_protocol = 0x01;
80
81 // Create embassy-usb DeviceBuilder using the driver and config. 74 // Create embassy-usb DeviceBuilder using the driver and config.
82 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 75 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
83 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 76 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
@@ -121,11 +114,10 @@ async fn main(spawner: Spawner) {
121 let seed = rng.next_u64(); 114 let seed = rng.next_u64();
122 115
123 // Init network stack 116 // Init network stack
124 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
125 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 117 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
126 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 118 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
127 119
128 unwrap!(spawner.spawn(net_task(stack))); 120 unwrap!(spawner.spawn(net_task(runner)));
129 121
130 // And now we can use it! 122 // And now we can use it!
131 123
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
index 2e890cdb5..3aa45dc79 100644
--- a/examples/stm32u0/Cargo.toml
+++ b/examples/stm32u0/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32u083rc to your chip name, if necessary. 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"] } 9embassy-stm32 = { version = "0.2.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"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", 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"] } 13embassy-usb = { version = "0.4.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 = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24 24
25micromath = "2.0.0" 25micromath = "2.0.0"
diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs
index fdbf1d374..50db0e082 100644
--- a/examples/stm32u0/src/bin/dac.rs
+++ b/examples/stm32u0/src/bin/dac.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dac::{DacCh1, Value}; 5use embassy_stm32::dac::{DacCh1, Value};
6use embassy_stm32::dma::NoDma;
7use {defmt_rtt as _, panic_probe as _}; 6use {defmt_rtt as _, panic_probe as _};
8 7
9#[cortex_m_rt::entry] 8#[cortex_m_rt::entry]
@@ -11,7 +10,7 @@ fn main() -> ! {
11 let p = embassy_stm32::init(Default::default()); 10 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!"); 11 info!("Hello World!");
13 12
14 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 13 let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
15 14
16 loop { 15 loop {
17 for v in 0..=255 { 16 for v in 0..=255 {
diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs
index 5693a3765..e03591daf 100644
--- a/examples/stm32u0/src/bin/spi.rs
+++ b/examples/stm32u0/src/bin/spi.rs
@@ -18,7 +18,7 @@ fn main() -> ! {
18 18
19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
20 20
21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PC13, Level::High, Speed::VeryHigh);
22 22
23 loop { 23 loop {
24 let mut buf = [0x0Au8; 4]; 24 let mut buf = [0x0Au8; 4];
diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml
index 36c5b63a6..bdbd86354 100644
--- a/examples/stm32u5/.cargo/config.toml
+++ b/examples/stm32u5/.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 STM32U585AIIx with your chip as listed in `probe-rs chip list` 2# replace STM32U5G9ZJTxQ with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32U585AIIx" 3runner = "probe-rs run --chip STM32U5G9ZJTxQ"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 20d64c6f7..777d3ed4c 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -5,22 +5,24 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u5g9zj 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.2.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.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", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.4.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 = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24embedded-graphics = { version = "0.8.1" }
25tinybmp = { version = "0.6.0" }
24 26
25micromath = "2.0.0" 27micromath = "2.0.0"
26 28
diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs
new file mode 100644
index 000000000..d2aa28087
--- /dev/null
+++ b/examples/stm32u5/src/bin/adc.rs
@@ -0,0 +1,109 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::adc;
6use embassy_stm32::adc::{adc4, AdcChannel};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: embassy_executor::Spawner) {
11 let config = embassy_stm32::Config::default();
12
13 let mut p = embassy_stm32::init(config);
14
15 // **** ADC1 init ****
16 let mut adc1 = adc::Adc::new(p.ADC1);
17 let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5
18 let mut adc1_pin2 = p.PA2; // A1
19 adc1.set_resolution(adc::Resolution::BITS14);
20 adc1.set_averaging(adc::Averaging::Samples1024);
21 adc1.set_sample_time(adc::SampleTime::CYCLES160_5);
22 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14);
23
24 // **** ADC2 init ****
25 let mut adc2 = adc::Adc::new(p.ADC2);
26 let mut adc2_pin1 = p.PC3; // A2
27 let mut adc2_pin2 = p.PB0; // A3
28 adc2.set_resolution(adc::Resolution::BITS14);
29 adc2.set_averaging(adc::Averaging::Samples1024);
30 adc2.set_sample_time(adc::SampleTime::CYCLES160_5);
31 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14);
32
33 // **** ADC4 init ****
34 let mut adc4 = adc4::Adc4::new(p.ADC4);
35 let mut adc4_pin1 = p.PC1; // A4
36 let mut adc4_pin2 = p.PC0; // A5
37 adc4.set_resolution(adc4::Resolution::BITS12);
38 adc4.set_averaging(adc4::Averaging::Samples256);
39 adc4.set_sample_time(adc4::SampleTime::CYCLES1_5);
40 let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12);
41
42 // **** ADC1 blocking read ****
43 let raw: u16 = adc1.blocking_read(&mut adc1_pin1);
44 let volt: f32 = 3.3 * raw as f32 / max1 as f32;
45 info!("Read adc1 pin 1 {}", volt);
46
47 let raw: u16 = adc1.blocking_read(&mut adc1_pin2);
48 let volt: f32 = 3.3 * raw as f32 / max1 as f32;
49 info!("Read adc1 pin 2 {}", volt);
50
51 // **** ADC2 blocking read ****
52 let raw: u16 = adc2.blocking_read(&mut adc2_pin1);
53 let volt: f32 = 3.3 * raw as f32 / max2 as f32;
54 info!("Read adc2 pin 1 {}", volt);
55
56 let raw: u16 = adc2.blocking_read(&mut adc2_pin2);
57 let volt: f32 = 3.3 * raw as f32 / max2 as f32;
58 info!("Read adc2 pin 2 {}", volt);
59
60 // **** ADC4 blocking read ****
61 let raw: u16 = adc4.blocking_read(&mut adc4_pin1);
62 let volt: f32 = 3.3 * raw as f32 / max4 as f32;
63 info!("Read adc4 pin 1 {}", volt);
64
65 let raw: u16 = adc4.blocking_read(&mut adc4_pin2);
66 let volt: f32 = 3.3 * raw as f32 / max4 as f32;
67 info!("Read adc4 pin 2 {}", volt);
68
69 // **** ADC1 async read ****
70 let mut degraded11 = adc1_pin1.degrade_adc();
71 let mut degraded12 = adc1_pin2.degrade_adc();
72 let mut measurements = [0u16; 2];
73
74 adc1.read(
75 p.GPDMA1_CH0.reborrow(),
76 [
77 (&mut degraded11, adc::SampleTime::CYCLES160_5),
78 (&mut degraded12, adc::SampleTime::CYCLES160_5),
79 ]
80 .into_iter(),
81 &mut measurements,
82 )
83 .await;
84 let volt1: f32 = 3.3 * measurements[0] as f32 / max1 as f32;
85 let volt2: f32 = 3.3 * measurements[1] as f32 / max1 as f32;
86
87 info!("Async read 1 pin 1 {}", volt1);
88 info!("Async read 1 pin 2 {}", volt2);
89
90 // **** ADC2 does not support async read ****
91
92 // **** ADC4 async read ****
93 let mut degraded41 = adc4_pin1.degrade_adc();
94 let mut degraded42 = adc4_pin2.degrade_adc();
95 let mut measurements = [0u16; 2];
96
97 // The channels must be in ascending order and can't repeat for ADC4
98 adc4.read(
99 p.GPDMA1_CH1.reborrow(),
100 [&mut degraded42, &mut degraded41].into_iter(),
101 &mut measurements,
102 )
103 .await
104 .unwrap();
105 let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32;
106 let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32;
107 info!("Async read 4 pin 1 {}", volt1);
108 info!("Async read 4 pin 2 {}", volt2);
109}
diff --git a/examples/stm32u5/src/bin/blinky.rs b/examples/stm32u5/src/bin/blinky.rs
index 7fe88c183..1fdfc7679 100644
--- a/examples/stm32u5/src/bin/blinky.rs
+++ b/examples/stm32u5/src/bin/blinky.rs
@@ -12,7 +12,8 @@ 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 led = Output::new(p.PH7, Level::Low, Speed::Medium); 15 // replace PC13 with the right pin for your board.
16 let mut led = Output::new(p.PC13, Level::Low, Speed::Medium);
16 17
17 loop { 18 loop {
18 defmt::info!("on!"); 19 defmt::info!("on!");
diff --git a/examples/stm32u5/src/bin/ferris.bmp b/examples/stm32u5/src/bin/ferris.bmp
new file mode 100644
index 000000000..7a222ab84
--- /dev/null
+++ b/examples/stm32u5/src/bin/ferris.bmp
Binary files differ
diff --git a/examples/stm32u5/src/bin/hspi_memory_mapped.rs b/examples/stm32u5/src/bin/hspi_memory_mapped.rs
new file mode 100644
index 000000000..9fef4855e
--- /dev/null
+++ b/examples/stm32u5/src/bin/hspi_memory_mapped.rs
@@ -0,0 +1,455 @@
1#![no_main]
2#![no_std]
3
4// Tested on an STM32U5G9J-DK2 demo board using the on-board MX66LM1G45G flash memory
5// The flash is connected to the HSPI1 port as an OCTA-DTR device
6//
7// Use embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ"
8
9use defmt::info;
10use embassy_executor::Spawner;
11use embassy_stm32::hspi::{
12 AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Hspi, HspiWidth, Instance, MemorySize,
13 MemoryType, TransferConfig, WrapSize,
14};
15use embassy_stm32::mode::Async;
16use embassy_stm32::rcc;
17use embassy_stm32::time::Hertz;
18use {defmt_rtt as _, panic_probe as _};
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Start hspi_memory_mapped");
23
24 // RCC config
25 let mut config = embassy_stm32::Config::default();
26 config.rcc.hse = Some(rcc::Hse {
27 freq: Hertz(16_000_000),
28 mode: rcc::HseMode::Oscillator,
29 });
30 config.rcc.pll1 = Some(rcc::Pll {
31 source: rcc::PllSource::HSE,
32 prediv: rcc::PllPreDiv::DIV1,
33 mul: rcc::PllMul::MUL10,
34 divp: None,
35 divq: None,
36 divr: Some(rcc::PllDiv::DIV1),
37 });
38 config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz
39 config.rcc.pll2 = Some(rcc::Pll {
40 source: rcc::PllSource::HSE,
41 prediv: rcc::PllPreDiv::DIV4,
42 mul: rcc::PllMul::MUL66,
43 divp: None,
44 divq: Some(rcc::PllDiv::DIV2),
45 divr: None,
46 });
47 config.rcc.mux.hspi1sel = rcc::mux::Hspisel::PLL2_Q; // 132 MHz
48
49 // Initialize peripherals
50 let p = embassy_stm32::init(config);
51
52 let flash_config = embassy_stm32::hspi::Config {
53 fifo_threshold: FIFOThresholdLevel::_4Bytes,
54 memory_type: MemoryType::Macronix,
55 device_size: MemorySize::_1GiB,
56 chip_select_high_time: ChipSelectHighTime::_2Cycle,
57 free_running_clock: false,
58 clock_mode: false,
59 wrap_size: WrapSize::None,
60 clock_prescaler: 0,
61 sample_shifting: false,
62 delay_hold_quarter_cycle: false,
63 chip_select_boundary: 0,
64 delay_block_bypass: false,
65 max_transfer: 0,
66 refresh: 0,
67 };
68
69 let use_dma = true;
70
71 info!("Testing flash in OCTA DTR mode and memory mapped mode");
72
73 let hspi = Hspi::new_octospi(
74 p.HSPI1,
75 p.PI3,
76 p.PH10,
77 p.PH11,
78 p.PH12,
79 p.PH13,
80 p.PH14,
81 p.PH15,
82 p.PI0,
83 p.PI1,
84 p.PH9,
85 p.PI2,
86 p.GPDMA1_CH7,
87 flash_config,
88 );
89
90 let mut flash = OctaDtrFlashMemory::new(hspi).await;
91
92 let flash_id = flash.read_id();
93 info!("FLASH ID: {=[u8]:x}", flash_id);
94
95 let mut rd_buf = [0u8; 16];
96 flash.read_memory(0, &mut rd_buf, use_dma).await;
97 info!("READ BUF: {=[u8]:#X}", rd_buf);
98
99 flash.erase_sector(0).await;
100 flash.read_memory(0, &mut rd_buf, use_dma).await;
101 info!("READ BUF: {=[u8]:#X}", rd_buf);
102 assert_eq!(rd_buf[0], 0xFF);
103 assert_eq!(rd_buf[15], 0xFF);
104
105 let mut wr_buf = [0u8; 16];
106 for i in 0..wr_buf.len() {
107 wr_buf[i] = i as u8;
108 }
109 info!("WRITE BUF: {=[u8]:#X}", wr_buf);
110 flash.write_memory(0, &wr_buf, use_dma).await;
111 flash.read_memory(0, &mut rd_buf, use_dma).await;
112 info!("READ BUF: {=[u8]:#X}", rd_buf);
113 assert_eq!(rd_buf[0], 0x00);
114 assert_eq!(rd_buf[15], 0x0F);
115
116 flash.enable_mm().await;
117 info!("Enabled memory mapped mode");
118
119 let first_u32 = unsafe { *(0xA0000000 as *const u32) };
120 info!("first_u32: 0x{=u32:X}", first_u32);
121 assert_eq!(first_u32, 0x03020100);
122
123 let second_u32 = unsafe { *(0xA0000004 as *const u32) };
124 assert_eq!(second_u32, 0x07060504);
125 info!("second_u32: 0x{=u32:X}", second_u32);
126
127 let first_u8 = unsafe { *(0xA0000000 as *const u8) };
128 assert_eq!(first_u8, 00);
129 info!("first_u8: 0x{=u8:X}", first_u8);
130
131 let second_u8 = unsafe { *(0xA0000001 as *const u8) };
132 assert_eq!(second_u8, 0x01);
133 info!("second_u8: 0x{=u8:X}", second_u8);
134
135 let third_u8 = unsafe { *(0xA0000002 as *const u8) };
136 assert_eq!(third_u8, 0x02);
137 info!("third_u8: 0x{=u8:X}", third_u8);
138
139 let fourth_u8 = unsafe { *(0xA0000003 as *const u8) };
140 assert_eq!(fourth_u8, 0x03);
141 info!("fourth_u8: 0x{=u8:X}", fourth_u8);
142
143 info!("DONE");
144}
145
146// Custom implementation for MX66UW1G45G NOR flash memory from Macronix.
147// Chip commands are hardcoded as they depend on the chip used.
148// This implementation enables Octa I/O (OPI) and Double Transfer Rate (DTR)
149
150pub struct OctaDtrFlashMemory<'d, I: Instance> {
151 hspi: Hspi<'d, I, Async>,
152}
153
154impl<'d, I: Instance> OctaDtrFlashMemory<'d, I> {
155 const MEMORY_PAGE_SIZE: usize = 256;
156
157 const CMD_READ_OCTA_DTR: u16 = 0xEE11;
158 const CMD_PAGE_PROGRAM_OCTA_DTR: u16 = 0x12ED;
159
160 const CMD_READ_ID_OCTA_DTR: u16 = 0x9F60;
161
162 const CMD_RESET_ENABLE: u8 = 0x66;
163 const CMD_RESET_ENABLE_OCTA_DTR: u16 = 0x6699;
164 const CMD_RESET: u8 = 0x99;
165 const CMD_RESET_OCTA_DTR: u16 = 0x9966;
166
167 const CMD_WRITE_ENABLE: u8 = 0x06;
168 const CMD_WRITE_ENABLE_OCTA_DTR: u16 = 0x06F9;
169
170 const CMD_SECTOR_ERASE_OCTA_DTR: u16 = 0x21DE;
171 const CMD_BLOCK_ERASE_OCTA_DTR: u16 = 0xDC23;
172
173 const CMD_READ_SR: u8 = 0x05;
174 const CMD_READ_SR_OCTA_DTR: u16 = 0x05FA;
175
176 const CMD_READ_CR2: u8 = 0x71;
177 const CMD_WRITE_CR2: u8 = 0x72;
178
179 const CR2_REG1_ADDR: u32 = 0x00000000;
180 const CR2_OCTA_DTR: u8 = 0x02;
181
182 const CR2_REG3_ADDR: u32 = 0x00000300;
183 const CR2_DC_6_CYCLES: u8 = 0x07;
184
185 pub async fn new(hspi: Hspi<'d, I, Async>) -> Self {
186 let mut memory = Self { hspi };
187
188 memory.reset_memory().await;
189 memory.enable_octa_dtr().await;
190 memory
191 }
192
193 async fn enable_octa_dtr(&mut self) {
194 self.write_enable_spi().await;
195 self.write_cr2_spi(Self::CR2_REG3_ADDR, Self::CR2_DC_6_CYCLES);
196 self.write_enable_spi().await;
197 self.write_cr2_spi(Self::CR2_REG1_ADDR, Self::CR2_OCTA_DTR);
198 }
199
200 pub async fn enable_mm(&mut self) {
201 let read_config = TransferConfig {
202 iwidth: HspiWidth::OCTO,
203 instruction: Some(Self::CMD_READ_OCTA_DTR as u32),
204 isize: AddressSize::_16Bit,
205 idtr: true,
206 adwidth: HspiWidth::OCTO,
207 adsize: AddressSize::_32Bit,
208 addtr: true,
209 dwidth: HspiWidth::OCTO,
210 ddtr: true,
211 dummy: DummyCycles::_6,
212 ..Default::default()
213 };
214
215 let write_config = TransferConfig {
216 iwidth: HspiWidth::OCTO,
217 isize: AddressSize::_16Bit,
218 idtr: true,
219 adwidth: HspiWidth::OCTO,
220 adsize: AddressSize::_32Bit,
221 addtr: true,
222 dwidth: HspiWidth::OCTO,
223 ddtr: true,
224 ..Default::default()
225 };
226 self.hspi.enable_memory_mapped_mode(read_config, write_config).unwrap();
227 }
228
229 async fn exec_command_spi(&mut self, cmd: u8) {
230 let transaction = TransferConfig {
231 iwidth: HspiWidth::SING,
232 instruction: Some(cmd as u32),
233 ..Default::default()
234 };
235 info!("Excuting command: 0x{:X}", transaction.instruction.unwrap());
236 self.hspi.blocking_command(&transaction).unwrap();
237 }
238
239 async fn exec_command_octa_dtr(&mut self, cmd: u16) {
240 let transaction = TransferConfig {
241 iwidth: HspiWidth::OCTO,
242 instruction: Some(cmd as u32),
243 isize: AddressSize::_16Bit,
244 idtr: true,
245 ..Default::default()
246 };
247 info!("Excuting command: 0x{:X}", transaction.instruction.unwrap());
248 self.hspi.blocking_command(&transaction).unwrap();
249 }
250
251 fn wait_write_finish_spi(&mut self) {
252 while (self.read_sr_spi() & 0x01) != 0 {}
253 }
254
255 fn wait_write_finish_octa_dtr(&mut self) {
256 while (self.read_sr_octa_dtr() & 0x01) != 0 {}
257 }
258
259 pub async fn reset_memory(&mut self) {
260 // servono entrambi i comandi?
261 self.exec_command_octa_dtr(Self::CMD_RESET_ENABLE_OCTA_DTR).await;
262 self.exec_command_octa_dtr(Self::CMD_RESET_OCTA_DTR).await;
263 self.exec_command_spi(Self::CMD_RESET_ENABLE).await;
264 self.exec_command_spi(Self::CMD_RESET).await;
265 self.wait_write_finish_spi();
266 }
267
268 async fn write_enable_spi(&mut self) {
269 self.exec_command_spi(Self::CMD_WRITE_ENABLE).await;
270 }
271
272 async fn write_enable_octa_dtr(&mut self) {
273 self.exec_command_octa_dtr(Self::CMD_WRITE_ENABLE_OCTA_DTR).await;
274 }
275
276 pub fn read_id(&mut self) -> [u8; 3] {
277 let mut buffer = [0; 6];
278 let transaction: TransferConfig = TransferConfig {
279 iwidth: HspiWidth::OCTO,
280 instruction: Some(Self::CMD_READ_ID_OCTA_DTR as u32),
281 isize: AddressSize::_16Bit,
282 idtr: true,
283 adwidth: HspiWidth::OCTO,
284 address: Some(0),
285 adsize: AddressSize::_32Bit,
286 addtr: true,
287 dwidth: HspiWidth::OCTO,
288 ddtr: true,
289 dummy: DummyCycles::_5,
290 ..Default::default()
291 };
292 info!("Reading flash id: 0x{:X}", transaction.instruction.unwrap());
293 self.hspi.blocking_read(&mut buffer, transaction).unwrap();
294 [buffer[0], buffer[2], buffer[4]]
295 }
296
297 pub async fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
298 let transaction = TransferConfig {
299 iwidth: HspiWidth::OCTO,
300 instruction: Some(Self::CMD_READ_OCTA_DTR as u32),
301 isize: AddressSize::_16Bit,
302 idtr: true,
303 adwidth: HspiWidth::OCTO,
304 address: Some(addr),
305 adsize: AddressSize::_32Bit,
306 addtr: true,
307 dwidth: HspiWidth::OCTO,
308 ddtr: true,
309 dummy: DummyCycles::_6,
310 ..Default::default()
311 };
312 if use_dma {
313 self.hspi.read(buffer, transaction).await.unwrap();
314 } else {
315 self.hspi.blocking_read(buffer, transaction).unwrap();
316 }
317 }
318
319 async fn perform_erase_octa_dtr(&mut self, addr: u32, cmd: u16) {
320 let transaction = TransferConfig {
321 iwidth: HspiWidth::OCTO,
322 instruction: Some(cmd as u32),
323 isize: AddressSize::_16Bit,
324 idtr: true,
325 adwidth: HspiWidth::OCTO,
326 address: Some(addr),
327 adsize: AddressSize::_32Bit,
328 addtr: true,
329 ..Default::default()
330 };
331 self.write_enable_octa_dtr().await;
332 self.hspi.blocking_command(&transaction).unwrap();
333 self.wait_write_finish_octa_dtr();
334 }
335
336 pub async fn erase_sector(&mut self, addr: u32) {
337 info!("Erasing 4K sector at address: 0x{:X}", addr);
338 self.perform_erase_octa_dtr(addr, Self::CMD_SECTOR_ERASE_OCTA_DTR).await;
339 }
340
341 pub async fn erase_block(&mut self, addr: u32) {
342 info!("Erasing 64K block at address: 0x{:X}", addr);
343 self.perform_erase_octa_dtr(addr, Self::CMD_BLOCK_ERASE_OCTA_DTR).await;
344 }
345
346 async fn write_page_octa_dtr(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
347 assert!(
348 (len as u32 + (addr & 0x000000ff)) <= Self::MEMORY_PAGE_SIZE as u32,
349 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
350 len,
351 addr
352 );
353
354 let transaction = TransferConfig {
355 iwidth: HspiWidth::OCTO,
356 instruction: Some(Self::CMD_PAGE_PROGRAM_OCTA_DTR as u32),
357 isize: AddressSize::_16Bit,
358 idtr: true,
359 adwidth: HspiWidth::OCTO,
360 address: Some(addr),
361 adsize: AddressSize::_32Bit,
362 addtr: true,
363 dwidth: HspiWidth::OCTO,
364 ddtr: true,
365 ..Default::default()
366 };
367 self.write_enable_octa_dtr().await;
368 if use_dma {
369 self.hspi.write(buffer, transaction).await.unwrap();
370 } else {
371 self.hspi.blocking_write(buffer, transaction).unwrap();
372 }
373 self.wait_write_finish_octa_dtr();
374 }
375
376 pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
377 let mut left = buffer.len();
378 let mut place = addr;
379 let mut chunk_start = 0;
380
381 while left > 0 {
382 let max_chunk_size = Self::MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
383 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
384 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
385 self.write_page_octa_dtr(place, chunk, chunk_size, use_dma).await;
386 place += chunk_size as u32;
387 left -= chunk_size;
388 chunk_start += chunk_size;
389 }
390 }
391
392 pub fn read_sr_spi(&mut self) -> u8 {
393 let mut buffer = [0; 1];
394 let transaction: TransferConfig = TransferConfig {
395 iwidth: HspiWidth::SING,
396 instruction: Some(Self::CMD_READ_SR as u32),
397 dwidth: HspiWidth::SING,
398 ..Default::default()
399 };
400 self.hspi.blocking_read(&mut buffer, transaction).unwrap();
401 // info!("Read MX66LM1G45G SR register: 0x{:x}", buffer[0]);
402 buffer[0]
403 }
404
405 pub fn read_sr_octa_dtr(&mut self) -> u8 {
406 let mut buffer = [0; 2];
407 let transaction: TransferConfig = TransferConfig {
408 iwidth: HspiWidth::OCTO,
409 instruction: Some(Self::CMD_READ_SR_OCTA_DTR as u32),
410 isize: AddressSize::_16Bit,
411 idtr: true,
412 adwidth: HspiWidth::OCTO,
413 address: Some(0),
414 adsize: AddressSize::_32Bit,
415 addtr: true,
416 dwidth: HspiWidth::OCTO,
417 ddtr: true,
418 dummy: DummyCycles::_5,
419 ..Default::default()
420 };
421 self.hspi.blocking_read(&mut buffer, transaction).unwrap();
422 // info!("Read MX66LM1G45G SR register: 0x{:x}", buffer[0]);
423 buffer[0]
424 }
425
426 pub fn read_cr2_spi(&mut self, addr: u32) -> u8 {
427 let mut buffer = [0; 1];
428 let transaction: TransferConfig = TransferConfig {
429 iwidth: HspiWidth::SING,
430 instruction: Some(Self::CMD_READ_CR2 as u32),
431 adwidth: HspiWidth::SING,
432 address: Some(addr),
433 adsize: AddressSize::_32Bit,
434 dwidth: HspiWidth::SING,
435 ..Default::default()
436 };
437 self.hspi.blocking_read(&mut buffer, transaction).unwrap();
438 // info!("Read MX66LM1G45G CR2[0x{:X}] register: 0x{:x}", addr, buffer[0]);
439 buffer[0]
440 }
441
442 pub fn write_cr2_spi(&mut self, addr: u32, value: u8) {
443 let buffer = [value; 1];
444 let transaction: TransferConfig = TransferConfig {
445 iwidth: HspiWidth::SING,
446 instruction: Some(Self::CMD_WRITE_CR2 as u32),
447 adwidth: HspiWidth::SING,
448 address: Some(addr),
449 adsize: AddressSize::_32Bit,
450 dwidth: HspiWidth::SING,
451 ..Default::default()
452 };
453 self.hspi.blocking_write(&buffer, transaction).unwrap();
454 }
455}
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
index 19a78eac9..d5f5d6f60 100644
--- a/examples/stm32u5/src/bin/i2c.rs
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -13,7 +13,7 @@ const WHOAMI: u8 = 0x0F;
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 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()); 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default());
17 17
18 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs
new file mode 100644
index 000000000..bd59a9148
--- /dev/null
+++ b/examples/stm32u5/src/bin/ltdc.rs
@@ -0,0 +1,461 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![allow(static_mut_refs)]
5
6/// This example was derived from examples\stm32h735\src\bin\ltdc.rs
7/// It demonstrates the LTDC lcd display peripheral and was tested on an STM32U5G9J-DK2 demo board (embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ")
8///
9use bouncy_box::BouncyBox;
10use defmt::{info, unwrap};
11use embassy_executor::Spawner;
12use embassy_stm32::gpio::{Level, Output, Speed};
13use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge};
14use embassy_stm32::{bind_interrupts, peripherals};
15use embassy_time::{Duration, Timer};
16use embedded_graphics::draw_target::DrawTarget;
17use embedded_graphics::geometry::{OriginDimensions, Point, Size};
18use embedded_graphics::image::Image;
19use embedded_graphics::pixelcolor::raw::RawU24;
20use embedded_graphics::pixelcolor::Rgb888;
21use embedded_graphics::prelude::*;
22use embedded_graphics::primitives::Rectangle;
23use embedded_graphics::Pixel;
24use heapless::{Entry, FnvIndexMap};
25use tinybmp::Bmp;
26use {defmt_rtt as _, panic_probe as _};
27
28const DISPLAY_WIDTH: usize = 800;
29const DISPLAY_HEIGHT: usize = 480;
30const MY_TASK_POOL_SIZE: usize = 2;
31
32// the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu
33pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
34pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
35
36bind_interrupts!(struct Irqs {
37 LTDC => ltdc::InterruptHandler<peripherals::LTDC>;
38});
39
40const NUM_COLORS: usize = 256;
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = rcc_setup::stm32u5g9zj_init();
45
46 // enable ICACHE
47 embassy_stm32::pac::ICACHE.cr().write(|w| {
48 w.set_en(true);
49 });
50
51 // blink the led on another task
52 let led = Output::new(p.PD2, Level::High, Speed::Low);
53 unwrap!(spawner.spawn(led_task(led)));
54
55 // numbers from STM32U5G9J-DK2.ioc
56 const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization
57 const RK050HR18H_HBP: u16 = 8; // Horizontal back porch
58 const RK050HR18H_HFP: u16 = 8; // Horizontal front porch
59 const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization
60 const RK050HR18H_VBP: u16 = 8; // Vertical back porch
61 const RK050HR18H_VFP: u16 = 8; // Vertical front porch
62
63 // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization
64 let ltdc_config = LtdcConfiguration {
65 active_width: DISPLAY_WIDTH as _,
66 active_height: DISPLAY_HEIGHT as _,
67 h_back_porch: RK050HR18H_HBP,
68 h_front_porch: RK050HR18H_HFP,
69 v_back_porch: RK050HR18H_VBP,
70 v_front_porch: RK050HR18H_VFP,
71 h_sync: RK050HR18H_HSYNC,
72 v_sync: RK050HR18H_VSYNC,
73 h_sync_polarity: PolarityActive::ActiveHigh,
74 v_sync_polarity: PolarityActive::ActiveHigh,
75 data_enable_polarity: PolarityActive::ActiveHigh,
76 pixel_clock_polarity: PolarityEdge::RisingEdge,
77 };
78
79 info!("init ltdc");
80 let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High);
81 let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High);
82 let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High);
83 let mut ltdc = Ltdc::new_with_pins(
84 p.LTDC, // PERIPHERAL
85 Irqs, // IRQS
86 p.PD3, // CLK
87 p.PE0, // HSYNC
88 p.PD13, // VSYNC
89 p.PB9, // B0
90 p.PB2, // B1
91 p.PD14, // B2
92 p.PD15, // B3
93 p.PD0, // B4
94 p.PD1, // B5
95 p.PE7, // B6
96 p.PE8, // B7
97 p.PC8, // G0
98 p.PC9, // G1
99 p.PE9, // G2
100 p.PE10, // G3
101 p.PE11, // G4
102 p.PE12, // G5
103 p.PE13, // G6
104 p.PE14, // G7
105 p.PC6, // R0
106 p.PC7, // R1
107 p.PE15, // R2
108 p.PD8, // R3
109 p.PD9, // R4
110 p.PD10, // R5
111 p.PD11, // R6
112 p.PD12, // R7
113 );
114 ltdc.init(&ltdc_config);
115 ltdc_de.set_low();
116 ltdc_bl_ctrl.set_high();
117 ltdc_disp_ctrl.set_high();
118
119 // we only need to draw on one layer for this example (not to be confused with the double buffer)
120 info!("enable bottom layer");
121 let layer_config = LtdcLayerConfig {
122 pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel
123 layer: LtdcLayer::Layer1,
124 window_x0: 0,
125 window_x1: DISPLAY_WIDTH as _,
126 window_y0: 0,
127 window_y1: DISPLAY_HEIGHT as _,
128 };
129
130 let ferris_bmp: Bmp<Rgb888> = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap();
131 let color_map = build_color_lookup_map(&ferris_bmp);
132 let clut = build_clut(&color_map);
133
134 // enable the bottom layer with a 256 color lookup table
135 ltdc.init_layer(&layer_config, Some(&clut));
136
137 // Safety: the DoubleBuffer controls access to the statically allocated frame buffers
138 // and it is the only thing that mutates their content
139 let mut double_buffer = DoubleBuffer::new(
140 unsafe { FB1.as_mut() },
141 unsafe { FB2.as_mut() },
142 layer_config,
143 color_map,
144 );
145
146 // this allows us to perform some simple animation for every frame
147 let mut bouncy_box = BouncyBox::new(
148 ferris_bmp.bounding_box(),
149 Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)),
150 2,
151 );
152
153 loop {
154 // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen
155 double_buffer.clear();
156 let position = bouncy_box.next_point();
157 let ferris = Image::new(&ferris_bmp, position);
158 unwrap!(ferris.draw(&mut double_buffer));
159
160 // perform async dma data transfer to the lcd screen
161 unwrap!(double_buffer.swap(&mut ltdc).await);
162 }
163}
164
165/// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work.
166fn build_color_lookup_map(bmp: &Bmp<Rgb888>) -> FnvIndexMap<u32, u8, NUM_COLORS> {
167 let mut color_map: FnvIndexMap<u32, u8, NUM_COLORS> = heapless::FnvIndexMap::new();
168 let mut counter: u8 = 0;
169
170 // add black to position 0
171 color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap();
172 counter += 1;
173
174 for Pixel(_point, color) in bmp.pixels() {
175 let raw = color.into_storage();
176 if let Entry::Vacant(v) = color_map.entry(raw) {
177 v.insert(counter).expect("more than 256 colors detected");
178 counter += 1;
179 }
180 }
181 color_map
182}
183
184/// builds the color look-up table from the color map provided
185fn build_clut(color_map: &FnvIndexMap<u32, u8, NUM_COLORS>) -> [ltdc::RgbColor; NUM_COLORS] {
186 let mut clut = [ltdc::RgbColor::default(); NUM_COLORS];
187 for (color, index) in color_map.iter() {
188 let color = Rgb888::from(RawU24::new(*color));
189 clut[*index as usize] = ltdc::RgbColor {
190 red: color.r(),
191 green: color.g(),
192 blue: color.b(),
193 };
194 }
195
196 clut
197}
198
199#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)]
200async fn led_task(mut led: Output<'static>) {
201 let mut counter = 0;
202 loop {
203 info!("blink: {}", counter);
204 counter += 1;
205
206 // on
207 led.set_low();
208 Timer::after(Duration::from_millis(50)).await;
209
210 // off
211 led.set_high();
212 Timer::after(Duration::from_millis(450)).await;
213 }
214}
215
216pub type TargetPixelType = u8;
217
218// A simple double buffer
219pub struct DoubleBuffer {
220 buf0: &'static mut [TargetPixelType],
221 buf1: &'static mut [TargetPixelType],
222 is_buf0: bool,
223 layer_config: LtdcLayerConfig,
224 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
225}
226
227impl DoubleBuffer {
228 pub fn new(
229 buf0: &'static mut [TargetPixelType],
230 buf1: &'static mut [TargetPixelType],
231 layer_config: LtdcLayerConfig,
232 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
233 ) -> Self {
234 Self {
235 buf0,
236 buf1,
237 is_buf0: true,
238 layer_config,
239 color_map,
240 }
241 }
242
243 pub fn current(&mut self) -> (&FnvIndexMap<u32, u8, NUM_COLORS>, &mut [TargetPixelType]) {
244 if self.is_buf0 {
245 (&self.color_map, self.buf0)
246 } else {
247 (&self.color_map, self.buf1)
248 }
249 }
250
251 pub async fn swap<T: ltdc::Instance>(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> {
252 let (_, buf) = self.current();
253 let frame_buffer = buf.as_ptr();
254 self.is_buf0 = !self.is_buf0;
255 ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await
256 }
257
258 /// Clears the buffer
259 pub fn clear(&mut self) {
260 let (color_map, buf) = self.current();
261 let black = Rgb888::new(0, 0, 0).into_storage();
262 let color_index = color_map.get(&black).expect("no black found in the color map");
263
264 for a in buf.iter_mut() {
265 *a = *color_index; // solid black
266 }
267 }
268}
269
270// Implement DrawTarget for
271impl DrawTarget for DoubleBuffer {
272 type Color = Rgb888;
273 type Error = ();
274
275 /// Draw a pixel
276 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
277 where
278 I: IntoIterator<Item = Pixel<Self::Color>>,
279 {
280 let size = self.size();
281 let width = size.width as i32;
282 let height = size.height as i32;
283 let (color_map, buf) = self.current();
284
285 for pixel in pixels {
286 let Pixel(point, color) = pixel;
287
288 if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height {
289 let index = point.y * width + point.x;
290 let raw_color = color.into_storage();
291
292 match color_map.get(&raw_color) {
293 Some(x) => {
294 buf[index as usize] = *x;
295 }
296 None => panic!("color not found in color map: {}", raw_color),
297 };
298 } else {
299 // Ignore invalid points
300 }
301 }
302
303 Ok(())
304 }
305}
306
307impl OriginDimensions for DoubleBuffer {
308 /// Return the size of the display
309 fn size(&self) -> Size {
310 Size::new(
311 (self.layer_config.window_x1 - self.layer_config.window_x0) as _,
312 (self.layer_config.window_y1 - self.layer_config.window_y0) as _,
313 )
314 }
315}
316
317mod rcc_setup {
318
319 use embassy_stm32::time::Hertz;
320 use embassy_stm32::{rcc, Config, Peripherals};
321
322 /// Sets up clocks for the stm32u5g9zj mcu
323 /// change this if you plan to use a different microcontroller
324 pub fn stm32u5g9zj_init() -> Peripherals {
325 // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator
326 let mut config = Config::default();
327 config.rcc.hse = Some(rcc::Hse {
328 freq: Hertz(16_000_000),
329 mode: rcc::HseMode::Oscillator,
330 });
331 config.rcc.pll1 = Some(rcc::Pll {
332 source: rcc::PllSource::HSE,
333 prediv: rcc::PllPreDiv::DIV1,
334 mul: rcc::PllMul::MUL10,
335 divp: None,
336 divq: None,
337 divr: Some(rcc::PllDiv::DIV1),
338 });
339 config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz
340 config.rcc.pll3 = Some(rcc::Pll {
341 source: rcc::PllSource::HSE,
342 prediv: rcc::PllPreDiv::DIV4, // PLL_M
343 mul: rcc::PllMul::MUL125, // PLL_N
344 divp: None,
345 divq: None,
346 divr: Some(rcc::PllDiv::DIV20),
347 });
348 config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz
349 embassy_stm32::init(config)
350 }
351}
352
353mod bouncy_box {
354 use embedded_graphics::geometry::Point;
355 use embedded_graphics::primitives::Rectangle;
356
357 enum Direction {
358 DownLeft,
359 DownRight,
360 UpLeft,
361 UpRight,
362 }
363
364 pub struct BouncyBox {
365 direction: Direction,
366 child_rect: Rectangle,
367 parent_rect: Rectangle,
368 current_point: Point,
369 move_by: usize,
370 }
371
372 // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box
373 impl BouncyBox {
374 pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self {
375 let center_box = parent_rect.center();
376 let center_img = child_rect.center();
377 let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2);
378 Self {
379 direction: Direction::DownRight,
380 child_rect,
381 parent_rect,
382 current_point,
383 move_by,
384 }
385 }
386
387 pub fn next_point(&mut self) -> Point {
388 let direction = &self.direction;
389 let img_height = self.child_rect.size.height as i32;
390 let box_height = self.parent_rect.size.height as i32;
391 let img_width = self.child_rect.size.width as i32;
392 let box_width = self.parent_rect.size.width as i32;
393 let move_by = self.move_by as i32;
394
395 match direction {
396 Direction::DownLeft => {
397 self.current_point.x -= move_by;
398 self.current_point.y += move_by;
399
400 let x_out_of_bounds = self.current_point.x < 0;
401 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
402
403 if x_out_of_bounds && y_out_of_bounds {
404 self.direction = Direction::UpRight
405 } else if x_out_of_bounds && !y_out_of_bounds {
406 self.direction = Direction::DownRight
407 } else if !x_out_of_bounds && y_out_of_bounds {
408 self.direction = Direction::UpLeft
409 }
410 }
411 Direction::DownRight => {
412 self.current_point.x += move_by;
413 self.current_point.y += move_by;
414
415 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
416 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
417
418 if x_out_of_bounds && y_out_of_bounds {
419 self.direction = Direction::UpLeft
420 } else if x_out_of_bounds && !y_out_of_bounds {
421 self.direction = Direction::DownLeft
422 } else if !x_out_of_bounds && y_out_of_bounds {
423 self.direction = Direction::UpRight
424 }
425 }
426 Direction::UpLeft => {
427 self.current_point.x -= move_by;
428 self.current_point.y -= move_by;
429
430 let x_out_of_bounds = self.current_point.x < 0;
431 let y_out_of_bounds = self.current_point.y < 0;
432
433 if x_out_of_bounds && y_out_of_bounds {
434 self.direction = Direction::DownRight
435 } else if x_out_of_bounds && !y_out_of_bounds {
436 self.direction = Direction::UpRight
437 } else if !x_out_of_bounds && y_out_of_bounds {
438 self.direction = Direction::DownLeft
439 }
440 }
441 Direction::UpRight => {
442 self.current_point.x += move_by;
443 self.current_point.y -= move_by;
444
445 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
446 let y_out_of_bounds = self.current_point.y < 0;
447
448 if x_out_of_bounds && y_out_of_bounds {
449 self.direction = Direction::DownLeft
450 } else if x_out_of_bounds && !y_out_of_bounds {
451 self.direction = Direction::UpLeft
452 } else if !x_out_of_bounds && y_out_of_bounds {
453 self.direction = Direction::DownRight
454 }
455 }
456 }
457
458 self.current_point
459 }
460 }
461}
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
index eb15d275a..a85acc4c7 100644
--- a/examples/stm32u5/src/bin/tsc.rs
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -2,8 +2,8 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::bind_interrupts;
6use embassy_stm32::tsc::{self, *}; 5use embassy_stm32::tsc::{self, *};
6use embassy_stm32::{bind_interrupts, peripherals};
7use embassy_time::Timer; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -33,63 +33,52 @@ async fn main(_spawner: embassy_executor::Spawner) {
33 synchro_pin_polarity: false, 33 synchro_pin_polarity: false,
34 acquisition_mode: false, 34 acquisition_mode: false,
35 max_count_interrupt: 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 }; 36 };
40 37
41 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); 38 let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default();
42 g1.set_io2(context.PB13, PinType::Sample); 39 g1.set_io2::<tsc::pin_roles::Sample>(context.PB13);
43 g1.set_io3(context.PB14, PinType::Shield); 40 g1.set_io3::<tsc::pin_roles::Shield>(context.PB14);
44 41
45 let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new(); 42 let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
46 g2.set_io1(context.PB4, PinType::Sample); 43 g2.set_io1::<tsc::pin_roles::Sample>(context.PB4);
47 g2.set_io2(context.PB5, PinType::Channel); 44 let sensor0 = g2.set_io2(context.PB5);
48 45
49 let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new(); 46 let mut g7: PinGroupWithRoles<peripherals::TSC, G7> = PinGroupWithRoles::default();
50 g7.set_io2(context.PE3, PinType::Sample); 47 g7.set_io2::<tsc::pin_roles::Sample>(context.PE3);
51 g7.set_io3(context.PE4, PinType::Channel); 48 let sensor1 = g7.set_io3(context.PE4);
52 49
53 let mut touch_controller = tsc::Tsc::new_async( 50 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
54 context.TSC, 51 g1: Some(g1.pin_group),
55 Some(g1), 52 g2: Some(g2.pin_group),
56 Some(g2), 53 g7: Some(g7.pin_group),
57 None, 54 ..Default::default()
58 None, 55 };
59 None, 56
60 None, 57 let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap();
61 Some(g7),
62 None,
63 config,
64 Irqs,
65 );
66 58
67 touch_controller.discharge_io(true); 59 let acquisition_bank = touch_controller.create_acquisition_bank(AcquisitionBankPins {
68 Timer::after_millis(1).await; 60 g2_pin: Some(sensor0),
61 g7_pin: Some(sensor1),
62 ..Default::default()
63 });
69 64
70 touch_controller.start(); 65 touch_controller.set_active_channels_bank(&acquisition_bank);
71 66
72 let mut group_two_val = 0;
73 let mut group_seven_val = 0;
74 info!("Starting touch_controller interface"); 67 info!("Starting touch_controller interface");
75 loop { 68 loop {
69 touch_controller.start();
76 touch_controller.pend_for_acquisition().await; 70 touch_controller.pend_for_acquisition().await;
77 touch_controller.discharge_io(true); 71 touch_controller.discharge_io(true);
78 Timer::after_millis(1).await; 72 Timer::after_millis(1).await;
79 73
80 if touch_controller.group_get_status(Group::Two) == GroupStatus::Complete { 74 let status = touch_controller.get_acquisition_bank_status(&acquisition_bank);
81 group_two_val = touch_controller.group_get_value(Group::Two);
82 }
83 75
84 if touch_controller.group_get_status(Group::Seven) == GroupStatus::Complete { 76 if status.all_complete() {
85 group_seven_val = touch_controller.group_get_value(Group::Seven); 77 let read_values = touch_controller.get_acquisition_bank_values(&acquisition_bank);
78 let group2_reading = read_values.get_group_reading(Group::Two).unwrap();
79 let group7_reading = read_values.get_group_reading(Group::Seven).unwrap();
80 info!("group 2 value: {}", group2_reading.sensor_value);
81 info!("group 7 value: {}", group7_reading.sensor_value);
86 } 82 }
87
88 info!(
89 "Group Two value: {}, Group Seven value: {},",
90 group_two_val, group_seven_val
91 );
92
93 touch_controller.start();
94 } 83 }
95} 84}
diff --git a/examples/stm32u5/src/bin/usb_hs_serial.rs b/examples/stm32u5/src/bin/usb_hs_serial.rs
new file mode 100644
index 000000000..d37e7777b
--- /dev/null
+++ b/examples/stm32u5/src/bin/usb_hs_serial.rs
@@ -0,0 +1,122 @@
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 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello World!");
22
23 let mut config = Config::default();
24 {
25 use embassy_stm32::rcc::*;
26 use embassy_stm32::time::Hertz;
27 config.rcc.hse = Some(Hse {
28 freq: Hertz(16_000_000),
29 mode: HseMode::Oscillator,
30 });
31 config.rcc.pll1 = Some(Pll {
32 source: PllSource::HSE,
33 prediv: PllPreDiv::DIV2, // HSE / 2 = 8MHz
34 mul: PllMul::MUL60, // 8MHz * 60 = 480MHz
35 divr: Some(PllDiv::DIV3), // 480MHz / 3 = 160MHz (sys_ck)
36 divq: Some(PllDiv::DIV10), // 480MHz / 10 = 48MHz (USB)
37 divp: Some(PllDiv::DIV15), // 480MHz / 15 = 32MHz (USBOTG)
38 });
39 config.rcc.mux.otghssel = mux::Otghssel::PLL1_P;
40 config.rcc.voltage_range = VoltageScale::RANGE1;
41 config.rcc.sys = Sysclk::PLL1_R;
42 }
43
44 let p = embassy_stm32::init(config);
45
46 // Create the driver, from the HAL.
47 let mut ep_out_buffer = [0u8; 256];
48 let mut config = embassy_stm32::usb::Config::default();
49 // Do not enable vbus_detection. This is a safe default that works in all boards.
50 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
51 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
52 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
53 config.vbus_detection = false;
54 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
55
56 // Create embassy-usb Config
57 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
58 config.manufacturer = Some("Embassy");
59 config.product = Some("USB-serial example");
60 config.serial_number = Some("12345678");
61
62 // Create embassy-usb DeviceBuilder using the driver and config.
63 // It needs some buffers for building the descriptors.
64 let mut config_descriptor = [0; 256];
65 let mut bos_descriptor = [0; 256];
66 let mut control_buf = [0; 64];
67
68 let mut state = State::new();
69
70 let mut builder = Builder::new(
71 driver,
72 config,
73 &mut config_descriptor,
74 &mut bos_descriptor,
75 &mut [], // no msos descriptors
76 &mut control_buf,
77 );
78
79 // Create classes on the builder.
80 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
81
82 // Build the builder.
83 let mut usb = builder.build();
84
85 // Run the USB device.
86 let usb_fut = usb.run();
87
88 // Do stuff with the class!
89 let echo_fut = async {
90 loop {
91 class.wait_connection().await;
92 info!("Connected");
93 let _ = echo(&mut class).await;
94 info!("Disconnected");
95 }
96 };
97
98 // Run everything concurrently.
99 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
100 join(usb_fut, echo_fut).await;
101}
102
103struct Disconnected {}
104
105impl From<EndpointError> for Disconnected {
106 fn from(val: EndpointError) -> Self {
107 match val {
108 EndpointError::BufferOverflow => panic!("Buffer overflow"),
109 EndpointError::Disabled => Disconnected {},
110 }
111 }
112}
113
114async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
115 let mut buf = [0; 64];
116 loop {
117 let n = class.read_packet(&mut buf).await?;
118 let data = &buf[..n];
119 info!("data: {:x}", data);
120 class.write_packet(data).await?;
121 }
122}
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 4d56395da..ff7f4e5be 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -13,7 +13,7 @@ use embassy_usb::Builder;
13use panic_probe as _; 13use panic_probe as _;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) {
48 // to enable vbus_detection to comply with the USB spec. If you enable it, the board 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. 49 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
50 config.vbus_detection = false; 50 config.vbus_detection = false;
51 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 51 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
52 52
53 // Create embassy-usb Config 53 // Create embassy-usb Config
54 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 54 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -56,13 +56,6 @@ async fn main(_spawner: Spawner) {
56 config.product = Some("USB-serial example"); 56 config.product = Some("USB-serial example");
57 config.serial_number = Some("12345678"); 57 config.serial_number = Some("12345678");
58 58
59 // Required for windows compatibility.
60 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
61 config.device_class = 0xEF;
62 config.device_sub_class = 0x02;
63 config.device_protocol = 0x01;
64 config.composite_with_iads = true;
65
66 // Create embassy-usb DeviceBuilder using the driver and config. 59 // Create embassy-usb DeviceBuilder using the driver and config.
67 // It needs some buffers for building the descriptors. 60 // It needs some buffers for building the descriptors.
68 let mut config_descriptor = [0; 256]; 61 let mut config_descriptor = [0; 256];
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 1e1a0efe2..dbe9660e2 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
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.2.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.6.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.4.0", 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.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
15 15
16defmt = "0.3" 16defmt = "1.0.1"
17defmt-rtt = "0.4" 17defmt-rtt = "1.0.0"
18 18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "1.0.0"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24static_cell = "2" 24static_cell = "2"
25 25
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 1cc50e134..041dc0cf5 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -151,11 +151,6 @@ async fn main(_spawner: Spawner) {
151 let response = mbox.ble_subsystem.read().await; 151 let response = mbox.ble_subsystem.read().await;
152 defmt::debug!("{}", response); 152 defmt::debug!("{}", response);
153 153
154 info!("set scan response data...");
155 mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap();
156 let response = mbox.ble_subsystem.read().await;
157 defmt::debug!("{}", response);
158
159 defmt::info!("initializing services and characteristics..."); 154 defmt::info!("initializing services and characteristics...");
160 let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap(); 155 let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap();
161 defmt::info!("{}", ble_context); 156 defmt::info!("{}", ble_context);
diff --git a/examples/stm32wba/.cargo/config.toml b/examples/stm32wba/.cargo/config.toml
index 477413397..c96a5cb6c 100644
--- a/examples/stm32wba/.cargo/config.toml
+++ b/examples/stm32wba/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip STM32WBA52CGUxT" 2runner = "probe-rs run --chip STM32WBA55CGUx"
3 3
4[build] 4[build]
5target = "thumbv8m.main-none-eabihf" 5target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index 401281c0b..2c638f9f4 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -5,19 +5,19 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "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.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.4.0", 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.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
13 13
14defmt = "0.3" 14defmt = "1.0.1"
15defmt-rtt = "0.4" 15defmt-rtt = "1.0.0"
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"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "1.0.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "1.0.0", features = ["print-defmt"] }
21heapless = { version = "0.8", default-features = false } 21heapless = { version = "0.8", default-features = false }
22static_cell = "2" 22static_cell = "2"
23 23
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 46af5218c..5ecd77443 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -6,20 +6,20 @@ license = "MIT OR Apache-2.0"
6 6
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.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "1.0.1"
16defmt-rtt = "0.4" 16defmt-rtt = "1.0.0"
17 17
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"
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 = "1.0.0", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24chrono = { version = "^0.4", default-features = false } 24chrono = { version = "^0.4", default-features = false }
25 25
diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x
index 0298caa4b..4590867a8 100644
--- a/examples/stm32wl/memory.x
+++ b/examples/stm32wl/memory.x
@@ -2,8 +2,8 @@ MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K 4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K
5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
6 RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 64K - 64 6 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128
7} 7}
8 8
9SECTIONS 9SECTIONS
@@ -12,4 +12,4 @@ SECTIONS
12 { 12 {
13 *(.shared_data) 13 *(.shared_data)
14 } > SHARED_RAM 14 } > SHARED_RAM
15} \ No newline at end of file 15}
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs
index ce7d0ec58..a2a90871d 100644
--- a/examples/stm32wl/src/bin/blinky.rs
+++ b/examples/stm32wl/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".shared_data"] 13#[unsafe(link_section = ".shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs
index 8b5204479..21bcd2ac6 100644
--- a/examples/stm32wl/src/bin/button.rs
+++ b/examples/stm32wl/src/bin/button.rs
@@ -9,7 +9,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::SharedData; 9use embassy_stm32::SharedData;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12#[link_section = ".shared_data"] 12#[unsafe(link_section = ".shared_data")]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14 14
15#[entry] 15#[entry]
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index 8dd1a6a5e..0a8aece34 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -10,7 +10,7 @@ use embassy_stm32::gpio::Pull;
10use embassy_stm32::SharedData; 10use embassy_stm32::SharedData;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".shared_data"] 13#[unsafe(link_section = ".shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 147f5d293..320a9723a 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -9,7 +9,7 @@ use embassy_stm32::flash::Flash;
9use embassy_stm32::SharedData; 9use embassy_stm32::SharedData;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12#[link_section = ".shared_data"] 12#[unsafe(link_section = ".shared_data")]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index df2ed0054..68b9d7d00 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{
14 RNG => rng::InterruptHandler<peripherals::RNG>; 14 RNG => rng::InterruptHandler<peripherals::RNG>;
15}); 15});
16 16
17#[link_section = ".shared_data"] 17#[unsafe(link_section = ".shared_data")]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19 19
20#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index 69a9ddc4c..d3709120f 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -12,7 +12,7 @@ use embassy_stm32::{Config, SharedData};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15#[link_section = ".shared_data"] 15#[unsafe(link_section = ".shared_data")]
16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index ece9b9201..505a85f47 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{
14 LPUART1 => InterruptHandler<peripherals::LPUART1>; 14 LPUART1 => InterruptHandler<peripherals::LPUART1>;
15}); 15});
16 16
17#[link_section = ".shared_data"] 17#[unsafe(link_section = ".shared_data")]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19 19
20/* 20/*
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 9bd37550c..9e553f52b 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.6.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } 12embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } 13embassy-time = { version = "0.4.0", 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