Created
June 1, 2015 18:08
-
-
Save Arnold1/acc773a324ecc355edae to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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