mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-23 20:51:31 +11:00
Merge branch 'main' into multicore-no-alloc
This commit is contained in:
commit
b932663cc9
|
@ -2,6 +2,7 @@
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"rp2040-hal",
|
"rp2040-hal",
|
||||||
|
"rp2040-hal-macros",
|
||||||
"boards/adafruit-feather-rp2040",
|
"boards/adafruit-feather-rp2040",
|
||||||
"boards/adafruit-itsy-bitsy-rp2040",
|
"boards/adafruit-itsy-bitsy-rp2040",
|
||||||
"boards/adafruit-kb2040",
|
"boards/adafruit-kb2040",
|
||||||
|
|
|
@ -390,9 +390,9 @@ to intervene to uphold that code of conduct.
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-feather-rp2040-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adafruit-feather-rp2040"
|
name = "adafruit-feather-rp2040"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Andrea Nall <anall@andreanal.com>"]
|
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-feather-rp2040"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-feather-rp2040"
|
||||||
description = "Board Support Package for the 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"
|
embedded-hal ="0.2.5"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
pio = "0.1.0"
|
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["boot2", "rt"]
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-itsy-bitsy-rp2040-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adafruit-itsy-bitsy-rp2040"
|
name = "adafruit-itsy-bitsy-rp2040"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
|
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_itsy_bitsy_rp2040"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_itsy_bitsy_rp2040"
|
||||||
description = "Board Support Package for the Adafruit ItsyBitsy RP2040"
|
description = "Board Support Package for the Adafruit ItsyBitsy RP2040"
|
||||||
|
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
|
||||||
embedded-hal ="0.2.5"
|
embedded-hal ="0.2.5"
|
||||||
smart-leds = "0.3"
|
smart-leds = "0.3"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
pio = "0.1.0"
|
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt", "boot2"]
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-kb2040-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adafruit-kb2040"
|
name = "adafruit-kb2040"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
|
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-kb2040"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-kb2040"
|
||||||
description = "Board Support Package for the Adafruit adafruit-kb2040"
|
description = "Board Support Package for the Adafruit adafruit-kb2040"
|
||||||
|
@ -28,5 +28,4 @@ rp2040-boot2 = "0.2"
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
embedded-time = "0.12.0"
|
embedded-time = "0.12.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
pio = "0.1.0"
|
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
|
||||||
|
|
|
@ -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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-macropad-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adafruit-macropad"
|
name = "adafruit-macropad"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Andrea Nall <anall@andreanal.com>"]
|
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad"
|
||||||
description = "Board Support Package for the 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-boot2 = { version = "0.2.0", optional = true }
|
||||||
rp2040-hal = { path = "../../rp2040-hal", version = "0.4.0"}
|
rp2040-hal = { path = "../../rp2040-hal", version = "0.4.0"}
|
||||||
cortex-m-rt = { version = "0.7", optional = true }
|
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]
|
[features]
|
||||||
default = ["rt", "boot2"]
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
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 }
|
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
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-qt-py-rp2040-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adafruit-qt-py-rp2040"
|
name = "adafruit-qt-py-rp2040"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Stephen Onnen <stephen.onnen@gmail.com>"]
|
authors = ["Stephen Onnen <stephen.onnen@gmail.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-qt-py-rp2040"
|
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"
|
description = "Board Support Package for the Adafruit QT Py RP2040"
|
||||||
|
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
|
||||||
embedded-hal ="0.2.5"
|
embedded-hal ="0.2.5"
|
||||||
smart-leds = "0.3"
|
smart-leds = "0.3"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
pio = "0.1.0"
|
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
|
||||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["boot2", "rt"]
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -21,7 +21,7 @@ embedded-hal ="0.2.5"
|
||||||
embedded-time = "0.12.0"
|
embedded-time = "0.12.0"
|
||||||
smart-leds = "0.3"
|
smart-leds = "0.3"
|
||||||
nb = "1.0.0"
|
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]
|
[features]
|
||||||
default = ["boot2", "rt"]
|
default = ["boot2", "rt"]
|
||||||
|
|
|
@ -85,9 +85,9 @@ to intervene to uphold that code of conduct.
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-explorer-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pimoroni-pico-explorer"
|
name = "pimoroni-pico-explorer"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
|
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-explorer"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-explorer"
|
||||||
description = "Board Support Package for the 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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp2040-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-lipo-16mb-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pimoroni-pico-lipo-16mb"
|
name = "pimoroni-pico-lipo-16mb"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
|
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-lipo-16mb"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-lipo-16mb"
|
||||||
description = "Board Support Package for the 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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses
|
//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses
|
||||||
//! for the on-board LED.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pimoroni-tiny2040"
|
name = "pimoroni-tiny2040"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Mike Bell <mdb036@gmail.com>"]
|
authors = ["Mike Bell <mdb036@gmail.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-tiny2040"
|
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-tiny2040"
|
||||||
description = "Board Support Package for the Pimoroni Tiny2040"
|
description = "Board Support Package for the Pimoroni Tiny2040"
|
||||||
|
|
|
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.3.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp-hal 0.4.0
|
||||||
|
|
||||||
## [0.2.0] - 2021-12-23
|
## [0.2.0] - 2021-12-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -31,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
[@jannic]: https://github.com/jannic
|
[@jannic]: https://github.com/jannic
|
||||||
[rp-rs]: https://github.com/rp-rs
|
[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.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
|
[0.1.3]: https://github.com/jannic/rp-microcontroller-rs/tree/rp-pico-0.1.3
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rp-pico"
|
name = "rp-pico"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
authors = ["evan <evanmolder@gmail.com>"]
|
authors = ["evan <evanmolder@gmail.com>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
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"
|
description = "Board Support Package for the Raspberry Pi Pico"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/rp-rs/rp-hal.git"
|
repository = "https://github.com/rp-rs/rp-hal.git"
|
||||||
|
@ -26,11 +26,11 @@ panic-halt= "0.2.0"
|
||||||
embedded-hal ="0.2.5"
|
embedded-hal ="0.2.5"
|
||||||
cortex-m-rtic = "0.6.0-rc.4"
|
cortex-m-rtic = "0.6.0-rc.4"
|
||||||
nb = "1.0"
|
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"
|
heapless = "0.7.9"
|
||||||
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
|
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
|
||||||
smart-leds = "0.3.0"
|
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"
|
ssd1306 = "0.7.0"
|
||||||
embedded-graphics = "0.7.1"
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
||||||
//! the on-board LED.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
|
||||||
//! the on-board LED.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! internally by this example. When the button is pressed, the LED will turn
|
//! internally by this example. When the button is pressed, the LED will turn
|
||||||
//! off.
|
//! off.
|
||||||
//!
|
//!
|
||||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
//! See the `Cargo.toml` file for Copyright and license details.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
//! - (o) connected lines
|
//! - (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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! using the PIO peripheral as an I2C bus controller.
|
//! 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.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! This will fade in/out the LED attached to GP25, which is the pin the Pico
|
//! This will fade in/out the LED attached to GP25, which is the pin the Pico
|
||||||
//! uses for the on-board LED.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -9,7 +9,7 @@ mod app {
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
use embedded_time::duration::Extensions;
|
use embedded_time::duration::Extensions;
|
||||||
use rp_pico::{
|
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,
|
XOSC_CRYSTAL_FREQ,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +27,11 @@ mod app {
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
|
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 resets = c.device.RESETS;
|
||||||
let mut watchdog = Watchdog::new(c.device.WATCHDOG);
|
let mut watchdog = Watchdog::new(c.device.WATCHDOG);
|
||||||
let _clocks = init_clocks_and_plls(
|
let _clocks = init_clocks_and_plls(
|
||||||
|
|
|
@ -80,14 +80,14 @@
|
||||||
//!
|
//!
|
||||||
//! If there are 5 different error patterns, all with short blinking pulses:
|
//! 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.
|
//! no SD card is present or some electrical problem.
|
||||||
//! - **3 short blink (in a loop)**: Card size could not be retrieved.
|
//! - **3 short blink (in a loop)**: Card size could not be retrieved.
|
||||||
//! - **4 short blink (in a loop)**: Error getting volume/partition 0.
|
//! - **4 short blink (in a loop)**: Error getting volume/partition 0.
|
||||||
//! - **5 short blink (in a loop)**: Error opening root directory.
|
//! - **5 short blink (in a loop)**: Error opening root directory.
|
||||||
//! - **6 short blink (in a loop)**: Could not open file 'O.TST'.
|
//! - **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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//! * GPIO 1 - UART RX (in to the RP2040)
|
//! * GPIO 1 - UART RX (in to the RP2040)
|
||||||
//! * GPIO 25 - An LED we can blink (active high)
|
//! * 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
//! * GPIO 1 - UART RX (in to the RP2040)
|
//! * GPIO 1 - UART RX (in to the RP2040)
|
||||||
//! * GPIO 25 - An LED we can blink (active high)
|
//! * 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! ASCII characters are converted to upercase, so you can tell it is working
|
//! ASCII characters are converted to upercase, so you can tell it is working
|
||||||
//! and not just local-echo!
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! ASCII characters are converted to upercase, so you can tell it is working
|
//! ASCII characters are converted to upercase, so you can tell it is working
|
||||||
//! and not just local-echo!
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! It generates movement reports which will twitch the cursor up and down by a
|
//! It generates movement reports which will twitch the cursor up and down by a
|
||||||
//! few pixels, several times a second.
|
//! 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
|
//! This is a port of
|
||||||
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
|
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
//! - (o) connected lines
|
//! - (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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -27,5 +27,5 @@ embedded-hal ="0.2.5"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
pio = "0.1.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"
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
under these terms.
|
||||||
|
|
|
@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- None
|
- None
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update to rp-hal 0.4.0
|
||||||
|
|
||||||
## [0.1.0] - 2021-12-20
|
## [0.1.0] - 2021-12-20
|
||||||
|
|
||||||
- Initial release
|
- 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
|
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/sparkfun-pro-micro-rp2040-v0.1.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sparkfun-pro-micro-rp2040"
|
name = "sparkfun-pro-micro-rp2040"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>"]
|
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>", "The rp-rs Developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/sparkfun-pro-micro-rp2040"
|
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"
|
description = "Board Support Package for the Sparkfun Pro Micro RP2040"
|
||||||
|
@ -23,7 +23,7 @@ smart-leds = "0.3.0"
|
||||||
embedded-time = "0.12.0"
|
embedded-time = "0.12.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
pio = "0.1.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]
|
[features]
|
||||||
default = ["boot2", "rt"]
|
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:
|
To use this crate, your `Cargo.toml` file should contain:
|
||||||
|
|
||||||
```toml
|
```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
|
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
|
## License
|
||||||
|
|
||||||
The contents of this repository are dual-licensed under the _MIT OR Apache
|
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
|
2.0_ License. That means you can chose either the MIT license or the
|
||||||
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
|
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
|
||||||
information on each specific licence.
|
information on each specific license.
|
||||||
|
|
||||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||||
under these terms.
|
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]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- removed i2c embassy driver prototype
|
||||||
|
|
||||||
|
## [0.4.0] - 2022-03-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- ROM function caching
|
- ROM function caching
|
||||||
|
@ -17,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- UART IRQ examples
|
- UART IRQ examples
|
||||||
- PIO side-set example
|
- PIO side-set example
|
||||||
- Stopped PIO state machines can change their clock divider
|
- Stopped PIO state machines can change their clock divider
|
||||||
|
- Added HAL IRQ example
|
||||||
|
|
||||||
### Changed
|
### 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 critical_section to use new spinlock implementation
|
||||||
- Update embedded-hal alpha support to version 1.0.0-alpha.7
|
- Update embedded-hal alpha support to version 1.0.0-alpha.7
|
||||||
- Avoid 64-bit division in clock calculations
|
- Avoid 64-bit division in clock calculations
|
||||||
|
- Update pio and pio-proc to 0.2.0
|
||||||
|
|
||||||
## [0.3.0] - 2021-12-19
|
## [0.3.0] - 2021-12-19
|
||||||
|
|
||||||
|
@ -90,7 +98,8 @@ The Minimum-Supported Rust Version (MSRV) for this release is 1.54.
|
||||||
|
|
||||||
- Initial release
|
- 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.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.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
|
[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]
|
[dependencies]
|
||||||
cortex-m = "0.7.2"
|
cortex-m = "0.7.2"
|
||||||
|
cortex-m-rt = ">=0.6.15,<0.8"
|
||||||
embedded-hal = { version = "0.2.5", features = ["unproven"] }
|
embedded-hal = { version = "0.2.5", features = ["unproven"] }
|
||||||
eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true }
|
eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true }
|
||||||
embedded-time = "0.12.0"
|
embedded-time = "0.12.0"
|
||||||
|
@ -18,7 +19,8 @@ itertools = { version = "0.10.1", default-features = false }
|
||||||
nb = "1.0"
|
nb = "1.0"
|
||||||
rp2040-pac = "0.3.0"
|
rp2040-pac = "0.3.0"
|
||||||
paste = "1.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"
|
usb-device = "0.2.8"
|
||||||
vcell = "0.1"
|
vcell = "0.1"
|
||||||
void = { version = "1.0.2", default-features = false }
|
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 }
|
futures = { version = "0.3", default-features = false, optional = true }
|
||||||
chrono = { version = "0.4", 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]
|
[dev-dependencies]
|
||||||
cortex-m-rt = "0.7"
|
cortex-m-rt = "0.7"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
rp2040-boot2 = "0.2.0"
|
rp2040-boot2 = "0.2.0"
|
||||||
hd44780-driver = "0.4.0"
|
hd44780-driver = "0.4.0"
|
||||||
pio-proc = "0.1.0"
|
pio-proc = "0.2.0"
|
||||||
dht-sensor = "0.2.1"
|
dht-sensor = "0.2.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
rt = ["rp2040-pac/rt"]
|
rt = ["rp2040-pac/rt"]
|
||||||
# This is commented out so that we can publish to crates.io
|
|
||||||
#
|
|
||||||
# embassy-traits = ["embassy_traits", "futures"]
|
|
||||||
rom-func-cache = []
|
rom-func-cache = []
|
||||||
disable-intrinsics = []
|
disable-intrinsics = []
|
||||||
rom-v2-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
|
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
|
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
|
preference, and return here to see documentation about specific peripherals on
|
||||||
the RP2040 and how to use them. See the `boards` folder in
|
the RP2040 and how to use them. See the `boards` folder in
|
||||||
https://github.com/rp-rs/rp-hal/ for more details.
|
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
|
To include this crate in your project, amend your `Cargo.toml` file to include
|
||||||
|
|
||||||
```toml
|
```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
|
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.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//!
|
//!
|
||||||
//! NOTE: The DHT11 driver only works reliably when compiled in release mode.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! It drives the LCD by pushing data out of six GPIO pins. It may need to be
|
//! 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.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -34,14 +34,11 @@ fn main() -> ! {
|
||||||
let led_pin_id = 25;
|
let led_pin_id = 25;
|
||||||
|
|
||||||
// Define some simple PIO program.
|
// Define some simple PIO program.
|
||||||
let program = pio_proc::pio!(
|
let program = pio_proc::pio_asm!(
|
||||||
32,
|
".wrap_target",
|
||||||
"
|
"set pins, 1 [31]",
|
||||||
.wrap_target
|
"set pins, 0 [31]",
|
||||||
set pins, 1 [31]
|
".wrap"
|
||||||
set pins, 0 [31]
|
|
||||||
.wrap
|
|
||||||
"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize and start PIO
|
// Initialize and start PIO
|
||||||
|
|
|
@ -36,15 +36,12 @@ fn main() -> ! {
|
||||||
let led_pin_id = 25;
|
let led_pin_id = 25;
|
||||||
|
|
||||||
// Define some simple PIO program.
|
// Define some simple PIO program.
|
||||||
let program = pio_proc::pio!(
|
let program = pio_proc::pio_asm!(
|
||||||
32,
|
".side_set 1", // each instruction may set 1 bit
|
||||||
"
|
".wrap_target",
|
||||||
.side_set 1 ; each instruction may set 1 bit
|
" nop side 1",
|
||||||
.wrap_target
|
" nop side 0",
|
||||||
nop side 1
|
".wrap",
|
||||||
nop side 0
|
|
||||||
.wrap
|
|
||||||
"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize and start PIO
|
// 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.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! It may need to be adapted to your particular board layout and/or pin
|
//! It may need to be adapted to your particular board layout and/or pin
|
||||||
//! assignment.
|
//! assignment.
|
||||||
//!
|
//!
|
||||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
//! See the `Cargo.toml` file for Copyright and license details.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! It may need to be adapted to your particular board layout and/or pin
|
//! It may need to be adapted to your particular board layout and/or pin
|
||||||
//! assignment.
|
//! assignment.
|
||||||
//!
|
//!
|
||||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
//! See the `Cargo.toml` file for Copyright and license details.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
//! 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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
|
@ -1,6 +1,71 @@
|
||||||
use super::Float;
|
use super::Float;
|
||||||
use crate::rom_data;
|
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 {
|
trait ROMDiv {
|
||||||
fn rom_div(self, b: Self) -> Self;
|
fn rom_div(self, b: Self) -> Self;
|
||||||
|
@ -9,14 +74,14 @@ trait ROMDiv {
|
||||||
impl ROMDiv for f32 {
|
impl ROMDiv for f32 {
|
||||||
fn rom_div(self, b: Self) -> Self {
|
fn rom_div(self, b: Self) -> Self {
|
||||||
// ROM implementation uses the hardware divider, so we have to save it
|
// 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 {
|
impl ROMDiv for f64 {
|
||||||
fn rom_div(self, b: Self) -> Self {
|
fn rom_div(self, b: Self) -> Self {
|
||||||
// ROM implementation uses the hardware divider, so we have to save it
|
// 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};
|
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>
|
impl<T: SubsystemReset + Deref<Target = Block>, Sda: PinId + BankPinId, Scl: PinId + BankPinId>
|
||||||
I2C<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Controller>
|
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)*
|
$($rest:ident)*
|
||||||
) => {
|
) => {
|
||||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||||
intrinsics! {
|
mod $alias {
|
||||||
extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
#[no_mangle]
|
||||||
$name($($argname),*)
|
pub extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||||
|
super::$name($($argname),*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +32,10 @@ macro_rules! intrinsics_aliases {
|
||||||
$($rest:ident)*
|
$($rest:ident)*
|
||||||
) => {
|
) => {
|
||||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||||
intrinsics! {
|
mod $alias {
|
||||||
|
#[no_mangle]
|
||||||
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||||
$name($($argname),*)
|
super::$name($($argname),*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![no_std]
|
#![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 cortex_m;
|
||||||
extern crate embedded_hal as hal;
|
extern crate embedded_hal as hal;
|
||||||
|
@ -49,6 +47,15 @@ pub mod xosc;
|
||||||
pub use adc::Adc;
|
pub use adc::Adc;
|
||||||
pub use clocks::Clock;
|
pub use clocks::Clock;
|
||||||
pub use i2c::I2C;
|
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 sio::Sio;
|
||||||
pub use spi::Spi;
|
pub use spi::Spi;
|
||||||
pub use timer::Timer;
|
pub use timer::Timer;
|
||||||
|
|
|
@ -44,7 +44,7 @@ use crate::Sio;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Operation is invalid on this core.
|
/// Operation is invalid on this core.
|
||||||
InvalidCore,
|
InvalidCore,
|
||||||
/// Core was unresposive to commands.
|
/// Core was unresponsive to commands.
|
||||||
Unresponsive,
|
Unresponsive,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -244,13 +244,11 @@ impl<P: PIOExt> PIO<P> {
|
||||||
/// let mut peripherals = pac::Peripherals::take().unwrap();
|
/// let mut peripherals = pac::Peripherals::take().unwrap();
|
||||||
/// let (mut pio, sm0, _, _, _) = peripherals.PIO0.split(&mut peripherals.RESETS);
|
/// let (mut pio, sm0, _, _, _) = peripherals.PIO0.split(&mut peripherals.RESETS);
|
||||||
/// // Install a program in instruction memory.
|
/// // Install a program in instruction memory.
|
||||||
/// let program = pio_proc::pio!(
|
/// let program = pio_proc::pio_asm!(
|
||||||
/// 32,
|
/// ".wrap_target",
|
||||||
/// ".wrap_target
|
/// "set pins, 1 [31]",
|
||||||
/// set pins, 1 [31]
|
/// "set pins, 0 [31]",
|
||||||
/// set pins, 0 [31]
|
/// ".wrap"
|
||||||
/// .wrap
|
|
||||||
/// "
|
|
||||||
/// ).program;
|
/// ).program;
|
||||||
/// let installed = pio.install(&program).unwrap();
|
/// let installed = pio.install(&program).unwrap();
|
||||||
/// // Configure a state machine to use the program.
|
/// // 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,
|
/// Type which, once destructed, restarts the clock dividers for all selected state machines,
|
||||||
/// effectively synchronizing them.
|
/// effectively synchronizing them.
|
||||||
pub struct Synchronize<'sm, SM: ValidStateMachine> {
|
pub struct Synchronize<'sm, SM: ValidStateMachine> {
|
||||||
|
|
|
@ -43,10 +43,10 @@ pub struct HwDivider {
|
||||||
|
|
||||||
/// Result of divide/modulo operation
|
/// Result of divide/modulo operation
|
||||||
pub struct DivResult<T> {
|
pub struct DivResult<T> {
|
||||||
/// The remainder of divide/modulo operation
|
|
||||||
pub remainder: T,
|
|
||||||
/// The quotient of divide/modulo operation
|
/// The quotient of divide/modulo operation
|
||||||
pub quotient: T,
|
pub quotient: T,
|
||||||
|
/// The remainder of divide/modulo operation
|
||||||
|
pub remainder: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Struct containing ownership markers for managing ownership of the SIO registers.
|
/// 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
|
// This takes advantage of how AAPCS defines a 64-bit return on 32-bit registers
|
||||||
where
|
// by packing it into r0[0:31] and r1[32:63]. So all we need to do is put
|
||||||
F: FnOnce(&pac::sio::RegisterBlock) -> R,
|
// 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
|
||||||
let sio = unsafe { &(*pac::SIO::ptr()) };
|
// result either way and r1 a scratch register, so the caller can't assume it
|
||||||
if !sio.div_csr.read().dirty().bit() {
|
// retains the argument value.
|
||||||
// Not dirty, so nothing is waiting for the calculation. So we can just
|
#[cfg(target_arch = "arm")]
|
||||||
// issue it directly without a save/restore.
|
core::arch::global_asm!(
|
||||||
f(sio)
|
".macro hwdivider_head",
|
||||||
} else {
|
"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
|
// 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.
|
// 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.
|
// The push takes 5 cycles, and we've already spent at least 7 checking
|
||||||
// Since we can't be sure the Rust implementation will optimize to the same,
|
// the DIRTY state to get here.
|
||||||
// just use an explicit wait.
|
"push {{r4-r6, lr}}",
|
||||||
while !sio.div_csr.read().ready().bit() {}
|
// 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
|
macro_rules! division_function {
|
||||||
let dividend = sio.div_udividend.read().bits();
|
(
|
||||||
let divisor = sio.div_udivisor.read().bits();
|
$name:ident $($intrinsic:ident)* ( $argty:ty ) {
|
||||||
let remainder = sio.div_remainder.read().bits();
|
$($begin:literal),+
|
||||||
let quotient = sio.div_quotient.read().bits();
|
}
|
||||||
|
) => {
|
||||||
|
#[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
|
"hwdivider_head",
|
||||||
// we have the full state, so the interruptor doesn't have to restore it. Once the
|
$($begin),+ ,
|
||||||
// write happens and the DIRTY flag is set, the interruptor becomes responsible for
|
"hwdivider_tail",
|
||||||
// restoring our state.
|
);
|
||||||
let result = f(sio);
|
|
||||||
|
|
||||||
// If we are interrupted here, then the interruptor will start an incorrect calculation
|
#[cfg(all(target_arch = "arm", feature = "disable-intrinsics"))]
|
||||||
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
|
core::arch::global_asm!(
|
||||||
// This sets DIRTY, so any interruptor will save the state.
|
// Mangle the name slightly, since this is a global symbol.
|
||||||
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
concat!(".global _rphal_", stringify!($name)),
|
||||||
// If we are interrupted here, the the interruptor may start the calculation using
|
concat!(".type _rphal_", stringify!($name), ", %function"),
|
||||||
// incorrectly signed inputs, but we'll restore the result ourselves.
|
".align 2",
|
||||||
// This sets DIRTY, so any interruptor will save the state.
|
concat!("_rphal_", stringify!($name), ":"),
|
||||||
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
|
"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
|
division_function! {
|
||||||
// on Cortex-M0. Each iteration of the inner loop is 3 cycles and it adds
|
signed_divmod __aeabi_idivmod __aeabi_idiv ( i32 ) {
|
||||||
// one extra iteration.
|
"str r0, [r2, #0x068]", // DIV_SDIVIDEND
|
||||||
#[inline(always)]
|
"str r1, [r2, #0x06c]" // DIV_SDIVISOR
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divider_unsigned(dividend: u32, divisor: u32) -> DivResult<u32> {
|
fn divider_unsigned(n: u32, d: u32) -> DivResult<u32> {
|
||||||
save_divider(|sio| {
|
let packed = unsafe { unsigned_divmod(n, d) };
|
||||||
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 {
|
DivResult {
|
||||||
remainder,
|
quotient: packed as u32,
|
||||||
quotient,
|
remainder: (packed >> 32) as u32,
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divider_signed(dividend: i32, divisor: i32) -> DivResult<i32> {
|
fn divider_signed(n: i32, d: i32) -> DivResult<i32> {
|
||||||
save_divider(|sio| {
|
let packed = unsafe { signed_divmod(n, d) };
|
||||||
sio.div_sdividend
|
// Double casts to avoid sign extension
|
||||||
.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 {
|
DivResult {
|
||||||
remainder,
|
quotient: packed as u32 as i32,
|
||||||
quotient,
|
remainder: (packed >> 32) as u32 as i32,
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HwDivider {
|
impl HwDivider {
|
||||||
|
@ -287,7 +339,6 @@ impl HwDivider {
|
||||||
}
|
}
|
||||||
|
|
||||||
intrinsics! {
|
intrinsics! {
|
||||||
#[aeabi = __aeabi_uidiv]
|
|
||||||
extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
||||||
divider_unsigned(n, d).quotient
|
divider_unsigned(n, d).quotient
|
||||||
}
|
}
|
||||||
|
@ -304,7 +355,6 @@ intrinsics! {
|
||||||
quo_rem.quotient
|
quo_rem.quotient
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aeabi = __aeabi_idiv]
|
|
||||||
extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
|
extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
|
||||||
divider_signed(n, d).quotient
|
divider_signed(n, d).quotient
|
||||||
}
|
}
|
||||||
|
@ -598,3 +648,22 @@ pub fn spinlock_state() -> [bool; 32] {
|
||||||
}
|
}
|
||||||
result
|
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 {
|
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 }) => {
|
($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.
|
/// An alarm that can be used to schedule events in the future. Alarms can also be configured to trigger interrupts.
|
||||||
pub struct $name(PhantomData<()>);
|
pub struct $name(PhantomData<()>);
|
||||||
|
|
||||||
impl $name {
|
impl Alarm for $name {
|
||||||
/// Clear the interrupt flag. This should be called after interrupt `
|
/// Clear the interrupt flag. This should be called after interrupt `
|
||||||
#[doc = $int_name]
|
#[doc = $int_name]
|
||||||
/// ` is called.
|
/// ` is called.
|
||||||
///
|
///
|
||||||
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
|
/// 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
|
// safety: TIMER.intr is a write-clear register, so we can atomically clear our interrupt
|
||||||
// by writing its value to this field
|
// by writing its value to this field
|
||||||
// Only one instance of this alarm index can exist, and only this alarm interacts with this bit
|
// 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].
|
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
|
||||||
///
|
///
|
||||||
/// [clear_interrupt]: #method.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.
|
// 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
|
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
|
||||||
// of the TIMER.inte register
|
// of the TIMER.inte register
|
||||||
|
@ -189,7 +222,7 @@ macro_rules! impl_alarm {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disable this alarm, preventing it from triggering an interrupt.
|
/// 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.
|
// 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
|
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
|
||||||
// of the TIMER.inte register
|
// 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()`
|
/// 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
|
/// [enable_interrupt]: #method.enable_interrupt
|
||||||
pub fn schedule<TIME: Into<Microseconds>>(
|
fn schedule<TIME: Into<Microseconds>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
countdown: TIME,
|
countdown: TIME,
|
||||||
) -> Result<(), ScheduleAlarmError> {
|
) -> Result<(), ScheduleAlarmError> {
|
||||||
|
@ -235,7 +268,7 @@ macro_rules! impl_alarm {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if this alarm is finished.
|
/// 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
|
// safety: This is a read action and should not have any UB
|
||||||
let bits: u32 = unsafe { &*TIMER::ptr() }.armed.read().bits();
|
let bits: u32 = unsafe { &*TIMER::ptr() }.armed.read().bits();
|
||||||
(bits & $armed_bit_mask) == 0
|
(bits & $armed_bit_mask) == 0
|
||||||
|
|
|
@ -16,14 +16,13 @@ use rp2040_pac::{UART0, UART1};
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
use eh1_0_alpha::serial as eh1;
|
use eh1_0_alpha::serial as eh1;
|
||||||
|
use pac::Peripherals;
|
||||||
|
|
||||||
/// An UART Peripheral based on an underlying UART device.
|
/// An UART Peripheral based on an underlying UART device.
|
||||||
pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
|
pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
|
||||||
device: D,
|
device: D,
|
||||||
_state: S,
|
_state: S,
|
||||||
pins: P,
|
pins: P,
|
||||||
config: UartConfig,
|
|
||||||
effective_baudrate: Baud,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
|
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 {
|
UartPeripheral {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
pins: self.pins,
|
pins: self.pins,
|
||||||
config: self.config,
|
|
||||||
effective_baudrate: self.effective_baudrate,
|
|
||||||
_state: state,
|
_state: state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +50,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
|
||||||
device,
|
device,
|
||||||
_state: Disabled,
|
_state: Disabled,
|
||||||
pins,
|
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,
|
frequency: Hertz,
|
||||||
) -> Result<UartPeripheral<Enabled, D, P>, Error> {
|
) -> Result<UartPeripheral<Enabled, D, P>, Error> {
|
||||||
let (mut device, pins) = self.free();
|
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| {
|
device.uartlcr_h.write(|w| {
|
||||||
// FIFOs are enabled
|
// FIFOs are enabled
|
||||||
|
@ -93,9 +88,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
|
||||||
|
|
||||||
Ok(UartPeripheral {
|
Ok(UartPeripheral {
|
||||||
device,
|
device,
|
||||||
config,
|
|
||||||
pins,
|
pins,
|
||||||
effective_baudrate,
|
|
||||||
_state: Enabled,
|
_state: Enabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -192,8 +185,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Enabled, D, P> {
|
||||||
device: reader.device,
|
device: reader.device,
|
||||||
_state: Enabled,
|
_state: Enabled,
|
||||||
pins: reader.pins,
|
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 {
|
let reader = Reader {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
pins: self.pins,
|
pins: self.pins,
|
||||||
config: self.config,
|
|
||||||
effective_baudrate: self.effective_baudrate,
|
|
||||||
};
|
};
|
||||||
// Safety: reader and writer will never write to the same address
|
// 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 {
|
let writer = Writer {
|
||||||
device: device_copy,
|
device: device_copy,
|
||||||
device_marker: core::marker::PhantomData,
|
device_marker: core::marker::PhantomData,
|
||||||
|
@ -224,11 +213,9 @@ impl<P: ValidUartPinout<UART1>> UartPeripheral<Enabled, UART1, P> {
|
||||||
let reader = Reader {
|
let reader = Reader {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
pins: self.pins,
|
pins: self.pins,
|
||||||
config: self.config,
|
|
||||||
effective_baudrate: self.effective_baudrate,
|
|
||||||
};
|
};
|
||||||
// Safety: reader and writer will never write to the same address
|
// 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 {
|
let writer = Writer {
|
||||||
device: device_copy,
|
device: device_copy,
|
||||||
device_marker: core::marker::PhantomData,
|
device_marker: core::marker::PhantomData,
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
//!
|
//!
|
||||||
//! This module is for receiving data with a UART.
|
//! This module is for receiving data with a UART.
|
||||||
|
|
||||||
use super::{UartConfig, UartDevice, ValidUartPinout};
|
use super::{UartDevice, ValidUartPinout};
|
||||||
use rp2040_pac::uart0::RegisterBlock;
|
use rp2040_pac::uart0::RegisterBlock;
|
||||||
|
|
||||||
use embedded_hal::serial::Read;
|
use embedded_hal::serial::Read;
|
||||||
use embedded_time::rate::Baud;
|
|
||||||
use nb::Error::*;
|
use nb::Error::*;
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
#[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 struct Reader<D: UartDevice, P: ValidUartPinout<D>> {
|
||||||
pub(super) device: D,
|
pub(super) device: D,
|
||||||
pub(super) pins: P,
|
pub(super) pins: P,
|
||||||
pub(super) config: UartConfig,
|
|
||||||
pub(super) effective_baudrate: Baud,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: UartDevice, P: ValidUartPinout<D>> Reader<D, P> {
|
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`]: struct.UartPeripheral.html
|
||||||
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
|
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
|
||||||
pub struct Writer<D: UartDevice, P: ValidUartPinout<D>> {
|
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) device_marker: PhantomData<D>,
|
||||||
pub(super) pins: PhantomData<P>,
|
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.
|
/// Upon success, the remaining (unwritten) slice is returned.
|
||||||
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
|
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.
|
/// Writes bytes to the UART.
|
||||||
///
|
///
|
||||||
/// This function blocks until the full buffer has been sent.
|
/// This function blocks until the full buffer has been sent.
|
||||||
pub fn write_full_blocking(&self, data: &[u8]) {
|
pub fn write_full_blocking(&self, data: &[u8]) {
|
||||||
write_full_blocking(self.device, data);
|
write_full_blocking(&self.device, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables the Transmit Interrupt.
|
/// Enables the Transmit Interrupt.
|
||||||
///
|
///
|
||||||
/// The relevant UARTx IRQ will fire when there is space in the transmit FIFO.
|
/// The relevant UARTx IRQ will fire when there is space in the transmit FIFO.
|
||||||
pub fn enable_tx_interrupt(&mut self) {
|
pub fn enable_tx_interrupt(&mut self) {
|
||||||
enable_tx_interrupt(self.device)
|
enable_tx_interrupt(&self.device)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables the Transmit Interrupt.
|
/// Disables the Transmit Interrupt.
|
||||||
pub fn disable_tx_interrupt(&mut self) {
|
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> {
|
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> {
|
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,
|
WouldBlock => WouldBlock,
|
||||||
Other(v) => match v {},
|
Other(v) => match v {},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue