Compare commits

..

2 Commits

Author SHA1 Message Date
occheung 82867178f9 fix: reduce warning 2020-09-14 17:33:50 +08:00
occheung f94528ae2a scpi: add attenuator command 2020-09-14 17:33:32 +08:00
9 changed files with 129 additions and 106 deletions

View File

@ -7,7 +7,6 @@ use core::sync::atomic::{AtomicU32, Ordering};
extern crate log; extern crate log;
use cortex_m; use cortex_m;
use cortex_m::asm::nop;
use cortex_m_rt::{ use cortex_m_rt::{
entry, entry,
exception, exception,
@ -15,14 +14,9 @@ use cortex_m_rt::{
extern crate smoltcp; extern crate smoltcp;
use stm32h7xx_hal::ethernet; use stm32h7xx_hal::ethernet;
use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::hal::digital::v2::InputPin;
use stm32h7xx_hal::hal::digital::v2::{
OutputPin,
InputPin,
};
use stm32h7xx_hal::rcc::CoreClocks; use stm32h7xx_hal::rcc::CoreClocks;
use stm32h7xx_hal::{pac, prelude::*, spi, stm32, stm32::interrupt}; use stm32h7xx_hal::{pac, prelude::*, spi, stm32, stm32::interrupt};
use Speed::*;
use core::{ use core::{
str, str,
@ -32,8 +26,8 @@ use core::mem::uninitialized;
// Exception: no phy::wait // Exception: no phy::wait
//use smoltcp::phy::wait as phy_wait; //use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; use smoltcp::wire::{IpAddress, IpCidr};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes}; use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::SocketSet; use smoltcp::socket::SocketSet;
use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer}; use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer};
use smoltcp::time::{Duration, Instant}; use smoltcp::time::{Duration, Instant};
@ -44,16 +38,6 @@ use embedded_nal::TcpStack;
use firmware; use firmware;
use firmware::{ use firmware::{
attenuator::Attenuator,
config_register::{
ConfigRegister,
CFGMask,
StatusMask,
},
dds::{
DDS,
DDSCFRMask,
},
cpld::{ cpld::{
CPLD, CPLD,
}, },
@ -63,6 +47,10 @@ use firmware::{
Channel1SwitchCommand, Channel1SwitchCommand,
Channel2SwitchCommand, Channel2SwitchCommand,
Channel3SwitchCommand, Channel3SwitchCommand,
Channel0AttenuationCommand,
Channel1AttenuationCommand,
Channel2AttenuationCommand,
Channel3AttenuationCommand,
ClockSourceCommand, ClockSourceCommand,
ClockDivisionCommand, ClockDivisionCommand,
}, },
@ -83,9 +71,6 @@ use scpi::{
ieee488_stb, ieee488_stb,
ieee488_tst, ieee488_tst,
ieee488_wai, ieee488_wai,
nquery,
//Helpers
qonly,
scpi_crate_version, scpi_crate_version,
scpi_status, scpi_status,
scpi_system, scpi_system,
@ -290,16 +275,20 @@ fn main() -> ! {
} }
}, },
"CHANNEL0" => { "CHANNEL0" => {
"SWitch" => Channel0SwitchCommand "SWitch" => Channel0SwitchCommand,
"Attenuation" => Channel0AttenuationCommand
}, },
"CHANNEL1" => { "CHANNEL1" => {
"SWitch" => Channel1SwitchCommand "SWitch" => Channel1SwitchCommand,
"Attenuation" => Channel1AttenuationCommand
}, },
"CHANNEL2" => { "CHANNEL2" => {
"SWitch" => Channel2SwitchCommand "SWitch" => Channel2SwitchCommand,
"Attenuation" => Channel2AttenuationCommand
}, },
"CHANNEL3" => { "CHANNEL3" => {
"SWitch" => Channel3SwitchCommand "SWitch" => Channel3SwitchCommand,
"Attenuation" => Channel3AttenuationCommand
}, },
"CLOCK" => { "CLOCK" => {
"SOURCE" => ClockSourceCommand, "SOURCE" => ClockSourceCommand,
@ -364,7 +353,7 @@ fn main() -> ! {
} }
if socket.can_recv() { if socket.can_recv() {
let mut data = socket.recv(|buffer| { let data = socket.recv(|buffer| {
(buffer.len(), buffer) (buffer.len(), buffer)
}).unwrap(); }).unwrap();
if str::from_utf8(data).unwrap().trim() == "quit" { if str::from_utf8(data).unwrap().trim() == "quit" {
@ -394,6 +383,7 @@ use stm32h7xx_hal::gpio::{
/* /*
* Migrated ethernet setup pins * Migrated ethernet setup pins
*/ */
#[allow(non_camel_case_types)]
pub fn setup_ethernet_pins<REF_CLK, MDIO, MDC, CRS_DV, RXD0, RXD1, TX_EN, TXD0, TXD1>( pub fn setup_ethernet_pins<REF_CLK, MDIO, MDC, CRS_DV, RXD0, RXD1, TX_EN, TXD0, TXD1>(
pa1: PA1<REF_CLK>, pa2: PA2<MDIO>, pc1: PC1<MDC>, pa7: PA7<CRS_DV>, pc4: PC4<RXD0>, pa1: PA1<REF_CLK>, pa2: PA2<MDIO>, pc1: PC1<MDC>, pa7: PA7<CRS_DV>, pc4: PC4<RXD0>,
pc5: PC5<RXD1>, pg11: PG11<TX_EN>, pg13: PG13<TXD0>, pb13: PB13<TXD1> pc5: PC5<RXD1>, pg11: PG11<TX_EN>, pg13: PG13<TXD0>, pb13: PB13<TXD1>

View File

@ -40,20 +40,16 @@ where
} }
let mut clone = self.data.clone(); let mut clone = self.data.clone();
// Transmit SPI once to set attenuation // Transmit SPI once to set attenuation
match self.spi.transfer(&mut clone).map_err(Error::SPI) { self.spi.transfer(&mut clone)
Err(e) => Err(Error::AttenuatorError), .map(|_| ())
Ok(_) => Ok(()), .map_err(|_| Error::AttenuatorError)
}
} }
pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error<E>> { pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error<E>> {
assert!(channel < 4); assert!(channel < 4);
let mut arr: [f32; 4] = self.get_attenuation()?; let mut arr: [f32; 4] = self.get_attenuation()?;
arr[channel as usize] = attenuation; arr[channel as usize] = attenuation;
match self.set_attenuation(arr) { self.set_attenuation(arr).map(|_| ())
Ok(v) => Ok(()),
Err(e) => Err(e)
}
} }
pub fn get_channel_attenuation(&mut self, channel: u8) -> Result<f32, Error<E>> { pub fn get_channel_attenuation(&mut self, channel: u8) -> Result<f32, Error<E>> {

View File

@ -9,6 +9,7 @@
macro_rules! construct_bitmask { macro_rules! construct_bitmask {
($collection: ident; $unsigned_type: ty; $($name: ident, $shift: expr, $width: expr),+) => { ($collection: ident; $unsigned_type: ty; $($name: ident, $shift: expr, $width: expr),+) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum $collection { pub enum $collection {
$( $(
$name, $name,

View File

@ -213,6 +213,7 @@ where
} }
} }
#[allow(non_snake_case)]
fn get_VCO_no(&mut self, f_sys_clk: u64, divider: u8) -> Result<u8, Error<E>> { fn get_VCO_no(&mut self, f_sys_clk: u64, divider: u8) -> Result<u8, Error<E>> {
// Select a VCO // Select a VCO
if divider == 1 { if divider == 1 {
@ -387,10 +388,9 @@ macro_rules! impl_register_io {
for i in 0..$reg_byte_size { for i in 0..$reg_byte_size {
arr[i+1] = bytes[i]; arr[i+1] = bytes[i];
} }
match self.spi.transfer(&mut arr).map_err(Error::SPI) { self.spi.transfer(&mut arr)
Ok(v) => Ok(()), .map(|_| ())
Err(e) => Err(e), .map_err(Error::SPI)
}
}, },
)* )*
_ => panic!("Bad address for DDS writing.") _ => panic!("Bad address for DDS writing.")

View File

@ -153,6 +153,7 @@ pub trait UrukulTraits {
fn set_channel_switch(&mut self, channel: u32, status: bool) -> Result<(), Self::Error>; fn set_channel_switch(&mut self, channel: u32, status: bool) -> Result<(), Self::Error>;
fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Self::Error>; fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Self::Error>;
fn set_clock_division(&mut self, division: u8) -> Result<(), Self::Error>; fn set_clock_division(&mut self, division: u8) -> Result<(), Self::Error>;
fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error>;
} }
impl<SPI, E> UrukulTraits for Urukul<SPI> impl<SPI, E> UrukulTraits for Urukul<SPI>
@ -163,10 +164,7 @@ where
fn get_channel_switch_status(&mut self, channel: u32) -> Result<bool, Self::Error> { fn get_channel_switch_status(&mut self, channel: u32) -> Result<bool, Self::Error> {
if channel < 4 { if channel < 4 {
match self.config_register.get_status(StatusMask::RF_SW) { self.config_register.get_status(StatusMask::RF_SW).map(|val| (val & (1 << channel)) != 0)
Ok(val) => Ok((val & (1 << channel)) != 0),
Err(_e) => Err(_e),
}
} else { } else {
Err(Error::ParameterError) Err(Error::ParameterError)
} }
@ -182,19 +180,16 @@ where
prev & (!(1 << channel)) prev & (!(1 << channel))
} }
}; };
match self.config_register.set_configurations(&mut [ self.config_register.set_configurations(&mut [
(CFGMask::RF_SW, next), (CFGMask::RF_SW, next),
]) { ]).map(|_| ())
Ok(_) => Ok(()),
Err(_e) => Err(_e),
}
} else { } else {
Err(Error::ParameterError) Err(Error::ParameterError)
} }
} }
fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Self::Error> { fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Self::Error> {
let result = match source { match source {
ClockSource::OSC => self.config_register.set_configurations(&mut [ ClockSource::OSC => self.config_register.set_configurations(&mut [
(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL0, 0),
(CFGMask::CLK_SEL1, 0), (CFGMask::CLK_SEL1, 0),
@ -206,15 +201,11 @@ where
ClockSource::SMA => self.config_register.set_configurations(&mut [ ClockSource::SMA => self.config_register.set_configurations(&mut [
(CFGMask::CLK_SEL0, 1), (CFGMask::CLK_SEL0, 1),
]), ]),
}; }.map(|_| ())
match result {
Ok(_) => Ok(()),
Err(_e) => Err(_e),
}
} }
fn set_clock_division(&mut self, division: u8) -> Result<(), Self::Error> { fn set_clock_division(&mut self, division: u8) -> Result<(), Self::Error> {
let result = match division { match division {
1 => self.config_register.set_configurations(&mut [ 1 => self.config_register.set_configurations(&mut [
(CFGMask::DIV, 1), (CFGMask::DIV, 1),
]), ]),
@ -225,10 +216,10 @@ where
(CFGMask::DIV, 3), (CFGMask::DIV, 3),
]), ]),
_ => Err(Error::ParameterError), _ => Err(Error::ParameterError),
}; }.map(|_| ())
match result {
Ok(_) => Ok(()),
Err(_e) => Err(_e),
} }
fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error> {
self.attenuator.set_channel_attenuation(channel, attenuation)
} }
} }

View File

@ -1,7 +1,10 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use panic_semihosting as _; #[macro_use]
extern crate log;
use log::{trace, debug, info, warn};
use stm32h7xx_hal::hal::digital::v2::{ use stm32h7xx_hal::hal::digital::v2::{
InputPin, InputPin,
@ -11,7 +14,6 @@ use stm32h7xx_hal::{pac, prelude::*, spi};
use cortex_m; use cortex_m;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
use firmware; use firmware;
use firmware::{ use firmware::{
@ -30,10 +32,13 @@ use firmware::{
} }
}; };
#[path = "../examples/util/logger.rs"]
mod logger;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap(); let mut cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let pwr = dp.PWR.constrain(); let pwr = dp.PWR.constrain();
@ -41,10 +46,17 @@ fn main() -> ! {
let rcc = dp.RCC.constrain(); let rcc = dp.RCC.constrain();
let ccdr = rcc let ccdr = rcc
.use_hse(8.mhz())
.sys_ck(400.mhz()) .sys_ck(400.mhz())
.pll1_q_ck(48.mhz()) .pll1_q_ck(48.mhz())
.pll1_r_ck(400.mhz())
.freeze(vos, &dp.SYSCFG); .freeze(vos, &dp.SYSCFG);
unsafe {
logger::enable_itm(&dp.DBGMCU, &mut cp.DCB, &mut cp.ITM);
}
logger::init();
let mut delay = cp.SYST.delay(ccdr.clocks); let mut delay = cp.SYST.delay(ccdr.clocks);
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
@ -58,10 +70,10 @@ fn main() -> ! {
let fpga_cdone = gpiod.pd15.into_pull_up_input(); let fpga_cdone = gpiod.pd15.into_pull_up_input();
match fpga_cdone.is_high() { match fpga_cdone.is_high() {
Ok(true) => hprintln!("FPGA is ready."), Ok(true) => info!("FPGA is ready."),
Ok(_) => hprintln!("FPGA is in reset state."), Ok(_) => info!("FPGA is in reset state."),
Err(_) => hprintln!("Error: Cannot read C_DONE"), Err(_) => info!("Error: Cannot read C_DONE"),
}.unwrap(); };
/* /*
* Using SPI1, AF5 * Using SPI1, AF5
@ -150,10 +162,10 @@ fn main() -> ! {
0x04, // Recirculate mode 0x04, // Recirculate mode
]).unwrap(); ]).unwrap();
hprintln!("{:#X?}", dds0.read_register(0x0E, &mut[ debug!("{:#X?}", dds0.read_register(0x0E, &mut[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]).unwrap()).unwrap(); ]).unwrap());
// Choose profile 0 // Choose profile 0
config.set_configurations(&mut [ config.set_configurations(&mut [

View File

@ -60,15 +60,10 @@ impl<'a, 'b, 'c, 'n> NetworkStack<'a, 'b, 'c, 'n> {
} }
pub fn update(&mut self, time: u32) -> bool { pub fn update(&mut self, time: u32) -> bool {
match self.network_interface.poll( self.network_interface.poll(
&mut self.sockets.borrow_mut(), &mut self.sockets.borrow_mut(),
net::time::Instant::from_millis(time as i64), net::time::Instant::from_millis(time as i64),
) { ).map_or(true, |changed| changed == false)
Ok(changed) => changed == false,
Err(e) => {
true
}
}
} }
fn get_ephemeral_port(&self) -> u16 { fn get_ephemeral_port(&self) -> u16 {

View File

@ -7,26 +7,9 @@ use scpi::NumericValues;
use core::convert::{TryFrom, TryInto}; use core::convert::{TryFrom, TryInto};
use core::str; use core::str;
use core::str::Utf8Error;
use scpi::ieee488::commands::*;
use scpi::scpi::commands::*;
use scpi::{ use scpi::{
ieee488_cls,
ieee488_ese,
ieee488_esr,
ieee488_idn,
ieee488_opc,
ieee488_rst,
ieee488_sre,
ieee488_stb,
ieee488_tst,
ieee488_wai,
nquery, nquery,
//Helpers
qonly, qonly,
scpi_crate_version,
scpi_status,
scpi_system,
}; };
use scpi::suffix::{Amplitude, Db}; use scpi::suffix::{Amplitude, Db};
use uom::si::frequency::{gigahertz, hertz, kilohertz, megahertz, Frequency}; use uom::si::frequency::{gigahertz, hertz, kilohertz, megahertz, Frequency};
@ -147,6 +130,10 @@ pub struct Channel2SwitchCommand {}
pub struct Channel3SwitchCommand {} pub struct Channel3SwitchCommand {}
pub struct ClockSourceCommand {} pub struct ClockSourceCommand {}
pub struct ClockDivisionCommand {} pub struct ClockDivisionCommand {}
pub struct Channel0AttenuationCommand {}
pub struct Channel1AttenuationCommand {}
pub struct Channel2AttenuationCommand {}
pub struct Channel3AttenuationCommand {}
impl<T: Device + UrukulTraits> Command<T> for Channel0SwitchCommand { impl<T: Device + UrukulTraits> Command<T> for Channel0SwitchCommand {
nquery!(); nquery!();
@ -270,14 +257,65 @@ impl<T:Device + UrukulTraits> Command<T> for ClockDivisionCommand {
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)), .map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|token| token.try_into())?; |token| token.try_into())?;
trace!("Received master clock division factor: {}", div); trace!("Received master clock division factor: {}", div);
match div { if div == 1.0 || div == 2.0 || div == 4.0 {
1.0 | 2.0 | 4.0 => {
debug!("Set master clock division as {}", div); debug!("Set master clock division as {}", div);
context.device.set_clock_division(div as u8) context.device.set_clock_division(div as u8)
.map_err(|_| Error::new(ErrorCode::HardwareError)) .map_err(|_| Error::new(ErrorCode::HardwareError))
} else {
Err(Error::new(ErrorCode::IllegalParameterValue))
} }
_ => Err(Error::new(ErrorCode::IllegalParameterValue)),
} }
}
impl<T:Device + UrukulTraits> Command<T> for Channel0AttenuationCommand {
nquery!();
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
let attenuation: f32 = args.next_data(false)?
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|token| token.try_into())?;
trace!("Received channel 0 attenuation input: {}", attenuation);
context.device.set_channel_attenuation(0, attenuation)
.map_err(|_| Error::new(ErrorCode::HardwareError))
}
}
impl<T:Device + UrukulTraits> Command<T> for Channel1AttenuationCommand {
nquery!();
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
let attenuation: f32 = args.next_data(false)?
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|token| token.try_into())?;
trace!("Received channel 1 attenuation input: {}", attenuation);
context.device.set_channel_attenuation(1, attenuation)
.map_err(|_| Error::new(ErrorCode::HardwareError))
}
}
impl<T:Device + UrukulTraits> Command<T> for Channel2AttenuationCommand {
nquery!();
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
let attenuation: f32 = args.next_data(false)?
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|token| token.try_into())?;
trace!("Received channel 2 attenuation input: {}", attenuation);
context.device.set_channel_attenuation(2, attenuation)
.map_err(|_| Error::new(ErrorCode::HardwareError))
}
}
impl<T:Device + UrukulTraits> Command<T> for Channel3AttenuationCommand {
nquery!();
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
let attenuation: f32 = args.next_data(false)?
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|token| token.try_into())?;
trace!("Received channel 3 attenuation input: {}", attenuation);
context.device.set_channel_attenuation(3, attenuation)
.map_err(|_| Error::new(ErrorCode::HardwareError))
} }
} }

View File

@ -51,13 +51,13 @@ where
fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> { fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> {
self.0.do_on_get_ref_mut_data(move |mut dev| { self.0.do_on_get_ref_mut_data(move |mut dev| {
dev.select_chip(self.1); dev.select_chip(self.1).map_err(|_| Error::CSError)?;
let result = dev.spi.transfer(words).map_err(Error::SPI); let result = dev.spi.transfer(words).map_err(Error::SPI)?;
dev.select_chip(0); dev.select_chip(0).map_err(|_| Error::CSError)?;
if self.2 { if self.2 {
dev.issue_io_update(); dev.issue_io_update().map_err(|_| Error::IOUpdateError)?;
} }
result Ok(result)
}) })
} }
} }