C/C++/Arduino use of Due(SAM3X8E), PDC, DMA etc. Seeking advice.

Hello.

I have some trouble understanding how to use SAM3X8E in the Due board, I can use and write to registers on the 8bit controllers and I have spent hours and hours and will continue spending hours reading the SAM3X datasheet but man is it hard to get.
I have read that its a steep learning curve to go from AVR 8bit to SAM 32bit or what to call it and I could really need a few answers.

How does one use the PDC, DMA functionality to lighten the burden of the CPU and enable "multi-tasking"?
I know that it isn't really multi-tasking but close enough, but as a example:

I can get the ADC running i free-running mode and I use it with only Due A0(SAM ADC Ch7), but I want to be able to direct the resulting data to.... some memory:)

From the datasheet;
"The channel EOC bit in the Status Register (ADC_SR) is set and the DRDY is set. In the case of
a connected PDC channel, DRDY rising triggers a data transfer request. In any case, either
EOC and DRDY can trigger an interrupt."

"If the ADC is used with a PDC, only the transfers of converted data from enabled channels are
performed and the resulting data buffers should be interpreted accordingly."

I don't at all get how its done and I might misunderstand something, but how does one set up a PDC?
Does someone have any suggestion of where I can learn more about how to use the SAM registers or is reading the datasheet and trying to understand samlib the only way to go?

And is it possible to get the due to send ADC results through the serial port to a PC with PDCs/DMAs?

I would think that the hole answer to this inquiry could be quite extensive but I have completely lost my direction and pointing me towards anything could really help me out.

There are no information regarding SAM3 internal workings that is not appreciated.

Regards

This document is for SAM4 but the description of what PDC is are exactly the same as the one in the SAM3X datasheet so for the time being I will treat it as being applicable for SAM3X:

Start from this page FFT Library for Arduino Due, SAM3X - Arduino Due - Arduino Forum
library code uses sampling over PDC-DMA, up to 1 msps tested.

Man do I feel stupid, long story short I did not think to check the example sketch untill now...

There are one thing I don't understand, how do I set the destination adress?
If I want the ADC PDC/DMA to send its content to say the UART, do you know how to do that?

Thanks for pointing me in the right direction.

I can't find an easy way to transfer per2per (peripheral to peripheral) in atmel's data sheet. There is a PDC, but it's only supports per2mem:

The Peripheral DMA Controller (PDC) transfers data between on-chip serial peripherals and the
on- and/or off-chip memories.

Another feature, closest to bare metal DMAC doesn't include ADC in it's supported channel list.
Probably, it coulld be done by programming two independent PDC channels, one for ADC->mem trasnfer, and another mem->USART. So, management two channels pointing to same memory buffers may be tricky. Last time I tried to program mem->USART PDC, I had to overwrite an arduino core files, to "loose" USART from Serial predefined interrupt sources.
http://forum.arduino.cc/index.php?topic=267115.0

Okey I see, I will see if that works out.
I have never done anything outside arduino and I'm slowly working my way towards Atmel studio 6.2 and to be able to do without arduino IDE completely, but when we talk about memory in this case.

This forum does some weird things sometimes...

But when reading the data sheet I never understand how one would configure a independent DMA, I don't understand how to set the addresses. But I'll work on it some more and get back here with the result.

How about a FIFO buffer.

//I might have misread what you mean but I get it now, PDC not DMA.

I don't quite understand the radix DMA example,

#define INP_BUFF FFT_SIZE //2048

volatile uint16_t sptr = 0 ;
volatile int16_t flag = 0 ;
uint16_t inp[2][INP_BUFF] = { 0}; // DMA likes ping-pongs buffer

and in adc_setup:

ADC->ADC_RPR = (uint32_t) inp[0]; // Receive Pointer Register - DMA buffer
ADC->ADC_RCR = INP_BUFF; // Receive Counter Register
ADC->ADC_RNPR = (uint32_t) inp[1]; // Receive Next Pointer Register - next DMA buffer
ADC->ADC_RNCR = INP_BUFF; // Receive Next Counter Register
ADC->ADC_PTCR = 1; //Transfer Control Register

and in adc_handler:

if((adc_get_status(ADC) & ADC_ISR_RXBUFF) == ADC_ISR_RXBUFF) {
flag = ++sptr;
sptr &= 0x01;
ADC->ADC_RNPR = (uint32_t) inp[sptr];
ADC->ADC_RNCR = INP_BUFF;
}

I dont understand how inp[] is used, is inp[] not a 2x2048 byte buffer?
Does the ADC fill up 2048 uint16_t with readings or is inp[0] one reading and inp[1] the next reading?
As how to the FFT function uses inp[]... I don't get how I should regard the buffer.

What I don't get is how should I read from the buffer, should I just print it out at wil or is there some timing or check for content that should be performed?

I dont understand how inp[] is used, is inp[] not a 2x2048 byte buffer?

It is 2x2048, one is inp[0][2048] and another inp[1][2048]. You may read more some books on array definition in C/C++.

Does the ADC fill up 2048 uint16_t with readings or is inp[0] one reading and inp[1] the next reading?

ADC fills up one array, that it was pointed to in initial setup :

ADC->ADC_RPR  =  (uint32_t) inp[0]; // Receive Pointer Register - DMA buffer

someone could explain it better than me, but again its C language, you can assign a pointer to memory address, inp[0] in this case a pointer to first cell in array number one. ADC starts filling data from this first address and continue up to the end. When PDC catch an events that array is complete, it's call an interrupt.
Inside an interrupt address switching happened, if it was [0] array filled up, than [1] is next, and vice - versa.
More nuances with C/C++:

flag = ++sptr; 
    sptr &=  0x01;

variable sptr is incremented each time when interrupt is called, but after sptr &= 0x01; it keeps only 0 or 1, so its never goes up to 2, 3, etc. Same if you do: if( sptr > 1) sptr = 0;

As how to the FFT function uses inp[]... I don't get how I should regard the buffer.

What I don't get is how should I read from the buffer, should I just print it out at wil or is there some timing or check for content that should be performed?

Strange questions, you should know what for do you need samples, before you start your project. The only things to keep in mind, you should process data in array before second one is filling, otherwise data is gonna to be overwritten.
Math is simple , conversion rate x array size = gives an amount of time . How do you process data is up to the logical context you are trying to solve, send to PC, filter, discard, switch blinking led or whatever.

Aha, I did not understand that the DMA does not get called before the buffer is full. It looked like the handler switched inp[] each sample, I'm sorry for my sometimes confused questions. I'm trying to do to many things at one time.

What I am trying to do is simply to send the buffer content to a PC, however that will take me some time to figure out. Although I get how arrays look like in structure I obviously does not get how to handle them in software.

One question that would help, what does signal that the buffer is full?

Aha, I did not understand that the DMA does not get called before the buffer is full.

I'd correct, that PDC ( not DMAC ) actually get called after each sample, but it goes in hardware interface, and PDC does transfer value between ADC output register and memory cell in one of arras. What you mean, is probably software interrupt handler, and thats right its called only once at the end of each of arrays.
There is a variable "flag", and it's received a value of "sptr" just before "sptr" resets down to 0 or 1, so "flag" keeps 1 or 2.
The reason why I introduced "flag" is to pass a message to main "loop" subroutine about one array is full, and inform which one. It 'd be possible to use "sptr" in the same role, but more code would be necessary, as "sptr" pointed to array that "is filing up " at the moment , not the ready one. You need previous array number, so peace of code like:

 if ( sptr != old valueSptr ) {
   int16_t indx_a  = sptr - 1;
         if ( indx_a  < 0 ) indx_a = 1;
 ////
 //// Here sampling data you process / send 
 ////
oldSptr = sptr;

And compare with:

  if ( flag )
  {   
   uint16_t indx_a = flag -1;
 ///
 //// Here sampling data you process / send 
 ///
 flag = 0;

Okey, I think I got that. Thanks for explaining.

I'm facing some difficulties in how to send the values, I have seen some use of SerialUSB.write() but I don't know enough about USB to receive that, although I'm working to learn how to implement USB HID and/or CDC in order to utilize it in a home made DAQ.

I do get that I facing some trouble regarding sending 16bit values over a 8bit serial port, but I can't even use Serial.write. I have been awake for some time and I might be missing something but I will look it over in the morning.

Thanks for you help

Is there a reason way I can't print out a uint16_t value over Serial.print but can print a int value?

If my ADC reads 2001 and I put it in a uint16_t the compiler complains about something regarding the size of the uint16_t buffer, but copying the value to a int buffer then it works...

and when used Serial.write and try to interpret it with matlab i get a stream of 227, 7, 226, 7 etc.
This has become a brick-wall in my C learning and I can't figure out what I am missing.

All I want to do is to set up the ADC with PDC and continuously write the value out on the Serial port as with Serial.print, I am reading about USB but it will take a while to understand enough.
I have a sketch to go with matlab where I can access different functions in the arduino through sending a string with commands and as soon as I can figure out how to do the above I will write a function so that matlab can call for the arduino to start sending values for a certain amount of time(or something).

Have you try "arduino send integer over serial" on google?
http://forum.arduino.cc/index.php?topic=39873.0
http://arduinobasics.blogspot.ca/2012/07/arduino-basics-simple-arduino-serial.html

Your questions are too general. I'd suggest, first to do research, make some tests with code samples posted on-line,
and then come back with your code-sketch that is "almost" working, but you need help to fix a specific issue or get advise on improvement.
Anyway, I have no idea what is matlab.

Kind of funny, I have searched for hours on end reading on how to send large values over serial.
But thanks for the links, most helpful.
I sometimes gets kind of stumped over the search terms used on google, I have searched for sending large values over serial, searching for sending integer values gives very different results. Now that might not be so strange but I have searched for days on end for info on how to use SAM3X8E registers and not found anything, then I stumbled on this by accident while reading about a completely different subject:
PIO:
http://codetron.net/arduino-due-in-atmel-studio-using-c-led-blinking/
UART:
http://codetron.net/uart-interface-sam3x8e-arduino-due/

By the way, I just found this, Simple printf for SAM microcontrollers:
http://www.infidigm.net/projects/sam_printf/

This stuff with PDC is really deep water for my level of knowledge, but I'll get back here when I have some actual code to post and ask about.

Thanks

//Am I right in thinking that if using SerialUSB.write there are no problem with 16bit values being sent?
Provided I know how to receive the USB stream.

This do not have anything to do with the subject but is this right?

boolean mySwitch=false;

/* If mySwitch is true, then populate the num1 variable
otherwise populate the num2 variable*/

if(**!**mySwitch)
{
num1=(num110)+(byteRead-48);
}
else
{
num2=(num2
10)+(byteRead-48);
}

I interpret if(!mySwitch) as if(not mySwitch) as if mySwitch was not true, how can !mySwitch mean that mySwitch is true?

Am I right in thinking that if using SerialUSB.write there are no problem with 16bit values being sent?

My guess, you are not. Serial was defined by ASCII to deal with bytes, 8-bit unsigned values. To send anything else over serial, like int16 int32 uintxx long float etc. you have to split a variable down to a few 8-bits, and than combine bytes back into variable at the other end. In other words create a communication protocol, that may include additional logical subroutine to initiate-keep-close a communication sessions.
It doesn't matter what is the hardware media you are using, USB RS232 BlueTooth etc.

I had been sloppy, when I finally googled "pingpong-buffer" and read about that it all made perfect sense.
I have a working code such as this:

void DMA_fcn()  //function called in loop after 'option = Serial.readStringUntil('|');', its one of a few _fcn
{
  while (option == "DMA")
  {
    adc_start(ADC);
    num = Serial.parseInt();
    for (int i = num; i > 0; i--)
    {
      if ( flag )
      {   
        uint16_t idx = flag -1;
        for (i = 0; i < nume; i++)  // nume = INP_BUFF/FFT_SIZE = 2048
          Serial.write(inp[idx][i] >> 8);
          Serial.write(inp[idx][i] & 0xff);
      
        }
      }
      flag = 0;
    }
    adc_stop(ADC);
  }  
}
//besides that the code has all the ADC ADC_handler setup from your example(-adc_start(ADC);

with the idea to call DMA|10 to get 10x'buffer size', I may re-work the hole communication system when I've learned more about parsing strings.
Anyway, now I am thinking about how to receive the values most efficient.

I have a working code such as this:

I doubt its working.

    for (int i = num; i > 0; i--)
    {
      if ( flag )
      {   
        uint16_t idx = flag -1;
        for (i = 0; i < nume; i++)  // nume = INP_BUFF/FFT_SIZE = 2048

Using same variable name inside nested loop may exhibits totally insane behavior.

Well, it might look like a misstake. But num is num is not the same as nume.
I can't defend the choice of variable name but in my head it works out very clearly:)
num is the number of arrays to read to the PC and nume is 2047, to end up as 2048 samples in matlab.

Thank you very much for all help and the example, I would never had been able to do this my self this nor next year.