Jump to content
  • 0

Eclypse Z7, Using 2 Channels of DAC simultaneously


Udayan Mallik

Question

@artvvb I am using an Eclypse Z7 with a DAC1411 and an ADC1410 to implement a control algorithm. I followed the instruction in https://www.hackster.io/whitney-knitter/hello-zmods-on-the-eclypse-z7-99107d

to define the FPGA architecture. However, when I attempt to write to the DACs, I can only access one channel of the DAC at a time. I cannot access both channels simultaneously. The AD9717 datasheet clearly states that the input interface uses a DDR protocol.  Is this something the provided hardware can do, or am I required to modify the blocks to produce simultaneous outputs.

Udayan Mallik

Edited by Udayan Mallik
Link to comment
Share on other sites

10 answers to this question

Recommended Posts

  • 0

@artvvb Here it is. You are required to modify the "main" routine and the "dacRampDemo" routine as shown below.

void dacRampDemo(float offset, float amplitude, float step, uint8_t channel, uint8_t frequencyDivider, uint8_t gain)
{
    ZMODDAC1411 dacZmod(ZMOD_DAC_BASE_ADDR, DMA_DAC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_DAC, DMA_DAC_IRQ);

xil_printf("Not Doing anything\n\r");

uint32_t *buf;
float val;
uint32_t valBuf_1, valBuf_2;
int16_t valRaw;
size_t length = (int)(amplitude/step) << 2;
int i;
if (length > ((1<<14) - 1))
{
// limit the length to maximum buffer size (1<<14 - 1)
length = ((1<<14) - 1);
// adjust step
step = amplitude/(length>>2);
}
buf = dacZmod.allocChannelsBuffer(length);
dacZmod.setOutputSampleFrequencyDivider(frequencyDivider);
dacZmod.setGain(channel, gain);
dacZmod.setGain(channel-1, gain);
i = 0;
// ramp up
for(val = -amplitude; val < amplitude; val += step)
{
    valRaw = dacZmod.getSignedRawFromVolt(val + offset, gain);
    valBuf_1 = dacZmod.arrangeChannelData(channel, valRaw);
    valBuf_2 = dacZmod.arrangeChannelData(channel-1, valRaw);
    buf[i++] = (valBuf_1<<16) | (valBuf_2>>16);
}
// ramp down
for(val = amplitude; val > -amplitude; val -= step)
{
    valRaw = dacZmod.getSignedRawFromVolt(val + offset, gain);
    valBuf_1 = dacZmod.arrangeChannelData(channel, valRaw);
    valBuf_2 = dacZmod.arrangeChannelData(channel-1, valRaw);
    buf[i++] = (valBuf_1<<16) | (valBuf_2>>16);
}
// send data to DAC and start the instrument
dacZmod.setData(buf, length);
dacZmod.start();
dacZmod.freeChannelsBuffer(buf, length);
}

int main()
{
    init_platform();
    xil_printf("Hello Eclypse Z7!\n\r");
    //xil_printf("Testing ADC ZMOD...\n\r");     // COMMENTED
    //adcDemo(0, 0, TRANSFER_LEN);            // COMMENTED
    xil_printf("Testing DAC ZMOD...\n\r");
    dacRampDemo(-0.05, 3.90, 0.005, 1, 255, 1);
    cleanup_platform();
    return 0;
}

Edited by Udayan Mallik
Link to comment
Share on other sites

  • 1

C ( and C++?) are highly typed languages so it is worth learning to be precise with constants and data types to avoid unexpected errors.

In C, 2 != 2.0f != 2.0. The first is an integer, the second a single precision float and the last is double which is what C defaults without the 'f' suffix. Yes, the compiler can automatically convert in some cases but it is better to be completely explicit. For example, your code maybe working just fine but you are implicitly using double (64 bit) floating point.

Link to comment
Share on other sites

  • 0

Hi @Udayan Mallik

I'm not extremely familiar with this particular guide, however, at a glance, the Zmod IPs and DMA setup will be providing two channels of data simultaneously. Each 32-bit word in the acquisition should have data from both channels packed into it. The acquire functions in zmodlib only take in the channel index for the purposes of setting a trigger on that channel. The same goes for DAC transfers, data from both channels is packed into each word of a DMA transfer.

Thanks,

Arthur

Link to comment
Share on other sites

  • 0

@artvvb I am attempting to create a Sine wave using the DAC1411 module. To that end, I have created three functions - 1 that reads a predefined waveform from a file, 1 that attempts to create the waveform on the fly using the math.h library and the sin function, and one that uses an array containing the values of a sine wave inside the function. None of the methods have produced a sine wave. Does Vitis not support complex math and FILE IO functions? Am I not allowed to use arrays? Is the fuinction dacrampdemo predefined/instantiated in a .h file? How do I add my function to that file?

Link to comment
Share on other sites

  • 0

File I/O isn't supported by default, as the demo uses a standalone (baremetal) OS. You'd need to add some way to either mount a file system or import the same data through some other mechanism (like including it in the text of a source file like a C header, as in your method of using arrays). Sending files over a serial connection is also possible, tera term (for example) has some built in features to support this, but you'd need to use something like the xuartps driver to implement something to buffer the received data in Eclypse software.

To include and use the functions in the math.h header, you need to modify the C/C++ Build Setting of your application project by adding "m" to the list libraries to link in, see the screenshot below.

You can use arrays as needed. If they are large (maybe larger than something like 4096 bytes by default), you may need to check that the linker script has sized the corresponding memory regions appropriately - to avoid stack overflows and such. It matters whether your array is a global, defined inside a function, or dynamically allocated.

dacRampDemo seems to just be instantiated in place in the main.c file in the article you linked.

Thanks,

Arthur

 

image.png

Edited by artvvb
clarify default stack/heap size
Link to comment
Share on other sites

  • 0

If you haven't yet, you could verify whether sin is the issue by checking the function calling sin by either throwing in some prints or stepping through it in the debugger.

How are you converting data from floating point to u16s to load into the transmit buffer? (edit, just noticed getSignedRawFromVolt, ought to be fine, but verifying this in the debugger may be useful)

It looks like m may not be required for C++ after all, as I ran the snippet below, successfully printing some nonzero values. This is the Xilinx AR I was referencing earlier: https://support.xilinx.com/s/article/52971

 

#include <math.h>
#include <iostream>

int main() {
	for (float i = 0.0f; i < 1.0f; i += 0.1f) {
		std::cout << sin(i) << std::endl;
	}
	return 0;
}

 

Edited by artvvb
Link to comment
Share on other sites

  • 0

Thank you for your response. I have successfully implemented a sine wave.

My equation used to be 3.9*sin(2*3.14*125*(1/100000000)*j*255) - this produces a Sine wave in Matlab (for j = 1:3138) and, if entered in google (try 3.9*sin(2*3.14*125*(1/100000000)*758*255) where j is 758 and can vary between 0:3138)

Evidently in an embedded system 1/100000000 = 0

However, since where there is a will there is always a way, changing the said number to 3.9*sin(2*3.14*125*(1/100000000.00)*j*255) does the trick (Converting the 100000000 to a 100000000.00). See image attached.

 

IMG_20220824_090910_157.jpg

Edited by Udayan Mallik
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...