7 releases (stable)
1.4.1 | Mar 5, 2021 |
---|---|
1.4.0 | Aug 23, 2020 |
1.0.0 | May 24, 2020 |
0.1.0 | May 24, 2020 |
#4 in #ni
57KB
1K
SLoC
ni-fpga-rs
Use this Rust interface to interact with NI FPGAs! See NI's documentation about the FPGA C interface for more information.
Supported types
This interface supports reading and writing the following types, both indvidually and in fixed-sized arrays:
Primitive types
- bool
- u8
- u16
- u32
- u64
- i8
- i16
- i32
- i64
- f32 (for SGL registers)
- f64 (for DBL registers)
Clusters
Clusters are supported via a derive macro. Arrays of Clusters are not guaranteed to be supported.
#[derive(Cluster)]
struct PWMConfig {
period: u16,
min_high: u16,
}
Enums
Enums are supported via a derive macro. Arrays of Enums are also supported. One of u8
, u16
, u32
, or u64
will be chosen as a backing type depending on the number of variants.
#[derive(Enum)]
enum SPIDebugState {
Idle,
CheckWindow,
CheckAvailable,
SetFIFOMark,
EnableSPI,
StuffFIFO,
CheckMark,
ShuffleData,
Disable,
}
Fixed-point numeric types
Signed and unsigned FXP types are implemented in the fxp
module. The types both take two generic parameters: word length and integer length. Word length is the actual number of bits used by the type. Integer length is such that the maximum value of the type is 2integer length - 1 (half if it is signed) and the resolution of the type is 2integer length - word length. For example, if an unsigned FXP has a word length of 8 and an integer length of 7, then its maximum value is 127 and its resolution is 0.5.
assert_eq!(
SignedFXP::<8, 7>::from_float(-1.5)? + SignedFXP::<8, 7>::from_float(4.0)?,
SignedFXP::<8, 7>::from_float(2.5)?,
);
Locating register offsets
Register offset can be found by introspecting /boot/user.lvbitx
on a roboRIO. This file is also present in first-rust-competition/cross-images images.
Full example
use ni_fpga::Session;
use ni_fpga_macros::{Cluster, Enum};
#[derive(Cluster, Debug)]
struct PWMConfig {
period: u16,
min_high: u16,
}
#[derive(Cluster, Debug)]
struct AnalogTriggerOutput {
in_hysteresis: bool,
over_limit: bool,
rising: bool,
falling: bool,
}
#[derive(Enum, Debug)]
enum SPIDebugState {
Idle,
CheckWindow,
CheckAvailable,
SetFIFOMark,
EnableSPI,
StuffFIFO,
CheckMark,
ShuffleData,
Disable,
}
fn main() -> Result<(), ni_fpga::Error> {
let session = Session::open(
"/boot/user.lvbitx",
"264D0BA312FF00B741D4742415E1D470",
"RIO0",
)?;
println!("Input voltage: {:?}", session.read::<u16>(99174)?);
println!("{:#?}", session.read::<PWMConfig>(98536)?);
println!("{:#?}", session.read::<[AnalogTriggerOutput; 8]>(98424)?);
println!("{:#?}", session.read::<SPIDebugState>(99314)?);
Ok(())
}
Contributing
Contributions are welcome and appreciated. Look at open issues to find tasks to work on. We especially need help with:
- Creating an automated testing strategy
- Improving documentation
- Adding support for IRQs and FIFOs (see NI API reference)
Dependencies
~1–1.5MB
~37K SLoC