mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-25 11:18:27 +08:00
Merge branch 'master' into nac3
This commit is contained in:
commit
e6f26b5c74
@ -33,6 +33,11 @@ Highlights:
|
||||
warning is logged. The warning is additional to the one already printed in the core device log upon
|
||||
detection of the error.
|
||||
* Removed worker DB warning for writing a dataset that is also in the archive
|
||||
* Extended Kasli gateware JSON description with configuration for SPI over DIO.
|
||||
See: https://github.com/m-labs/artiq/pull/1800
|
||||
* ``PCA9548`` I2C switch class renamed to ``I2CSwitch``, to accomodate support for PCA9547, and
|
||||
possibly other switches in future. Readback has been removed, and now only one channel per
|
||||
switch is supported.
|
||||
|
||||
Breaking changes:
|
||||
|
||||
|
@ -134,7 +134,7 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["dio", "urukul", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser", "hvamp"]
|
||||
"enum": ["dio", "dio_spi", "urukul", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser", "hvamp"]
|
||||
},
|
||||
"board": {
|
||||
"type": "string"
|
||||
@ -179,6 +179,89 @@
|
||||
},
|
||||
"required": ["ports", "bank_direction_low", "bank_direction_high"]
|
||||
}
|
||||
}, {
|
||||
"title": "DIO_SPI",
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "dio_spi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"spi": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"clk": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
},
|
||||
"mosi": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
},
|
||||
"miso": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
},
|
||||
"cs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["clk"]
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"ttl": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"pin": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
},
|
||||
"direction": {
|
||||
"type": "string",
|
||||
"enum": ["input", "output"]
|
||||
},
|
||||
"edge_counter": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": ["pin", "direction"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["ports", "spi"]
|
||||
}
|
||||
}, {
|
||||
"title": "Urukul",
|
||||
"if": {
|
||||
|
@ -32,6 +32,11 @@ def i2c_read(busno: int32, ack: bool) -> int32:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def i2c_switch_select(busno: TInt32, address: TInt32, mask: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@kernel
|
||||
def i2c_poll(busno, busaddr):
|
||||
"""Poll I2C device at address.
|
||||
@ -136,8 +141,10 @@ def i2c_read_many(busno, busaddr, addr, data):
|
||||
i2c_stop(busno)
|
||||
|
||||
|
||||
class PCA9548:
|
||||
"""Driver for the PCA9548 I2C bus switch.
|
||||
class I2CSwitch:
|
||||
"""Driver for the I2C bus switch.
|
||||
|
||||
PCA954X (or other) type detection is done by the CPU during I2C init.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
@ -150,25 +157,18 @@ class PCA9548:
|
||||
self.busno = busno
|
||||
self.address = address
|
||||
|
||||
@kernel
|
||||
def select(self, mask):
|
||||
"""Enable/disable channels.
|
||||
|
||||
:param mask: Bit mask of enabled channels
|
||||
"""
|
||||
i2c_write_byte(self.busno, self.address, mask)
|
||||
|
||||
@kernel
|
||||
def set(self, channel):
|
||||
"""Enable one channel.
|
||||
|
||||
:param channel: channel number (0-7)
|
||||
"""
|
||||
self.select(1 << channel)
|
||||
i2c_switch_select(self.busno, self.address >> 1, 1 << channel)
|
||||
|
||||
@kernel
|
||||
def readback(self):
|
||||
return i2c_read_byte(self.busno, self.address)
|
||||
def unset(self):
|
||||
"""Disable output of the I2C switch.
|
||||
"""
|
||||
i2c_switch_select(self.busno, self.address >> 1, 0)
|
||||
|
||||
|
||||
class TCA6424A:
|
||||
|
@ -37,13 +37,17 @@ class KasliEEPROM:
|
||||
@kernel
|
||||
def select(self):
|
||||
mask = 1 << self.port
|
||||
self.sw0.select(mask)
|
||||
self.sw1.select(mask >> 8)
|
||||
if self.port < 8:
|
||||
self.sw0.set(self.port)
|
||||
self.sw1.unset()
|
||||
else:
|
||||
self.sw0.unset()
|
||||
self.sw1.set(self.port - 8)
|
||||
|
||||
@kernel
|
||||
def deselect(self):
|
||||
self.sw0.select(0)
|
||||
self.sw1.select(0)
|
||||
self.sw0.unset()
|
||||
self.sw1.unset()
|
||||
|
||||
@kernel
|
||||
def write_i32(self, addr, value):
|
||||
|
@ -226,7 +226,7 @@ def setup_from_ddb(ddb):
|
||||
dds_sysclk = v["arguments"]["sysclk"]
|
||||
widget = _WidgetDesc(k, comment, _DDSWidget, (bus_channel, channel, k))
|
||||
description.add(widget)
|
||||
elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53XX")
|
||||
elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53xx")
|
||||
or (v["module"] == "artiq.coredevice.zotino" and v["class"] == "Zotino")):
|
||||
spi_device = v["arguments"]["spi_device"]
|
||||
spi_device = ddb[spi_device]
|
||||
|
@ -27,13 +27,13 @@ device_db = {
|
||||
"i2c_switch0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548",
|
||||
"class": "I2CSwitch",
|
||||
"arguments": {"address": 0xe0}
|
||||
},
|
||||
"i2c_switch1": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548",
|
||||
"class": "I2CSwitch",
|
||||
"arguments": {"address": 0xe2}
|
||||
},
|
||||
|
||||
|
@ -31,7 +31,7 @@ device_db = {
|
||||
"i2c_switch": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548"
|
||||
"class": "I2CSwitch"
|
||||
},
|
||||
|
||||
# Generic TTL
|
||||
|
@ -159,6 +159,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||
api!(i2c_stop = ::nrt_bus::i2c::stop),
|
||||
api!(i2c_write = ::nrt_bus::i2c::write),
|
||||
api!(i2c_read = ::nrt_bus::i2c::read),
|
||||
api!(i2c_switch_select = ::nrt_bus::i2c::switch_select),
|
||||
|
||||
api!(spi_set_config = ::nrt_bus::spi::set_config),
|
||||
api!(spi_write = ::nrt_bus::spi::write),
|
||||
|
@ -43,6 +43,17 @@ pub mod i2c {
|
||||
data
|
||||
}) as i32
|
||||
}
|
||||
|
||||
pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
send(&I2cSwitchSelectRequest {
|
||||
busno: busno as u32,
|
||||
address: address as u8,
|
||||
mask: mask as u8 });
|
||||
recv!(&I2cBasicReply { succeeded } => { if !succeeded {
|
||||
raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub mod spi {
|
||||
|
@ -179,11 +179,11 @@ fn init() -> Result<()> {
|
||||
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
{
|
||||
i2c::pca9548_select(BUSNO, 0x70, 0)?;
|
||||
i2c::pca9548_select(BUSNO, 0x71, 1 << 3)?;
|
||||
i2c::switch_select(BUSNO, 0x70, 0)?;
|
||||
i2c::switch_select(BUSNO, 0x71, 1 << 3)?;
|
||||
}
|
||||
#[cfg(soc_platform = "kc705")]
|
||||
i2c::pca9548_select(BUSNO, 0x74, 1 << 7)?;
|
||||
i2c::switch_select(BUSNO, 0x74, 1 << 7)?;
|
||||
|
||||
if ident()? != 0x0182 {
|
||||
return Err("Si5324 does not have expected product number");
|
||||
|
@ -188,12 +188,15 @@ mod imp {
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn pca9548_select(busno: u8, address: u8, channels: u8) -> Result<(), &'static str> {
|
||||
pub fn switch_select(busno: u8, address: u8, mask: u8) -> Result<(), &'static str> {
|
||||
// address in 7-bit form
|
||||
// mask in format of 1 << channel (or 0 for disabling output)
|
||||
// PCA9548 support only for now
|
||||
start(busno)?;
|
||||
if !write(busno, address << 1)? {
|
||||
return Err("PCA9548 failed to ack write address")
|
||||
}
|
||||
if !write(busno, channels)? {
|
||||
if !write(busno, mask)? {
|
||||
return Err("PCA9548 failed to ack control word")
|
||||
}
|
||||
stop(busno)?;
|
||||
@ -210,7 +213,7 @@ mod imp {
|
||||
pub fn stop(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) }
|
||||
pub fn write(_busno: u8, _data: u8) -> Result<bool, &'static str> { Err(NO_I2C) }
|
||||
pub fn read(_busno: u8, _ack: bool) -> Result<u8, &'static str> { Err(NO_I2C) }
|
||||
pub fn pca9548_select(_busno: u8, _address: u8, _channels: u8) -> Result<(), &'static str> { Err(NO_I2C) }
|
||||
pub fn switch_select(_busno: u8, _address: u8, _mask: u8) -> Result<(), &'static str> { Err(NO_I2C) }
|
||||
}
|
||||
|
||||
pub use self::imp::*;
|
||||
|
@ -31,8 +31,8 @@ impl EEPROM {
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
fn select(&self) -> Result<(), &'static str> {
|
||||
let mask: u16 = 1 << self.port;
|
||||
i2c::pca9548_select(self.busno, 0x70, mask as u8)?;
|
||||
i2c::pca9548_select(self.busno, 0x71, (mask >> 8) as u8)?;
|
||||
i2c::switch_select(self.busno, 0x70, mask as u8)?;
|
||||
i2c::switch_select(self.busno, 0x71, (mask >> 8) as u8)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ impl IoExpander {
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
fn select(&self) -> Result<(), &'static str> {
|
||||
let mask: u16 = 1 << self.port;
|
||||
i2c::pca9548_select(self.busno, 0x70, mask as u8)?;
|
||||
i2c::pca9548_select(self.busno, 0x71, (mask >> 8) as u8)?;
|
||||
i2c::switch_select(self.busno, 0x70, mask as u8)?;
|
||||
i2c::switch_select(self.busno, 0x71, (mask >> 8) as u8)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ pub enum Packet {
|
||||
I2cReadRequest { destination: u8, busno: u8, ack: bool },
|
||||
I2cReadReply { succeeded: bool, data: u8 },
|
||||
I2cBasicReply { succeeded: bool },
|
||||
I2cSwitchSelectRequest { destination: u8, busno: u8, address: u8, mask: u8 },
|
||||
|
||||
SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 },
|
||||
SpiWriteRequest { destination: u8, busno: u8, data: u32 },
|
||||
@ -154,6 +155,12 @@ impl Packet {
|
||||
0x87 => Packet::I2cBasicReply {
|
||||
succeeded: reader.read_bool()?
|
||||
},
|
||||
0x88 => Packet::I2cSwitchSelectRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?,
|
||||
address: reader.read_u8()?,
|
||||
mask: reader.read_u8()?,
|
||||
},
|
||||
|
||||
0x90 => Packet::SpiSetConfigRequest {
|
||||
destination: reader.read_u8()?,
|
||||
@ -313,6 +320,13 @@ impl Packet {
|
||||
writer.write_u8(0x87)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
},
|
||||
Packet::I2cSwitchSelectRequest { destination, busno, address, mask } => {
|
||||
writer.write_u8(0x88)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
writer.write_u8(address)?;
|
||||
writer.write_u8(mask)?;
|
||||
},
|
||||
|
||||
Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => {
|
||||
writer.write_u8(0x90)?;
|
||||
|
@ -65,6 +65,7 @@ pub enum Message<'a> {
|
||||
I2cReadRequest { busno: u32, ack: bool },
|
||||
I2cReadReply { succeeded: bool, data: u8 },
|
||||
I2cBasicReply { succeeded: bool },
|
||||
I2cSwitchSelectRequest { busno: u32, address: u8, mask: u8 },
|
||||
|
||||
SpiSetConfigRequest { busno: u32, flags: u8, length: u8, div: u8, cs: u8 },
|
||||
SpiWriteRequest { busno: u32, data: u32 },
|
||||
|
@ -115,6 +115,28 @@ mod remote_i2c {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn switch_select(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, address: u8, mask: u8) -> Result<u8, &'static str> {
|
||||
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cPca954xSelectRequest {
|
||||
destination: destination,
|
||||
busno: busno,
|
||||
address: address,
|
||||
mask: mask,
|
||||
});
|
||||
match reply {
|
||||
Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => {
|
||||
if succeeded { Ok(()) } else { Err("i2c basic reply error") }
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
Err("received unexpected aux packet")
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
@ -259,6 +281,11 @@ pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex,
|
||||
Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff })
|
||||
}
|
||||
}
|
||||
&kern::I2cSwitchSelectRequest { busno, address, mask } => {
|
||||
let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno,
|
||||
switch_select, address, mask).is_ok();
|
||||
kern_send(io, &kern::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
|
||||
&kern::SpiSetConfigRequest { busno, flags, length, div, cs } => {
|
||||
let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno,
|
||||
|
@ -269,6 +269,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::I2cSwitchSelectRequest { destination: _destination, busno, address, mask } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
||||
let succeeded = i2c::switch_select(busno, address, mask).is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
|
||||
drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno, flags, length, div, cs } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
||||
|
@ -30,7 +30,7 @@ def process_header(output, description):
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.core",
|
||||
"class": "Core",
|
||||
"arguments": {{"host": core_addr, "ref_period": {ref_period}, "target": "{cpu_target}"}},
|
||||
"arguments": {{"host": core_addr, "ref_period": {ref_period}, "target": "{cpu_target}"}},
|
||||
}},
|
||||
"core_log": {{
|
||||
"type": "controller",
|
||||
@ -52,13 +52,13 @@ def process_header(output, description):
|
||||
"i2c_switch0": {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548",
|
||||
"class": "I2CSwitch",
|
||||
"arguments": {{"address": 0xe0}}
|
||||
}},
|
||||
"i2c_switch1": {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548",
|
||||
"class": "I2CSwitch",
|
||||
"arguments": {{"address": 0xe2}}
|
||||
}},
|
||||
}}
|
||||
@ -102,8 +102,7 @@ class PeripheralManager:
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "{class_name}",
|
||||
"arguments": {{"channel": 0x{channel:06x}}},
|
||||
}}
|
||||
""",
|
||||
}}""",
|
||||
name=name[i],
|
||||
class_name=classes[i // 4],
|
||||
channel=rtio_offset + next(channel))
|
||||
@ -117,25 +116,64 @@ class PeripheralManager:
|
||||
"module": "artiq.coredevice.edge_counter",
|
||||
"class": "EdgeCounter",
|
||||
"arguments": {{"channel": 0x{channel:06x}}},
|
||||
}}
|
||||
""",
|
||||
}}""",
|
||||
name=name[i],
|
||||
channel=rtio_offset + next(channel))
|
||||
return next(channel)
|
||||
|
||||
def process_dio_spi(self, rtio_offset, peripheral):
|
||||
channel = count(0)
|
||||
for spi in peripheral["spi"]:
|
||||
self.gen("""
|
||||
device_db["{name}"] = {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
"arguments": {{"channel": 0x{channel:06x}}}
|
||||
}}""",
|
||||
name=self.get_name(spi.get("name", "dio_spi")),
|
||||
channel=rtio_offset + next(channel))
|
||||
for ttl in peripheral.get("ttl", []):
|
||||
ttl_class_names = {
|
||||
"input": "TTLInOut",
|
||||
"output": "TTLOut"
|
||||
}
|
||||
name = self.get_name(ttl.get("name", "ttl"))
|
||||
self.gen("""
|
||||
device_db["{name}"] = {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "{class_name}",
|
||||
"arguments": {{"channel": 0x{channel:06x}}},
|
||||
}}""",
|
||||
name=name,
|
||||
class_name=ttl_class_names[ttl["direction"]],
|
||||
channel=rtio_offset + next(channel))
|
||||
if ttl.get("edge_counter", False):
|
||||
self.gen("""
|
||||
device_db["{name}_counter"] = {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.edge_counter",
|
||||
"class": "EdgeCounter",
|
||||
"arguments": {{"channel": 0x{channel:06x}}},
|
||||
}}""",
|
||||
name=name,
|
||||
channel=rtio_offset + next(channel))
|
||||
return next(channel)
|
||||
|
||||
def process_urukul(self, rtio_offset, peripheral):
|
||||
urukul_name = self.get_name("urukul")
|
||||
synchronization = peripheral["synchronization"]
|
||||
channel = count(0)
|
||||
self.gen("""
|
||||
device_db["eeprom_{name}"]={{
|
||||
device_db["eeprom_{name}"] = {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.kasli_i2c",
|
||||
"class": "KasliEEPROM",
|
||||
"arguments": {{"port": "EEM{eem}"}}
|
||||
}}
|
||||
|
||||
device_db["spi_{name}"]={{
|
||||
device_db["spi_{name}"] = {{
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
|
@ -70,6 +70,65 @@ class DIO(_EEM):
|
||||
target.rtio_channels.append(rtio.Channel.from_phy(counter))
|
||||
|
||||
|
||||
class DIO_SPI(_EEM):
|
||||
@staticmethod
|
||||
def io(eem, spi, ttl, iostandard):
|
||||
def spi_subsignals(clk, mosi, miso, cs, pol):
|
||||
signals = [Subsignal("clk", Pins(_eem_pin(eem, clk, pol)))]
|
||||
if mosi is not None:
|
||||
signals.append(Subsignal("mosi",
|
||||
Pins(_eem_pin(eem, mosi, pol))))
|
||||
if miso is not None:
|
||||
signals.append(Subsignal("miso",
|
||||
Pins(_eem_pin(eem, miso, pol))))
|
||||
if cs:
|
||||
signals.append(Subsignal("cs_n", Pins(
|
||||
*(_eem_pin(eem, pin, pol) for pin in cs))))
|
||||
return signals
|
||||
|
||||
spi = [
|
||||
("dio{}_spi{}_{}".format(eem, i, pol), i,
|
||||
*spi_subsignals(clk, mosi, miso, cs, pol),
|
||||
iostandard(eem))
|
||||
for i, (clk, mosi, miso, cs) in enumerate(spi) for pol in "pn"
|
||||
]
|
||||
ttl = [
|
||||
("dio{}".format(eem), i,
|
||||
Subsignal("p", Pins(_eem_pin(eem, pin, "p"))),
|
||||
Subsignal("n", Pins(_eem_pin(eem, pin, "n"))),
|
||||
iostandard(eem))
|
||||
for i, (pin, _, _) in enumerate(ttl)
|
||||
]
|
||||
return spi + ttl
|
||||
|
||||
@classmethod
|
||||
def add_std(cls, target, eem, spi, ttl, iostandard=default_iostandard):
|
||||
cls.add_extension(target, eem, spi, ttl, iostandard=iostandard)
|
||||
|
||||
for i in range(len(spi)):
|
||||
phy = spi2.SPIMaster(
|
||||
target.platform.request("dio{}_spi{}_p".format(eem, i)),
|
||||
target.platform.request("dio{}_spi{}_n".format(eem, i))
|
||||
)
|
||||
target.submodules += phy
|
||||
target.rtio_channels.append(
|
||||
rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
||||
dci = iostandard(eem).name == "LVDS"
|
||||
for i, (_, ttl_cls, edge_counter_cls) in enumerate(ttl):
|
||||
pads = target.platform.request("dio{}".format(eem), i)
|
||||
phy = ttl_cls(pads.p, pads.n, dci=dci)
|
||||
target.submodules += phy
|
||||
target.rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||
|
||||
if edge_counter_cls is not None:
|
||||
state = getattr(phy, "input_state", None)
|
||||
if state is not None:
|
||||
counter = edge_counter_cls(state)
|
||||
target.submodules += counter
|
||||
target.rtio_channels.append(rtio.Channel.from_phy(counter))
|
||||
|
||||
|
||||
class Urukul(_EEM):
|
||||
@staticmethod
|
||||
def io(eem, eem_aux, iostandard):
|
||||
|
@ -19,6 +19,21 @@ def peripheral_dio(module, peripheral, **kwargs):
|
||||
edge_counter_cls=edge_counter_cls, **kwargs)
|
||||
|
||||
|
||||
def peripheral_dio_spi(module, peripheral, **kwargs):
|
||||
ttl_classes = {
|
||||
"input": ttl_serdes_7series.InOut_8X,
|
||||
"output": ttl_serdes_7series.Output_8X
|
||||
}
|
||||
if len(peripheral["ports"]) != 1:
|
||||
raise ValueError("peripheral dio_spi must be assigned one port")
|
||||
spi = [(s["clk"], s.get("mosi"), s.get("miso"), s.get("cs", []))
|
||||
for s in peripheral["spi"]]
|
||||
ttl = [(t["pin"], ttl_classes[t["direction"]],
|
||||
edge_counter.SimpleEdgeCounter if t.get("edge_counter") else None)
|
||||
for t in peripheral.get("ttl", [])]
|
||||
eem.DIO_SPI.add_std(module, peripheral["ports"][0], spi, ttl, **kwargs)
|
||||
|
||||
|
||||
def peripheral_urukul(module, peripheral, **kwargs):
|
||||
if len(peripheral["ports"]) == 1:
|
||||
port, port_aux = peripheral["ports"][0], None
|
||||
@ -112,6 +127,7 @@ def peripheral_hvamp(module, peripheral, **kwargs):
|
||||
|
||||
peripheral_processors = {
|
||||
"dio": peripheral_dio,
|
||||
"dio_spi": peripheral_dio_spi,
|
||||
"urukul": peripheral_urukul,
|
||||
"sampler": peripheral_sampler,
|
||||
"suservo": peripheral_suservo,
|
||||
|
@ -3,10 +3,10 @@ import os, unittest
|
||||
from artiq.experiment import *
|
||||
from artiq.test.hardware_testbench import ExperimentCase
|
||||
from artiq.coredevice.exceptions import I2CError
|
||||
from artiq.coredevice.i2c import PCA9548
|
||||
from artiq.coredevice.i2c import I2CSwitch
|
||||
|
||||
|
||||
class I2CSwitch(EnvExperiment):
|
||||
class I2CSwitchTest(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("i2c_switch")
|
||||
@ -25,7 +25,7 @@ class NonexistentI2CBus(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("i2c_switch") # HACK: only run this test on boards with I2C
|
||||
self.broken_switch = PCA9548(self._HasEnvironment__device_mgr, 255)
|
||||
self.broken_switch = I2CSwitch(self._HasEnvironment__device_mgr, 255)
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
@ -34,7 +34,7 @@ class NonexistentI2CBus(EnvExperiment):
|
||||
|
||||
class I2CTest(ExperimentCase):
|
||||
def test_i2c_switch(self):
|
||||
self.execute(I2CSwitch)
|
||||
self.execute(I2CSwitchTest)
|
||||
self.assertTrue(self.dataset_mgr.get("passed"))
|
||||
|
||||
def test_nonexistent_bus(self):
|
||||
|
Loading…
Reference in New Issue
Block a user