Skip to content

Instantly share code, notes, and snippets.

@Arnold1
Created June 1, 2015 18:08
Show Gist options
  • Save Arnold1/acc773a324ecc355edae to your computer and use it in GitHub Desktop.
Save Arnold1/acc773a324ecc355edae to your computer and use it in GitHub Desktop.
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 = 0x10000;
const AWG_CHB_OFFSET: usize = 0x20000;
#[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; //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::MapOffset(AWG_BASE_ADDR/10),
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")
}
let awgReg: *mut awg_reg;
let chaMem: *mut [u32; n];
let chbMem: *mut [u32; n];
unsafe {
//awgReg = data as *mut awg_reg; //
awgReg = data.offset(AWG_BASE_ADDR) as *mut awg_reg;
chaMem = data.offset(AWG_BASE_ADDR + AWG_CHA_OFFSET as isize) as *mut [u32; n];
chbMem = data.offset(AWG_BASE_ADDR + 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 as f32 / n as f32) as f32).cos()).round() as i32;
if (*data)[i] < 0 {
(*data)[i] += (1 << 14);
}
}
}
}
#[inline(never)]
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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment