Skip to content

Commit 4525138

Browse files
authored
Merge pull request #96 from tknopp/dac-rework
16-bit DAC rework and FIR bypass
2 parents 61e5758 + aeb69d9 commit 4525138

31 files changed

+1082
-476
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Changelog
2+
3+
## 0.11.0
4+
5+
### Breaking Changes
6+
- **Breaking**: Updated ADC and DAC pipeline requires a new ADC and DAC calibration after the update!
7+
- **Breaking**: When not using the ADC calibration the integer values will now be in the range of [-32768, 32767] instead of [-8192, 8191]
8+
9+
### Updated ADC Pipeline
10+
- The decimating pipeline after the ADC now uses the full 16-bit accuracy decreasing the quantization noise which becomes dominant over the ADC noise at high decimations (>256)
11+
- The FIR filter added in v0.6.0 can now be switched on and off using `firEnabled!`. For all standard applications the filter should be left on for improved anti-aliasing and flatter frequency response. The filter can be turned off for applications where the delay introduced by the filter is unwanted, e.g. time-based multiplexing
12+
13+
### Updated DAC Pipeline
14+
- increased amplitude resolution of waveform signal components to 16-bit, decreasing the discretization of the sine amplitude from 122 µV to 15 µV
15+
- increase resolution of DAC pipeline to 16-bit until the final output quantization for improved accuracy when combining different components
16+
- prevent potential overflow in DAC pipeline when adding multiple components
17+
- reintroduced signal limiter, which was mistakenly removed in a previous release
18+
- removed hard limit of 1 V from amplitude components, as the DAC might be able to produce higher amplitudes depending on the calibration
19+
20+
### General Updates
21+
- extended instant reset to ramp down the outputs if ramping is enabled instead of cutting
22+
- (re)added SCPI interface to enable instant reset
23+
- added 3-bit counter output with configurable counter speed outputting on DIO2_N (LSB) to DIO4_N (MSB)
24+
- Improved passing of error messages from SCPI server to the Julia client, SCPI errors still do not throw, but additional info is output as log messages
25+
- added `calibReset!(rp)` to reset ADC and DAC calibration to default
26+
- added `serverversion(rp)` to query the version of the server running of the RedPitaya
27+
- improved `imgversion` to not error on server versions prior to the introduction
28+
- added two examples on FIR switching
29+
- deprecated `enableRampDown!` and `enableRampDown` due to misleading names and functionality. Use `startRampDown!(rp, channel)` in the future to start a ramp down. It is not and was never possible to stop a triggered ramp down contrary to what the existence of `enableRampDown!(rp, channel, false)` might suggest.
30+
31+

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ all: linux
6363
daq_bitfiles: $(addsuffix .bit, $(addprefix bitfiles/daq_,$(DAQ_PARTS)))
6464

6565
bitfiles/daq_%.bit: daq_cores
66-
ifeq ("$(wildcard bitfiles/daq_$*.bit)","")
66+
ifneq ("$(wildcard bitfiles/daq_$*.bit)","")
6767
vivado -nolog -nojournal -mode batch -source src/fpga/build.tcl -tclargs $*
6868
vivado -nolog -nojournal -mode batch -source scripts/runSynthAndImpl.tcl -tclargs $*
6969
mkdir -p bitfiles

docs/src/connections.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ The project uses most but not all connections that are used in the original RedP
1212
* `DIO4_P` outputs a high for 10 ms after a 100 ms pause on low to provide an alive signal.
1313
* `DIO5_P` can be set to high via the configuration register to provide the mutual trigger signal.
1414
* `DIO7_P`, `DIO7_N`, `DIO6_P`, `DIO6_N`, `DIO5_N`, `DIO4_N`, `DIO3_N`, `DIO2_N` can be used as arbitrary outputs set via the server.
15+
* `DIO2_N` (LSB) to `DIO4_N` (MSB) can output a 3-bit counter configurable by `counterSamplesPerStep!` (deactivate with 0)
1516
* `DIO0_N` and `DIO1_N` are used for the clock selection in a cluster.
17+

docs/src/generation.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# Signal Generation
2-
Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 16-bit DAC channel and four of those are digital pins using PDM, see [Connections](connections.md). The output signals are composed of three parts: parameterized waveforms ``W_i(t)``, an offset ``o_i`` and repeating arbitrary LUT tables. The latter are called sequences ``seq_i(t)``. The resulting signal of the DAC channel can be described as:
2+
Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 14-bit DAC channel and four of those are digital pins using PDM, see [Connections](connections.md). The output signals are composed of three parts: parameterized waveforms ``W_i(t)``, an offset ``o_i`` and repeating arbitrary LUT tables. The latter are called sequences ``seq_i(t)``. The resulting signal of the DAC channel can be described as:
33

44
```math
55
S_i(t) = seq_i(t) + o_i + W_i(t)
66
```
77
## Waveforms
8-
Each of the 16-bit DAC channel can output a compositve waveform with four components. Each component can be parametrized by its amplitude ``a_{i,j}``, frequency ``f_{i,j}`` and phase ``\varphi_{i,j}``, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms ``w_{i,j}``(sine, triangle, sawtooth):
8+
Each of the 14-bit DAC channels can output a compositve waveform with three components. Each component can be parametrized by its amplitude ``a_{i,j}``, frequency ``f_{i,j}`` and phase ``\varphi_{i,j}``, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms ``w_{i,j}``(sine, triangle, sawtooth):
99
```math
10-
W_i(t) = \sum_{j=1}^{4}a_{i,j} w_{i,j}(2\pi f_{i,j}t + \varphi_{i, j})
10+
W_i(t) = \sum_{j=1}^{3}a_{i,j} w_{i,j}(2\pi f_{i,j}t + \varphi_{i, j})
1111
```
12+
13+
Additionally there is a fourth waveform which can be user-configured to an arbitrary waveform. The arbitrary waveform is defined by a 16384 sample buffer representing a single period, which is then also parameterized using a frequency and phase. Note, that the amplitude of the waveform has to be adjusted by updating the buffer.
1214
## Ramping
1315
The signals output on the DAC channel can also be multiplied with an increasing/decreasing ramping factor ``r(t)``. Ramping and the ramping duration can be enabled and set on a per channel basis. The increasing factor starts from 0 and goes to 1 from the acquisition start on. The decreasing factor goes from 1 to 0.
1416

docs/src/scpi.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ During an active trigger the buffer is periodically updated by the server. If th
8989
|RP:CALib:DAC:CHannel#:OFFset? | channel (0, 1) | Return the DAC offset value for given channel from EEPROM | Any | RP:CAL:DAC:CH1:OFF? |
9090
|RP:CALib:DAC:CHannel#:SCAle | channel (0, 1), scale| Store the DAC scale value for given channel in EEPROM | C | RP:CAL:DAC:CH1:SCA 1.0 |
9191
|RP:CALib:DAC:CHannel#:SCAle? | channel (0, 1) | Return the DAC scale value for given channel from EEPROM | Any | RP:CAL:DAC:CH1:SCA? |
92-
92+
|RP:CALib:DAC:CHannel#:LIMit:UPper | channel (0, 1), upper limit| Store the DAC upper limit value (in V) for given channel in EEPROM | C | RP:CAL:DAC:CH1:LIM:UP 1.0 |
93+
|RP:CALib:DAC:CHannel#:LIMit:UPper? | channel (0, 1) | Return the DAC upper limit value (in V) for given channel from EEPROM | Any | RP:CAL:DAC:CH1:LIM:UP? |
94+
|RP:CALib:DAC:CHannel#:LIMit:LOWer | channel (0, 1), lower limit| Store the DAC lower limit value (in V) for given channel in EEPROM | C | RP:CAL:DAC:CH1:LIM:LOW -1.0 |
95+
|RP:CALib:DAC:CHannel#:LIMit:LOWer? | channel (0, 1) | Return the DAC lower limit value (in V) for given channel from EEPROM | Any | RP:CAL:DAC:CH1:LIM:LOW? |
96+
|RP:CALib:RESet | | Reset all EEPROM calibration values to their default | C | RP:CAL:RES |
9397
## DIO
9498

9599
| Command | Arguments | Description | Example |

src/client/julia/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "RedPitayaDAQServer"
22
uuid = "c544963a-496b-56d4-a5fe-f99a3f174c8f"
33
authors = ["Tobias Knopp <tobias@knoppweb.de>"]
4-
version = "0.10.0"
4+
version = "0.11.0"
55

66
[deps]
77
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/client/julia/src/ADC.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export TriggerMode, INTERNAL, EXTERNAL, ADCPerformanceData, RPStatus, Performanc
22
decimation, decimation!, numChan, samplesPerPeriod, samplesPerPeriod!, periodsPerFrame, periodsPerFrame!,
33
currentWP, currentPeriod, currentFrame, masterTrigger, masterTrigger!, keepAliveReset, keepAliveReset!,
44
triggerMode, triggerMode!, overwritten, corrupted, serverStatus, performanceData,
5-
readSamples, startPipelinedData, stopTransmission, triggerPropagation, triggerPropagation!
5+
readSamples, startPipelinedData, stopTransmission, triggerPropagation, triggerPropagation!, firEnabled, firEnabled!
66

77
"""
88
TriggerMode
@@ -280,6 +280,29 @@ scpiCommand(::typeof(keepAliveReset)) = "RP:TRIGger?"
280280
scpiReturn(::typeof(keepAliveReset)) = String
281281
parseReturn(::typeof(keepAliveReset), ret) = occursin("ON", ret)
282282

283+
"""
284+
firEnabled!(rp::RedPitaya, val::Bool)
285+
286+
Set the firEnabled to `val`.
287+
"""
288+
function firEnabled!(rp::RedPitaya, val::Bool)
289+
return query(rp, scpiCommand(firEnabled!, val), scpiReturn(firEnabled!))
290+
end
291+
scpiCommand(::typeof(firEnabled!), val::Bool) = scpiCommand(firEnabled!, val ? "ON" : "OFF")
292+
scpiCommand(::typeof(firEnabled!), val::String) = string("RP:ADC:FIREnabled ", val)
293+
scpiReturn(::typeof(firEnabled!)) = Bool
294+
"""
295+
firEnabled(rp::RedPitaya)
296+
297+
Determine whether the firEnabled is set.
298+
"""
299+
firEnabled(rp::RedPitaya) = occursin("ON", query(rp, scpiCommand(firEnabled)))
300+
scpiCommand(::typeof(firEnabled)) = "RP:ADC:FIREnabled?"
301+
scpiReturn(::typeof(firEnabled)) = String
302+
parseReturn(::typeof(firEnabled), ret) = occursin("ON", ret)
303+
304+
305+
283306

284307
# "INTERNAL" or "EXTERNAL"
285308
"""

src/client/julia/src/Acquisition.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ function readSamplesHeartbeat(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaCl
4040
end
4141
end
4242

43-
correctFilterDelay(rpu::Union{RedPitaya, RedPitayaCluster}, wpStart) = correctFilterDelay(wpStart, decimation(rpu))
44-
correctFilterDelay(rpcv::RedPitayaClusterView, wpStart) = correctFilterDelay(rpcv.rpc, wpStart)
45-
function correctFilterDelay(wpStart::Int64, dec::Int64)
43+
correctFilterDelay(rpu::Union{RedPitaya, RedPitayaCluster}, wpStart; kwargs...) = correctFilterDelay(wpStart, decimation(rpu); fir_enabled=firEnabled(rpu), kwargs...)
44+
correctFilterDelay(rpcv::RedPitayaClusterView, wpStart; kwargs...) = correctFilterDelay(rpcv.rpc, wpStart; kwargs...)
45+
function correctFilterDelay(wpStart::Int64, dec::Int64; fir_enabled::Bool = true)
4646
cic_stages = 6
4747
fir_taps = 92
48-
cicDelay = (((dec/2-1)/2*cic_stages))/dec
49-
firDelay = ((fir_taps-1)/2)/2
48+
dec_div = fir_enabled ? 2 : 1
49+
50+
cicDelay = fir_enabled ? ((((dec/dec_div-1)/2*cic_stages))/dec) : (dec-1)/2*cic_stages/dec
51+
firDelay = fir_enabled ? (((fir_taps-1)/2)/2) : 0
5052
delay = Int64(round((cicDelay + firDelay), RoundUp))
5153
correctedWp = wpStart + delay
5254
@debug "Filter delay corrected $wpStart to $correctedWp ($cicDelay, $firDelay, $delay)"
@@ -66,7 +68,8 @@ Request and receive `numOfRequestedSamples` samples from `wpStart` on in a pipel
6668
6769
If `rpInfo` is set to a `RPInfo`, the `PerformanceData` sent after every `chunkSize` samples will be pushed into `rpInfo`.
6870
"""
69-
function readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64; chunkSize::Int64 = 25000, rpInfo=nothing, correct_filter_delay::Bool = true)
71+
function readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64;
72+
chunkSize::Int64 = 25000, rpInfo=nothing, correct_filter_delay::Bool = true)
7073
numOfReceivedSamples = 0
7174
index = 1
7275
rawData = zeros(Int16, numChan(rpu), numOfRequestedSamples)
@@ -109,7 +112,8 @@ Request and receive `numOfRequestedSamples` samples from `wpStart` on in a pipel
109112
110113
See [`SampleChunk`](@ref).
111114
"""
112-
function readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel; chunkSize::Int64 = 25000, correct_filter_delay::Bool = true)
115+
function readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel;
116+
chunkSize::Int64 = 25000, correct_filter_delay::Bool = true)
113117
numOfReceivedSamples = 0
114118
chunkBuffer = zeros(Int16, chunkSize * 2, length(rpu))
115119

@@ -189,7 +193,7 @@ See [`readSamples`](@ref), [`convertSamplesToFrames`](@ref), [`samplesPerPeriod`
189193
- `rpInfo=nothing`: see `readSamples`
190194
- `useCalibration`: convert from Int16 samples to Float32 values based on `RedPitaya`s calibration
191195
"""
192-
function readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false, correct_filter_delay::Bool = true)
196+
function readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; useCalibration = false, kwargs...)
193197
numSampPerPeriod = samplesPerPeriod(rpu)
194198
numPeriods = periodsPerFrame(rpu)
195199
numSampPerFrame = numSampPerPeriod * numPeriods
@@ -202,7 +206,7 @@ function readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}
202206
numOfRequestedSamples = numFrames * numSampPerFrame
203207

204208
# rawSamples Int16 numofChan(rpc) x numOfRequestedSamples
205-
rawSamples = readSamples(rpu, Int64(wpStart), Int64(numOfRequestedSamples), chunkSize = chunkSize, rpInfo = rpInfo, correct_filter_delay = correct_filter_delay)
209+
rawSamples = readSamples(rpu, Int64(wpStart), Int64(numOfRequestedSamples); kwargs...)
206210

207211
# Reshape/Avg Data
208212
if useCalibration
@@ -302,7 +306,7 @@ See [`readSamples`](@ref), [`convertSamplesToPeriods!`](@ref), [`samplesPerPerio
302306
- `rpInfo=nothing`: see `readSamples`
303307
- `useCalibration`: convert samples based on `RedPitaya`s calibration
304308
"""
305-
function readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false, correct_filter_delay::Bool = true)
309+
function readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1; useCalibration = false, kwargs...)
306310
numSampPerPeriod = samplesPerPeriod(rpu)
307311

308312
if rem(numSampPerPeriod,numBlockAverages) != 0
@@ -316,7 +320,7 @@ function readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView
316320
numOfRequestedSamples = numPeriods * numSampPerPeriod
317321

318322
# rawSamples Int16 numofChan(rpc) x numOfRequestedSamples
319-
rawSamples = readSamples(rpu, Int64(wpStart), Int64(numOfRequestedSamples), chunkSize = chunkSize, rpInfo = rpInfo, correct_filter_delay = correct_filter_delay)
323+
rawSamples = readSamples(rpu, Int64(wpStart), Int64(numOfRequestedSamples); kwargs...)
320324

321325
# Reshape/Avg Data
322326
if useCalibration

src/client/julia/src/Cluster.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function RedPitayaCluster(hosts::Vector{String}, port::Int64=5025, dataPort::Int
5252

5353
@sync for (i, rp) enumerate(rps)
5454
@async begin
55+
serverMode!(rp, CONFIGURATION)
5556
triggerMode!(rp, modes[i])
5657
triggerPropagation!(rp, true)
5758
end
@@ -103,7 +104,7 @@ function RPInfo(rpc::RedPitayaCluster)
103104
end
104105

105106
for op in [:currentFrame, :currentPeriod, :currentWP, :periodsPerFrame, :samplesPerPeriod, :decimation, :keepAliveReset,
106-
:triggerMode, :samplesPerStep, :serverMode, :masterTrigger,
107+
:triggerMode, :samplesPerStep, :serverMode, :masterTrigger, :firEnabled,
107108
:counterTrigger_enabled, :counterTrigger_enabled!, :counterTrigger_presamples,
108109
:counterTrigger_isArmed, :counterTrigger_arm!, :counterTrigger_reset!,
109110
:counterTrigger_reset, :counterTrigger_lastCounter, :counterTrigger_referenceCounter,
@@ -121,10 +122,10 @@ for op in [:currentFrame, :currentPeriod, :currentWP, :periodsPerFrame, :samples
121122
end
122123

123124
for op in [:periodsPerFrame!, :samplesPerPeriod!, :decimation!, :triggerMode!, :samplesPerStep!,
124-
:keepAliveReset!, :serverMode!,
125+
:keepAliveReset!, :serverMode!, :firEnabled!,
125126
:counterTrigger_enabled!, :counterTrigger_presamples!, :counterTrigger_arm!,
126127
:counterTrigger_reset!, :counterTrigger_referenceCounter!,
127-
:counterTrigger_sourceType!, :counterTrigger_sourceChannel!]
128+
:counterTrigger_sourceType!, :counterTrigger_sourceChannel!, :enableInstantReset!]
128129
@eval begin
129130
@doc """
130131
$($op)(rpc::RedPitayaCluster, value)
@@ -142,7 +143,7 @@ for op in [:periodsPerFrame!, :samplesPerPeriod!, :decimation!, :triggerMode!, :
142143
end
143144
end
144145

145-
for op in [:clearSequence!, :sequence!, :stopTransmission]
146+
for op in [:clearSequence!, :sequence!, :stopTransmission, :enableInstantReset, :instantResetTriggered]
146147
@eval begin
147148
@doc """
148149
$($op)(rpc::RedPitayaCluster)
@@ -234,7 +235,7 @@ for op in [:signalTypeDAC!, :amplitudeDAC!, :frequencyDAC!, :phaseDAC!]
234235
end
235236
end
236237

237-
for op in [:offsetDAC, :rampingDAC, :enableRamping, :enableRampDown]
238+
for op in [:offsetDAC, :rampingDAC, :enableRamping, :enableRampDown, :startRampDown!]
238239
@eval begin
239240
@doc """
240241
$($op)(rpc::RedPitayaCluster, chan::Integer)

0 commit comments

Comments
 (0)