[Help] Arduino Due Sampling values on digital pins @ 50MHz

Hey guys, I’ll preface with saying I’m kind of a beginner. I have read documentation, scanned posts etc, but still feel a bit lost so I hope you don’t mind helping me out and reviewing my approach.

Background
Essentially, I’m supposed to use an Arduino Due to sample signals that happen at 50 MHz. I know the Due has a processor speed of 84MHz. However, where I get confused is in whether or not the pins (I’ll be using digital pins 22,24,26,28,30,32,34,36) will be able to sample at that speed as well. Not that I need them to, but I would like to know how fast they can read the data coming in. I read up on clock distribution and getting the clock signal to go to every part that needs it, but still don’t really have a good understanding of how that works or whether that would effect the clock speed listed on the specs (84 MHz).

So, back to my goal: Read values (6 data, 1 clk, 1 sync) coming in on 8 digital pins. Only when there’s an assertion on the sync line, should I begin to record the data. So, I need to record the 6 bits of data that come when sync is first high, then 23 successive rounds of the 6 bits of data. Note that the other side (a custom controller board) is sending information at a rate of 50 MHz, and the info is stable on its falling edge.

In general, I’m looking for the lowest latency approach!

Questions

  1. Since it’s supposed to be running fast, I don’t think I should poll the pins constantly. Having said that, I don’t have a great feel for how fast fast is for electronics. So, should I try set up an interrupt on pin 36 (will be used for SYNC), and when it’s 1 have the logic that pertains to recording the data? Or should I poll pin 36 to see if the SYNC assertion has happened?

  2. After I recognise that sync is high, would the best approach be to have a for-loop that occurs 24 times and has a timer so that each iteration of the loop syncs up with the 50MHz rate that the other side is sending information at? Something like:

// SYNC IS HIGH

int data_packet[144]; // Var to save total data 
     
for(int j = 0; j < 24; j++){

    data_packet[0+j*6] = digitalRead(ip_b0);  // save values on input pins
    data_packet[1+j*6] = digitalRead(ip_b1);
    data_packet[2+j*6] = digitalRead(ip_b2);
    data_packet[3+j*6] = digitalRead(ip_b3);
    data_packet[4+j*6] = digitalRead(ip_b4);
    data_packet[5+j*6] = digitalRead(ip_b5);
        
    j++;

    // timer to elapse for 20 ns? (1/50MHz)
}

Or should I try some sort of timer interrupt? Having said that, I noticed the Due doesn’t really have timer documentation and people seem to be having difficulty with it based on google searches. So I’m a little nervous about both approaches. Does anyone have any tips regarding the timer aspect, or alternatives to propose?

Sorry this is so long, I wanted to make sure I was as detailed as I could be! Thanks!

I don't think it is possible to sample at 50MHz. AFAIK, the digital pins can read and write up to 21MHz. To get 21MHz, you'll have to write some inline assembly (with loop unrolling) or use DMA (read from register, write to array).

Gericom:
I don't think it is possible to sample at 50MHz. AFAIK, the digital pins can read and write up to 21MHz. To get 21MHz, you'll have to write some inline assembly (with loop unrolling) or use DMA (read from register, write to array).

Is there anyway to confirm this? I'm having a tough time with the documentation aspect. :frowning:
Are there any other pins that can comfortably record data coming in at 50 MHz? I'm guessing I probably need to use different hardware.

Edit: Is there a particular reason or limitation set somewhere that dictates that the digital pin can only read up to 21 MHz?

pepe:
Hi

84 MHz is only the frequency of the MCU clock. That doesn’t mean the MCU can achieve 84 million instructions per second, nor it can sample 84 million data per second on its IOs.

In fact, one the digitalRead() function represents several tens of machine instructions, each of them taking several MCU clock periods to be executed.

C/C++ programming only allows the Due to achieve a sample rate of few hundreds of thousand samples per second.

A sample rate of 50 MS/s is not realistic at all, even with assembly programming.

Sorry to turn you into my teacher, but I’m not great at understanding these concepts and would really appreciate if you could point me in the right direction! Sometimes I have a hard time wrapping my head around how clock speed is distributed / dominated by certain parts of the system and why some parts have much lower speed limitations.

So from what I understand, the microcontroller clock operates at 84 MHz (that is 84 000 000 ticks per second). However, one instruction might take many ticks to happen (and one function takes many instructions). That is why, although the clock is 84 MHz, the way the Due interprets the code and how long the code takes to actually execute reduces how fast this can occur. Is this correct? Aside from the fact that functions take many instructions and that the programming language might slow it down, are there any other considerations that affect the execution speed?

Also, why does C/C++ programming only allow the Due to achieve a sample rate of few hundreds of thousand samples per second?

Sorry for the bother, and thanks for the response!

For that sort of data rate you'll have to use the DMA controller - its a steep learning curve.
I'm not sure how fast the DMA can pull readings from the PIO controllers though.

What are you actually trying to achieve? A logic analyser?

It is one thing to sample a signal on an input pin, but you then have to do something with it which also takes some instructions to perform.

Basically the CPU runs machine code instructions, then number of clock cycles per instruction is given in the processors data sheet, it changes from instruction to instruction.

If you write code in a high level language like C a compiler translates those lines of code into a bunch of machine code instructions before you start. Therefore it is complected to translate how long any one C function will take. This is further complicated by the fact that with each C function there is overhead where the return address is put on a stack, register values are put somewhere and local variables for that function are created.

Most of the time it is much simpler to write something and time it, either by using a software clock, or by putting a pin high at the start of a code section and low at the end and using an oscilloscope to measure the width of the resulting pulse.

DMA - stands for Direct Memory Addressing and is special hardware that can do things like transferring input values into memory without passing through the CPU. The DMA speed is yet another parameter that will be given in the processor's data sheet. Although there will be overhead in setting up and stopping the DMA hardware.

MarkT:
For that sort of data rate you'll have to use the DMA controller - its a steep learning curve.
I'm not sure how fast the DMA can pull readings from the PIO controllers though.

What are you actually trying to achieve? A logic analyser?

Thanks for the tip! I looked into some DMA stuff, but there wasn't a lot of great documentation. As you said, the learning curve appears steep so I'm feeling a bit overwhelmed and don't quite know where to start.

I'm basically trying to sample, record and package data coming in from a custom controller board. That board deals with touch input.

Grumpy_Mike:
...
DMA - stands for Direct Memory Addressing and is special hardware that can do things like transferring input values into memory without passing through the CPU. The DMA speed is yet another parameter that will be given in the processor's data sheet. Although there will be overhead in setting up and stopping the DMA hardware.

Thanks for the explanation! I really appreciate it.

Hey guys, aside from the DMA stuff and speed requirements, could someone advise me on the programming practice aspect? So, for now ignore 50 MHz. Let’s just say I want things to go as fast as I can given the Due’s specs.

(reiteration of initial questions)
Questions

  1. Should I try set up an interrupt on pin 36 (will be used for SYNC), and when it’s 1 move on to the logic that pertains to recording the data? Or should I poll pin 36 to see if the SYNC assertion has happened?

  2. After I recognise that sync is high, would the best approach be to have a for-loop that occurs 24 times and has a timer so that each iteration of the loop syncs up with the chosen frequency rate? Something like:

// SYNC IS HIGH

int data_packet[144]; // Var to save total data 
     
for(int j = 0; j < 24; j++){

    data_packet[0+j*6] = digitalRead(ip_b0);  // save values on input pins
    data_packet[1+j*6] = digitalRead(ip_b1);
    data_packet[2+j*6] = digitalRead(ip_b2);
    data_packet[3+j*6] = digitalRead(ip_b3);
    data_packet[4+j*6] = digitalRead(ip_b4);
    data_packet[5+j*6] = digitalRead(ip_b5);
        
    j++;

    // timer to elapse for 20 ns? (1/50MHz)
}

Or should I try some sort of timer interrupt? I can’t find great tutorials or documentation for the Due’s timer and people seem to be having difficulty with it based on google searches. Does anyone have any tips regarding the timer aspect, could they point me in any helpful directions?

Edit: Also, I wasn’t able to find anything about DMA speed in the datasheet. I saw some general stuff regarding the DMA on page 34 of the doc at http://www.atmel.com/Images/doc11057.pdf...but yeah, a bit lost regarding the speed part. Is this just something I have to go out on a limb for, try out and measure, and then see if it meets my requirements? Thanks!

Well that code is a bit wonky.
Why multiply by 6 and why increment j twice once in the for loop and once at the end of the loop.
You need to store the data in a different bit of the array so this would be best:-

// SYNC IS HIGH

int data_packet[144]; // Var to save total data 
     
for(int j = 0; j < 24; j= j+6){

    data_packet[0+j] = digitalRead(ip_b0);  // save values on input pins
    data_packet[1+j] = digitalRead(ip_b1);
    data_packet[2+j] = digitalRead(ip_b2);
    data_packet[3+j] = digitalRead(ip_b3);
    data_packet[4+j] = digitalRead(ip_b4);
    data_packet[5+j] = digitalRead(ip_b5);

    // timer to elapse for 20 ns? (1/50MHz)
}

Even so taking two bytes to store one bit is wasteful. Make data_packet a byte type variable and that speeds things up and cuts down on the memory requirement.

But to speed things up do not use digitalRead but use direct port addressing. Maybe if you get the pin assignment correct you could read all six bits into one byte.

Grumpy_Mike:
Well that code is a bit wonky.
Why multiply by 6 and why increment j twice once in the for loop and once at the end of the loop.

...

Even so taking two bytes to store one bit is wasteful. Make data_packet a byte type variable and that speeds things up and cuts down on the memory requirement.

But to speed things up do not use digitalRead but use direct port addressing. Maybe if you get the pin assignment correct you could read all six bits into one byte.

These are wonderful tips! Thanks. You're totally right - my code was kind of wonky haha. I'll definitely look into direct port addressing. However, could you perhaps clarify "you could read all six bits into one byte"? If I change data_packet to a byte type, I can still only get 6 bits to put into it at a time. I know I'm missing some major understanding about that point, but I'm not sure what it is.

Sorry for asking so many questions. I really appreciate all the help though!

When you use direct port addressing you read on a Due 32 input bits with one line of code. With a UNO it is 8 bits you read.
So if you pick the right bits to have your data on they can be the lower 6 bits in these 32 bits and can be transfers into one byte of your array with just one operation.

Look up port manapulation for the UNO to get the idea.

Thank you! I'll definitely take a look.

Sorry to drag this topic on for so long, but does anyone with DMA experience think the DMA getting data from the GPIO pins at 50MHz is possible?

It seems that the DMA controller doesn't actually connect to the PIO peripheral
at all, so its irrelevant. See table 28.1 in the AT91SAM datasheet. If it could
run at 50MHz it would probably saturate the bandwidth of RAM anyway,
preventing the processor from accessing it!

These kind of datarates suggest you need external datapath hardware, perhaps
an SDRAM, in order to capture what you need.

MarkT:
It seems that the DMA controller doesn't actually connect to the PIO peripheral
at all, so its irrelevant.

Woah, thanks for the information! I was having a bit of trouble figuring things out with the datasheet. As you can guess, I'm pretty inexperienced with this stuff, so I really appreciate you helping me sort through this.

You can actually use the dma controller for this. You need to make it read from memory (not from periphal), and use the pio pdsr register as address. I have done it before.

Refer to page 1423, Table 46-43 I/O Characteristics:

There are only 2 pins (pin group 1) on the DUE that are rated with maximum frequency 65MHz.
The highest divided clock rate compatible with pin group 1 is 42MHz.

Most all other pins (pin group 2) are rated with maximum frequency of 35MHz.
The highest divided clock rate compatible with pin group 2 is 21MHz.

Regardless of DMA, which allows the microcontroller to run tasks in parallel and increase data throughput, the I/O characteristics remain in effect.