Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 1170 pads and select impls for HAL 0.5 #26

Merged
merged 10 commits into from
Nov 30, 2022
21 changes: 19 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ All notable changes to this project will be documented in this file.
- **BREAKING** Remove typenum dependency, and use const generics. Requires
at least Rust 1.51.

- **BREAKING** the GPIO `Pin` trait is now generic over the GPIO module.
A const generic replaces the associated type `Module`.

- **BREAKING** rename feature flags and module: `"imxrt106x" => "imxrt1060"`

For rational on this change, see
Expand All @@ -25,8 +28,10 @@ All notable changes to this project will be documented in this file.
- etc.

- **BREAKING** in the ADC module, we remove the `ADC` trait. Users should
replace usages of `adc::ADC` with `consts::Unsigned`. The `Adc1` and `Adc2`
types are now aliases for `U1` and `U2`.
replace usages of `adc::ADC` with constants that indicate ADC1, ADC2, etc.

`gpio::Pin` is no longer a trait bound for the `adc::Pin` trait. Users who
relied on this guarantee should explicitly require the bound.

`adc::Pin::INPUT` is now an associated `u32` constant, not a type. Cast the
`u32` as needed for your implementation. See the before and after below for
Expand Down Expand Up @@ -61,6 +66,18 @@ All notable changes to this project will be documented in this file.
- Add uSDHC pin traits.
- Add select uSDHC pins for the i.MX RT 1060.

- Basic i.MX RT 1170 support with the `"imxrt1170"` feature. Includes minimal
pad implementations for

- LPI2C
- LPSPI
- LPUART
- FlexPWM

that are sufficient for evaluating the 1170EVK.

- Add CCM clock output pin trait with 1010, 1170 implementations.

## [0.1.5] - 2022-01-01

### Added
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ keywords = ["imxrt", "nxp", "embedded", "no_std"]
categories = ["embedded", "no-std"]

[features]
imxrt1170 = []
imxrt1060 = []
imxrt1010 = []

Expand Down
18 changes: 13 additions & 5 deletions daisy.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import xml.etree.ElementTree as ET


def daisy_constant(path):
tree = ET.parse(path)
root = tree.getroot()
iomuxc = root.find("./peripherals/peripheral[name='IOMUXC']")
def daisy_constant(iomuxc):
base_address = int(iomuxc.find("./baseAddress").text, 16)

for register in iomuxc.findall("./registers/register"):
Expand All @@ -35,7 +32,18 @@ def daisy_constant(path):
print(constant)


def search_iomuxces(path):
tree = ET.parse(path)
root = tree.getroot()
iomuxc = root.find("./peripherals/peripheral[name='IOMUXC']")
iomuxc_lpsr = root.find("./peripherals/peripheral[name='IOMUXC_LPSR']")

if iomuxc:
daisy_constant(iomuxc)
if iomuxc_lpsr:
daisy_constant(iomuxc_lpsr)

if __name__ == "__main__":
import sys

daisy_constant(sys.argv[1])
search_iomuxces(sys.argv[1])
74 changes: 55 additions & 19 deletions iomuxc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,23 @@
///
/// See `ErasedPads` for more information."""

def iomuxc(path):
tree = ET.parse(path)
root = tree.getroot()
iomuxc = root.find("./peripherals/peripheral[name='IOMUXC']")

class GpioImpl:
"""A pad's GPIO implementation."""

__slots__ = [
"alt",
"module",
"offset",
]

def __init__(self, alt, module, offset):
self.alt = alt
self.module = module
self.offset = offset


def extract_pads(iomuxc):
base_address = int(iomuxc.find("./baseAddress").text, 16)

# Collect MUX and PAD absolute register addresses.
Expand Down Expand Up @@ -69,13 +82,21 @@ def iomuxc(path):
[gpio_offset] = re.findall("\d+", gpio_text)
gpio_module = 1
gpio_offset = int(gpio_offset)
# But wait! The 1176 SVD has a third form, "GPIO_MUXx_IOyz",
# which is mixed with the first form...
elif gpio_match := re.search("GPIO_MUX\d_IO\d", desc):
gpio_text = gpio_match.group(0)
[gpio_module, gpio_offset] = re.findall("\d+", gpio_text)
gpio_module = int(gpio_module)
gpio_offset = int(gpio_offset)
else:
# There's no (expected) GPIO alt. This path is handled
# later during code generation.
continue
pads[name]["GPIO_ALT"] = alt_value = int(alt.find("./value").text, 16)
pads[name]["GPIO_MODULE"] = gpio_module
pads[name]["GPIO_OFFSET"] = gpio_offset
alt_value = int(alt.find("./value").text, 16)
gpio_impls = pads[name].get("GPIO", [])
gpio_impls.append(GpioImpl(alt_value, gpio_module, gpio_offset))
pads[name]["GPIO"] = gpio_impls

elif "SW_PAD_CTL_PAD_" in name:
name = name.replace("SW_PAD_CTL_PAD_", "")
Expand All @@ -84,12 +105,25 @@ def iomuxc(path):

# Sanity check.
for name, registers in pads.items():
assert("PAD" in registers and "MUX" in registers)
assert "PAD" in registers and "MUX" in registers

return pads


def iomuxc(path):
tree = ET.parse(path)
root = tree.getroot()
iomuxc = root.find("./peripherals/peripheral[name='IOMUXC']")
iomuxc_lpsr = root.find("./peripherals/peripheral[name='IOMUXC_LPSR']")

pads = extract_pads(iomuxc)
if iomuxc_lpsr:
pads |= extract_pads(iomuxc_lpsr)

# Create pad groups.
groups = defaultdict(list)
for name in pads.keys():
group = name[:-len("_01")]
group = name[: -len("_01")]
groups[group].append(name)

# Generate Rust modules
Expand All @@ -115,22 +149,21 @@ def iomuxc(path):
print(f"pub type {pad_name} = crate::Pad<{mux_reg_name}, {pad_reg_name}>;")

# impl gpio::Pin
if "GPIO_ALT" in registers:
for gpio_impl in registers.get("GPIO", []):
print()
print(f"impl crate::gpio::Pin for {pad_name} {{")
print(f"const ALT: u32 = {registers['GPIO_ALT']};")
print(f"type Module = crate::consts::U{registers['GPIO_MODULE']};")
print(f"type Offset = crate::consts::U{registers['GPIO_OFFSET']};")
print(f"impl crate::gpio::Pin<{gpio_impl.module}> for {pad_name} {{")
print(f"const ALT: u32 = {gpio_impl.alt};")
print(f"const OFFSET: u32 = {gpio_impl.offset};")
print("}")
else:
print(f"// {pad_name} does not have a GPIO alternate.")
if registers.get("GPIO") is None:
print(f"// {pad_name} does not have any GPIO alternates.")
print()

# Pads struct
print(f"/// All pads with prefix {group}.")
print("pub struct Pads {")
for pad_name in pad_names:
pad_number = pad_name[-len("01"):]
pad_number = pad_name[-len("01") :]
print(f"pub p{pad_number}: {pad_name},")
print("}")

Expand All @@ -146,14 +179,14 @@ def iomuxc(path):
print(NEW_DOCSTRING)
print("#[inline] pub const unsafe fn new() -> Self { Self {")
for pad_name in pad_names:
pad_number = pad_name[-len("01"):]
pad_number = pad_name[-len("01") :]
print(f"p{pad_number}: {pad_name}::new(),")
print("} }")

print(ERASE_DOCSTRING)
print("#[inline] pub const fn erase(self) -> ErasedPads { [")
for pad_name in sorted(pad_names):
pad_number = pad_name[-len("01"):]
pad_number = pad_name[-len("01") :]
print(f"self.p{pad_number}.erase(),")
print("] }")
print("}")
Expand All @@ -167,6 +200,7 @@ def iomuxc(path):
for group in groups.keys():
print(f"pub {group.lower()}: {group.lower()}::Pads,")
print("}")
print()

print("impl Pads {")
print(NEW_DOCSTRING)
Expand All @@ -180,6 +214,7 @@ def iomuxc(path):
print(f"{group.lower()}: self.{group.lower()}.erase(),")
print("} }")
print("}")
print()

# Generate top-level ErasedPads struct
print("/// All erased pads.")
Expand All @@ -188,5 +223,6 @@ def iomuxc(path):
print(f"pub {group.lower()}: {group.lower()}::ErasedPads,")
print("}")


if __name__ == "__main__":
iomuxc(sys.argv[1])
24 changes: 11 additions & 13 deletions src/adc.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
//! ADC pad configuration

use crate::consts::Unsigned;

/// Type number for ADC1
pub type Adc1 = crate::consts::U1;
/// Type number for ADC2
pub type Adc2 = crate::consts::U2;
pub const ADC1: u8 = 1;
pub const ADC2: u8 = 2;

/// Describes an ADC input pin
///
/// ADC pins are specialized GPIO pins. Some pads may be used in both `Adc1`
/// and `Adc2`, so implementations will indicate their compatibility by
/// supplying an identifier in place of `ADCx`.
pub trait Pin<U: Unsigned>: super::gpio::Pin {
/// Some pads may be used in both `ADC1` and `ADC2`, so implementations
/// indicate their compatibility by supplying a constant `N`.
pub trait Pin<const N: u8>: super::Iomuxc {
/// The input pin identifier
///
/// Starts at `0`, and increments up.
Expand All @@ -23,18 +18,21 @@ pub trait Pin<U: Unsigned>: super::gpio::Pin {
///
/// Due to a requirement in the ADC module, `prepare` will disable the pull/keeper
/// on the pin. The configuration change will not affect any other settings.
pub fn prepare<U: Unsigned, P: Pin<U>>(pin: &mut P) {
pub fn prepare<P: Pin<N>, const N: u8>(pin: &mut P) {
// See the note in the ADC section of the reference manual
// (using iMXRT1060, rev 2). ADC input signals connect to
// GPIO, and we need to disable the keeper to prevent signal
// jumps.
super::alternate(pin, <P as super::gpio::Pin>::ALT);
super::configure(pin, super::Config::modify().set_pull_keeper(None));
// Not putting the ADC into the GPIO alternate. Reference
// manuals indicate that the alt (mode) doesn't matter. We're
// expecting that the GPIO input path is implicit, regardless
// of the alt.
}

#[allow(unused)] // Used in chip-specific modules...
macro_rules! adc {
(module: $module:ty, pad: $pad:ty, input: $input:expr) => {
(module: $module:expr, pad: $pad:ty, input: $input:expr) => {
impl Pin<$module> for $pad {
const INPUT: u32 = $input;
}
Expand Down
13 changes: 13 additions & 0 deletions src/imxrt1010/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,16 @@ mod lpuart;

mod pads;
pub use pads::*;

mod ccm {
pub use crate::ccm::{Function, Observable, Pin};

impl Pin for super::pads::gpio_sd::GPIO_SD_02 {
const ALT: u32 = 3;
type Function = Observable<1>;
}
impl Pin for super::pads::gpio_sd::GPIO_SD_01 {
const ALT: u32 = 3;
type Function = Observable<2>;
}
}
Loading