I have a Zynq FMCOMMS2 setup that is working great with Linux+No-OS and generating internal tones with the DDS from the ADI-provided axi_ad9361 HDL block. Very happy with how well everything is going so far.
My design has a Xilinx system generator block going directly into the dac_data_i0 and dac_data_q0 ports of the axi_ad9361, currently using 1rx mode only, which already works for the internal DDS tone test. There is a Xilinx DDS IP core in the system generator design with an AXI port attached (this works from a previous design), and it needs to effectively replicate what the ADI-provided axi_ad9361 DDS already does. The axi_ad9361 is set up to use 2's complement everywhere, and this has also worked for the internal DDS tone generation.
The Sysgen DDS generates 16-bit 2's complement words with decimal point at 15 bits, e.g. 16_15. That then gets scaled (output = i*2^k, where i is the input and k is the scale factor) by scale of 4 to compensate for the lowest 4 bits of the 16-bit word being dropped to make the 12-bit DAC word for the AD9361 chip - this is done in the ADI Verilog code inside of axi_ad9361. So now there's 16_11, that's what goes into dac_data_i0 and dac_data_q0 ports of the axi_ad9361. At start-up, the Sysgen DDS should be generating a 15MHz tone, I can do this with the internal DDS just fine...
When I run my code, register 0x4418 - REG_CHAN_CNTRL_7 - has a value of 0x02, i.e. DMA transfer. The output on the spectrum analyzer is the same as if I gave it 0x03 - which is 0 input to the DAC. So clearly something is not working.
Is there something inherently wrong with this approach? Is there something that should be paid attention to? The actual configuration I do to configure everything is below, I can r/w registers and see the right values. I've tried leaving 0x4420 - REG_USR_CNTRL_3 user datatype etc. - at default, didn't help:
// Initialize both the AD9361 radio chip and the axi_ad9361 PL IP with sane start-up values.
// Once the AD9361 has been initialized and a pointer to the initialized structure exists, define the current state.
st = ad9361_phy->adc_state;
// Configure the axi_ad9361 PL block to push dac_data_i/q input signals to the interface of the AD9361 chip.
// This changes the REG_CHAN_CNTRL_7 register of the axi_ad9361 block (offset 0x4418 + 0x40 per channel, etc.).
axiadc_write(st, 0x4418, 0x02);
// Write to REG_CNTRL_2 register of the axi_ad9361 block for even parity, frame mode, and 1 RF channel.
axiadc_write(st, 0x4048, 0x00000020);
// Write to the REG_USR_CNTRL_3 register of the axi_ad9361 block for big endian, 2's complement.
axiadc_write(st, 0x4420, 0x03001010);
// Get all channels programmed with streaming DMA option.
dac_datasel(st, -1, DATA_SEL_DMA);