This is an old revision of the document!
TDD (Time-Division Duplex) mode allows the user to control the time period of the receive and transmit bursts.
The generic TDD controller is in essence a waveform generator capable of addressing RF applications which require Time Division Duplexing, as well as controlling other modules of general applications through its dedicated 32 channel outputs.
The reason of creating the generic TDD controller was to reduce the naming confusion around the existing repurposed TDD core built for AD9361, as well as expanding its number of output channels for systems which require more than six controlling signals.
Device Family | LUTs | FFs |
---|---|---|
Xilinx Zynq UltraScale+ | 990 | 2738 |
Name | Description |
---|---|
axi_tdd.sv | Top module |
axi_tdd_pkg.sv | SystemVerilog Package |
axi_tdd_regmap.sv | Register Map with CDC synchronizers |
axi_tdd_counter.sv | Internal counters and FSM logic |
axi_tdd_channel.sv | Channel waveform generator |
axi_tdd_sync_gen.sv | Synchronization pulse generator |
axi_tdd_ip.tcl | TCL script to generate the Vivado IP-integrator project |
axi_tdd_hw.tcl | TCL script to generate the Quartus IP-integrator project |
cf_axi_tdd.c | TDD Linux Driver |
zynqmp-zcu102-rev10-ad9081-m8-l4-tdd.dts | Device tree using TDD |
Name | Description | Max value | Default |
---|---|---|---|
ID | Instance identification number | - | 0 |
CHANNEL_COUNT | Number of channels | 32 | 8 |
DEFAULT_POLARITY | Initial channel polarity | 32'hFFFFFFFF | 8'h00 |
REGISTER_WIDTH | Internal counter and register width | 32 | 32 |
BURST_COUNT_WIDTH | Burst counter width | 32 | 32 |
SYNC_INTERNAL | Enable support for internal sync signal | 1 | 1 |
SYNC_EXTERNAL | Enable support for external sync signal | 1 | 0 |
SYNC_EXTERNAL_CDC | Enable synchronization of external sync signal | 1 | 0 |
SYNC_COUNT_WIDTH | Sync generator counter width | 64 | 64 |
Name | Type | Description |
---|---|---|
s_axi_aclk | Clock | System clock |
s_axi_aresetn | Synchronous active low reset | System reset |
s_axi | AXI-Lite bus slave | Memory mapped AXI-Lite bus that provides access to module's register map |
clk | Clock | Core clock |
resetn | Synchronous active low reset | Core reset |
sync_in | input | External synchronization input signal |
sync_out | output | Module synchronization output signal |
tdd_channel | output | Channels output |
Access Type | Name | Description |
---|---|---|
HR | Hardware-reset | Register field is reset by hardware. |
R | Read-only | Reads will return the current register value. Writes have no effect. |
RW | Read-write | Reads will return the current register value. Writes will change the current register value. |
U | Unimplemented | Register field is unimplemented. |
The central idea of the TDD controller is “frame”-based operation, i.e. all the timing defined for the individual channels is relative to the beginning of a frame. The FRAME_LENGTH
value controls the length of a single frame, while the BURST_COUNT
value controls how many frames should be played after enabling the device (a value of 0 means frames will be repeated indefinitely). Before the start of a burst, an optional startup delay is inserted, defined by the STARTUP_DELAY
value in clock cycles.
This diagram tries to illustrate how the different channels can be enabled at different times relative to the beginning of a frame (to be updated)
In order to begin its operation, the peripheral must be enabled. This is done by setting the ENABLE
bit. Next, the peripheral waits to receive a sync signal. There are 3 possible sync sources, which can be independently activated through their corresponding enabling bits: SYNC_INT
, SYNC_EXT
and SYNC_SOFT
can all be active at the same time.
The external synchronization capability allows the alignment of frames between multiple devices in different locations, for example using a GPSDO 1 PPS output. The internal sync signal is generated based on a dedicated counter, when its value matches the one defined in SYNC_COUNTER_LOW
/ SYNC_COUNTER_HIGH
. The software generated sync pulse is triggered at an arbitrary point in time when writing a ‘1’ value in SYNC_SOFT
.
The next diagram shows the peripheral’s FSM, which transitions between 4 states: IDLE, ARMED, WAITING and RUNNING.
In case a synchronization signal is received while the TDD core is running, the signal can reset the internal counter to zero by setting SYNC_RST
to ‘1’. This can alter the counter value in both WAITING or RUNNING states.
The generic TDD controller can have up to 32 output channels, each of them having its unique values when the channel is set/reset under CHX_ON
/ CHX_OFF
. They are continuously compared to internal counter’s value while the core is RUNNING.
Every bit in CHANNEL_ENABLE
/ CHANNEL_POLARITY
corresponds to a specific channel. The bit position is correlated to the channel index, so the LSB will always be associated with CH0 and the MSB with CH31.
The following registers will not be updated unless the peripheral is disabled:
BURST_COUNT
STARTUP_DELAY
FRAME_LENGTH
CHANNEL_POLARITY
SYNC_COUNTER_LOW
SYNC_COUNTER_HIGH
CHX_ON
CHX_OFF
The user should configure them before enabling the peripheral. Any subsequent write while the peripheral is enabled will be ignored.
An exception to this rule is CHANNEL_ENABLE
, which allows enabling / disabling independent channels on-the-fly. The new value will come into effect only when in ARMED state or at the end of a frame. CONTROL
can also be modified on-the-fly with immediate effect (after going through the synchronization stage).
STATUS
can be used for debugging purposes, reflecting the current peripheral state.
By adapting the synthesis parameters to the application requirements, the module is highly flexible and can substantially reduce resource utilization.
The linux driver defines an iio interface. The driver can be instantiated in the device tree as follows:
axi_tdd_0: axi-tdd-0@9c460000 { compatible = "adi,axi-tdd-1.00"; reg = <0x9c460000 0x10000>; clocks = <&zynqmp_clk PL0_REF>, <&hmc7044 6>; clock-names = "s_axi_aclk", "intf_clk"; };
clk
to calculate the required register values from the times provided to the iio attributes (T / clk_rate
).
The resulting IIO device looks like this, where there is one channel per combination of rx
, tx
and primary
, secondary
. Keep in mind that these channels are only used to structure their attributes, and don't carry any information themselves.
iio:device2: axi-core-tdd 4 channels found: data1: (output, WARN:iio_channel_get_type()=UNKNOWN) 6 channel-specific attributes found: attr 0: dp_off_ms value: 0 attr 1: dp_on_ms value: 0 attr 2: off_ms value: 0 attr 3: on_ms value: 0 attr 4: vco_off_ms value: 0 attr 5: vco_on_ms value: 0 data1: (input, WARN:iio_channel_get_type()=UNKNOWN) 6 channel-specific attributes found: attr 0: dp_off_ms value: 0 attr 1: dp_on_ms value: 0 attr 2: off_ms value: 0 attr 3: on_ms value: 0 attr 4: vco_off_ms value: 0 attr 5: vco_on_ms value: 0 data0: (output, WARN:iio_channel_get_type()=UNKNOWN) 6 channel-specific attributes found: attr 0: dp_off_ms value: 0 attr 1: dp_on_ms value: 0 attr 2: off_ms value: 0 attr 3: on_ms value: 0 attr 4: vco_off_ms value: 0 attr 5: vco_on_ms value: 0 data0: (input, WARN:iio_channel_get_type()=UNKNOWN) 6 channel-specific attributes found: attr 0: dp_off_ms value: 0 attr 1: dp_on_ms value: 0 attr 2: off_ms value: 0 attr 3: on_ms value: 0 attr 4: vco_off_ms value: 0 attr 5: vco_on_ms value: 0 10 device-specific attributes found: attr 0: burst_count value: 0 attr 1: counter_int value: 0 attr 2: dma_gateing_mode value: rx_tx attr 3: dma_gateing_mode_available value: rx_tx rx_only tx_only none attr 4: en value: 0 attr 5: en_mode value: rx_tx attr 6: en_mode_available value: rx_tx rx_only tx_only attr 7: frame_length_ms value: 0 attr 8: secondary value: 0 attr 9: sync_terminal_type value: 0 1 debug attributes found: debug attr 0: direct_reg_access value: 0x10061 No trigger on this device
zynqmp-zcu102-rev10-ad9081-m8-l4-tdd.dts | Device tree using TDD |