diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index b75de123c..d6ebeb7db 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -1,6 +1,6 @@ from artiq.language.core import * -from artiq.language.types import * -from artiq.coredevice.rt2wb import * +from artiq.language.units import MHz +from artiq.coredevice.rt2wb import rt2wb_write, rt2wb_read_sync SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3) @@ -26,56 +26,63 @@ class SPIMaster: """ def __init__(self, dmgr, ref_period, channel): self.core = dmgr.get("core") + self.ref_period = ref_period self.ref_period_mu = seconds_to_mu(ref_period, self.core) self.channel = channel - self.write_div = 0 - self.read_div = 0 - # a full transfer takes prep_mu + xfer_mu - self.prep_mu = 0 - # chained transfers can happen every xfer_mu - self.xfer_mu = 0 - # The second transfer of a chain be written ref_period_mu - # after the first. Read data is available every xfer_mu starting - # a bit before prep_mu + xfer_mu. - - @portable - def predict_xfer_mu(self, write_length, read_length): - # this is only the intrinsic bit cycle duration - return int(self.ref_period_mu*( - write_length*self.write_div + - read_length*self.read_div)) - - @portable - def predict_prep_mu(self, write_div): - return int(self.ref_period_mu*( - 2 + # intermediate transfers - # one write_div for the wait+idle cycle - self.write_div)) + self.write_period_mu = 0 + self.read_period_mu = 0 + self.xfer_period_mu = 0 + # A full transfer takes write_period_mu + xfer_period_mu. + # Chained transfers can happen every xfer_period_mu. + # The second transfer of a chain can be written 2*ref_period_mu + # after the first. Read data is available every xfer_period_mu starting + # a bit after xfer_period_mu (depending on clk_phase). + # To chain transfers together, new data must be written before + # pending transfer's read data becomes available. @kernel - def set_config(self, flags=0, write_div=6, read_div=6): - self.write_div = write_div - self.read_div = read_div - self.prep_mu = self.predict_prep_mu(write_div) + def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz): + write_div = round(1/(write_freq*self.ref_period)) + read_div = round(1/(read_freq*self.ref_period)) + self.set_config_mu(flags, write_div, read_div) + + @kernel + def set_config_mu(self, flags=0, write_div=6, read_div=6): rt2wb_write(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | - ((write_div - 2) << 8) | ((read_div - 2) << 20)) - delay_mu(self.ref_period_mu) + ((write_div - 2) << 16) | ((read_div - 2) << 24)) + self.write_period_mu = int(write_div*self.ref_period_mu) + self.read_period_mu = int(read_div*self.ref_period_mu) + delay_mu(2*self.ref_period_mu) + + @portable + def get_xfer_period_mu(self, write_length, read_length): + return int(write_length*self.write_period_mu + + read_length*self.read_period_mu) @kernel def set_xfer(self, chip_select=0, write_length=0, read_length=0): - self.xfer_mu = self.predict_xfer_mu(write_length, read_length) rt2wb_write(now_mu(), self.channel, SPI_XFER_ADDR, chip_select | (write_length << 16) | (read_length << 24)) - delay_mu(self.ref_period_mu) + self.xfer_period_mu = self.get_xfer_period_mu( + write_length, read_length) + delay_mu(int(2*self.ref_period_mu)) @kernel def write(self, data): rt2wb_write(now_mu(), self.channel, SPI_DATA_ADDR, data) - delay_mu(int(self.prep_mu + self.xfer_mu)) + delay_mu(int(self.write_period_mu + self.xfer_period_mu)) + + @kernel + def read_async(self): + rt2wb_write(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0) + delay_mu(int(2*self.ref_period_mu)) @kernel def read_sync(self): - r = rt2wb_read_sync(now_mu(), self.channel, SPI_DATA_ADDR | - SPI_RT2WB_READ, int(self.ref_period_mu)) - delay_mu(self.ref_period_mu) - return r + return rt2wb_read_sync(now_mu(), self.channel, SPI_DATA_ADDR | + SPI_RT2WB_READ, int(2*self.ref_period_mu)) + + @kernel + def get_config_sync(self): + return rt2wb_read_sync(now_mu(), self.channel, SPI_CONFIG_ADDR | + SPI_RT2WB_READ, int(2*self.ref_period_mu))