2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-25 03:08:27 +08:00

DDS over RTIO (batch mode not supported yet)

This commit is contained in:
Sebastien Bourdeauducq 2015-05-08 14:44:39 +08:00
parent a91bb48ced
commit a36c51eb83
17 changed files with 201 additions and 271 deletions

View File

@ -1,10 +1,10 @@
from artiq.language.core import *
from artiq.language.db import *
from artiq.language.units import *
from artiq.coredevice import ttl
PHASE_MODE_DEFAULT = -1
# keep in sync with dds.h
PHASE_MODE_CONTINUOUS = 0
PHASE_MODE_ABSOLUTE = 1
PHASE_MODE_TRACKING = 2
@ -13,34 +13,24 @@ PHASE_MODE_TRACKING = 2
class DDS(AutoDB):
"""Core device Direct Digital Synthesis (DDS) driver.
Controls DDS devices managed directly by the core device's runtime. It also
uses a RTIO TTL channel (through :class:`artiq.coredevice.ttl.TTLOut`) to
control a RF switch that gates the output of the DDS device.
Controls DDS devices managed directly by the core device's runtime.
:param dds_sysclk: DDS system frequency, used for computing the frequency
tuning words.
:param reg_channel: channel number of the DDS device to control.
:param rtio_switch: RTIO channel number of the RF switch associated with
the DDS device.
:param channel: channel number of the DDS device to control.
"""
class DBKeys:
core = Device()
dds_sysclk = Parameter(1*GHz)
reg_channel = Argument()
rtio_switch = Argument()
dds_sysclk = Argument(1*GHz)
channel = Argument()
def build(self):
self.previous_on = False
self.previous_frequency = 0*MHz
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
self.sw = ttl.TTLOut(core=self.core, channel=self.rtio_switch)
self.phase_mode = PHASE_MODE_CONTINUOUS
@portable
def frequency_to_ftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given
frequency.
"""
return round(2**32*frequency/self.dds_sysclk)
@ -48,10 +38,14 @@ class DDS(AutoDB):
def ftw_to_frequency(self, ftw):
"""Returns the frequency corresponding to the given frequency tuning
word.
"""
return ftw*self.dds_sysclk/2**32
@kernel
def init(self):
"""Resets and initializes the DDS."""
syscall("dds_init", time_to_cycles(now()), self.channel)
@kernel
def set_phase_mode(self, phase_mode):
"""Sets the phase mode of the DDS channel. Supported phase modes are:
@ -69,74 +63,21 @@ class DDS(AutoDB):
accumulator is set to the value it would have if the DDS had been
running at the specified frequency since the start of the
experiment.
"""
self.phase_mode = phase_mode
syscall("dds_phase_clear_en", self.reg_channel,
self.phase_mode != PHASE_MODE_CONTINUOUS)
@kernel
def on(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
"""Sets the DDS channel to the specified frequency and turns it on.
If the DDS channel was already on, a real-time frequency and phase
update is performed.
def set(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
"""Sets the DDS channel to the specified frequency and phase.
:param frequency: frequency to generate.
:param phase_mode: if specified, overrides the default phase mode set
by ``set_phase_mode`` for this call.
:param phase_offset: adds an offset, in turns, to the phase.
"""
if phase_mode != PHASE_MODE_DEFAULT:
old_phase_mode = self.phase_mode
self.set_phase_mode(phase_mode)
if phase_mode == PHASE_MODE_DEFAULT:
phase_mode = self.phase_mode
if self.previous_frequency != frequency:
merge = self.sw.o_previous_timestamp == time_to_cycles(now())
if not merge:
self.sw.sync()
# Channel is already on:
# Precise timing of frequency change is required.
# Channel is off:
# Use soft timing on FUD to prevent conflicts when reprogramming
# several channels that need to be turned on at the same time.
rt_fud = merge or self.previous_on
if self.phase_mode != PHASE_MODE_CONTINUOUS:
sysclk_per_microcycle = int(self.dds_sysclk*
self.core.ref_period)
else:
sysclk_per_microcycle = 0
syscall("dds_program", time_to_cycles(now()), self.reg_channel,
self.frequency_to_ftw(frequency), int(phase_offset*2**14),
sysclk_per_microcycle,
rt_fud, self.phase_mode == PHASE_MODE_TRACKING)
self.previous_frequency = frequency
self.sw.on()
self.previous_on = True
if phase_mode != PHASE_MODE_DEFAULT:
self.set_phase_mode(old_phase_mode)
@kernel
def off(self):
"""Turns the DDS channel off.
"""
self.sw.off()
self.previous_on = False
@kernel
def pulse(self, frequency, duration,
phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
"""Pulses the DDS channel for the specified duration at the specified
frequency.
See ``on`` for a description of the parameters.
Equivalent to a ``on``, ``delay``, ``off`` sequence.
"""
self.on(frequency, phase_mode, phase_offset)
delay(duration)
self.off()
syscall("dds_set", time_to_cycles(now()), self.channel,
self.frequency_to_ftw(frequency), round(phase_offset*2**14),
self.phase_mode)

View File

@ -21,8 +21,8 @@ _syscalls = {
"rtio_set_sensitivity": "Iii:n",
"rtio_get_counter": "n:I",
"rtio_get": "iI:I",
"dds_phase_clear_en": "ib:n",
"dds_program": "Iiiiibb:n",
"dds_init": "Ii:n",
"dds_set": "Iiiii:n",
}

View File

@ -36,8 +36,8 @@ class AD9858(Module):
Read timing:
Address is set one cycle before assertion of rd_n.
rd_n is asserted for 3 cycles.
Data is sampled 2 cycles into the assertion of rd_n.
rd_n is asserted for read_wait_cycles, data is sampled at the end.
rd_n is deasserted and data bus is not driven again before hiz_wait_cycles.
Design:
All IO pads are registered.
@ -48,7 +48,7 @@ class AD9858(Module):
Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D
valid), D prop is ~15 + 10 + 20 + 10 = 55ns
"""
def __init__(self, pads, drive_fud=False,
def __init__(self, pads,
read_wait_cycles=10, hiz_wait_cycles=3,
bus=None):
if bus is None:
@ -84,9 +84,8 @@ class AD9858(Module):
bus.dat_r.eq(dr)
)
if drive_fud:
fud = Signal()
self.sync += pads.fud_n.eq(~fud)
fud = Signal()
self.sync += pads.fud_n.eq(~fud)
pads.wr_n.reset = 1
pads.rd_n.reset = 1
@ -106,7 +105,7 @@ class AD9858(Module):
If(bus.adr[0],
NextState("GPIO")
).Else(
NextState("FUD") if drive_fud else None
NextState("FUD")
)
).Else(
If(bus.we,
@ -141,19 +140,18 @@ class AD9858(Module):
)
fsm.act("WAIT_HIZ",
rx.eq(1),
# For some reason, AD9858 has a address hold time to RD inactive.
# For some reason, AD9858 has an address hold time to RD inactive.
hold_address.eq(1),
self.hiz_timer.wait.eq(1),
If(self.hiz_timer.done, NextState("IDLE"))
)
if drive_fud:
fsm.act("FUD",
# 4ns FUD setup to SYNCLK
# 0ns FUD hold to SYNCLK
fud.eq(1),
bus.ack.eq(1),
NextState("IDLE")
)
fsm.act("FUD",
# 4ns FUD setup to SYNCLK
# 0ns FUD hold to SYNCLK
fud.eq(1),
bus.ack.eq(1),
NextState("IDLE")
)
fsm.act("GPIO",
bus.ack.eq(1),
bus_r_gpio.eq(1),

View File

@ -291,6 +291,10 @@ class RTIO(Module):
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
for c in channels)
self.data_width = data_width
self.address_width = address_width
self.fine_ts_width = fine_ts_width
# CSRs
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
data_width, address_width,

View File

@ -1,10 +1,14 @@
from migen.fhdl.std import *
from migen.bus import wishbone
from artiq.gateware.rtio import rtlink
class RT2WB(Module):
def __init__(self, wb, address_width):
def __init__(self, address_width, wb=None):
if wb is None:
wb = wishbone.Interface()
self.wb = wb
self.rtlink = rtlink.Interface(
rtlink.OInterface(
flen(wb.dat_w),
@ -18,7 +22,7 @@ class RT2WB(Module):
# # #
active = Signal()
self.sync.rio_phy += [
self.sync.rio += [
If(self.rtlink.o.stb,
active.eq(1),
wb.adr.eq(self.rtlink.o.address[:address_width]),
@ -35,6 +39,6 @@ class RT2WB(Module):
wb.cyc.eq(active),
wb.stb.eq(active),
self.i.stb.eq(wb.ack & ~wb.we),
self.i.data.eq(wb.dat_r)
self.rtlink.i.stb.eq(wb.ack & ~wb.we),
self.rtlink.i.data.eq(wb.dat_r)
]

View File

@ -54,19 +54,19 @@
"type": "local",
"module": "artiq.coredevice.dds",
"class": "DDS",
"arguments": {"reg_channel": 0, "rtio_switch": 5}
"arguments": {"channel": 0}
},
"dds1": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "DDS",
"arguments": {"reg_channel": 1, "rtio_switch": 6}
"arguments": {"channel": 1}
},
"dds2": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "DDS",
"arguments": {"reg_channel": 2, "rtio_switch": 7}
"arguments": {"channel": 2}
},
"qc_q1_0": {

View File

@ -9,10 +9,17 @@ class DDSTest(Experiment, AutoDB):
dds0 = Device()
dds1 = Device()
dds2 = Device()
ttl0 = Device()
ttl1 = Device()
ttl2 = Device()
led = Device()
@kernel
def run(self):
# with dds_batch:
# self.dds1.set(120*MHz)
# self.dds2.set(200*MHz)
for i in range(10000):
if i & 0x200:
self.led.on()
@ -20,7 +27,8 @@ class DDSTest(Experiment, AutoDB):
self.led.off()
with parallel:
with sequential:
self.dds0.pulse(100*MHz + 4*i*kHz, 500*us)
self.dds1.pulse(120*MHz, 500*us)
self.dds2.pulse(200*MHz, 100*us)
self.dds0.set(100*MHz + 4*i*kHz)
self.ttl0.pulse(500*us)
self.ttl1.pulse(500*us)
self.ttl2.pulse(100*us)
self.led.off()

View File

@ -34,7 +34,9 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
-T ksupport.ld \
-N -o $@ \
$(MSCDIR)/software/libbase/crt0-$(CPU).o \
$^
$^ \
-L$(MSCDIR)/software/libcompiler-rt \
-lcompiler-rt
@chmod -x $@
ksupport_data.o: ksupport.bin

View File

@ -4,6 +4,26 @@
#include "dds.h"
#include "bridge.h"
static void dds_write(int addr, int data)
{
rtio_chan_sel_write(RTIO_DDS_CHANNEL);
rtio_o_address_write(addr);
rtio_o_data_write(data);
rtio_o_timestamp_write(rtio_get_counter() + 8000);
rtio_o_we_write(1);
}
static int dds_read(int addr)
{
int r;
dds_write(addr | 128, 0);
while(rtio_i_status_read() & RTIO_I_STATUS_EMPTY);
r = rtio_i_data_read();
rtio_i_re_write(1);
return r;
}
static void send_ready(void)
{
struct msg_base msg;
@ -41,16 +61,16 @@ void bridge_main(void)
struct msg_brg_dds_sel *msg;
msg = (struct msg_brg_dds_sel *)umsg;
DDS_WRITE(DDS_GPIO, msg->channel);
dds_write(DDS_GPIO, msg->channel);
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_BRG_DDS_RESET: {
unsigned int g;
g = DDS_READ(DDS_GPIO);
DDS_WRITE(DDS_GPIO, g | (1 << 7));
DDS_WRITE(DDS_GPIO, g);
g = dds_read(DDS_GPIO);
dds_write(DDS_GPIO, g | (1 << 7));
dds_write(DDS_GPIO, g);
mailbox_acknowledge();
break;
@ -61,7 +81,7 @@ void bridge_main(void)
msg = (struct msg_brg_dds_read_request *)umsg;
rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY;
rmsg.data = DDS_READ(msg->address);
rmsg.data = dds_read(msg->address);
mailbox_send_and_wait(&rmsg);
break;
}
@ -69,12 +89,12 @@ void bridge_main(void)
struct msg_brg_dds_write *msg;
msg = (struct msg_brg_dds_write *)umsg;
DDS_WRITE(msg->address, msg->data);
dds_write(msg->address, msg->data);
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_BRG_DDS_FUD:
rtio_fud(rtio_get_counter() + 8000);
dds_write(DDS_FUD, 0);
mailbox_acknowledge();
break;
default:

View File

@ -4,64 +4,66 @@
#include "rtio.h"
#include "dds.h"
void dds_init(void)
{
int i;
#define DURATION_WRITE 5
#define DURATION_PROGRAM (8*DURATION_WRITE)
for(i=0;i<8;i++) {
DDS_WRITE(DDS_GPIO, i);
DDS_WRITE(DDS_GPIO, i | (1 << 7));
DDS_WRITE(DDS_GPIO, i);
dds_phase_clear_en(i, 0);
}
}
#define DDS_WRITE(addr, data) do { \
rtio_o_address_write(addr); \
rtio_o_data_write(data); \
rtio_o_timestamp_write(now); \
rtio_write_and_process_status(now, RTIO_DDS_CHANNEL); \
now += DURATION_WRITE; \
} while(0)
void dds_phase_clear_en(int channel, int phase_clear_en)
void dds_init(long long int timestamp, int channel)
{
long long int now;
rtio_chan_sel_write(RTIO_DDS_CHANNEL);
now = timestamp - 7*DURATION_WRITE;
DDS_WRITE(DDS_GPIO, channel);
DDS_WRITE(DDS_GPIO, channel | (1 << 7));
DDS_WRITE(DDS_GPIO, channel);
DDS_WRITE(0x00, 0x78);
DDS_WRITE(0x01, 0x00);
DDS_WRITE(0x02, phase_clear_en ? 0x40 : 0x00);
DDS_WRITE(0x02, 0x00);
DDS_WRITE(0x03, 0x00);
}
/*
* DDS phase modes:
* - continuous: Set sysclk_per_microcycle=0 to disable POW alteration.
* phase_tracking is ignored, set to 0.
* Disable phase accumulator clearing prior to programming.
* - absolute: Set sysclk_per_microcycle to its nominal value
* and phase_tracking=0.
* Enable phase accumulator clearing prior to programming.
* - tracking: Set sysclk_per_microcycle to its nominal value
* and phase_tracking=1.
* Enable phase accumulator clearing prior to programming.
*/
void dds_program(long long int timestamp, int channel,
unsigned int ftw, unsigned int pow, unsigned int sysclk_per_microcycle,
int rt_fud, int phase_tracking)
static void dds_set_one(long long int now, long long int timestamp, int channel,
unsigned int ftw, unsigned int pow, int phase_mode)
{
long long int fud_time;
unsigned int phase_time_offset;
rtio_fud_sync();
DDS_WRITE(DDS_GPIO, channel);
if(phase_mode == PHASE_MODE_CONTINUOUS)
/* Do not clear phase accumulator on FUD */
DDS_WRITE(0x02, 0x00);
else
/* Clear phase accumulator on FUD */
DDS_WRITE(0x02, 0x40);
DDS_WRITE(DDS_FTW0, ftw & 0xff);
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
phase_time_offset = phase_tracking ? timestamp : 0;
if(rt_fud)
fud_time = timestamp;
else {
fud_time = rtio_get_counter() + 8000;
/* POW is mod 2**14, so wraparound on negative values is OK */
phase_time_offset -= timestamp - fud_time;
}
pow += phase_time_offset*ftw*sysclk_per_microcycle >> 18;
if(phase_mode == PHASE_MODE_TRACKING)
/* We assume that the RTIO clock is DDS SYNCLK */
pow += (timestamp >> RTIO_FINE_TS_WIDTH)*ftw >> 18;
DDS_WRITE(DDS_POW0, pow & 0xff);
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
rtio_fud(fud_time);
}
void dds_set(long long int timestamp, int channel,
unsigned int ftw, unsigned int pow, int phase_mode)
{
long long int now;
rtio_chan_sel_write(RTIO_DDS_CHANNEL);
dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode);
now = timestamp;
DDS_WRITE(DDS_FUD, 0);
}

View File

@ -4,24 +4,23 @@
#include <hw/common.h>
#include <generated/mem.h>
#define DDS_READ(addr) \
MMPTR(DDS_BASE + (addr)*4)
#define DDS_WRITE(addr, data) \
MMPTR(DDS_BASE + (addr)*4) = data
#define DDS_FTW0 0x0a
#define DDS_FTW1 0x0b
#define DDS_FTW2 0x0c
#define DDS_FTW3 0x0d
#define DDS_POW0 0x0e
#define DDS_POW1 0x0f
#define DDS_FUD 0x40
#define DDS_GPIO 0x41
void dds_init(void);
void dds_phase_clear_en(int channel, int phase_clear_en);
void dds_program(long long int timestamp, int channel,
unsigned int ftw, unsigned int pow, unsigned int sysclk_per_microcycle,
int rt_fud, int phase_tracking);
enum {
PHASE_MODE_CONTINUOUS = 0,
PHASE_MODE_ABSOLUTE = 1,
PHASE_MODE_TRACKING = 2
};
void dds_init(long long int timestamp, int channel);
void dds_set(long long int timestamp, int channel,
unsigned int ftw, unsigned int pow, int phase_mode);
#endif /* __DDS_H */

View File

@ -17,8 +17,8 @@ services = [
("rtio_set_sensitivity", "rtio_set_sensitivity"),
("rtio_get_counter", "rtio_get_counter"),
("rtio_get", "rtio_get"),
("dds_phase_clear_en", "dds_phase_clear_en"),
("dds_program", "dds_program"),
("dds_init", "dds_init"),
("dds_set", "dds_set"),
]),
("eh", [
("setjmp", "exception_setjmp"),

View File

@ -78,7 +78,6 @@ long long int now_init(void)
mailbox_acknowledge();
if(now < 0) {
dds_init();
rtio_init();
now = 125000;
}

View File

@ -3,42 +3,17 @@
#include "exceptions.h"
#include "rtio.h"
#define RTIO_O_STATUS_FULL 1
#define RTIO_O_STATUS_UNDERFLOW 2
#define RTIO_O_STATUS_SEQUENCE_ERROR 4
#define RTIO_I_STATUS_EMPTY 1
#define RTIO_I_STATUS_OVERFLOW 2
long long int previous_fud_end_time;
void rtio_init(void)
{
previous_fud_end_time = 0;
rtio_reset_write(1);
rtio_reset_write(0);
rtio_reset_phy_write(0);
}
static void write_and_process_status(long long int timestamp, int channel)
long long int rtio_get_counter(void)
{
int status;
rtio_o_we_write(1);
status = rtio_o_status_read();
if(status) {
if(status & RTIO_O_STATUS_FULL)
while(rtio_o_status_read() & RTIO_O_STATUS_FULL);
if(status & RTIO_O_STATUS_UNDERFLOW) {
rtio_o_underflow_reset_write(1);
exception_raise_params(EID_RTIO_UNDERFLOW,
timestamp, channel, rtio_get_counter());
}
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
rtio_o_sequence_error_reset_write(1);
exception_raise_params(EID_RTIO_SEQUENCE_ERROR,
timestamp, channel, 0);
}
}
rtio_counter_update_write(1);
return rtio_counter_read();
}
void rtio_set_o(long long int timestamp, int channel, int value)
@ -47,7 +22,7 @@ void rtio_set_o(long long int timestamp, int channel, int value)
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(0);
rtio_o_data_write(value);
write_and_process_status(timestamp, channel);
rtio_write_and_process_status(timestamp, channel);
}
void rtio_set_oe(long long int timestamp, int channel, int oe)
@ -56,7 +31,7 @@ void rtio_set_oe(long long int timestamp, int channel, int oe)
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(1);
rtio_o_data_write(oe);
write_and_process_status(timestamp, channel);
rtio_write_and_process_status(timestamp, channel);
}
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity)
@ -65,13 +40,7 @@ void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity)
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(2);
rtio_o_data_write(sensitivity);
write_and_process_status(timestamp, channel);
}
long long int rtio_get_counter(void)
{
rtio_counter_update_write(1);
return rtio_counter_read();
rtio_write_and_process_status(timestamp, channel);
}
long long int rtio_get(int channel, long long int time_limit)
@ -99,39 +68,3 @@ long long int rtio_get(int channel, long long int time_limit)
rtio_i_re_write(1);
return r;
}
void rtio_fud_sync(void)
{
while(rtio_get_counter() < previous_fud_end_time);
}
void rtio_fud(long long int fud_time)
{
long long int fud_end_time;
int status;
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
rtio_o_address_write(0);
fud_end_time = fud_time + 3*8;
previous_fud_end_time = fud_end_time;
rtio_o_timestamp_write(fud_time);
rtio_o_data_write(1);
rtio_o_we_write(1);
rtio_o_timestamp_write(fud_end_time);
rtio_o_data_write(0);
rtio_o_we_write(1);
status = rtio_o_status_read();
if(status) {
if(status & RTIO_O_STATUS_UNDERFLOW) {
rtio_o_underflow_reset_write(1);
exception_raise_params(EID_RTIO_UNDERFLOW,
fud_time, RTIO_FUD_CHANNEL, rtio_get_counter());
}
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
rtio_o_sequence_error_reset_write(1);
exception_raise_params(EID_RTIO_SEQUENCE_ERROR,
fud_time, RTIO_FUD_CHANNEL, 0);
}
}
}

View File

@ -1,14 +1,43 @@
#ifndef __RTIO_H
#define __RTIO_H
#include <generated/csr.h>
#include "exceptions.h"
#define RTIO_O_STATUS_FULL 1
#define RTIO_O_STATUS_UNDERFLOW 2
#define RTIO_O_STATUS_SEQUENCE_ERROR 4
#define RTIO_I_STATUS_EMPTY 1
#define RTIO_I_STATUS_OVERFLOW 2
void rtio_init(void);
long long int rtio_get_counter(void);
static inline void rtio_write_and_process_status(long long int timestamp, int channel)
{
int status;
rtio_o_we_write(1);
status = rtio_o_status_read();
if(status) {
if(status & RTIO_O_STATUS_FULL)
while(rtio_o_status_read() & RTIO_O_STATUS_FULL);
if(status & RTIO_O_STATUS_UNDERFLOW) {
rtio_o_underflow_reset_write(1);
exception_raise_params(EID_RTIO_UNDERFLOW,
timestamp, channel, rtio_get_counter());
}
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
rtio_o_sequence_error_reset_write(1);
exception_raise_params(EID_RTIO_SEQUENCE_ERROR,
timestamp, channel, 0);
}
}
}
void rtio_set_o(long long int timestamp, int channel, int value);
void rtio_set_oe(long long int timestamp, int channel, int oe);
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity);
long long int rtio_get_counter(void);
long long int rtio_get(int channel, long long int time_limit);
void rtio_fud_sync(void);
void rtio_fud(long long int fud_time);
#endif /* __RTIO_H */

View File

@ -11,6 +11,7 @@ from targets.kc705 import MiniSoC
from artiq.gateware.soc import AMPSoC
from artiq.gateware import rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
from artiq.gateware.rtio.phy.wishbone import RT2WB
class _RTIOCRG(Module, AutoCSR):
@ -40,7 +41,6 @@ class NIST_QC1(MiniSoC, AMPSoC):
csr_map.update(MiniSoC.csr_map)
mem_map = {
"rtio": 0x20000000, # (shadow @0xa0000000)
"dds": 0x50000000, # (shadow @0xd0000000)
"mailbox": 0x70000000 # (shadow @0xf0000000)
}
mem_map.update(MiniSoC.mem_map)
@ -75,20 +75,20 @@ class NIST_QC1(MiniSoC, AMPSoC):
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
fud = Signal()
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
phy = ttl_simple.Output(fud)
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
self.submodules.dds = RenameClockDomains(
ad9858.AD9858(platform.request("dds")),
"rio")
phy = RT2WB(7, self.dds.bus)
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
# RTIO core
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
self.submodules.rtio = rtio.RTIO(rtio_channels,
clk_freq=125000000)
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads)
self.comb += dds_pads.fud_n.eq(~fud)
if isinstance(platform.toolchain, XilinxVivadoToolchain):
platform.add_platform_command("""
@ -106,9 +106,5 @@ set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk]
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
rtio_csrs)
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]),
self.dds.bus)
self.add_memory_region("dds", self.mem_map["dds"] | 0x80000000, 64*4)
default_subtarget = NIST_QC1

View File

@ -9,6 +9,7 @@ from targets.pipistrello import BaseSoC
from artiq.gateware.soc import AMPSoC
from artiq.gateware import rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
from artiq.gateware.rtio.phy.wishbone import RT2WB
class _RTIOCRG(Module, AutoCSR):
@ -61,7 +62,6 @@ class NIST_QC1(BaseSoC, AMPSoC):
csr_map.update(BaseSoC.csr_map)
mem_map = {
"rtio": 0x20000000, # (shadow @0xa0000000)
"dds": 0x50000000, # (shadow @0xd0000000)
"mailbox": 0x70000000 # (shadow @0xf0000000)
}
mem_map.update(BaseSoC.mem_map)
@ -110,20 +110,19 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
fud = Signal()
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
phy = ttl_simple.Output(fud)
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
self.submodules.dds = RenameClockDomains(
ad9858.AD9858(platform.request("dds")),
"rio")
phy = RT2WB(7, self.dds.bus)
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
# RTIO core
self.submodules.rtiocrg = _RTIOCRG(platform)
self.submodules.rtio = rtio.RTIO(rtio_channels,
clk_freq=125000000)
dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads)
self.comb += dds_pads.fud_n.eq(~fud)
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
# CPU connections
rtio_csrs = self.rtio.get_csrs()
@ -133,9 +132,5 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
rtio_csrs)
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]),
self.dds.bus)
self.add_memory_region("dds", self.mem_map["dds"] | 0x80000000, 64*4)
default_subtarget = NIST_QC1