I recently started to learn Rust (http://www.rust-lang.org/). Rust recently stabilizes at version 1.0.
What is Rust?
A systems programming language that runs blazingly fast, prevents almost all crashes, and eliminates data races.
The following steps show to to setup the rust compiler and compile a simplified version of the generate application (can only generate a sine signal) to your RP
The used red pitaya's ecosystem is here (thanks to pavel), make sure that you set the right size for the uio in the patch file.
https://github.com/pavel-demin/red-pitaya-notes
I used /dev/uio in my app, bc I dont want to directly access /dev/mem. You can also use /dev/mem (not tested yet)...
If there is interest I can post my github...
Install the Rust Cross Compiler (Rust 1.0.0) for ARM (armv7l):
Code: Select all
$ git clone https://github.com/rust-lang/rust
$ cd rust
$ git checkout stable
$ ./configure --target=arm-unknown-linux-gnueabihf,x86_64-unknown-linux-gnu
$ make -j$(nproc)
$ sudo make install
Code: Select all
$ mkdir local_cargo
$ curl -sSf https://static.rust-lang.org/rustup.sh | sh -s -- --prefix=local_cargo
Code: Select all
$ cargo build --target=arm-unknown-linux-gnueabihf
main.rs:
Code: Select all
// from crates.io
extern crate mmap;
extern crate libc;
use std::thread;
use std::env;
mod fpga_awg;
fn main() {
if let Some(arg1) = env::args().nth(1) {
let mut awg = fpga_awg::fpgaAwg::new();
let mut params: fpga_awg::awgParam = fpga_awg::awgParam::default();
let mut data: [i32; fpga_awg::n] = [0; fpga_awg::n];
awg.syntesize_signal(1.0, 1000.0, &mut data, &mut params);
awg.write_data_fpga(0, &mut data, &mut params);
// blink led1...just for fun :)
for i in 0..20 {
awg.toggle(1);
thread::sleep_ms(arg1.parse::<u32>().unwrap());
}
}
}
Code: Select all
use std::ptr;
use std::fs;
use std::io::{Write, SeekFrom, Seek};
use std::os::unix::prelude::AsRawFd;
use mmap::{MemoryMap, MapOption};
use libc;
use std::f32;
use std::default::Default;
pub const n: usize = (16*1024);
const c_awg_smpl_freq: f32 = 125e6;
const AWG_BASE_ADDR: isize = 0x200000;
const AWG_CHA_OFFSET: usize = 0x210000;
const AWG_CHB_OFFSET: usize = 0x220000;
#[derive(Default)]
pub struct awgParam {
offsgain: i32, //< AWG offset & gain.
wrap: u32, //< AWG buffer wrap value.
step: u32, //< AWG step interval.
}
struct awg_reg {
state_machine_conf: u32,
cha_scale_off: u32,
cha_count_wrap: u32,
cha_start_off: u32,
cha_count_step: u32,
reserved_regs: [u32; 4],
chb_scale_off: u32,
chb_count_wrap: u32,
chb_start_off: u32,
chb_count_step: u32,
}
pub struct fpgaAwg {
mmap: MemoryMap,
data: *mut u8,
awgReg: *mut awg_reg,
chaMem: *mut [u32; n],
chbMem: *mut [u32; n],
}
impl fpgaAwg {
pub fn new() -> fpgaAwg {
let size: usize = 0x400000;
let mut f = fs::OpenOptions::new().read(true)
.write(true)
.open("/dev/uio0")
.unwrap();
let mmap_opts = &[
// Then make the mapping *public* so it is written back to the file
MapOption::MapNonStandardFlags(libc::MAP_SHARED),
MapOption::MapReadable,
MapOption::MapWritable,
MapOption::MapFd(f.as_raw_fd()),
];
let mmap = MemoryMap::new(size, mmap_opts).unwrap();
let data = mmap.data();
if data.is_null() {
panic!("Could not access data from memory mapped file")
}
else {
println!("successful data access to memory mapped file");
}
let awgReg: *mut awg_reg;
let chaMem: *mut [u32; n];
let chbMem: *mut [u32; n];
unsafe {
awgReg = data.offset(AWG_BASE_ADDR) as *mut awg_reg;
chaMem = data.offset(AWG_CHA_OFFSET as isize) as *mut [u32; n];
chbMem = data.offset(AWG_CHB_OFFSET as isize) as *mut [u32; n];
}
fpgaAwg {mmap: mmap, data: data, awgReg: awgReg, chaMem: chaMem, chbMem: chbMem}
}
pub fn toggle(&mut self, led_pin: u32) {
unsafe {
*(self.data.offset(0x30) as *mut u32) ^= 1 << led_pin;
}
}
pub fn syntesize_signal(&mut self, ampl: f32, freq: f32, data: &mut [i32; n], awg: &mut awgParam) {
let mut amp: u32 = (ampl * 4000.0) as u32;
if (amp > 8191) {
amp = 8191;
}
const dcoffs: i32 = -155;
unsafe {
(*awg).offsgain = (dcoffs << 16) + 0x1fff;
(*awg).step = (65536.0 * freq/c_awg_smpl_freq * n as f32).round() as u32;
(*awg).wrap = (65536.0 * (n-1) as f32).round() as u32;
for i in 0..n {
(*data)[i] = (amp as f32 * (2.0 * f32::consts::PI * (i/n) as f32).cos()).round() as i32;
if (*data)[i] < 0 {
(*data)[i] += (1 << 14);
}
}
}
}
pub fn write_data_fpga(&mut self, ch: u32, data: *mut [i32; n], awg: *mut awgParam) {
let i: u32;
unsafe {
if(ch == 0) {
/* Channel A */
(*self.awgReg).state_machine_conf = 0x000041;
(*self.awgReg).cha_scale_off = (*awg).offsgain as u32;
(*self.awgReg).cha_count_wrap = (*awg).wrap;
(*self.awgReg).cha_count_step = (*awg).step;
(*self.awgReg).cha_start_off = 0;
for i in 0..n {
(*self.chaMem)[i] = (*data)[i] as u32;
}
} else if (ch == 1) {
/* Channel B */
(*self.awgReg).state_machine_conf = 0x410000;
(*self.awgReg).chb_scale_off = (*awg).offsgain as u32;
(*self.awgReg).chb_count_wrap = (*awg).wrap;
(*self.awgReg).chb_count_step = (*awg).step;
(*self.awgReg).chb_start_off = 0;
for i in 0..n {
(*self.chbMem)[i] = (*data)[i] as u32;
}
} else {
panic!("wrong channel selected");
}
/* Enable both channels */
/* TODO: Should this only happen for the specified channel?
* Otherwise, the not-to-be-affected channel is restarted as well
* causing unwanted disturbances on that channel.
*/
(*self.awgReg).state_machine_conf = 0x110011;
}
}
}
Code: Select all
$ ./acquire 16000 64 | awk '{ print $1 "," $2}' > out.csv