Is this feasible using MEGA 2560?

Hello all,

This is my first post and also new to Arduino world. I am thinking of using MEGA 2560 board as a prototype for my project that I currently do with binary ripple counters and multiplying DAC.

In board sense, wondering if I can use this board to act as an arbitrary waveform generator where the data pattern is uploaded at runtime as the user needs to and the board should output 14bit data pattern continuously with reference to an input clock (one data out per one clock input). The pattern should repeat itself as defined by the length of the pattern loaded. Whenever it starts to repeat the pattern it needs to output a signal (pulse or TTL) as well. The basic process is fixed, i.e. sending out a run time defined length of data pattern over the digital pins.

Is this something that can be done using this board? The important aspects here to consider is,

  1. User should be able to update the pattern at runtime
  2. The pattern wont be a fixed length and can vary depending on the user needs
  3. Must output a signal for every repeat of the pattern
  4. Able to update the pattern from PC side application (visual studio)

thanks

Do you want to output the 14 bits on 14 different I/O pins?

What will those pins be connected to?

What is the shortest interval between each successive 14 bit output?

I suspect the most likely limitation is the speed.

...R

Thanks for your reply Robin.

Yes, the idea is to output the 14bits on 14 different I/O pins which are then connected to a 14bit parallel DAC with the same clock feeding into the DAC as well. The clock range will be in the range of 15KHz -30KHz.

Hope that helps

At 30Khz you would need to output two bytes on two I/O ports every 33 microsecs. That should be doable.

However a lot will depend on how much calculation is needed to figure what to output on the I/O ports. You have not described that part of the project.

I am also assuming that it will be OK for the output to pause while the user is providing new data.

...R

There isn't much calculation here, very straight forward.

Here is how I imagine the workflow would be

  1. Data pattern is generated on the PC application, the length of the data at max will be ~530 (12 or 14bit) data points
  2. The above data is uploaded to MEGA flash (permitting on board storage which I think should be totally fine)
  3. The only process that will be running continuously is to send out each data point (2 bytes) per clock input. For instance, incase of 530 data points, it should output a TTL signal for every 530 clocks and repeat from first data point.
  4. Whenever the user wants to update data pattern, it will be generated on PC application and uploaded to the board (Ok for any delay it will have during this time)

This is all there is to it. Pretty simple actually.

Let me know if you want to know more details.

530 unsigned integers is 1060 bytes. You might even be able to do it in RAM on an Arduino UNO. The 'clock' could be an external interrupt. The ISR would send out the next two bytes (you don't need to use all 16 bits), increment the counter, and turn on the "cycle" pin on roll-over.

Direct port manipulation would speed up the writes. The MEGA has plenty of 8-bit ports you could write. The UNO only has three ports (B, C, and D) and most of those have bits you should not touch.

kris123berkeley:
This is all there is to it. Pretty simple actually.

That sounds very straightforward.

I suggest you start thinking of the data being held as 16 bit values (you can easily treat the 2 (or 4) highest bits as 0) so that only 14 (or 12) bits have an effect. If you want to output a clock as well as the data you could use the high bit for the clock.

A Mega has the advantage that it has some I/O ports in which all 8 pins are available. Two of them will give you 16 bits. Using Port manipluation you can write the two I/O ports with two successive instructions 62.5 nanoseconds apart. I don't think there is any way to output more than 8 bits without that short gap.

...R

Robin2:
Using Port manipluation you can write the two I/O ports with two successive instructions 62.5 nanoseconds apart. I don't think there is any way to output more than 8 bits without that short gap.

...R

This is a bit of info that I need to think about on how it effects the overall output waveform.
The only extra register I need to have access or update whenever the data pattern is updated is the one that holds the count value (10bit). The process uses this register value to cycle the loop continuously as long as the board is powered up. I am gonna go ahead and order this board and start playing with it.

thanks for all the info to both of you and I am sure will be back with more questions once I start playing with it.

It just occurred to me that if your DAC only updates when it receives the CLK signal then the time gap between the outputs of the two bytes to make the full 16 bits will not be noticeable to the DAC as long as the CLK is part of the second byte to be written or is written separately after the two 8-bit values have been updated.

...R

Yes, thats where I started looking into the timing diagrams of the DAC7821 which I plan to use. On pg:16 it says that the data is loaded into the input register when the clock (CS line) goes low and is latched to output DAC register when it goes high. In that case, I guess I should keep the clock low as long as the Mega is done outputting both bytes on the output lines and then pull clock to high just for long enough for 2 bytes to be written (as per the datasheet must be >=10ns). I can use the same clock input that I use with MEGA and delay it the amount of time (62.5ns as per your info + whatever time MEGA takes to latch out the data onto output lines) and then invert it for proper operation of DAC. At the moment my clock is 1us pulse.

One quick question, is it possible to use one of the PWM outputs of the MEGA to output a defined width pulse according to the input clock but delayed finite amount of time (basically the time it takes to write out 2bytes of data)?

kris123berkeley:
One quick question, is it possible to use one of the PWM outputs of the MEGA to output a defined width pulse according to the input clock but delayed finite amount of time (basically the time it takes to write out 2bytes of data)?

No need to do it in hardware. Just have the ISR send a clock pulse after it puts the data on the pins.
One hardware trick of the AVR chips: Write a 1 to any bit of the PINx register (Port input register) to toggle an output pin. Write the bit twice to send a short pulse.

Looking at the datasheet I would do things in this order

  • Set R/W low to signify loading data (if you never read back the data this could be permanently low).
  • Set CS low
  • Write the data to the I/O ports
  • Set CS HIGH to cause the data to be loaded into the DAC

I don't think the timing of any of these is critical as long as they are done in the correct order. The DAC can operate faster than the Arduino.

...R

Robin2:

  • Set CS low
  • Write the data to the I/O ports
  • Set CS HIGH to cause the data to be loaded into the DAC

I don't think the timing of any of these is critical as long as they are done in the correct order. The DAC can operate faster than the Arduino.

...R

I am thinking more like writing data to I/O ports before setting CS to low, that way data is available for DAC on its input lines to load into the input register as soon as the CS goes low and wait for like 20ns before switching CS to high.

But if it works in either case, thats good. Have to follow John's suggestion on toggling clock pulse output.

Ordered everything I needed for this today. Excited to try it out.

Just received the board and started playing with it by doing a simple step of recognizing the input clock and turning on/off on board led (while probing the pin output [pin 13] for that as well).

Using the online example for interrupt, I can successfully see it running, but there is too much delay and doesnt work all the time

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(interruptPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
}

void blink() {
state = !state;
digitalWrite(LED_BUILTIN, state);
}

Using actual clock (4us pulse at 15.45KHz), it is everywhere, most of the time it misses. When I change the duty cycle to 50% pulses, it works but there is a considerable amount of jitter and the lag is about 9us. If I move the digitalWrite command into loop section, the delay increases to about 15us.

Is there any other way to get this working at minimum delay and with 4us pulses? Is there some kind of clock frequency adjustments that can be updated to get the interrupt polling run faster?

digitalWrite() is a very slow function because it has to figure out which I/O pin every time.

There is a DigitalWriteFast library which is a great deal faster.

However if you want something to happen close to full clock speed you MUST use port manipulation

...R

Thanks for the tip. Port manipulation did improve a lot on the delay (~4us). But there is jitter in the output, sometimes it misses and the output phase inverts. Is there a way to make this more reliable. Before getting the rest of the logic going, I guess this should be straightened out for more stable output.

You need to post the latest version of your program and give a detailed description of what it does and what you want it to do that is different.

...R

This is what I am using

const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
DDRB = 0xFF;
}

void loop() {
}

void blink() {
state = !state;
if (state)
PORTB = 0x32;
else
PORTB = 0x00;
}

In the attached video, you can see the jitter and phase change. Would like to see the output (CH2), close to identical to CH1 signal except for some fixed delay.

oscope.mpg (1.85 MB)

Since you aren't using millis() you can turn off the Timer0 interrupt mask (TIMSK0 = 0;).