Merge branch 'main' into multicore-no-alloc

This commit is contained in:
Liam Murphy 2022-05-03 17:40:22 +10:00 committed by GitHub
commit b932663cc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 1124 additions and 516 deletions

View file

@ -2,6 +2,7 @@
resolver = "2"
members = [
"rp2040-hal",
"rp2040-hal-macros",
"boards/adafruit-feather-rp2040",
"boards/adafruit-itsy-bitsy-rp2040",
"boards/adafruit-kb2040",

View file

@ -390,9 +390,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-feather-rp2040-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-feather-rp2040-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-feather-rp2040-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-feather-rp2040-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "adafruit-feather-rp2040"
version = "0.2.0"
authors = ["Andrea Nall <anall@andreanal.com>"]
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-feather-rp2040"
description = "Board Support Package for the Adafruit Feather RP2040"
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
embedded-hal ="0.2.5"
nb = "1.0.0"
smart-leds = "0.3.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
[features]
default = ["boot2", "rt"]

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Feather.
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit-feather-rp2040 = "0.1.0"
adafruit-feather-rp2040 = "0.2.0"
```
In your program, you will need to call `adafruit_feather_rp2040::Pins::new` to create
@ -90,9 +90,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-itsy-bitsy-rp2040-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-itsy-bitsy-rp2040-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-itsy-bitsy-rp2040-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-itsy-bitsy-rp2040-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "adafruit-itsy-bitsy-rp2040"
version = "0.2.0"
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_itsy_bitsy_rp2040"
description = "Board Support Package for the Adafruit ItsyBitsy RP2040"
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
embedded-hal ="0.2.5"
smart-leds = "0.3"
nb = "1.0.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
[features]
default = ["rt", "boot2"]

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the ItsyBitsy RP2040.
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit-itsy-bitsy-rp2040 = "0.1.0"
adafruit-itsy-bitsy-rp2040 = "0.2.0"
```
In your program, you will need to call `adafruit_itsy_bitsy_rp2040::Pins::new` to create
@ -90,9 +90,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-kb2040-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-kb2040-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-kb2040-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-kb2040-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "adafruit-kb2040"
version = "0.2.0"
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>"]
authors = ["Andrew Christiansen <andrewtaylorchristiansen@gmail.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-kb2040"
description = "Board Support Package for the Adafruit adafruit-kb2040"
@ -28,5 +28,4 @@ rp2040-boot2 = "0.2"
smart-leds = "0.3.0"
embedded-time = "0.12.0"
nb = "1.0.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the KB2040.
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit-kb2040 = "0.1.0"
adafruit-kb2040 = "0.2.0"
```
In your program, you will need to call `adafruit-kb2040::Pins::new` to create
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-macropad-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-macropad-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-macropad-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-macropad-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "adafruit-macropad"
version = "0.2.0"
authors = ["Andrea Nall <anall@andreanal.com>"]
authors = ["Andrea Nall <anall@andreanal.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad"
description = "Board Support Package for the Adafruit Macropad"
@ -15,6 +15,10 @@ cortex-m = "0.7.2"
rp2040-boot2 = { version = "0.2.0", optional = true }
rp2040-hal = { path = "../../rp2040-hal", version = "0.4.0"}
cortex-m-rt = { version = "0.7", optional = true }
[dev-dependencies]
embedded-time = "0.12.0"
panic-halt= "0.2.0"
embedded-hal ="0.2.5"
[features]
default = ["rt", "boot2"]

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Feather.
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit-macropad = "0.1.0"
adafruit-macropad = "0.2.0"
```
In your program, you will need to call `adafruit_macropad::Pins::new` to create
@ -82,9 +82,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -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);
}
}

View file

@ -72,3 +72,5 @@ hal::bsp_pins!(
aliases: { FunctionSpi: Miso }
},
);
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-qt-py-rp2040-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/adafruit-qt-py-rp2040-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-qt-py-rp2040-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/adafruit-qt-py-rp2040-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "adafruit-qt-py-rp2040"
version = "0.2.0"
authors = ["Stephen Onnen <stephen.onnen@gmail.com>"]
authors = ["Stephen Onnen <stephen.onnen@gmail.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit-qt-py-rp2040"
description = "Board Support Package for the Adafruit QT Py RP2040"
@ -22,8 +22,7 @@ panic-halt= "0.2.0"
embedded-hal ="0.2.5"
smart-leds = "0.3"
nb = "1.0.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
[features]
default = ["boot2", "rt"]

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the QT Py.
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit-qt-py-rp2040 = { git = "https://github.com/rp-rs/rp-hal.git" }
adafruit-qt-py-rp2040 = "0.2.0"
```
In your program, you will need to call `adafruit_qt_py_rp2040::Pins::new` to create
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -21,7 +21,7 @@ embedded-hal ="0.2.5"
embedded-time = "0.12.0"
smart-leds = "0.3"
nb = "1.0.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
[features]
default = ["boot2", "rt"]

View file

@ -85,9 +85,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-explorer-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-explorer-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-explorer-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-explorer-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "pimoroni-pico-explorer"
version = "0.2.0"
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-explorer"
description = "Board Support Package for the Pico Explorer"

View file

@ -17,7 +17,7 @@ RP2040 chip according to how it is connected up on the Pico Explorer.
To use this crate, your `Cargo.toml` file should contain:
```toml
pimoroni-pico-explorer = "0.1.0"
pimoroni-pico-explorer = "0.2.0"
```
In your program, you will need to call `pimoroni_pico_explorer::Pins::new` to create
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp2040-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-lipo-16mb-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/pimoroni-pico-lipo-16mb-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-lipo-16mb-v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/pimoroni-pico-lipo-16mb-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "pimoroni-pico-lipo-16mb"
version = "0.2.0"
authors = ["Hmvp <hmvp@users.noreply.github.com>"]
authors = ["Hmvp <hmvp@users.noreply.github.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-pico-lipo-16mb"
description = "Board Support Package for the Pico LiPo 16MB"

View file

@ -18,7 +18,7 @@ space, and so it may not work if you only have the 4MB variant.
To use this crate, your `Cargo.toml` file should contain:
```toml
pimoroni-pico-lipo-16mb = { git = "https://github.com/rp-rs/rp-hal.git" }
pimoroni-pico-lipo-16mb = "0.2.0"
```
In your program, you will need to call `pimoroni_pico_lipo_16mb::Pins::new` to create
@ -88,9 +88,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -5,7 +5,7 @@
//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses
//! for the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -1,7 +1,7 @@
[package]
name = "pimoroni-tiny2040"
version = "0.1.0"
authors = ["Mike Bell <mdb036@gmail.com>"]
authors = ["Mike Bell <mdb036@gmail.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pimoroni-tiny2040"
description = "Board Support Package for the Pimoroni Tiny2040"

View file

@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.3.0] - 2022-03-11
### Changed
- Update to rp-hal 0.4.0
## [0.2.0] - 2021-12-23
### Added
@ -31,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[@jannic]: https://github.com/jannic
[rp-rs]: https://github.com/rp-rs
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/rp-pico-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/rp-pico-v0.3.0...HEAD
[0.3.0]: https://github.com/rp-rs/rp-hal/releases/tag/rp-pico-v0.3.0
[0.2.0]: https://github.com/rp-rs/rp-hal/releases/tag/rp-pico-v0.2.0
[0.1.3]: https://github.com/jannic/rp-microcontroller-rs/tree/rp-pico-0.1.3

View file

@ -1,9 +1,9 @@
[package]
name = "rp-pico"
version = "0.3.0"
authors = ["evan <evanmolder@gmail.com>"]
authors = ["evan <evanmolder@gmail.com>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/pico"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico"
description = "Board Support Package for the Raspberry Pi Pico"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rp-rs/rp-hal.git"
@ -26,11 +26,11 @@ panic-halt= "0.2.0"
embedded-hal ="0.2.5"
cortex-m-rtic = "0.6.0-rc.4"
nb = "1.0"
i2c-pio = { git = "https://github.com/ithinuel/i2c-pio-rs", rev = "df06e4ac94a5b2c985d6a9426dc4cc9be0d535c0" }
i2c-pio = { git = "https://github.com/ithinuel/i2c-pio-rs", rev = "fa155bbae4e8553b448a66cc47236db38b7524dd" }
heapless = "0.7.9"
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
smart-leds = "0.3.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
ssd1306 = "0.7.0"
embedded-graphics = "0.7.1"

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Pico.
To use this crate, your `Cargo.toml` file should contain:
```toml
rp-pico = "0.2.0"
rp-pico = "0.3.0"
```
In your program, you will need to call `rp_pico::Pins::new` to create
@ -129,9 +129,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -5,7 +5,7 @@
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
//! the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -5,7 +5,7 @@
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
//! the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//! internally by this example. When the button is pressed, the LED will turn
//! off.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -36,7 +36,7 @@
//! - (o) connected lines
//! ```
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -6,7 +6,7 @@
//! using the PIO peripheral as an I2C bus controller.
//! The pins used for the I2C can be remapped to any other pin available to the PIO0 peripheral.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -5,7 +5,7 @@
//! This will fade in/out the LED attached to GP25, which is the pin the Pico
//! uses for the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -9,7 +9,7 @@ mod app {
use embedded_hal::digital::v2::OutputPin;
use embedded_time::duration::Extensions;
use rp_pico::{
hal::{self, clocks::init_clocks_and_plls, watchdog::Watchdog, Sio},
hal::{self, clocks::init_clocks_and_plls, timer::Alarm, watchdog::Watchdog, Sio},
XOSC_CRYSTAL_FREQ,
};
@ -27,6 +27,11 @@ mod app {
#[init]
fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
// Soft-reset does not release the hardware spinlocks
// Release them now to avoid a deadlock after debug or watchdog reset
unsafe {
hal::sio::spinlock_reset();
}
let mut resets = c.device.RESETS;
let mut watchdog = Watchdog::new(c.device.WATCHDOG);
let _clocks = init_clocks_and_plls(

View file

@ -80,14 +80,14 @@
//!
//! If there are 5 different error patterns, all with short blinking pulses:
//!
//! - **2 short blink (in a loop)**: Block device could not be aquired, either
//! - **2 short blink (in a loop)**: Block device could not be acquired, either
//! no SD card is present or some electrical problem.
//! - **3 short blink (in a loop)**: Card size could not be retrieved.
//! - **4 short blink (in a loop)**: Error getting volume/partition 0.
//! - **5 short blink (in a loop)**: Error opening root directory.
//! - **6 short blink (in a loop)**: Could not open file 'O.TST'.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -12,7 +12,7 @@
//! * GPIO 1 - UART RX (in to the RP2040)
//! * GPIO 25 - An LED we can blink (active high)
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -10,7 +10,7 @@
//! * GPIO 1 - UART RX (in to the RP2040)
//! * GPIO 25 - An LED we can blink (active high)
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//! ASCII characters are converted to upercase, so you can tell it is working
//! and not just local-echo!
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//! ASCII characters are converted to upercase, so you can tell it is working
//! and not just local-echo!
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -6,7 +6,7 @@
//! It generates movement reports which will twitch the cursor up and down by a
//! few pixels, several times a second.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
//!
//! This is a port of
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs

View file

@ -35,7 +35,7 @@
//! - (o) connected lines
//! ```
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -27,5 +27,5 @@ embedded-hal ="0.2.5"
nb = "1.0.0"
smart-leds = "0.3.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
embedded-time = "0.12.0"

View file

@ -16,7 +16,7 @@ RP2040 chip according to how it is connected up on the Stamp
To use this crate, your `Cargo.toml` file should contain:
```toml
solderparty-rp2040-stamp = { git = "https://github.com/rp-rs/rp-hal.git" }
solderparty-rp2040-stamp = "0.1.0"
```
In your program, you will need to call `solderparty_rp2040_stamp::Pins::new` to create
@ -86,9 +86,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -15,9 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None
## [0.2.0] - 2022-03-11
### Changed
- Update to rp-hal 0.4.0
## [0.1.0] - 2021-12-20
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.1.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.2.0...HEAD
[0.2.0]: https://github.com/rp-rs/rp-hal/compare/sparkfun-pro-micro-rp2040-v0.1.0...v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/sparkfun-pro-micro-rp2040-v0.1.0

View file

@ -1,7 +1,7 @@
[package]
name = "sparkfun-pro-micro-rp2040"
version = "0.2.0"
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>"]
authors = ["Wilfried Chauveau <wilfried.chauveau@ithinuel.me>", "The rp-rs Developers"]
edition = "2018"
homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/sparkfun-pro-micro-rp2040"
description = "Board Support Package for the Sparkfun Pro Micro RP2040"
@ -23,7 +23,7 @@ smart-leds = "0.3.0"
embedded-time = "0.12.0"
nb = "1.0.0"
pio = "0.1.0"
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "fd6b6604d65a66242b52ccf7f24a95ca325991dd" }
[features]
default = ["boot2", "rt"]

View file

@ -17,7 +17,7 @@ RP2040 chip according to how it is connected up on the Pro Micro RP2040.
To use this crate, your `Cargo.toml` file should contain:
```toml
sparkfun-pro-micro-rp2040 = "0.1.0"
sparkfun-pro-micro-rp2040 = "0.2.0"
```
In your program, you will need to call `sparkfun_pro_micro_rp2040::Pins::new` to create
@ -87,9 +87,9 @@ to intervene to uphold that code of conduct.
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
2.0_ License. That means you can chose either the MIT license or the
Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific license.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View 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"

View 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.

View 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
}

View file

@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Removed
- removed i2c embassy driver prototype
## [0.4.0] - 2022-03-09
### Added
- ROM function caching
@ -17,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- UART IRQ examples
- PIO side-set example
- Stopped PIO state machines can change their clock divider
- Added HAL IRQ example
### Changed
@ -32,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update critical_section to use new spinlock implementation
- Update embedded-hal alpha support to version 1.0.0-alpha.7
- Avoid 64-bit division in clock calculations
- Update pio and pio-proc to 0.2.0
## [0.3.0] - 2021-12-19
@ -90,7 +98,8 @@ The Minimum-Supported Rust Version (MSRV) for this release is 1.54.
- Initial release
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/v0.3.0...HEAD
[Unreleased]: https://github.com/rp-rs/rp-hal/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/rp-rs/rp-hal/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/rp-rs/rp-hal/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/rp-rs/rp-hal/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/rp-rs/rp-hal/releases/tag/v0.1.0

View file

@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
cortex-m = "0.7.2"
cortex-m-rt = ">=0.6.15,<0.8"
embedded-hal = { version = "0.2.5", features = ["unproven"] }
eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true }
embedded-time = "0.12.0"
@ -18,7 +19,8 @@ itertools = { version = "0.10.1", default-features = false }
nb = "1.0"
rp2040-pac = "0.3.0"
paste = "1.0"
pio = "0.1.0"
pio = "0.2.0"
rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" }
usb-device = "0.2.8"
vcell = "0.1"
void = { version = "1.0.2", default-features = false }
@ -28,30 +30,21 @@ critical-section = { version = "0.2.4", features = ["custom-impl"] }
futures = { version = "0.3", default-features = false, optional = true }
chrono = { version = "0.4", default-features = false, optional = true }
# namespaced features will let us use "dep:embassy-traits" in the features rather than using this
# trick of renaming the crate.
#
# This is commented out so that we can publish to crates.io
#
# [dependencies.embassy_traits]
# git = "https://github.com/embassy-rs/embassy"
# rev = "6d6e6f55b8a9ecd38b5a6d3bb11f74b2654afdeb"
# package = "embassy-traits"
# optional = true
[dev-dependencies]
cortex-m-rt = "0.7"
panic-halt = "0.2.0"
rp2040-boot2 = "0.2.0"
hd44780-driver = "0.4.0"
pio-proc = "0.1.0"
pio-proc = "0.2.0"
dht-sensor = "0.2.1"
[features]
rt = ["rp2040-pac/rt"]
# This is commented out so that we can publish to crates.io
#
# embassy-traits = ["embassy_traits", "futures"]
rom-func-cache = []
disable-intrinsics = []
rom-v2-intrinsics = []
[[example]]
# irq example uses cortex-m-rt::interrupt, need rt feature for that
name = "gpio_irq_example"
required-features = ["rt"]

View file

@ -57,7 +57,7 @@ hardware-abstraction interfaces defined in the Rust Embedded Working Group's
We also provide a series of *Board Support Package* (BSP) crates, which take
this HAL crate and pre-configure the pins according to a specific PCB design. If
you are using on of the supported boards, you should use one of those crates in
you are using one of the supported boards, you should use one of those crates in
preference, and return here to see documentation about specific peripherals on
the RP2040 and how to use them. See the `boards` folder in
https://github.com/rp-rs/rp-hal/ for more details.
@ -68,7 +68,7 @@ https://github.com/rp-rs/rp-hal/ for more details.
To include this crate in your project, amend your `Cargo.toml` file to include
```toml
rp2040-hal = "0.3.0"
rp2040-hal = "0.4.0"
```
To obtain a copy of the source code (e.g. if you want to propose a bug-fix or

View file

@ -5,7 +5,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//!
//! NOTE: The DHT11 driver only works reliably when compiled in release mode.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -17,7 +17,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//! It drives the LCD by pushing data out of six GPIO pins. It may need to be
//! adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -34,14 +34,11 @@ fn main() -> ! {
let led_pin_id = 25;
// Define some simple PIO program.
let program = pio_proc::pio!(
32,
"
.wrap_target
set pins, 1 [31]
set pins, 0 [31]
.wrap
"
let program = pio_proc::pio_asm!(
".wrap_target",
"set pins, 1 [31]",
"set pins, 0 [31]",
".wrap"
);
// Initialize and start PIO

View file

@ -36,15 +36,12 @@ fn main() -> ! {
let led_pin_id = 25;
// Define some simple PIO program.
let program = pio_proc::pio!(
32,
"
.side_set 1 ; each instruction may set 1 bit
.wrap_target
nop side 1
nop side 0
.wrap
"
let program = pio_proc::pio_asm!(
".side_set 1", // each instruction may set 1 bit
".wrap_target",
" nop side 1",
" nop side 0",
".wrap",
);
// Initialize and start PIO

View 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 {}
}

View file

@ -5,7 +5,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -7,7 +7,7 @@
//! It may need to be adapted to your particular board layout and/or pin
//! assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -6,7 +6,7 @@
//! It may need to be adapted to your particular board layout and/or pin
//! assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -4,7 +4,7 @@
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

View file

@ -1,6 +1,71 @@
use super::Float;
use crate::rom_data;
use crate::sio::save_divider;
// Make sure this stays as a separate call, because when it's inlined the
// compiler will move the save of the registers used to contain the divider
// state into the function prologue. That save and restore (push/pop) takes
// longer than the actual division, so doing it in the common case where
// they are not required wastes a lot of time.
#[inline(never)]
#[cold]
fn save_divider_and_call<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let sio = unsafe { &(*pac::SIO::ptr()) };
// Since we can't save the signed-ness of the calculation, we have to make
// sure that there's at least an 8 cycle delay before we read the result.
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
// Since we can't be sure the Rust implementation will optimize to the same,
// just use an explicit wait.
while !sio.div_csr.read().ready().bit() {}
// Read the quotient last, since that's what clears the dirty flag
let dividend = sio.div_udividend.read().bits();
let divisor = sio.div_udivisor.read().bits();
let remainder = sio.div_remainder.read().bits();
let quotient = sio.div_quotient.read().bits();
// If we get interrupted here (before a write sets the DIRTY flag) its fine, since
// we have the full state, so the interruptor doesn't have to restore it. Once the
// write happens and the DIRTY flag is set, the interruptor becomes responsible for
// restoring our state.
let result = f();
// If we are interrupted here, then the interruptor will start an incorrect calculation
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
// This sets DIRTY, so any interruptor will save the state.
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
// If we are interrupted here, the the interruptor may start the calculation using
// incorrectly signed inputs, but we'll restore the result ourselves.
// This sets DIRTY, so any interruptor will save the state.
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
// If we are interrupted here, the interruptor will have restored everything but the
// quotient may be wrongly signed. If the calculation started by the above writes is
// still ongoing it is stopped, so it won't replace the result we're restoring.
// DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
sio.div_remainder.write(|w| unsafe { w.bits(remainder) });
// State fully restored after the quotient write. This sets both DIRTY and READY, so
// whatever we may have interrupted can read the result.
sio.div_quotient.write(|w| unsafe { w.bits(quotient) });
result
}
fn save_divider<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let sio = unsafe { &(*pac::SIO::ptr()) };
if !sio.div_csr.read().dirty().bit() {
// Not dirty, so nothing is waiting for the calculation. So we can just
// issue it directly without a save/restore.
f()
} else {
save_divider_and_call(f)
}
}
trait ROMDiv {
fn rom_div(self, b: Self) -> Self;
@ -9,14 +74,14 @@ trait ROMDiv {
impl ROMDiv for f32 {
fn rom_div(self, b: Self) -> Self {
// ROM implementation uses the hardware divider, so we have to save it
save_divider(|_sio| rom_data::float_funcs::fdiv(self, b))
save_divider(|| rom_data::float_funcs::fdiv(self, b))
}
}
impl ROMDiv for f64 {
fn rom_div(self, b: Self) -> Self {
// ROM implementation uses the hardware divider, so we have to save it
save_divider(|_sio| rom_data::double_funcs::ddiv(self, b))
save_divider(|| rom_data::double_funcs::ddiv(self, b))
}
}

View file

@ -14,9 +14,6 @@ use eh1_0_alpha::i2c as eh1;
use super::{i2c_reserved_addr, Controller, Error, SclPin, SdaPin, I2C};
#[cfg(feature = "embassy-traits")]
mod embassy_support;
impl<T: SubsystemReset + Deref<Target = Block>, Sda: PinId + BankPinId, Scl: PinId + BankPinId>
I2C<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Controller>
{

View file

@ -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
}
}
}

View file

@ -13,9 +13,10 @@ macro_rules! intrinsics_aliases {
$($rest:ident)*
) => {
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
intrinsics! {
extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
$name($($argname),*)
mod $alias {
#[no_mangle]
pub extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
super::$name($($argname),*)
}
}
@ -31,9 +32,10 @@ macro_rules! intrinsics_aliases {
$($rest:ident)*
) => {
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
intrinsics! {
mod $alias {
#[no_mangle]
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
$name($($argname),*)
super::$name($($argname),*)
}
}

View file

@ -5,8 +5,6 @@
#![warn(missing_docs)]
#![no_std]
#![cfg_attr(feature = "embassy-traits", feature(generic_associated_types))]
#![cfg_attr(feature = "embassy-traits", feature(type_alias_impl_trait))]
extern crate cortex_m;
extern crate embedded_hal as hal;
@ -49,6 +47,15 @@ pub mod xosc;
pub use adc::Adc;
pub use clocks::Clock;
pub use i2c::I2C;
/// Attribute to declare the entry point of the program
///
/// This is based on and can be used like the [entry attribute from
/// cortex-m-rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html).
///
/// It extends that macro with code to unlock all spinlocks at the beginning
/// of `main`. As spinlocks are not automatically unlocked on software resets,
/// this can prevent unexpected deadlocks when running from a debugger.
pub use rp2040_hal_macros::entry;
pub use sio::Sio;
pub use spi::Spi;
pub use timer::Timer;

View file

@ -44,7 +44,7 @@ use crate::Sio;
pub enum Error {
/// Operation is invalid on this core.
InvalidCore,
/// Core was unresposive to commands.
/// Core was unresponsive to commands.
Unresponsive,
}

View file

@ -244,13 +244,11 @@ impl<P: PIOExt> PIO<P> {
/// let mut peripherals = pac::Peripherals::take().unwrap();
/// let (mut pio, sm0, _, _, _) = peripherals.PIO0.split(&mut peripherals.RESETS);
/// // Install a program in instruction memory.
/// let program = pio_proc::pio!(
/// 32,
/// ".wrap_target
/// set pins, 1 [31]
/// set pins, 0 [31]
/// .wrap
/// "
/// let program = pio_proc::pio_asm!(
/// ".wrap_target",
/// "set pins, 1 [31]",
/// "set pins, 0 [31]",
/// ".wrap"
/// ).program;
/// let installed = pio.install(&program).unwrap();
/// // Configure a state machine to use the program.
@ -657,6 +655,352 @@ impl<P: PIOExt, SM: StateMachineIndex> StateMachine<(P, SM), Stopped> {
}
}
impl<P: PIOExt, SM: StateMachineIndex, State> StateMachine<(P, SM), State> {
/// Create a group of state machines, which can be started/stopped synchronously
pub fn with<SM2: StateMachineIndex>(
self,
other_sm: StateMachine<(P, SM2), State>,
) -> StateMachineGroup2<P, SM, SM2, State> {
StateMachineGroup2 {
sm1: self,
sm2: other_sm,
}
}
}
/// Group of 2 state machines, which can be started/stopped synchronously.
pub struct StateMachineGroup2<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
State,
> {
sm1: StateMachine<(P, SM1Idx), State>,
sm2: StateMachine<(P, SM2Idx), State>,
}
/// Group of 3 state machines, which can be started/stopped synchronously.
pub struct StateMachineGroup3<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
State,
> {
sm1: StateMachine<(P, SM1Idx), State>,
sm2: StateMachine<(P, SM2Idx), State>,
sm3: StateMachine<(P, SM3Idx), State>,
}
/// Group of 4 state machines, which can be started/stopped synchronously.
pub struct StateMachineGroup4<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
SM4Idx: StateMachineIndex,
State,
> {
sm1: StateMachine<(P, SM1Idx), State>,
sm2: StateMachine<(P, SM2Idx), State>,
sm3: StateMachine<(P, SM3Idx), State>,
sm4: StateMachine<(P, SM4Idx), State>,
}
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex, State>
StateMachineGroup2<P, SM1Idx, SM2Idx, State>
{
/// Split the group, releasing the contained state machines
#[allow(clippy::type_complexity)]
pub fn free(
self,
) -> (
StateMachine<(P, SM1Idx), State>,
StateMachine<(P, SM2Idx), State>,
) {
(self.sm1, self.sm2)
}
/// Add another state machine to the group
pub fn with<SM3Idx: StateMachineIndex>(
self,
other_sm: StateMachine<(P, SM3Idx), State>,
) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, State> {
StateMachineGroup3 {
sm1: self.sm1,
sm2: self.sm2,
sm3: other_sm,
}
}
fn mask(&self) -> u32 {
(1 << SM1Idx::id()) | (1 << SM2Idx::id())
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
State,
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, State>
{
/// Split the group, releasing the contained state machines
#[allow(clippy::type_complexity)]
pub fn free(
self,
) -> (
StateMachine<(P, SM1Idx), State>,
StateMachine<(P, SM2Idx), State>,
StateMachine<(P, SM3Idx), State>,
) {
(self.sm1, self.sm2, self.sm3)
}
/// Add another state machine to the group
pub fn with<SM4Idx: StateMachineIndex>(
self,
other_sm: StateMachine<(P, SM4Idx), State>,
) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, State> {
StateMachineGroup4 {
sm1: self.sm1,
sm2: self.sm2,
sm3: self.sm3,
sm4: other_sm,
}
}
fn mask(&self) -> u32 {
(1 << SM1Idx::id()) | (1 << SM2Idx::id()) | (1 << SM3Idx::id())
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
SM4Idx: StateMachineIndex,
State,
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, State>
{
/// Split the group, releasing the contained state machines
#[allow(clippy::type_complexity)]
pub fn free(
self,
) -> (
StateMachine<(P, SM1Idx), State>,
StateMachine<(P, SM2Idx), State>,
StateMachine<(P, SM3Idx), State>,
StateMachine<(P, SM4Idx), State>,
) {
(self.sm1, self.sm2, self.sm3, self.sm4)
}
fn mask(&self) -> u32 {
(1 << SM1Idx::id()) | (1 << SM2Idx::id()) | (1 << SM3Idx::id()) | (1 << SM4Idx::id())
}
}
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex>
StateMachineGroup2<P, SM1Idx, SM2Idx, Stopped>
{
/// Start grouped state machines
pub fn start(mut self) -> StateMachineGroup2<P, SM1Idx, SM2Idx, Running> {
self.sm1.sm.set_ctrl_bits(self.mask());
StateMachineGroup2 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
}
}
/// Sync grouped state machines
pub fn sync(mut self) -> Self {
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
self
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Stopped>
{
/// Start grouped state machines
pub fn start(mut self) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Running> {
self.sm1.sm.set_ctrl_bits(self.mask());
StateMachineGroup3 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
sm3: StateMachine {
sm: self.sm3.sm,
program: self.sm3.program,
_phantom: core::marker::PhantomData,
},
}
}
/// Sync grouped state machines
pub fn sync(mut self) -> Self {
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
self
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
SM4Idx: StateMachineIndex,
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Stopped>
{
/// Start grouped state machines
pub fn start(mut self) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Running> {
self.sm1.sm.set_ctrl_bits(self.mask());
StateMachineGroup4 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
sm3: StateMachine {
sm: self.sm3.sm,
program: self.sm3.program,
_phantom: core::marker::PhantomData,
},
sm4: StateMachine {
sm: self.sm4.sm,
program: self.sm4.program,
_phantom: core::marker::PhantomData,
},
}
}
/// Sync grouped state machines
pub fn sync(mut self) -> Self {
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
self
}
}
impl<P: PIOExt, SM1Idx: StateMachineIndex, SM2Idx: StateMachineIndex>
StateMachineGroup2<P, SM1Idx, SM2Idx, Running>
{
/// Stop grouped state machines
pub fn stop(mut self) -> StateMachineGroup2<P, SM1Idx, SM2Idx, Stopped> {
self.sm1.sm.clear_ctrl_bits(self.mask());
StateMachineGroup2 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
}
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Running>
{
/// Stop grouped state machines
pub fn stop(mut self) -> StateMachineGroup3<P, SM1Idx, SM2Idx, SM3Idx, Stopped> {
self.sm1.sm.clear_ctrl_bits(self.mask());
StateMachineGroup3 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
sm3: StateMachine {
sm: self.sm3.sm,
program: self.sm3.program,
_phantom: core::marker::PhantomData,
},
}
}
}
impl<
P: PIOExt,
SM1Idx: StateMachineIndex,
SM2Idx: StateMachineIndex,
SM3Idx: StateMachineIndex,
SM4Idx: StateMachineIndex,
> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Running>
{
/// Stop grouped state machines
pub fn stop(mut self) -> StateMachineGroup4<P, SM1Idx, SM2Idx, SM3Idx, SM4Idx, Stopped> {
self.sm1.sm.clear_ctrl_bits(self.mask());
StateMachineGroup4 {
sm1: StateMachine {
sm: self.sm1.sm,
program: self.sm1.program,
_phantom: core::marker::PhantomData,
},
sm2: StateMachine {
sm: self.sm2.sm,
program: self.sm2.program,
_phantom: core::marker::PhantomData,
},
sm3: StateMachine {
sm: self.sm3.sm,
program: self.sm3.program,
_phantom: core::marker::PhantomData,
},
sm4: StateMachine {
sm: self.sm4.sm,
program: self.sm4.program,
_phantom: core::marker::PhantomData,
},
}
}
/// Sync grouped state machines
pub fn sync(mut self) -> Self {
self.sm1.sm.set_ctrl_bits(self.mask() << 8);
self
}
}
/// Type which, once destructed, restarts the clock dividers for all selected state machines,
/// effectively synchronizing them.
pub struct Synchronize<'sm, SM: ValidStateMachine> {

View file

@ -43,10 +43,10 @@ pub struct HwDivider {
/// Result of divide/modulo operation
pub struct DivResult<T> {
/// The remainder of divide/modulo operation
pub remainder: T,
/// The quotient of divide/modulo operation
pub quotient: T,
/// The remainder of divide/modulo operation
pub remainder: T,
}
/// Struct containing ownership markers for managing ownership of the SIO registers.
@ -171,107 +171,159 @@ impl SioFifo {
}
}
pub(crate) fn save_divider<F, R>(f: F) -> R
where
F: FnOnce(&pac::sio::RegisterBlock) -> R,
{
let sio = unsafe { &(*pac::SIO::ptr()) };
if !sio.div_csr.read().dirty().bit() {
// Not dirty, so nothing is waiting for the calculation. So we can just
// issue it directly without a save/restore.
f(sio)
} else {
// Since we can't save the signed-ness of the calculation, we have to make
// sure that there's at least an 8 cycle delay before we read the result.
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
// Since we can't be sure the Rust implementation will optimize to the same,
// just use an explicit wait.
while !sio.div_csr.read().ready().bit() {}
// This takes advantage of how AAPCS defines a 64-bit return on 32-bit registers
// by packing it into r0[0:31] and r1[32:63]. So all we need to do is put
// the remainder in the high order 32 bits of a 64 bit result. We can also
// alias the division operators to these for a similar reason r0 is the
// result either way and r1 a scratch register, so the caller can't assume it
// retains the argument value.
#[cfg(target_arch = "arm")]
core::arch::global_asm!(
".macro hwdivider_head",
"ldr r2, =(0xd0000000)", // SIO_BASE
// Check the DIRTY state of the divider by shifting it into the C
// status bit.
"ldr r3, [r2, #0x078]", // DIV_CSR
"lsrs r3, #2", // DIRTY = 1, so shift 2 down
// We only need to save the state when DIRTY, otherwise we can just do the
// division directly.
"bcs 2f",
"1:",
// Do the actual division now, we're either not DIRTY, or we've saved the
// state and branched back here so it's safe now.
".endm",
".macro hwdivider_tail",
// 8 cycle delay to wait for the result. Each branch takes two cycles
// and fits into a 2-byte Thumb instruction, so this is smaller than
// 8 NOPs.
"b 3f",
"3: b 3f",
"3: b 3f",
"3: b 3f",
"3:",
// Read the quotient last, since that's what clears the dirty flag.
"ldr r1, [r2, #0x074]", // DIV_REMAINDER
"ldr r0, [r2, #0x070]", // DIV_QUOTIENT
// Either return to the caller or back to the state restore.
"bx lr",
"2:",
// Since we can't save the signed-ness of the calculation, we have to make
// sure that there's at least an 8 cycle delay before we read the result.
// The push takes 5 cycles, and we've already spent at least 7 checking
// the DIRTY state to get here.
"push {{r4-r6, lr}}",
// Read the quotient last, since that's what clears the dirty flag.
"ldr r3, [r2, #0x060]", // DIV_UDIVIDEND
"ldr r4, [r2, #0x064]", // DIV_UDIVISOR
"ldr r5, [r2, #0x074]", // DIV_REMAINDER
"ldr r6, [r2, #0x070]", // DIV_QUOTIENT
// If we get interrupted here (before a write sets the DIRTY flag) it's
// fine, since we have the full state, so the interruptor doesn't have to
// restore it. Once the write happens and the DIRTY flag is set, the
// interruptor becomes responsible for restoring our state.
"bl 1b",
// If we are interrupted here, then the interruptor will start an incorrect
// calculation using a wrong divisor, but we'll restore the divisor and
// result ourselves correctly. This sets DIRTY, so any interruptor will
// save the state.
"str r3, [r2, #0x060]", // DIV_UDIVIDEND
// If we are interrupted here, the the interruptor may start the
// calculation using incorrectly signed inputs, but we'll restore the
// result ourselves. This sets DIRTY, so any interruptor will save the
// state.
"str r4, [r2, #0x064]", // DIV_UDIVISOR
// If we are interrupted here, the interruptor will have restored
// everything but the quotient may be wrongly signed. If the calculation
// started by the above writes is still ongoing it is stopped, so it won't
// replace the result we're restoring. DIRTY and READY set, but only
// DIRTY matters to make the interruptor save the state.
"str r5, [r2, #0x074]", // DIV_REMAINDER
// State fully restored after the quotient write. This sets both DIRTY
// and READY, so whatever we may have interrupted can read the result.
"str r6, [r2, #0x070]", // DIV_QUOTIENT
"pop {{r4-r6, pc}}",
".endm",
);
// Read the quotient last, since that's what clears the dirty flag
let dividend = sio.div_udividend.read().bits();
let divisor = sio.div_udivisor.read().bits();
let remainder = sio.div_remainder.read().bits();
let quotient = sio.div_quotient.read().bits();
macro_rules! division_function {
(
$name:ident $($intrinsic:ident)* ( $argty:ty ) {
$($begin:literal),+
}
) => {
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
core::arch::global_asm!(
// Mangle the name slightly, since this is a global symbol.
concat!(".global _rphal_", stringify!($name)),
concat!(".type _rphal_", stringify!($name), ", %function"),
".align 2",
concat!("_rphal_", stringify!($name), ":"),
$(
concat!(".global ", stringify!($intrinsic)),
concat!(".type ", stringify!($intrinsic), ", %function"),
concat!(stringify!($intrinsic), ":"),
)*
// If we get interrupted here (before a write sets the DIRTY flag) its fine, since
// we have the full state, so the interruptor doesn't have to restore it. Once the
// write happens and the DIRTY flag is set, the interruptor becomes responsible for
// restoring our state.
let result = f(sio);
"hwdivider_head",
$($begin),+ ,
"hwdivider_tail",
);
// If we are interrupted here, then the interruptor will start an incorrect calculation
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
// This sets DIRTY, so any interruptor will save the state.
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
// If we are interrupted here, the the interruptor may start the calculation using
// incorrectly signed inputs, but we'll restore the result ourselves.
// This sets DIRTY, so any interruptor will save the state.
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
// If we are interrupted here, the interruptor will have restored everything but the
// quotient may be wrongly signed. If the calculation started by the above writes is
// still ongoing it is stopped, so it won't replace the result we're restoring.
// DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
sio.div_remainder.write(|w| unsafe { w.bits(remainder) });
// State fully restored after the quotient write. This sets both DIRTY and READY, so
// whatever we may have interrupted can read the result.
sio.div_quotient.write(|w| unsafe { w.bits(quotient) });
#[cfg(all(target_arch = "arm", feature = "disable-intrinsics"))]
core::arch::global_asm!(
// Mangle the name slightly, since this is a global symbol.
concat!(".global _rphal_", stringify!($name)),
concat!(".type _rphal_", stringify!($name), ", %function"),
".align 2",
concat!("_rphal_", stringify!($name), ":"),
result
"hwdivider_head",
$($begin),+ ,
"hwdivider_tail",
);
#[cfg(target_arch = "arm")]
extern "aapcs" {
// Connect a local name to global symbol above through FFI.
#[link_name = concat!("_rphal_", stringify!($name)) ]
fn $name(n: $argty, d: $argty) -> u64;
}
#[cfg(not(target_arch = "arm"))]
#[allow(unused_variables)]
unsafe fn $name(n: $argty, d: $argty) -> u64 { 0 }
};
}
division_function! {
unsigned_divmod __aeabi_uidivmod __aeabi_uidiv ( u32 ) {
"str r0, [r2, #0x060]", // DIV_UDIVIDEND
"str r1, [r2, #0x064]" // DIV_UDIVISOR
}
}
// Don't use cortex_m::asm::delay(8) because that ends up delaying 15 cycles
// on Cortex-M0. Each iteration of the inner loop is 3 cycles and it adds
// one extra iteration.
#[inline(always)]
fn divider_delay() {
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
cortex_m::asm::nop();
division_function! {
signed_divmod __aeabi_idivmod __aeabi_idiv ( i32 ) {
"str r0, [r2, #0x068]", // DIV_SDIVIDEND
"str r1, [r2, #0x06c]" // DIV_SDIVISOR
}
}
fn divider_unsigned(dividend: u32, divisor: u32) -> DivResult<u32> {
save_divider(|sio| {
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
divider_delay();
// Note: quotient must be read last
let remainder = sio.div_remainder.read().bits();
let quotient = sio.div_quotient.read().bits();
DivResult {
remainder,
quotient,
}
})
fn divider_unsigned(n: u32, d: u32) -> DivResult<u32> {
let packed = unsafe { unsigned_divmod(n, d) };
DivResult {
quotient: packed as u32,
remainder: (packed >> 32) as u32,
}
}
fn divider_signed(dividend: i32, divisor: i32) -> DivResult<i32> {
save_divider(|sio| {
sio.div_sdividend
.write(|w| unsafe { w.bits(dividend as u32) });
sio.div_sdivisor
.write(|w| unsafe { w.bits(divisor as u32) });
divider_delay();
// Note: quotient must be read last
let remainder = sio.div_remainder.read().bits() as i32;
let quotient = sio.div_quotient.read().bits() as i32;
DivResult {
remainder,
quotient,
}
})
fn divider_signed(n: i32, d: i32) -> DivResult<i32> {
let packed = unsafe { signed_divmod(n, d) };
// Double casts to avoid sign extension
DivResult {
quotient: packed as u32 as i32,
remainder: (packed >> 32) as u32 as i32,
}
}
impl HwDivider {
@ -287,7 +339,6 @@ impl HwDivider {
}
intrinsics! {
#[aeabi = __aeabi_uidiv]
extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
divider_unsigned(n, d).quotient
}
@ -304,7 +355,6 @@ intrinsics! {
quo_rem.quotient
}
#[aeabi = __aeabi_idiv]
extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
divider_signed(n, d).quotient
}
@ -598,3 +648,22 @@ pub fn spinlock_state() -> [bool; 32] {
}
result
}
/// Free all spinlocks, regardless of their current status
///
/// RP2040 does not release all spinlocks on reset.
/// The C SDK clears these all during entry, and so do we if you call hal::entry!
/// But if someone is using the default cortex-m entry they risk hitting deadlocks so provide *something* to help out
///
/// # Safety
/// Where possible, you should use the hal::entry macro attribute on main instead of this.
/// You should call this as soon as possible after reset - preferably as the first entry in fn main(), before *ANY* use of spinlocks, atomics, or critical_section
pub unsafe fn spinlock_reset() {
// Using raw pointers to avoid taking peripherals accidently at startup
const SIO_BASE: u32 = 0xd0000000;
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
const SPINLOCK_COUNT: usize = 32;
for i in 0..SPINLOCK_COUNT {
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
}
}

View file

@ -148,18 +148,51 @@ impl embedded_hal::timer::Cancel for CountDown<'_> {
}
}
/// Alarm abstraction.
pub trait Alarm {
/// Clear the interrupt flag.
///
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
fn clear_interrupt(&mut self);
/// Enable this alarm to trigger an interrupt.
///
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
///
/// [clear_interrupt]: #method.clear_interrupt
fn enable_interrupt(&mut self);
/// Disable this alarm, preventing it from triggering an interrupt.
fn disable_interrupt(&mut self);
/// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
/// this will trigger interrupt whenever this time elapses.
///
/// The RP2040 has been observed to take a little while to schedule an alarm. For this
/// reason, the minimum time that this function accepts is `10.microseconds()`
///
/// [enable_interrupt]: #method.enable_interrupt
fn schedule<TIME: Into<Microseconds>>(
&mut self,
countdown: TIME,
) -> Result<(), ScheduleAlarmError>;
/// Return true if this alarm is finished.
fn finished(&self) -> bool;
}
macro_rules! impl_alarm {
($name:ident { rb: $timer_alarm:ident, int: $int_alarm:ident, int_name: $int_name:tt, armed_bit_mask: $armed_bit_mask: expr }) => {
/// An alarm that can be used to schedule events in the future. Alarms can also be configured to trigger interrupts.
pub struct $name(PhantomData<()>);
impl $name {
impl Alarm for $name {
/// Clear the interrupt flag. This should be called after interrupt `
#[doc = $int_name]
/// ` is called.
///
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
pub fn clear_interrupt(&mut self) {
fn clear_interrupt(&mut self) {
// safety: TIMER.intr is a write-clear register, so we can atomically clear our interrupt
// by writing its value to this field
// Only one instance of this alarm index can exist, and only this alarm interacts with this bit
@ -177,7 +210,7 @@ macro_rules! impl_alarm {
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
///
/// [clear_interrupt]: #method.clear_interrupt
pub fn enable_interrupt(&mut self) {
fn enable_interrupt(&mut self) {
// safety: using the atomic set alias means we can atomically set our interrupt enable bit.
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
// of the TIMER.inte register
@ -189,7 +222,7 @@ macro_rules! impl_alarm {
}
/// Disable this alarm, preventing it from triggering an interrupt.
pub fn disable_interrupt(&mut self) {
fn disable_interrupt(&mut self) {
// safety: using the atomic set alias means we can atomically clear our interrupt enable bit.
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
// of the TIMER.inte register
@ -207,7 +240,7 @@ macro_rules! impl_alarm {
/// The RP2040 has been observed to take a little while to schedule an alarm. For this reason, the minimum time that this function accepts is `10.microseconds()`
///
/// [enable_interrupt]: #method.enable_interrupt
pub fn schedule<TIME: Into<Microseconds>>(
fn schedule<TIME: Into<Microseconds>>(
&mut self,
countdown: TIME,
) -> Result<(), ScheduleAlarmError> {
@ -235,7 +268,7 @@ macro_rules! impl_alarm {
}
/// Return true if this alarm is finished.
pub fn finished(&self) -> bool {
fn finished(&self) -> bool {
// safety: This is a read action and should not have any UB
let bits: u32 = unsafe { &*TIMER::ptr() }.armed.read().bits();
(bits & $armed_bit_mask) == 0

View file

@ -16,14 +16,13 @@ use rp2040_pac::{UART0, UART1};
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::serial as eh1;
use pac::Peripherals;
/// An UART Peripheral based on an underlying UART device.
pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
device: D,
_state: S,
pins: P,
config: UartConfig,
effective_baudrate: Baud,
}
impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
@ -31,8 +30,6 @@ impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
UartPeripheral {
device: self.device,
pins: self.pins,
config: self.config,
effective_baudrate: self.effective_baudrate,
_state: state,
}
}
@ -53,8 +50,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
device,
_state: Disabled,
pins,
config: common_configs::_9600_8_N_1, // placeholder
effective_baudrate: Baud(0),
}
}
@ -65,7 +60,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
frequency: Hertz,
) -> Result<UartPeripheral<Enabled, D, P>, Error> {
let (mut device, pins) = self.free();
let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?;
configure_baudrate(&mut device, &config.baudrate, &frequency)?;
device.uartlcr_h.write(|w| {
// FIFOs are enabled
@ -93,9 +88,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
Ok(UartPeripheral {
device,
config,
pins,
effective_baudrate,
_state: Enabled,
})
}
@ -192,8 +185,6 @@ impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Enabled, D, P> {
device: reader.device,
_state: Enabled,
pins: reader.pins,
config: reader.config,
effective_baudrate: reader.effective_baudrate,
}
}
}
@ -204,11 +195,9 @@ impl<P: ValidUartPinout<UART0>> UartPeripheral<Enabled, UART0, P> {
let reader = Reader {
device: self.device,
pins: self.pins,
config: self.config,
effective_baudrate: self.effective_baudrate,
};
// Safety: reader and writer will never write to the same address
let device_copy = unsafe { &*UART0::ptr() };
let device_copy = unsafe { Peripherals::steal().UART0 };
let writer = Writer {
device: device_copy,
device_marker: core::marker::PhantomData,
@ -224,11 +213,9 @@ impl<P: ValidUartPinout<UART1>> UartPeripheral<Enabled, UART1, P> {
let reader = Reader {
device: self.device,
pins: self.pins,
config: self.config,
effective_baudrate: self.effective_baudrate,
};
// Safety: reader and writer will never write to the same address
let device_copy = unsafe { &*UART1::ptr() };
let device_copy = unsafe { Peripherals::steal().UART1 };
let writer = Writer {
device: device_copy,
device_marker: core::marker::PhantomData,

View file

@ -2,11 +2,10 @@
//!
//! This module is for receiving data with a UART.
use super::{UartConfig, UartDevice, ValidUartPinout};
use super::{UartDevice, ValidUartPinout};
use rp2040_pac::uart0::RegisterBlock;
use embedded_hal::serial::Read;
use embedded_time::rate::Baud;
use nb::Error::*;
#[cfg(feature = "eh1_0_alpha")]
@ -167,8 +166,6 @@ pub(crate) fn read_full_blocking<D: UartDevice>(
pub struct Reader<D: UartDevice, P: ValidUartPinout<D>> {
pub(super) device: D,
pub(super) pins: P,
pub(super) config: UartConfig,
pub(super) effective_baudrate: Baud,
}
impl<D: UartDevice, P: ValidUartPinout<D>> Reader<D, P> {

View file

@ -114,7 +114,7 @@ pub(crate) fn disable_tx_interrupt(rb: &RegisterBlock) {
/// [`UartPeripheral`]: struct.UartPeripheral.html
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
pub struct Writer<D: UartDevice, P: ValidUartPinout<D>> {
pub(super) device: &'static RegisterBlock,
pub(super) device: D,
pub(super) device_marker: PhantomData<D>,
pub(super) pins: PhantomData<P>,
}
@ -129,26 +129,26 @@ impl<D: UartDevice, P: ValidUartPinout<D>> Writer<D, P> {
///
/// Upon success, the remaining (unwritten) slice is returned.
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
write_raw(self.device, data)
write_raw(&self.device, data)
}
/// Writes bytes to the UART.
///
/// This function blocks until the full buffer has been sent.
pub fn write_full_blocking(&self, data: &[u8]) {
write_full_blocking(self.device, data);
write_full_blocking(&self.device, data);
}
/// Enables the Transmit Interrupt.
///
/// The relevant UARTx IRQ will fire when there is space in the transmit FIFO.
pub fn enable_tx_interrupt(&mut self) {
enable_tx_interrupt(self.device)
enable_tx_interrupt(&self.device)
}
/// Disables the Transmit Interrupt.
pub fn disable_tx_interrupt(&mut self) {
disable_tx_interrupt(self.device)
disable_tx_interrupt(&self.device)
}
}
@ -164,7 +164,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for Writer<D, P> {
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
transmit_flushed(self.device)
transmit_flushed(&self.device)
}
}
@ -184,7 +184,7 @@ impl<D: UartDevice, P: ValidUartPinout<D>> eh1::nb::Write<u8> for Writer<D, P> {
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
transmit_flushed(self.device).map_err(|e| match e {
transmit_flushed(&self.device).map_err(|e| match e {
WouldBlock => WouldBlock,
Other(v) => match v {},
})