mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-23 12:41:31 +11:00
Merge branch 'main' into multicore-no-alloc
This commit is contained in:
commit
b932663cc9
|
@ -2,6 +2,7 @@
|
|||
resolver = "2"
|
||||
members = [
|
||||
"rp2040-hal",
|
||||
"rp2040-hal-macros",
|
||||
"boards/adafruit-feather-rp2040",
|
||||
"boards/adafruit-itsy-bitsy-rp2040",
|
||||
"boards/adafruit-kb2040",
|
||||
|
|
|
@ -390,9 +390,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-feather-rp2040-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-feather-rp2040-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-feather-rp2040-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-feather-rp2040-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "adafruit-feather-rp2040"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Nall <anall@andreanal.com>"]
|
||||
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-feather-rp2040"
|
||||
description = "Board Support Package for the Adafruit Feather RP2040"
|
||||
|
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
|
|||
embedded-hal ="0.2.5"
|
||||
nb = "1.0.0"
|
||||
smart-leds = "0.3.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
||||
[features]
|
||||
default = ["boot2", "rt"]
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Feather.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
adafruit-feather-rp2040 = "0.1.0"
|
||||
adafruit-feather-rp2040 = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `adafruit_feather_rp2040::Pins::new` to create
|
||||
|
@ -90,9 +90,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-itsy-bitsy-rp2040-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-itsy-bitsy-rp2040-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-itsy-bitsy-rp2040-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-itsy-bitsy-rp2040-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "adafruit-itsy-bitsy-rp2040"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
|
||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_itsy_bitsy_rp2040"
|
||||
description = "Board Support Package for the Adafruit ItsyBitsy RP2040"
|
||||
|
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
|
|||
embedded-hal ="0.2.5"
|
||||
smart-leds = "0.3"
|
||||
nb = "1.0.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
||||
[features]
|
||||
default = ["rt", "boot2"]
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the ItsyBitsy RP2040.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
adafruit-itsy-bitsy-rp2040 = "0.1.0"
|
||||
adafruit-itsy-bitsy-rp2040 = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `adafruit_itsy_bitsy_rp2040::Pins::new` to create
|
||||
|
@ -90,9 +90,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-kb2040-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-kb2040-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-kb2040-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-kb2040-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "adafruit-kb2040"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
|
||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-kb2040"
|
||||
description = "Board Support Package for the Adafruit adafruit-kb2040"
|
||||
|
@ -28,5 +28,4 @@ rp2040-boot2 = "0.2"
|
|||
smart-leds = "0.3.0"
|
||||
embedded-time = "0.12.0"
|
||||
nb = "1.0.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the KB2040.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
adafruit-kb2040 = "0.1.0"
|
||||
adafruit-kb2040 = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `adafruit-kb2040::Pins::new` to create
|
||||
|
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-macropad-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-macropad-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-macropad-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-macropad-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "adafruit-macropad"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Nall <anall@andreanal.com>"]
|
||||
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad"
|
||||
description = "Board Support Package for the Adafruit Macropad"
|
||||
|
@ -15,6 +15,10 @@ cortex-m = "0.7.2"
|
|||
rp2040-boot2 = { version = "0.2.0", optional = true }
|
||||
rp2040-hal = { path = "../../rp2040-hal", version = "0.4.0"}
|
||||
cortex-m-rt = { version = "0.7", optional = true }
|
||||
[dev-dependencies]
|
||||
embedded-time = "0.12.0"
|
||||
panic-halt= "0.2.0"
|
||||
embedded-hal ="0.2.5"
|
||||
|
||||
[features]
|
||||
default = ["rt", "boot2"]
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Feather.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
adafruit-macropad = "0.1.0"
|
||||
adafruit-macropad = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `adafruit_macropad::Pins::new` to create
|
||||
|
@ -82,9 +82,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
//! Blinks the LED on a Adafruit MacroPad board
|
||||
//!
|
||||
//! This will blink on-board LED.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use adafruit_macropad::{
|
||||
hal::{
|
||||
clocks::{init_clocks_and_plls, Clock},
|
||||
pac,
|
||||
watchdog::Watchdog,
|
||||
Sio,
|
||||
},
|
||||
Pins, XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_time::rate::*;
|
||||
use panic_halt as _;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let core = pac::CorePeripherals::take().unwrap();
|
||||
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
let clocks = init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
pac.PLL_USB,
|
||||
&mut pac.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
let mut led_pin = pins.led.into_push_pull_output();
|
||||
|
||||
loop {
|
||||
led_pin.set_high().unwrap();
|
||||
delay.delay_ms(1500);
|
||||
led_pin.set_low().unwrap();
|
||||
delay.delay_ms(1500);
|
||||
}
|
||||
}
|
|
@ -72,3 +72,5 @@ hal::bsp_pins!(
|
|||
aliases: { FunctionSpi: Miso }
|
||||
},
|
||||
);
|
||||
|
||||
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-qt-py-rp2040-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-qt-py-rp2040-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-qt-py-rp2040-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-qt-py-rp2040-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "adafruit-qt-py-rp2040"
|
||||
version = "0.2.0"
|
||||
authors = ["Stephen Onnen <stephen.onnen@gmail.com>"]
|
||||
authors = ["Stephen Onnen <stephen.onnen@gmail.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-qt-py-rp2040"
|
||||
description = "Board Support Package for the Adafruit QT Py RP2040"
|
||||
|
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
|
|||
embedded-hal ="0.2.5"
|
||||
smart-leds = "0.3"
|
||||
nb = "1.0.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
||||
[features]
|
||||
default = ["boot2", "rt"]
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the QT Py.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
adafruit-qt-py-rp2040 = { git = "https://github.com/rp-rs/rp-hal.git" }
|
||||
adafruit-qt-py-rp2040 = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `adafruit_qt_py_rp2040::Pins::new` to create
|
||||
|
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -21,7 +21,7 @@ embedded-hal ="0.2.5"
|
|||
embedded-time = "0.12.0"
|
||||
smart-leds = "0.3"
|
||||
nb = "1.0.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
||||
[features]
|
||||
default = ["boot2", "rt"]
|
||||
|
|
|
@ -85,9 +85,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-explorer-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-explorer-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-explorer-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-explorer-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "pimoroni-pico-explorer"
|
||||
version = "0.2.0"
|
||||
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
|
||||
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-explorer"
|
||||
description = "Board Support Package for the Pico Explorer"
|
||||
|
|
|
@ -17,7 +17,7 @@ RP2040 chip according to how it is connected up on the Pico Explorer.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
pimoroni-pico-explorer = "0.1.0"
|
||||
pimoroni-pico-explorer = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `pimoroni_pico_explorer::Pins::new` to create
|
||||
|
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp2040-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-lipo-16mb-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-lipo-16mb-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-lipo-16mb-v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-lipo-16mb-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "pimoroni-pico-lipo-16mb"
|
||||
version = "0.2.0"
|
||||
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
|
||||
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-lipo-16mb"
|
||||
description = "Board Support Package for the Pico LiPo 16MB"
|
||||
|
|
|
@ -18,7 +18,7 @@ space, and so it may not work if you only have the 4MB variant.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
pimoroni-pico-lipo-16mb = { git = "https://github.com/rp-rs/rp-hal.git" }
|
||||
pimoroni-pico-lipo-16mb = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `pimoroni_pico_lipo_16mb::Pins::new` to create
|
||||
|
@ -88,9 +88,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses
|
||||
//! for the on-board LED.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "pimoroni-tiny2040"
|
||||
version = "0.1.0"
|
||||
authors = ["Mike Bell <mdb036@gmail.com>"]
|
||||
authors = ["Mike Bell <mdb036@gmail.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-tiny2040"
|
||||
description = "Board Support Package for the Pimoroni Tiny2040"
|
||||
|
|
|
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.3.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp-hal 0.4.0
|
||||
|
||||
## [0.2.0] - 2021-12-23
|
||||
|
||||
### Added
|
||||
|
@ -31,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
[@jannic]: https://github.com/jannic
|
||||
[rp-rs]: https://github.com/rp-rs
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/rp-pico-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/rp-pico-v0.3.0...HEAD
|
||||
[0.3.0]: https://github.com/rp-rs/rp-hal/releases/tag/rp-pico-v0.3.0
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/rp-pico-v0.2.0
|
||||
[0.1.3]: https://github.com/jannic/rp-microcontroller-rs/tree/rp-pico-0.1.3
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[package]
|
||||
name = "rp-pico"
|
||||
version = "0.3.0"
|
||||
authors = ["evan <evanmolder@gmail.com>"]
|
||||
authors = ["evan <evanmolder@gmail.com>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pico"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico"
|
||||
description = "Board Support Package for the Raspberry Pi Pico"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rp-rs/rp-hal.git"
|
||||
|
@ -26,11 +26,11 @@ panic-halt= "0.2.0"
|
|||
embedded-hal ="0.2.5"
|
||||
cortex-m-rtic = "0.6.0-rc.4"
|
||||
nb = "1.0"
|
||||
i2c-pio = { git = "https://github.com/ithinuel/i2c-pio-rs", rev = "df06e4ac94a5b2c985d6a9426dc4cc9be0d535c0" }
|
||||
i2c-pio = { git = "https://github.com/ithinuel/i2c-pio-rs", rev = "fa155bbae4e8553b448a66cc47236db38b7524dd" }
|
||||
heapless = "0.7.9"
|
||||
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
|
||||
smart-leds = "0.3.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
ssd1306 = "0.7.0"
|
||||
embedded-graphics = "0.7.1"
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Pico.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
rp-pico = "0.2.0"
|
||||
rp-pico = "0.3.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `rp_pico::Pins::new` to create
|
||||
|
@ -129,9 +129,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
||||
//! the on-board LED.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
||||
//! the on-board LED.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! internally by this example. When the button is pressed, the LED will turn
|
||||
//! off.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
//! - (o) connected lines
|
||||
//! ```
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! using the PIO peripheral as an I2C bus controller.
|
||||
//! The pins used for the I2C can be remapped to any other pin available to the PIO0 peripheral.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! This will fade in/out the LED attached to GP25, which is the pin the Pico
|
||||
//! uses for the on-board LED.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -9,7 +9,7 @@ mod app {
|
|||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_time::duration::Extensions;
|
||||
use rp_pico::{
|
||||
hal::{self, clocks::init_clocks_and_plls, watchdog::Watchdog, Sio},
|
||||
hal::{self, clocks::init_clocks_and_plls, timer::Alarm, watchdog::Watchdog, Sio},
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,11 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
// Soft-reset does not release the hardware spinlocks
|
||||
// Release them now to avoid a deadlock after debug or watchdog reset
|
||||
unsafe {
|
||||
hal::sio::spinlock_reset();
|
||||
}
|
||||
let mut resets = c.device.RESETS;
|
||||
let mut watchdog = Watchdog::new(c.device.WATCHDOG);
|
||||
let _clocks = init_clocks_and_plls(
|
||||
|
|
|
@ -80,14 +80,14 @@
|
|||
//!
|
||||
//! If there are 5 different error patterns, all with short blinking pulses:
|
||||
//!
|
||||
//! - **2 short blink (in a loop)**: Block device could not be aquired, either
|
||||
//! - **2 short blink (in a loop)**: Block device could not be acquired, either
|
||||
//! no SD card is present or some electrical problem.
|
||||
//! - **3 short blink (in a loop)**: Card size could not be retrieved.
|
||||
//! - **4 short blink (in a loop)**: Error getting volume/partition 0.
|
||||
//! - **5 short blink (in a loop)**: Error opening root directory.
|
||||
//! - **6 short blink (in a loop)**: Could not open file 'O.TST'.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
//! * GPIO 1 - UART RX (in to the RP2040)
|
||||
//! * GPIO 25 - An LED we can blink (active high)
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//! * GPIO 1 - UART RX (in to the RP2040)
|
||||
//! * GPIO 25 - An LED we can blink (active high)
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! ASCII characters are converted to upercase, so you can tell it is working
|
||||
//! and not just local-echo!
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! ASCII characters are converted to upercase, so you can tell it is working
|
||||
//! and not just local-echo!
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! It generates movement reports which will twitch the cursor up and down by a
|
||||
//! few pixels, several times a second.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
//!
|
||||
//! This is a port of
|
||||
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
//! - (o) connected lines
|
||||
//! ```
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -27,5 +27,5 @@ embedded-hal ="0.2.5"
|
|||
nb = "1.0.0"
|
||||
smart-leds = "0.3.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
embedded-time = "0.12.0"
|
||||
|
|
|
@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Stamp
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
solderparty-rp2040-stamp = { git = "https://github.com/rp-rs/rp-hal.git" }
|
||||
solderparty-rp2040-stamp = "0.1.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `solderparty_rp2040_stamp::Pins::new` to create
|
||||
|
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None
|
||||
|
||||
## [0.2.0] - 2022-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to rp-hal 0.4.0
|
||||
|
||||
## [0.1.0] - 2021-12-20
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.2.0...HEAD
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.1.0...v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/sparkfun-pro-micro-rp2040-v0.1.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "sparkfun-pro-micro-rp2040"
|
||||
version = "0.2.0"
|
||||
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>"]
|
||||
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>", "The rp-rs Developers"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/sparkfun-pro-micro-rp2040"
|
||||
description = "Board Support Package for the Sparkfun Pro Micro RP2040"
|
||||
|
@ -23,7 +23,7 @@ smart-leds = "0.3.0"
|
|||
embedded-time = "0.12.0"
|
||||
nb = "1.0.0"
|
||||
pio = "0.1.0"
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||
|
||||
[features]
|
||||
default = ["boot2", "rt"]
|
||||
|
|
|
@ -17,7 +17,7 @@ RP2040 chip according to how it is connected up on the Pro Micro RP2040.
|
|||
To use this crate, your `Cargo.toml` file should contain:
|
||||
|
||||
```toml
|
||||
sparkfun-pro-micro-rp2040 = "0.1.0"
|
||||
sparkfun-pro-micro-rp2040 = "0.2.0"
|
||||
```
|
||||
|
||||
In your program, you will need to call `sparkfun_pro_micro_rp2040::Pins::new` to create
|
||||
|
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
|
|||
## License
|
||||
|
||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
||||
2.0_ License. That means you can chose either the MIT licence or the
|
||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific licence.
|
||||
2.0_ License. That means you can chose either the MIT license or the
|
||||
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||
information on each specific license.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
under these terms.
|
||||
|
|
20
rp2040-hal-macros/Cargo.toml
Normal file
20
rp2040-hal-macros/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
description = "Macros used by rp2040-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "rp2040-hal-macros"
|
||||
readme = "README.md"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
cortex-m-rt = "0.7.0"
|
||||
|
||||
[dependencies.syn]
|
||||
features = ["extra-traits", "full"]
|
||||
version = "1.0"
|
||||
|
27
rp2040-hal-macros/README.md
Normal file
27
rp2040-hal-macros/README.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# `rp2040-hal-macros`
|
||||
|
||||
Macros used by rp2040-hal.
|
||||
|
||||
## Entry macro
|
||||
|
||||
Extension of the `cortex-m-rt` `#[entry]` with rp2040 specific initialization code.
|
||||
|
||||
Currently, it just unlocks all spinlocks before calling the entry function.
|
||||
|
||||
# License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 (`APACHE2.0` or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
- MIT license (`MIT` or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
## Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
59
rp2040-hal-macros/src/lib.rs
Normal file
59
rp2040-hal-macros/src/lib.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::{parse, parse_macro_input, Item, ItemFn, Stmt};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut f = parse_macro_input!(input as ItemFn);
|
||||
|
||||
if !args.is_empty() {
|
||||
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let clear_locks: TokenStream = quote!(unsafe {
|
||||
const SIO_BASE: u32 = 0xd0000000;
|
||||
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
|
||||
const SPINLOCK_COUNT: usize = 32;
|
||||
for i in 0..SPINLOCK_COUNT {
|
||||
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
|
||||
}
|
||||
})
|
||||
.into();
|
||||
let clear_locks = parse_macro_input!(clear_locks as Stmt);
|
||||
|
||||
// statics must stay first so cortex_m_rt::entry still finds them
|
||||
let stmts = insert_after_static(f.block.stmts, clear_locks);
|
||||
f.block.stmts = stmts;
|
||||
|
||||
quote!(
|
||||
#[::cortex_m_rt::entry]
|
||||
#f
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Insert new statements after initial block of statics
|
||||
fn insert_after_static(stmts: impl IntoIterator<Item = Stmt>, insert: Stmt) -> Vec<Stmt> {
|
||||
let mut istmts = stmts.into_iter();
|
||||
let mut stmts = vec![];
|
||||
for stmt in istmts.by_ref() {
|
||||
match stmt {
|
||||
Stmt::Item(Item::Static(var)) => {
|
||||
stmts.push(Stmt::Item(Item::Static(var)));
|
||||
}
|
||||
_ => {
|
||||
stmts.push(insert);
|
||||
stmts.push(stmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stmts.extend(istmts);
|
||||
|
||||
stmts
|
||||
}
|
|
@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
|
||||
- removed i2c embassy driver prototype
|
||||
|
||||
## [0.4.0] - 2022-03-09
|
||||
|
||||
### Added
|
||||
|
||||
- ROM function caching
|
||||
|
@ -17,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- UART IRQ examples
|
||||
- PIO side-set example
|
||||
- Stopped PIO state machines can change their clock divider
|
||||
- Added HAL IRQ example
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -32,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Update critical_section to use new spinlock implementation
|
||||
- Update embedded-hal alpha support to version 1.0.0-alpha.7
|
||||
- Avoid 64-bit division in clock calculations
|
||||
- Update pio and pio-proc to 0.2.0
|
||||
|
||||
## [0.3.0] - 2021-12-19
|
||||
|
||||
|
@ -90,7 +98,8 @@ The Minimum-Supported Rust Version (MSRV) for this release is 1.54.
|
|||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/v0.3.0...HEAD
|
||||
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/v0.4.0...HEAD
|
||||
[0.4.0]: https://github.com/rp-rs/rp-hal/compare/v0.3.0...v0.4.0
|
||||
[0.3.0]: https://github.com/rp-rs/rp-hal/compare/v0.2.0...v0.3.0
|
||||
[0.2.0]: https://github.com/rp-rs/rp-hal/compare/v0.1.0...v0.2.0
|
||||
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/v0.1.0
|
||||
|
|
|
@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
cortex-m = "0.7.2"
|
||||
cortex-m-rt = ">=0.6.15,<0.8"
|
||||
embedded-hal = { version = "0.2.5", features = ["unproven"] }
|
||||
eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true }
|
||||
embedded-time = "0.12.0"
|
||||
|
@ -18,7 +19,8 @@ itertools = { version = "0.10.1", default-features = false }
|
|||
nb = "1.0"
|
||||
rp2040-pac = "0.3.0"
|
||||
paste = "1.0"
|
||||
pio = "0.1.0"
|
||||
pio = "0.2.0"
|
||||
rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" }
|
||||
usb-device = "0.2.8"
|
||||
vcell = "0.1"
|
||||
void = { version = "1.0.2", default-features = false }
|
||||
|
@ -28,30 +30,21 @@ critical-section = { version = "0.2.4", features = ["custom-impl"] }
|
|||
futures = { version = "0.3", default-features = false, optional = true }
|
||||
chrono = { version = "0.4", default-features = false, optional = true }
|
||||
|
||||
# namespaced features will let us use "dep:embassy-traits" in the features rather than using this
|
||||
# trick of renaming the crate.
|
||||
#
|
||||
# This is commented out so that we can publish to crates.io
|
||||
#
|
||||
# [dependencies.embassy_traits]
|
||||
# git = "https://github.com/embassy-rs/embassy"
|
||||
# rev = "6d6e6f55b8a9ecd38b5a6d3bb11f74b2654afdeb"
|
||||
# package = "embassy-traits"
|
||||
# optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
cortex-m-rt = "0.7"
|
||||
panic-halt = "0.2.0"
|
||||
rp2040-boot2 = "0.2.0"
|
||||
hd44780-driver = "0.4.0"
|
||||
pio-proc = "0.1.0"
|
||||
pio-proc = "0.2.0"
|
||||
dht-sensor = "0.2.1"
|
||||
|
||||
[features]
|
||||
rt = ["rp2040-pac/rt"]
|
||||
# This is commented out so that we can publish to crates.io
|
||||
#
|
||||
# embassy-traits = ["embassy_traits", "futures"]
|
||||
rom-func-cache = []
|
||||
disable-intrinsics = []
|
||||
rom-v2-intrinsics = []
|
||||
|
||||
[[example]]
|
||||
# irq example uses cortex-m-rt::interrupt, need rt feature for that
|
||||
name = "gpio_irq_example"
|
||||
required-features = ["rt"]
|
||||
|
|
|
@ -57,7 +57,7 @@ hardware-abstraction interfaces defined in the Rust Embedded Working Group's
|
|||
|
||||
We also provide a series of *Board Support Package* (BSP) crates, which take
|
||||
this HAL crate and pre-configure the pins according to a specific PCB design. If
|
||||
you are using on of the supported boards, you should use one of those crates in
|
||||
you are using one of the supported boards, you should use one of those crates in
|
||||
preference, and return here to see documentation about specific peripherals on
|
||||
the RP2040 and how to use them. See the `boards` folder in
|
||||
https://github.com/rp-rs/rp-hal/ for more details.
|
||||
|
@ -68,7 +68,7 @@ https://github.com/rp-rs/rp-hal/ for more details.
|
|||
To include this crate in your project, amend your `Cargo.toml` file to include
|
||||
|
||||
```toml
|
||||
rp2040-hal = "0.3.0"
|
||||
rp2040-hal = "0.4.0"
|
||||
```
|
||||
|
||||
To obtain a copy of the source code (e.g. if you want to propose a bug-fix or
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//!
|
||||
//! NOTE: The DHT11 driver only works reliably when compiled in release mode.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! It drives the LCD by pushing data out of six GPIO pins. It may need to be
|
||||
//! adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -34,14 +34,11 @@ fn main() -> ! {
|
|||
let led_pin_id = 25;
|
||||
|
||||
// Define some simple PIO program.
|
||||
let program = pio_proc::pio!(
|
||||
32,
|
||||
"
|
||||
.wrap_target
|
||||
set pins, 1 [31]
|
||||
set pins, 0 [31]
|
||||
.wrap
|
||||
"
|
||||
let program = pio_proc::pio_asm!(
|
||||
".wrap_target",
|
||||
"set pins, 1 [31]",
|
||||
"set pins, 0 [31]",
|
||||
".wrap"
|
||||
);
|
||||
|
||||
// Initialize and start PIO
|
||||
|
|
|
@ -36,15 +36,12 @@ fn main() -> ! {
|
|||
let led_pin_id = 25;
|
||||
|
||||
// Define some simple PIO program.
|
||||
let program = pio_proc::pio!(
|
||||
32,
|
||||
"
|
||||
.side_set 1 ; each instruction may set 1 bit
|
||||
.wrap_target
|
||||
nop side 1
|
||||
nop side 0
|
||||
.wrap
|
||||
"
|
||||
let program = pio_proc::pio_asm!(
|
||||
".side_set 1", // each instruction may set 1 bit
|
||||
".wrap_target",
|
||||
" nop side 1",
|
||||
" nop side 0",
|
||||
".wrap",
|
||||
);
|
||||
|
||||
// Initialize and start PIO
|
||||
|
|
96
rp2040-hal/examples/pio_synchronized.rs
Normal file
96
rp2040-hal/examples/pio_synchronized.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
//! This example toggles the GPIO0 and GPIO1 pins, with each controlled from a
|
||||
//! separate PIO state machine.
|
||||
//!
|
||||
//! Despite running in separate state machines, the clocks are sychronized at
|
||||
//! the rise and fall times will be simultaneous.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use hal::gpio::{FunctionPio0, Pin};
|
||||
use hal::pac;
|
||||
use hal::pio::PIOExt;
|
||||
use hal::Sio;
|
||||
use panic_halt as _;
|
||||
use rp2040_hal as hal;
|
||||
|
||||
#[link_section = ".boot2"]
|
||||
#[used]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = hal::gpio::Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
|
||||
// configure pins for Pio0.
|
||||
let _: Pin<_, FunctionPio0> = pins.gpio0.into_mode();
|
||||
let _: Pin<_, FunctionPio0> = pins.gpio1.into_mode();
|
||||
|
||||
// PIN id for use inside of PIO
|
||||
let pin0 = 0;
|
||||
let pin1 = 1;
|
||||
|
||||
// Define some simple PIO program.
|
||||
let program = pio_proc::pio_asm!(
|
||||
"
|
||||
.wrap_target
|
||||
set pins, 1 [31]
|
||||
set pins, 0 [31]
|
||||
.wrap
|
||||
"
|
||||
);
|
||||
|
||||
// Initialize and start PIO
|
||||
let (mut pio, sm0, sm1, _, _) = pac.PIO0.split(&mut pac.RESETS);
|
||||
// I'm "measuring" the phase offset between the two pins by connecting
|
||||
// then through a LED. If there is a clock offset, there will be a
|
||||
// short time with a voltage between the pins, so the LED will flash up.
|
||||
// With a slow clock this is not visible, so use a reasonably fast clock.
|
||||
let div = 256f32;
|
||||
|
||||
let installed = pio.install(&program.program).unwrap();
|
||||
let (mut sm0, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
|
||||
.set_pins(pin0, 1)
|
||||
.clock_divisor(div)
|
||||
.build(sm0);
|
||||
// The GPIO pin needs to be configured as an output.
|
||||
sm0.set_pindirs([(pin0, hal::pio::PinDir::Output)]);
|
||||
|
||||
// NOTE: with the current rp-hal, I need to call pio.install() twice. This
|
||||
// should be investigated further as it seems wrong.
|
||||
let installed = pio.install(&program.program).unwrap();
|
||||
let (mut sm1, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
|
||||
.set_pins(pin1, 1)
|
||||
.clock_divisor(div)
|
||||
.build(sm1);
|
||||
// The GPIO pin needs to be configured as an output.
|
||||
sm1.set_pindirs([(pin1, hal::pio::PinDir::Output)]);
|
||||
|
||||
// Start both SMs at the same time
|
||||
let group = sm0.with(sm1).sync().start();
|
||||
cortex_m::asm::delay(10_000_000);
|
||||
|
||||
// Stop both SMs at the same time
|
||||
let group = group.stop();
|
||||
cortex_m::asm::delay(10_000_000);
|
||||
|
||||
// Start them again and extract the individual state machines
|
||||
let (sm1, sm2) = group.start().free();
|
||||
cortex_m::asm::delay(10_000_000);
|
||||
|
||||
// Stop the two state machines separately
|
||||
let _sm1 = sm1.stop();
|
||||
cortex_m::asm::delay(10_000_000);
|
||||
let _sm2 = sm2.stop();
|
||||
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! It may need to be adapted to your particular board layout and/or pin
|
||||
//! assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! It may need to be adapted to your particular board layout and/or pin
|
||||
//! assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
|
|
@ -1,6 +1,71 @@
|
|||
use super::Float;
|
||||
use crate::rom_data;
|
||||
use crate::sio::save_divider;
|
||||
|
||||
// Make sure this stays as a separate call, because when it's inlined the
|
||||
// compiler will move the save of the registers used to contain the divider
|
||||
// state into the function prologue. That save and restore (push/pop) takes
|
||||
// longer than the actual division, so doing it in the common case where
|
||||
// they are not required wastes a lot of time.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn save_divider_and_call<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
let sio = unsafe { &(*pac::SIO::ptr()) };
|
||||
|
||||
// Since we can't save the signed-ness of the calculation, we have to make
|
||||
// sure that there's at least an 8 cycle delay before we read the result.
|
||||
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
|
||||
// Since we can't be sure the Rust implementation will optimize to the same,
|
||||
// just use an explicit wait.
|
||||
while !sio.div_csr.read().ready().bit() {}
|
||||
|
||||
// Read the quotient last, since that's what clears the dirty flag
|
||||
let dividend = sio.div_udividend.read().bits();
|
||||
let divisor = sio.div_udivisor.read().bits();
|
||||
let remainder = sio.div_remainder.read().bits();
|
||||
let quotient = sio.div_quotient.read().bits();
|
||||
|
||||
// If we get interrupted here (before a write sets the DIRTY flag) its fine, since
|
||||
// we have the full state, so the interruptor doesn't have to restore it. Once the
|
||||
// write happens and the DIRTY flag is set, the interruptor becomes responsible for
|
||||
// restoring our state.
|
||||
let result = f();
|
||||
|
||||
// If we are interrupted here, then the interruptor will start an incorrect calculation
|
||||
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
|
||||
// This sets DIRTY, so any interruptor will save the state.
|
||||
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
||||
// If we are interrupted here, the the interruptor may start the calculation using
|
||||
// incorrectly signed inputs, but we'll restore the result ourselves.
|
||||
// This sets DIRTY, so any interruptor will save the state.
|
||||
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
||||
// If we are interrupted here, the interruptor will have restored everything but the
|
||||
// quotient may be wrongly signed. If the calculation started by the above writes is
|
||||
// still ongoing it is stopped, so it won't replace the result we're restoring.
|
||||
// DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
|
||||
sio.div_remainder.write(|w| unsafe { w.bits(remainder) });
|
||||
// State fully restored after the quotient write. This sets both DIRTY and READY, so
|
||||
// whatever we may have interrupted can read the result.
|
||||
sio.div_quotient.write(|w| unsafe { w.bits(quotient) });
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn save_divider<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
let sio = unsafe { &(*pac::SIO::ptr()) };
|
||||
if !sio.div_csr.read().dirty().bit() {
|
||||
// Not dirty, so nothing is waiting for the calculation. So we can just
|
||||
// issue it directly without a save/restore.
|
||||
f()
|
||||
} else {
|
||||
save_divider_and_call(f)
|
||||
}
|
||||
}
|
||||
|
||||
trait ROMDiv {
|
||||
fn rom_div(self, b: Self) -> Self;
|
||||
|
@ -9,14 +74,14 @@ trait ROMDiv {
|
|||
impl ROMDiv for f32 {
|
||||
fn rom_div(self, b: Self) -> Self {
|
||||
// ROM implementation uses the hardware divider, so we have to save it
|
||||
save_divider(|_sio| rom_data::float_funcs::fdiv(self, b))
|
||||
save_divider(|| rom_data::float_funcs::fdiv(self, b))
|
||||
}
|
||||
}
|
||||
|
||||
impl ROMDiv for f64 {
|
||||
fn rom_div(self, b: Self) -> Self {
|
||||
// ROM implementation uses the hardware divider, so we have to save it
|
||||
save_divider(|_sio| rom_data::double_funcs::ddiv(self, b))
|
||||
save_divider(|| rom_data::double_funcs::ddiv(self, b))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ use eh1_0_alpha::i2c as eh1;
|
|||
|
||||
use super::{i2c_reserved_addr, Controller, Error, SclPin, SdaPin, I2C};
|
||||
|
||||
#[cfg(feature = "embassy-traits")]
|
||||
mod embassy_support;
|
||||
|
||||
impl<T: SubsystemReset + Deref<Target = Block>, Sda: PinId + BankPinId, Scl: PinId + BankPinId>
|
||||
I2C<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Controller>
|
||||
{
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
use core::{future::Future, iter::Peekable, ops::Deref, task::Poll};
|
||||
|
||||
use super::{Block, Controller, Error, I2C};
|
||||
|
||||
impl<T: Deref<Target = Block>, PINS> I2C<T, PINS, Controller> {
|
||||
async fn non_blocking_read_internal<'a, U: Iterator<Item = &'a mut u8> + 'a>(
|
||||
&mut self,
|
||||
mut buffer: Peekable<U>,
|
||||
) -> Result<(), Error> {
|
||||
let mut first = true;
|
||||
while let Some(byte) = buffer.next() {
|
||||
let last = buffer.peek().is_none();
|
||||
|
||||
// wait until there is space in the FIFO to write the next byte
|
||||
block_on(|| {
|
||||
if self.tx_fifo_full() {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
self.i2c.ic_data_cmd.write(|w| {
|
||||
if first {
|
||||
w.restart().enable();
|
||||
first = false;
|
||||
} else {
|
||||
w.restart().disable();
|
||||
}
|
||||
|
||||
if last {
|
||||
w.stop().enable();
|
||||
} else {
|
||||
w.stop().disable();
|
||||
}
|
||||
|
||||
w.cmd().read()
|
||||
});
|
||||
|
||||
block_on(|| {
|
||||
if let Some(abort_reason) = self.read_and_clear_abort_reason() {
|
||||
Poll::Ready(Err(Error::Abort(abort_reason)))
|
||||
} else if self.i2c.ic_rxflr.read().bits() != 0 {
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
|
||||
*byte = self.i2c.ic_data_cmd.read().dat().bits();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn non_blocking_write_internal(
|
||||
&mut self,
|
||||
bytes: impl IntoIterator<Item = u8>,
|
||||
do_stop: bool,
|
||||
) -> Result<(), Error> {
|
||||
let mut bytes = bytes.into_iter().peekable();
|
||||
while let Some(byte) = bytes.next() {
|
||||
let last = bytes.peek().is_none();
|
||||
|
||||
self.i2c.ic_data_cmd.write(|w| {
|
||||
if do_stop && last {
|
||||
w.stop().enable();
|
||||
} else {
|
||||
w.stop().disable();
|
||||
}
|
||||
unsafe { w.dat().bits(byte) }
|
||||
});
|
||||
|
||||
// Wait until the transmission of the address/data from the internal
|
||||
// shift register has completed. For this to function correctly, the
|
||||
// TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag
|
||||
// was set in i2c_init.
|
||||
block_on(|| {
|
||||
if self.i2c.ic_raw_intr_stat.read().tx_empty().is_inactive() {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
let abort_reason = self.read_and_clear_abort_reason();
|
||||
|
||||
if abort_reason.is_some() || (do_stop && last) {
|
||||
// If the transaction was aborted or if it completed
|
||||
// successfully wait until the STOP condition has occured.
|
||||
|
||||
block_on(|| {
|
||||
if self.i2c.ic_raw_intr_stat.read().stop_det().is_inactive() {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
self.i2c.ic_clr_stop_det.read().clr_stop_det();
|
||||
}
|
||||
|
||||
// Note the hardware issues a STOP automatically on an abort condition.
|
||||
// Note also the hardware clears RX FIFO as well as TX on abort,
|
||||
// ecause we set hwparam IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
|
||||
if let Some(abort_reason) = abort_reason {
|
||||
return Err(Error::Abort(abort_reason));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
async fn block_on<F: FnMut() -> Poll<T>, T>(mut f: F) -> T {
|
||||
futures::future::poll_fn(|cx| {
|
||||
// always ready to scan
|
||||
cx.waker().wake_by_ref();
|
||||
|
||||
f()
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
impl<T, PINS, A> embassy_traits::i2c::I2c<A> for I2C<T, PINS, Controller>
|
||||
where
|
||||
T: Deref<Target = Block>,
|
||||
A: embassy_traits::i2c::AddressMode + 'static + Into<u16>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
#[rustfmt::skip]
|
||||
type WriteFuture<'a>
|
||||
where
|
||||
Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||
|
||||
#[rustfmt::skip]
|
||||
type ReadFuture<'a>
|
||||
where
|
||||
Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||
|
||||
#[rustfmt::skip]
|
||||
type WriteReadFuture<'a>
|
||||
where
|
||||
Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
let mut buffer = buffer.iter_mut().peekable();
|
||||
let addr: u16 = address.into();
|
||||
|
||||
async move {
|
||||
self.setup(addr);
|
||||
|
||||
Self::validate(addr, None, Some(buffer.peek().is_none()))?;
|
||||
|
||||
self.non_blocking_read_internal(buffer).await
|
||||
}
|
||||
}
|
||||
|
||||
fn write<'a>(&'a mut self, address: A, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
async move {
|
||||
let addr: u16 = address.into();
|
||||
Self::validate(addr, Some(bytes.is_empty()), None)?;
|
||||
self.setup(addr);
|
||||
|
||||
self.non_blocking_write_internal(bytes.iter().cloned(), true)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
fn write_read<'a>(
|
||||
&'a mut self,
|
||||
address: A,
|
||||
bytes: &'a [u8],
|
||||
buffer: &'a mut [u8],
|
||||
) -> Self::WriteReadFuture<'a> {
|
||||
async move {
|
||||
let addr: u16 = address.into();
|
||||
Self::validate(addr, Some(bytes.is_empty()), Some(buffer.is_empty()))?;
|
||||
self.setup(addr);
|
||||
|
||||
self.non_blocking_write_internal(bytes.iter().cloned(), false)
|
||||
.await?;
|
||||
self.non_blocking_read_internal(buffer.iter_mut().peekable())
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T, PINS, A> embassy_traits::i2c::WriteIter<A> for I2C<T, PINS, Controller>
|
||||
where
|
||||
T: Deref<Target = Block>,
|
||||
A: embassy_traits::i2c::AddressMode + 'static + Into<u16>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
#[rustfmt::skip]
|
||||
type WriteIterFuture<'a, U>
|
||||
where
|
||||
U: 'a + IntoIterator<Item = u8>,
|
||||
Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||
|
||||
fn write_iter<'a, U>(&'a mut self, address: A, bytes: U) -> Self::WriteIterFuture<'a, U>
|
||||
where
|
||||
U: IntoIterator<Item = u8> + 'a,
|
||||
{
|
||||
let addr: u16 = address.into();
|
||||
async move {
|
||||
let mut bytes = bytes.into_iter().peekable();
|
||||
Self::validate(addr, Some(bytes.peek().is_none()), None)?;
|
||||
|
||||
self.setup(addr);
|
||||
|
||||
self.non_blocking_write_internal(bytes, true).await
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,9 +13,10 @@ macro_rules! intrinsics_aliases {
|
|||
$($rest:ident)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
intrinsics! {
|
||||
extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||
$name($($argname),*)
|
||||
mod $alias {
|
||||
#[no_mangle]
|
||||
pub extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,9 +32,10 @@ macro_rules! intrinsics_aliases {
|
|||
$($rest:ident)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
intrinsics! {
|
||||
mod $alias {
|
||||
#[no_mangle]
|
||||
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||
$name($($argname),*)
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#![warn(missing_docs)]
|
||||
#![no_std]
|
||||
#![cfg_attr(feature = "embassy-traits", feature(generic_associated_types))]
|
||||
#![cfg_attr(feature = "embassy-traits", feature(type_alias_impl_trait))]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate embedded_hal as hal;
|
||||
|
@ -49,6 +47,15 @@ pub mod xosc;
|
|||
pub use adc::Adc;
|
||||
pub use clocks::Clock;
|
||||
pub use i2c::I2C;
|
||||
/// Attribute to declare the entry point of the program
|
||||
///
|
||||
/// This is based on and can be used like the [entry attribute from
|
||||
/// cortex-m-rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html).
|
||||
///
|
||||
/// It extends that macro with code to unlock all spinlocks at the beginning
|
||||
/// of `main`. As spinlocks are not automatically unlocked on software resets,
|
||||
/// this can prevent unexpected deadlocks when running from a debugger.
|
||||
pub use rp2040_hal_macros::entry;
|
||||
pub use sio::Sio;
|
||||
pub use spi::Spi;
|
||||
pub use timer::Timer;
|
||||
|
|
|
@ -44,7 +44,7 @@ use crate::Sio;
|
|||
pub enum Error {
|
||||
/// Operation is invalid on this core.
|
||||
InvalidCore,
|
||||
/// Core was unresposive to commands.
|
||||
/// Core was unresponsive to commands.
|
||||
Unresponsive,
|
||||
}
|
||||
|
||||
|
|
|
@ -244,13 +244,11 @@ impl<P: PIOExt> PIO<P> {
|
|||
/// let mut peripherals = pac::Peripherals::take().unwrap();
|
||||
/// let (mut pio, sm0, _, _, _) = peripherals.PIO0.split(&mut peripherals.RESETS);
|
||||
/// // Install a program in instruction memory.
|
||||
/// let program = pio_proc::pio!(
|
||||
/// 32,
|
||||
/// ".wrap_target
|
||||
/// set pins, 1 [31]
|
||||
/// set pins, 0 [31]
|
||||
/// .wrap
|
||||
/// "
|
||||
/// let program = pio_proc::pio_asm!(
|
||||
/// ".wrap_target",
|
||||
/// "set pins, 1 [31]",
|
||||
/// "set pins, 0 [31]",
|
||||
/// ".wrap"
|
||||
/// ).program;
|
||||
/// let installed = pio.install(&program).unwrap();
|
||||
/// // Configure a state machine to use the program.
|
||||
|
@ -657,6 +655,352 @@ impl<P: PIOExt, SM: StateMachineIndex> StateMachine<(P, SM), Stopped> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<P: PIOExt, SM: StateMachineIndex, State> StateMachine<(P, SM), State> {
|
||||
/// Create a group of state machines, which can be started/stopped synchronously
|
||||
pub fn with<SM2: StateMachineIndex>(
|
||||
self,
|
||||
other_sm: StateMachine<(P, SM2), State>,
|
||||
) -> StateMachineGroup2<P, SM, SM2, State> {
|
||||
StateMachineGroup2 {
|
||||
sm1: self,
|
||||
sm2: other_sm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Group of 2 state machines, which can be started/stopped synchronously.
|
||||
pub struct StateMachineGroup2<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
State,
|
||||
> {
|
||||
sm1: StateMachine<(P, SM1Idx), State>,
|
||||
sm2: StateMachine<(P, SM2Idx), State>,
|
||||
}
|
||||
|
||||
/// Group of 3 state machines, which can be started/stopped synchronously.
|
||||
pub struct StateMachineGroup3<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
State,
|
||||
> {
|
||||
sm1: StateMachine<(P, SM1Idx), State>,
|
||||
sm2: StateMachine<(P, SM2Idx), State>,
|
||||
sm3: StateMachine<(P, SM3Idx), State>,
|
||||
}
|
||||
|
||||
/// Group of 4 state machines, which can be started/stopped synchronously.
|
||||
pub struct StateMachineGroup4<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
SM4Idx: StateMachineIndex,
|
||||
State,
|
||||
> {
|
||||
sm1: StateMachine<(P, SM1Idx), State>,
|
||||
sm2: StateMachine<(P, SM2Idx), State>,
|
||||
sm3: StateMachine<(P, SM3Idx), State>,
|
||||
sm4: StateMachine<(P, SM4Idx), State>,
|
||||
}
|
||||
|
||||
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex, State>
|
||||
StateMachineGroup2<P, SM1Idx, SM2Idx, State>
|
||||
{
|
||||
/// Split the group, releasing the contained state machines
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn free(
|
||||
self,
|
||||
) -> (
|
||||
StateMachine<(P, SM1Idx), State>,
|
||||
StateMachine<(P, SM2Idx), State>,
|
||||
) {
|
||||
(self.sm1, self.sm2)
|
||||
}
|
||||
|
||||
/// Add another state machine to the group
|
||||
pub fn with<SM3Idx: StateMachineIndex>(
|
||||
self,
|
||||
other_sm: StateMachine<(P, SM3Idx), State>,
|
||||
) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, State> {
|
||||
StateMachineGroup3 {
|
||||
sm1: self.sm1,
|
||||
sm2: self.sm2,
|
||||
sm3: other_sm,
|
||||
}
|
||||
}
|
||||
|
||||
fn mask(&self) -> u32 {
|
||||
(1 << SM1Idx::id()) | (1 << SM2Idx::id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
State,
|
||||
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, State>
|
||||
{
|
||||
/// Split the group, releasing the contained state machines
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn free(
|
||||
self,
|
||||
) -> (
|
||||
StateMachine<(P, SM1Idx), State>,
|
||||
StateMachine<(P, SM2Idx), State>,
|
||||
StateMachine<(P, SM3Idx), State>,
|
||||
) {
|
||||
(self.sm1, self.sm2, self.sm3)
|
||||
}
|
||||
|
||||
/// Add another state machine to the group
|
||||
pub fn with<SM4Idx: StateMachineIndex>(
|
||||
self,
|
||||
other_sm: StateMachine<(P, SM4Idx), State>,
|
||||
) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, State> {
|
||||
StateMachineGroup4 {
|
||||
sm1: self.sm1,
|
||||
sm2: self.sm2,
|
||||
sm3: self.sm3,
|
||||
sm4: other_sm,
|
||||
}
|
||||
}
|
||||
|
||||
fn mask(&self) -> u32 {
|
||||
(1 << SM1Idx::id()) | (1 << SM2Idx::id()) | (1 << SM3Idx::id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
SM4Idx: StateMachineIndex,
|
||||
State,
|
||||
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, State>
|
||||
{
|
||||
/// Split the group, releasing the contained state machines
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn free(
|
||||
self,
|
||||
) -> (
|
||||
StateMachine<(P, SM1Idx), State>,
|
||||
StateMachine<(P, SM2Idx), State>,
|
||||
StateMachine<(P, SM3Idx), State>,
|
||||
StateMachine<(P, SM4Idx), State>,
|
||||
) {
|
||||
(self.sm1, self.sm2, self.sm3, self.sm4)
|
||||
}
|
||||
|
||||
fn mask(&self) -> u32 {
|
||||
(1 << SM1Idx::id()) | (1 << SM2Idx::id()) | (1 << SM3Idx::id()) | (1 << SM4Idx::id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex>
|
||||
StateMachineGroup2<P, SM1Idx, SM2Idx, Stopped>
|
||||
{
|
||||
/// Start grouped state machines
|
||||
pub fn start(mut self) -> StateMachineGroup2<P, SM1Idx, SM2Idx, Running> {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask());
|
||||
StateMachineGroup2 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync grouped state machines
|
||||
pub fn sync(mut self) -> Self {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Stopped>
|
||||
{
|
||||
/// Start grouped state machines
|
||||
pub fn start(mut self) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Running> {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask());
|
||||
StateMachineGroup3 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm3: StateMachine {
|
||||
sm: self.sm3.sm,
|
||||
program: self.sm3.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync grouped state machines
|
||||
pub fn sync(mut self) -> Self {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
SM4Idx: StateMachineIndex,
|
||||
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Stopped>
|
||||
{
|
||||
/// Start grouped state machines
|
||||
pub fn start(mut self) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Running> {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask());
|
||||
StateMachineGroup4 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm3: StateMachine {
|
||||
sm: self.sm3.sm,
|
||||
program: self.sm3.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm4: StateMachine {
|
||||
sm: self.sm4.sm,
|
||||
program: self.sm4.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync grouped state machines
|
||||
pub fn sync(mut self) -> Self {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex>
|
||||
StateMachineGroup2<P, SM1Idx, SM2Idx, Running>
|
||||
{
|
||||
/// Stop grouped state machines
|
||||
pub fn stop(mut self) -> StateMachineGroup2<P, SM1Idx, SM2Idx, Stopped> {
|
||||
self.sm1.sm.clear_ctrl_bits(self.mask());
|
||||
StateMachineGroup2 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Running>
|
||||
{
|
||||
/// Stop grouped state machines
|
||||
pub fn stop(mut self) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Stopped> {
|
||||
self.sm1.sm.clear_ctrl_bits(self.mask());
|
||||
StateMachineGroup3 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm3: StateMachine {
|
||||
sm: self.sm3.sm,
|
||||
program: self.sm3.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
P: PIOExt,
|
||||
SM1Idx: StateMachineIndex,
|
||||
SM2Idx: StateMachineIndex,
|
||||
SM3Idx: StateMachineIndex,
|
||||
SM4Idx: StateMachineIndex,
|
||||
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Running>
|
||||
{
|
||||
/// Stop grouped state machines
|
||||
pub fn stop(mut self) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Stopped> {
|
||||
self.sm1.sm.clear_ctrl_bits(self.mask());
|
||||
StateMachineGroup4 {
|
||||
sm1: StateMachine {
|
||||
sm: self.sm1.sm,
|
||||
program: self.sm1.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm2: StateMachine {
|
||||
sm: self.sm2.sm,
|
||||
program: self.sm2.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm3: StateMachine {
|
||||
sm: self.sm3.sm,
|
||||
program: self.sm3.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
sm4: StateMachine {
|
||||
sm: self.sm4.sm,
|
||||
program: self.sm4.program,
|
||||
_phantom: core::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync grouped state machines
|
||||
pub fn sync(mut self) -> Self {
|
||||
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Type which, once destructed, restarts the clock dividers for all selected state machines,
|
||||
/// effectively synchronizing them.
|
||||
pub struct Synchronize<'sm, SM: ValidStateMachine> {
|
||||
|
|
|
@ -43,10 +43,10 @@ pub struct HwDivider {
|
|||
|
||||
/// Result of divide/modulo operation
|
||||
pub struct DivResult<T> {
|
||||
/// The remainder of divide/modulo operation
|
||||
pub remainder: T,
|
||||
/// The quotient of divide/modulo operation
|
||||
pub quotient: T,
|
||||
/// The remainder of divide/modulo operation
|
||||
pub remainder: T,
|
||||
}
|
||||
|
||||
/// Struct containing ownership markers for managing ownership of the SIO registers.
|
||||
|
@ -171,107 +171,159 @@ impl SioFifo {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn save_divider<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&pac::sio::RegisterBlock) -> R,
|
||||
{
|
||||
let sio = unsafe { &(*pac::SIO::ptr()) };
|
||||
if !sio.div_csr.read().dirty().bit() {
|
||||
// Not dirty, so nothing is waiting for the calculation. So we can just
|
||||
// issue it directly without a save/restore.
|
||||
f(sio)
|
||||
} else {
|
||||
// Since we can't save the signed-ness of the calculation, we have to make
|
||||
// sure that there's at least an 8 cycle delay before we read the result.
|
||||
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
|
||||
// Since we can't be sure the Rust implementation will optimize to the same,
|
||||
// just use an explicit wait.
|
||||
while !sio.div_csr.read().ready().bit() {}
|
||||
// This takes advantage of how AAPCS defines a 64-bit return on 32-bit registers
|
||||
// by packing it into r0[0:31] and r1[32:63]. So all we need to do is put
|
||||
// the remainder in the high order 32 bits of a 64 bit result. We can also
|
||||
// alias the division operators to these for a similar reason r0 is the
|
||||
// result either way and r1 a scratch register, so the caller can't assume it
|
||||
// retains the argument value.
|
||||
#[cfg(target_arch = "arm")]
|
||||
core::arch::global_asm!(
|
||||
".macro hwdivider_head",
|
||||
"ldr r2, =(0xd0000000)", // SIO_BASE
|
||||
// Check the DIRTY state of the divider by shifting it into the C
|
||||
// status bit.
|
||||
"ldr r3, [r2, #0x078]", // DIV_CSR
|
||||
"lsrs r3, #2", // DIRTY = 1, so shift 2 down
|
||||
// We only need to save the state when DIRTY, otherwise we can just do the
|
||||
// division directly.
|
||||
"bcs 2f",
|
||||
"1:",
|
||||
// Do the actual division now, we're either not DIRTY, or we've saved the
|
||||
// state and branched back here so it's safe now.
|
||||
".endm",
|
||||
".macro hwdivider_tail",
|
||||
// 8 cycle delay to wait for the result. Each branch takes two cycles
|
||||
// and fits into a 2-byte Thumb instruction, so this is smaller than
|
||||
// 8 NOPs.
|
||||
"b 3f",
|
||||
"3: b 3f",
|
||||
"3: b 3f",
|
||||
"3: b 3f",
|
||||
"3:",
|
||||
// Read the quotient last, since that's what clears the dirty flag.
|
||||
"ldr r1, [r2, #0x074]", // DIV_REMAINDER
|
||||
"ldr r0, [r2, #0x070]", // DIV_QUOTIENT
|
||||
// Either return to the caller or back to the state restore.
|
||||
"bx lr",
|
||||
"2:",
|
||||
// Since we can't save the signed-ness of the calculation, we have to make
|
||||
// sure that there's at least an 8 cycle delay before we read the result.
|
||||
// The push takes 5 cycles, and we've already spent at least 7 checking
|
||||
// the DIRTY state to get here.
|
||||
"push {{r4-r6, lr}}",
|
||||
// Read the quotient last, since that's what clears the dirty flag.
|
||||
"ldr r3, [r2, #0x060]", // DIV_UDIVIDEND
|
||||
"ldr r4, [r2, #0x064]", // DIV_UDIVISOR
|
||||
"ldr r5, [r2, #0x074]", // DIV_REMAINDER
|
||||
"ldr r6, [r2, #0x070]", // DIV_QUOTIENT
|
||||
// If we get interrupted here (before a write sets the DIRTY flag) it's
|
||||
// fine, since we have the full state, so the interruptor doesn't have to
|
||||
// restore it. Once the write happens and the DIRTY flag is set, the
|
||||
// interruptor becomes responsible for restoring our state.
|
||||
"bl 1b",
|
||||
// If we are interrupted here, then the interruptor will start an incorrect
|
||||
// calculation using a wrong divisor, but we'll restore the divisor and
|
||||
// result ourselves correctly. This sets DIRTY, so any interruptor will
|
||||
// save the state.
|
||||
"str r3, [r2, #0x060]", // DIV_UDIVIDEND
|
||||
// If we are interrupted here, the the interruptor may start the
|
||||
// calculation using incorrectly signed inputs, but we'll restore the
|
||||
// result ourselves. This sets DIRTY, so any interruptor will save the
|
||||
// state.
|
||||
"str r4, [r2, #0x064]", // DIV_UDIVISOR
|
||||
// If we are interrupted here, the interruptor will have restored
|
||||
// everything but the quotient may be wrongly signed. If the calculation
|
||||
// started by the above writes is still ongoing it is stopped, so it won't
|
||||
// replace the result we're restoring. DIRTY and READY set, but only
|
||||
// DIRTY matters to make the interruptor save the state.
|
||||
"str r5, [r2, #0x074]", // DIV_REMAINDER
|
||||
// State fully restored after the quotient write. This sets both DIRTY
|
||||
// and READY, so whatever we may have interrupted can read the result.
|
||||
"str r6, [r2, #0x070]", // DIV_QUOTIENT
|
||||
"pop {{r4-r6, pc}}",
|
||||
".endm",
|
||||
);
|
||||
|
||||
// Read the quotient last, since that's what clears the dirty flag
|
||||
let dividend = sio.div_udividend.read().bits();
|
||||
let divisor = sio.div_udivisor.read().bits();
|
||||
let remainder = sio.div_remainder.read().bits();
|
||||
let quotient = sio.div_quotient.read().bits();
|
||||
macro_rules! division_function {
|
||||
(
|
||||
$name:ident $($intrinsic:ident)* ( $argty:ty ) {
|
||||
$($begin:literal),+
|
||||
}
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
core::arch::global_asm!(
|
||||
// Mangle the name slightly, since this is a global symbol.
|
||||
concat!(".global _rphal_", stringify!($name)),
|
||||
concat!(".type _rphal_", stringify!($name), ", %function"),
|
||||
".align 2",
|
||||
concat!("_rphal_", stringify!($name), ":"),
|
||||
$(
|
||||
concat!(".global ", stringify!($intrinsic)),
|
||||
concat!(".type ", stringify!($intrinsic), ", %function"),
|
||||
concat!(stringify!($intrinsic), ":"),
|
||||
)*
|
||||
|
||||
// If we get interrupted here (before a write sets the DIRTY flag) its fine, since
|
||||
// we have the full state, so the interruptor doesn't have to restore it. Once the
|
||||
// write happens and the DIRTY flag is set, the interruptor becomes responsible for
|
||||
// restoring our state.
|
||||
let result = f(sio);
|
||||
"hwdivider_head",
|
||||
$($begin),+ ,
|
||||
"hwdivider_tail",
|
||||
);
|
||||
|
||||
// If we are interrupted here, then the interruptor will start an incorrect calculation
|
||||
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
|
||||
// This sets DIRTY, so any interruptor will save the state.
|
||||
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
||||
// If we are interrupted here, the the interruptor may start the calculation using
|
||||
// incorrectly signed inputs, but we'll restore the result ourselves.
|
||||
// This sets DIRTY, so any interruptor will save the state.
|
||||
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
||||
// If we are interrupted here, the interruptor will have restored everything but the
|
||||
// quotient may be wrongly signed. If the calculation started by the above writes is
|
||||
// still ongoing it is stopped, so it won't replace the result we're restoring.
|
||||
// DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
|
||||
sio.div_remainder.write(|w| unsafe { w.bits(remainder) });
|
||||
// State fully restored after the quotient write. This sets both DIRTY and READY, so
|
||||
// whatever we may have interrupted can read the result.
|
||||
sio.div_quotient.write(|w| unsafe { w.bits(quotient) });
|
||||
#[cfg(all(target_arch = "arm", feature = "disable-intrinsics"))]
|
||||
core::arch::global_asm!(
|
||||
// Mangle the name slightly, since this is a global symbol.
|
||||
concat!(".global _rphal_", stringify!($name)),
|
||||
concat!(".type _rphal_", stringify!($name), ", %function"),
|
||||
".align 2",
|
||||
concat!("_rphal_", stringify!($name), ":"),
|
||||
|
||||
result
|
||||
"hwdivider_head",
|
||||
$($begin),+ ,
|
||||
"hwdivider_tail",
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
extern "aapcs" {
|
||||
// Connect a local name to global symbol above through FFI.
|
||||
#[link_name = concat!("_rphal_", stringify!($name)) ]
|
||||
fn $name(n: $argty, d: $argty) -> u64;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "arm"))]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn $name(n: $argty, d: $argty) -> u64 { 0 }
|
||||
};
|
||||
}
|
||||
|
||||
division_function! {
|
||||
unsigned_divmod __aeabi_uidivmod __aeabi_uidiv ( u32 ) {
|
||||
"str r0, [r2, #0x060]", // DIV_UDIVIDEND
|
||||
"str r1, [r2, #0x064]" // DIV_UDIVISOR
|
||||
}
|
||||
}
|
||||
|
||||
// Don't use cortex_m::asm::delay(8) because that ends up delaying 15 cycles
|
||||
// on Cortex-M0. Each iteration of the inner loop is 3 cycles and it adds
|
||||
// one extra iteration.
|
||||
#[inline(always)]
|
||||
fn divider_delay() {
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
cortex_m::asm::nop();
|
||||
division_function! {
|
||||
signed_divmod __aeabi_idivmod __aeabi_idiv ( i32 ) {
|
||||
"str r0, [r2, #0x068]", // DIV_SDIVIDEND
|
||||
"str r1, [r2, #0x06c]" // DIV_SDIVISOR
|
||||
}
|
||||
}
|
||||
|
||||
fn divider_unsigned(dividend: u32, divisor: u32) -> DivResult<u32> {
|
||||
save_divider(|sio| {
|
||||
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
||||
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
||||
|
||||
divider_delay();
|
||||
|
||||
// Note: quotient must be read last
|
||||
let remainder = sio.div_remainder.read().bits();
|
||||
let quotient = sio.div_quotient.read().bits();
|
||||
|
||||
DivResult {
|
||||
remainder,
|
||||
quotient,
|
||||
}
|
||||
})
|
||||
fn divider_unsigned(n: u32, d: u32) -> DivResult<u32> {
|
||||
let packed = unsafe { unsigned_divmod(n, d) };
|
||||
DivResult {
|
||||
quotient: packed as u32,
|
||||
remainder: (packed >> 32) as u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn divider_signed(dividend: i32, divisor: i32) -> DivResult<i32> {
|
||||
save_divider(|sio| {
|
||||
sio.div_sdividend
|
||||
.write(|w| unsafe { w.bits(dividend as u32) });
|
||||
sio.div_sdivisor
|
||||
.write(|w| unsafe { w.bits(divisor as u32) });
|
||||
|
||||
divider_delay();
|
||||
|
||||
// Note: quotient must be read last
|
||||
let remainder = sio.div_remainder.read().bits() as i32;
|
||||
let quotient = sio.div_quotient.read().bits() as i32;
|
||||
|
||||
DivResult {
|
||||
remainder,
|
||||
quotient,
|
||||
}
|
||||
})
|
||||
fn divider_signed(n: i32, d: i32) -> DivResult<i32> {
|
||||
let packed = unsafe { signed_divmod(n, d) };
|
||||
// Double casts to avoid sign extension
|
||||
DivResult {
|
||||
quotient: packed as u32 as i32,
|
||||
remainder: (packed >> 32) as u32 as i32,
|
||||
}
|
||||
}
|
||||
|
||||
impl HwDivider {
|
||||
|
@ -287,7 +339,6 @@ impl HwDivider {
|
|||
}
|
||||
|
||||
intrinsics! {
|
||||
#[aeabi = __aeabi_uidiv]
|
||||
extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
||||
divider_unsigned(n, d).quotient
|
||||
}
|
||||
|
@ -304,7 +355,6 @@ intrinsics! {
|
|||
quo_rem.quotient
|
||||
}
|
||||
|
||||
#[aeabi = __aeabi_idiv]
|
||||
extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
|
||||
divider_signed(n, d).quotient
|
||||
}
|
||||
|
@ -598,3 +648,22 @@ pub fn spinlock_state() -> [bool; 32] {
|
|||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Free all spinlocks, regardless of their current status
|
||||
///
|
||||
/// RP2040 does not release all spinlocks on reset.
|
||||
/// The C SDK clears these all during entry, and so do we if you call hal::entry!
|
||||
/// But if someone is using the default cortex-m entry they risk hitting deadlocks so provide *something* to help out
|
||||
///
|
||||
/// # Safety
|
||||
/// Where possible, you should use the hal::entry macro attribute on main instead of this.
|
||||
/// You should call this as soon as possible after reset - preferably as the first entry in fn main(), before *ANY* use of spinlocks, atomics, or critical_section
|
||||
pub unsafe fn spinlock_reset() {
|
||||
// Using raw pointers to avoid taking peripherals accidently at startup
|
||||
const SIO_BASE: u32 = 0xd0000000;
|
||||
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
|
||||
const SPINLOCK_COUNT: usize = 32;
|
||||
for i in 0..SPINLOCK_COUNT {
|
||||
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,18 +148,51 @@ impl embedded_hal::timer::Cancel for CountDown<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Alarm abstraction.
|
||||
pub trait Alarm {
|
||||
/// Clear the interrupt flag.
|
||||
///
|
||||
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
|
||||
fn clear_interrupt(&mut self);
|
||||
|
||||
/// Enable this alarm to trigger an interrupt.
|
||||
///
|
||||
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
|
||||
///
|
||||
/// [clear_interrupt]: #method.clear_interrupt
|
||||
fn enable_interrupt(&mut self);
|
||||
|
||||
/// Disable this alarm, preventing it from triggering an interrupt.
|
||||
fn disable_interrupt(&mut self);
|
||||
|
||||
/// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
|
||||
/// this will trigger interrupt whenever this time elapses.
|
||||
///
|
||||
/// The RP2040 has been observed to take a little while to schedule an alarm. For this
|
||||
/// reason, the minimum time that this function accepts is `10.microseconds()`
|
||||
///
|
||||
/// [enable_interrupt]: #method.enable_interrupt
|
||||
fn schedule<TIME: Into<Microseconds>>(
|
||||
&mut self,
|
||||
countdown: TIME,
|
||||
) -> Result<(), ScheduleAlarmError>;
|
||||
|
||||
/// Return true if this alarm is finished.
|
||||
fn finished(&self) -> bool;
|
||||
}
|
||||
|
||||
macro_rules! impl_alarm {
|
||||
($name:ident { rb: $timer_alarm:ident, int: $int_alarm:ident, int_name: $int_name:tt, armed_bit_mask: $armed_bit_mask: expr }) => {
|
||||
/// An alarm that can be used to schedule events in the future. Alarms can also be configured to trigger interrupts.
|
||||
pub struct $name(PhantomData<()>);
|
||||
|
||||
impl $name {
|
||||
impl Alarm for $name {
|
||||
/// Clear the interrupt flag. This should be called after interrupt `
|
||||
#[doc = $int_name]
|
||||
/// ` is called.
|
||||
///
|
||||
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
|
||||
pub fn clear_interrupt(&mut self) {
|
||||
fn clear_interrupt(&mut self) {
|
||||
// safety: TIMER.intr is a write-clear register, so we can atomically clear our interrupt
|
||||
// by writing its value to this field
|
||||
// Only one instance of this alarm index can exist, and only this alarm interacts with this bit
|
||||
|
@ -177,7 +210,7 @@ macro_rules! impl_alarm {
|
|||
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
|
||||
///
|
||||
/// [clear_interrupt]: #method.clear_interrupt
|
||||
pub fn enable_interrupt(&mut self) {
|
||||
fn enable_interrupt(&mut self) {
|
||||
// safety: using the atomic set alias means we can atomically set our interrupt enable bit.
|
||||
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
|
||||
// of the TIMER.inte register
|
||||
|
@ -189,7 +222,7 @@ macro_rules! impl_alarm {
|
|||
}
|
||||
|
||||
/// Disable this alarm, preventing it from triggering an interrupt.
|
||||
pub fn disable_interrupt(&mut self) {
|
||||
fn disable_interrupt(&mut self) {
|
||||
// safety: using the atomic set alias means we can atomically clear our interrupt enable bit.
|
||||
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
|
||||
// of the TIMER.inte register
|
||||
|
@ -207,7 +240,7 @@ macro_rules! impl_alarm {
|
|||
/// The RP2040 has been observed to take a little while to schedule an alarm. For this reason, the minimum time that this function accepts is `10.microseconds()`
|
||||
///
|
||||
/// [enable_interrupt]: #method.enable_interrupt
|
||||
pub fn schedule<TIME: Into<Microseconds>>(
|
||||
fn schedule<TIME: Into<Microseconds>>(
|
||||
&mut self,
|
||||
countdown: TIME,
|
||||
) -> Result<(), ScheduleAlarmError> {
|
||||
|
@ -235,7 +268,7 @@ macro_rules! impl_alarm {
|
|||
}
|
||||
|
||||
/// Return true if this alarm is finished.
|
||||
pub fn finished(&self) -> bool {
|
||||
fn finished(&self) -> bool {
|
||||
// safety: This is a read action and should not have any UB
|
||||
let bits: u32 = unsafe { &*TIMER::ptr() }.armed.read().bits();
|
||||
(bits & $armed_bit_mask) == 0
|
||||
|
|
|
@ -16,14 +16,13 @@ use rp2040_pac::{UART0, UART1};
|
|||
|
||||
#[cfg(feature = "eh1_0_alpha")]
|
||||
use eh1_0_alpha::serial as eh1;
|
||||
use pac::Peripherals;
|
||||
|
||||
/// An UART Peripheral based on an underlying UART device.
|
||||
pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
|
||||
device: D,
|
||||
_state: S,
|
||||
pins: P,
|
||||
config: UartConfig,
|
||||
effective_baudrate: Baud,
|
||||
}
|
||||
|
||||
impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
|
||||
|
@ -31,8 +30,6 @@ impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
|
|||
UartPeripheral {
|
||||
device: self.device,
|
||||
pins: self.pins,
|
||||
config: self.config,
|
||||
effective_baudrate: self.effective_baudrate,
|
||||
_state: state,
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +50,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
|
|||
device,
|
||||
_state: Disabled,
|
||||
pins,
|
||||
config: common_configs::_9600_8_N_1, // placeholder
|
||||
effective_baudrate: Baud(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +60,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
|
|||
frequency: Hertz,
|
||||
) -> Result<UartPeripheral<Enabled, D, P>, Error> {
|
||||
let (mut device, pins) = self.free();
|
||||
let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?;
|
||||
configure_baudrate(&mut device, &config.baudrate, &frequency)?;
|
||||
|
||||
device.uartlcr_h.write(|w| {
|
||||
// FIFOs are enabled
|
||||
|
@ -93,9 +88,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
|
|||
|
||||
Ok(UartPeripheral {
|
||||
device,
|
||||
config,
|
||||
pins,
|
||||
effective_baudrate,
|
||||
_state: Enabled,
|
||||
})
|
||||
}
|
||||
|
@ -192,8 +185,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Enabled, D, P> {
|
|||
device: reader.device,
|
||||
_state: Enabled,
|
||||
pins: reader.pins,
|
||||
config: reader.config,
|
||||
effective_baudrate: reader.effective_baudrate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,11 +195,9 @@ impl<P: ValidUartPinout<UART0>> UartPeripheral<Enabled, UART0, P> {
|
|||
let reader = Reader {
|
||||
device: self.device,
|
||||
pins: self.pins,
|
||||
config: self.config,
|
||||
effective_baudrate: self.effective_baudrate,
|
||||
};
|
||||
// Safety: reader and writer will never write to the same address
|
||||
let device_copy = unsafe { &*UART0::ptr() };
|
||||
let device_copy = unsafe { Peripherals::steal().UART0 };
|
||||
let writer = Writer {
|
||||
device: device_copy,
|
||||
device_marker: core::marker::PhantomData,
|
||||
|
@ -224,11 +213,9 @@ impl<P: ValidUartPinout<UART1>> UartPeripheral<Enabled, UART1, P> {
|
|||
let reader = Reader {
|
||||
device: self.device,
|
||||
pins: self.pins,
|
||||
config: self.config,
|
||||
effective_baudrate: self.effective_baudrate,
|
||||
};
|
||||
// Safety: reader and writer will never write to the same address
|
||||
let device_copy = unsafe { &*UART1::ptr() };
|
||||
let device_copy = unsafe { Peripherals::steal().UART1 };
|
||||
let writer = Writer {
|
||||
device: device_copy,
|
||||
device_marker: core::marker::PhantomData,
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
//!
|
||||
//! This module is for receiving data with a UART.
|
||||
|
||||
use super::{UartConfig, UartDevice, ValidUartPinout};
|
||||
use super::{UartDevice, ValidUartPinout};
|
||||
use rp2040_pac::uart0::RegisterBlock;
|
||||
|
||||
use embedded_hal::serial::Read;
|
||||
use embedded_time::rate::Baud;
|
||||
use nb::Error::*;
|
||||
|
||||
#[cfg(feature = "eh1_0_alpha")]
|
||||
|
@ -167,8 +166,6 @@ pub(crate) fn read_full_blocking<D: UartDevice>(
|
|||
pub struct Reader<D: UartDevice, P: ValidUartPinout<D>> {
|
||||
pub(super) device: D,
|
||||
pub(super) pins: P,
|
||||
pub(super) config: UartConfig,
|
||||
pub(super) effective_baudrate: Baud,
|
||||
}
|
||||
|
||||
impl<D: UartDevice, P: ValidUartPinout<D>> Reader<D, P> {
|
||||
|
|
|
@ -114,7 +114,7 @@ pub(crate) fn disable_tx_interrupt(rb: &RegisterBlock) {
|
|||
/// [`UartPeripheral`]: struct.UartPeripheral.html
|
||||
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
|
||||
pub struct Writer<D: UartDevice, P: ValidUartPinout<D>> {
|
||||
pub(super) device: &'static RegisterBlock,
|
||||
pub(super) device: D,
|
||||
pub(super) device_marker: PhantomData<D>,
|
||||
pub(super) pins: PhantomData<P>,
|
||||
}
|
||||
|
@ -129,26 +129,26 @@ impl<D: UartDevice, P: ValidUartPinout<D>> Writer<D, P> {
|
|||
///
|
||||
/// Upon success, the remaining (unwritten) slice is returned.
|
||||
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
|
||||
write_raw(self.device, data)
|
||||
write_raw(&self.device, data)
|
||||
}
|
||||
|
||||
/// Writes bytes to the UART.
|
||||
///
|
||||
/// This function blocks until the full buffer has been sent.
|
||||
pub fn write_full_blocking(&self, data: &[u8]) {
|
||||
write_full_blocking(self.device, data);
|
||||
write_full_blocking(&self.device, data);
|
||||
}
|
||||
|
||||
/// Enables the Transmit Interrupt.
|
||||
///
|
||||
/// The relevant UARTx IRQ will fire when there is space in the transmit FIFO.
|
||||
pub fn enable_tx_interrupt(&mut self) {
|
||||
enable_tx_interrupt(self.device)
|
||||
enable_tx_interrupt(&self.device)
|
||||
}
|
||||
|
||||
/// Disables the Transmit Interrupt.
|
||||
pub fn disable_tx_interrupt(&mut self) {
|
||||
disable_tx_interrupt(self.device)
|
||||
disable_tx_interrupt(&self.device)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for Writer<D, P> {
|
|||
}
|
||||
|
||||
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||
transmit_flushed(self.device)
|
||||
transmit_flushed(&self.device)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> eh1::nb::Write<u8> for Writer<D, P> {
|
|||
}
|
||||
|
||||
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||
transmit_flushed(self.device).map_err(|e| match e {
|
||||
transmit_flushed(&self.device).map_err(|e| match e {
|
||||
WouldBlock => WouldBlock,
|
||||
Other(v) => match v {},
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue