Macro atsamd_hal::bsp_pins
source · [−]macro_rules! bsp_pins {
(
$(
$( #[$id_cfg:meta] )*
$Id:ident {
$( #[$name_doc:meta] )*
$( name: $name:ident $(,)? )?
$(
aliases: {
$(
$( #[$alias_cfg:meta] )*
$Mode:ident: $Alias:ident $(,)?
)+
}
)?
} $(,)?
)+
) => { ... };
}
Expand description
Helper macro to give meaningful names to GPIO pins
The atsamd_hal::gpio
module generally refers to each Pin
by
its PinId
. However, in the context of a BSP, pins can often be given
more meaningful names. This macro gives BSP authors a convenient way to
provide custom names for each pin.
Calling the macro
The bsp_pins!
macro takes a series of PinId
blocks. Each block starts
with a PinId
and is delimited by curly brackets. Within each block, there
are two optional fields, name
and aliases
. The name
field represents
the principal name or function assigned to the pin and is given in
snake_case
. If the name
field is absent, the pin name will default to
its PinId
(converted to snake_case
). The aliases
field represents any
number of alternative names for the pin, where each name corresponds to the
pin in a particular PinMode
. Note that each alias is given in
PascalCase
.
The example below defines a name
and two aliases
for pin PA24
. In
PinMode
AlternateC
, the pin is used as an SPI MOSI pin. In PinMode
AlternateD
, it is used as a UART TX pin. In both cases, it is a serial
output, so its name
is serial_out
.
atsamd_hal::bsp_pins!(
PA24 {
name: serial_out,
aliases: {
AlternateC: SpiMosi,
AlternateD: UartTx,
}
}
);
Expanding the macro
When expanded, the bsp_pins!
macro will define a number of structs, type
aliases, constants and macros.
A new Pins
struct
First, it will define a new, more-useful Pins
struct. The Pins
struct
defined in the gpio
module is intended for general use. It contains all
the pins for a given chip, and each pin is named according to its PinId
.
The Pins
struct defined by this macro, on the other hand, contains only
the declared pins, and each pin is named appropriately.
The field name for each pin within the Pins
struct is based on the macro
name
field. For example, the serial_out
pin from the example above could
be accessed like this:
let mut peripherals = pac::Peripherals::take().unwrap();
let pins = bsp::Pins::new(peripherals.PORT);
let out = pins.serial_out;
However, that is not the only way to access each pin. While the name
field
represents the principal name, each pin can also be accessed using its
corresponding aliases
.
In Rust, each struct field can only have one name. To provide access to the
same struct field using several different names, the bsp_pins!
macro
defines another macro, pin_alias!
. Based on the example above, we could
use the pin_alias!
macro to access pin PA24
without ever referring to
the serial_out
field.
let mut peripherals = pac::Peripherals::take().unwrap();
let pins = bsp::Pins::new(peripherals.PORT);
let mosi = pin_alias!(pins.spi_mosi);
Note that the SpiMosi
alias was translated to snake_case
when accessing
the Pins
field. The same is true for the UartTx
alias.
let mut peripherals = pac::Peripherals::take().unwrap();
let pins = bsp::Pins::new(peripherals.PORT);
let tx = pin_alias!(pins.uart_tx);
Type aliases
Next, the macro defines several useful type aliases for each pin. It
provides aliases for the corresponding PinId
, PinMode
and fully
specified Pin
type of each alternate name.
The example above would exand to
pub type SpiMosi = Pin<PA24, AlternateC>;
pub type SpiMosiId = PA24;
pub type SpiMosiMode = AlternateC;
pub type UartTx = Pin<PA24, AlternateD>;
pub type UartTxId = PA24;
pub type UartTxMode = AlternateD;
Each PascalCase
alias provided in the macro is used for the Pin
type,
and the suffixes Id
and Mode
are appended to for the corresponding
PinId
and PinMode
types.
DYN
constants
Although the pin
API is more common, there are use cases for the
type-erased, dyn_pin
API as well. The bsp_pins!
macro
also defines some useful constants for these cases. In particular, it
defines DynPinId
and DynPinMode
constants for each alias.
The example above would effectively expand to
pub const SPI_MOSI_ID: DynPinId = DynPinId { group: DynGroup::A, num: 24 };
pub const SPI_MOSI_MODE: DynPinMode = DYN_ALTERNATE_C;
pub const UART_TX_ID: DynPinId = DynPinId { group: DynGroup::A, num: 24 };
pub const UART_TX_MODE: DynPinMode = DYN_ALTERNATE_D;
The PascalCase
alias provided in the macro is converted to
SCREAMING_CASE
, and the suffixes _ID
and _MODE
are appended for the
corresponding DynPinId
and DynPinMode
constants.
Attributes and documentation
BSP authors can also add attributes and documentation to various parts of
the macro declaration. Attributes can be added to the entire PinId
block.
These attributes will be propagated to every use of the corresponding
PinId
. Attributes applied to each alias, on the other hand, will only be
propagated to items specific to that alias, like the corresponding DYN
constants. Finally, any documentation (or other attributes) provided for the
name
field will be propagated to the corresponding field of the
bsp::Pins
struct defined by this macro.
atsamd_hal::bsp_pins!(
#[cfg(feature = "has_pin_PA24")]
PA24 {
/// Documentation that will appear on the corresponding field in the
/// `bsp::Pins` struct
name: serial_out,
aliases: {
#[cfg(feature = "uses_SPI")]
AlternateC: SpiMosi,
#[cfg(feature = "uses_UART")]
AlternateD: UartTx,
}
}
);