Use this Rust interface to interact with NI FPGAs! See NI's documentation about the FPGA C interface for more information.
This interface supports reading and writing the following types, both indvidually and in fixed-sized arrays:
- bool
- u8
- u16
- u32
- u64
- i8
- i16
- i32
- i64
- f32 (for SGL registers)
- f64 (for DBL registers)
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 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,
}
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)?,
);
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.
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(())
}
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)