Magician:
I would look for alternative, for example SPI is supported by PDC, so you can add parallel to serial external register IC, depends on bit's width 8-16-32 etc. SPI driven with 42MHz clock may provide over 5 mega read/sec for 8- bits register
Thank you very much, that helped. In fact, my ADC also is sending out the data as serial data clocked at around 28Mhz, 18 bit and each bit valid at rising clock edge and without any delay between each 18 bit transfers. Clock is generated on the ADC board fixed. So it would be a two wire setup.
Do you think one could abuse the Due as a SPI slave to sample that kind of data or am I missing some obvious restriction? I would also be happy with not sending out the data but logging it to a SD Card using the SD Fat library which supports SPI with DMA on Due but i have the feeling there will be more complications.
Do you think one could abuse the Due as a SPI slave to sample that kind of data or am I missing some obvious restriction?
AFAIK, DUE doesn't support 18-bits. Section 33.2 in SAM3X datasheet:
• Master or Slave Serial Peripheral Bus Interface
– 8- to 16-bit Programmable Data Length Per Chip Select
– Programmable Phase and Polarity Per Chip Select
– Programmable Transfer Delay Between Consecutive Transfers and Delay Before SPI
Clock per Chip Select
– Programmable Delay Between Chip Selects
– Selectable Mode Fault Detection
• Connection to DMA Channel Capabilities Optimizes Data Transfers
– One channel for the Receiver, One Channel for the Transmitter
if I got it right, by using the code underneath, I'll be using the maximum sampling rate possible (the quickest). Is there a way to define a precise sampling rate? (i need 44,1kHz).
As far as I know, as you have to make a reading every 22,67 us and the only time reference you have is the micros(), that is an integer, the answer is "no".
Magician:
AFAIK, DUE doesn't support 18-bits. Section 33.2 in SAM3X datasheet:
Thank you, I am aware of that. But as the bitflow is continous, I would just save the bytes one after another and let Matlab figure out which bits belong to which full 18bit ADC read.
The missing piece of information for me is:
Would the SAM3X be fine with continous reads with only two lines - Clock and Data - while the Arduinos outputline would just be pulled to ground and chipselect on a fixed potential too?
Would the SAM3X be fine with continous reads with only two lines - Clock and Data - while the Arduinos outputline would just be pulled to ground and chipselect on a fixed potential too?
No, SPI is 3-wire interface.
Your idea is non-sense, no way to shift in 18-bits on 16-bits interface.
You better to post ADC part name, link to datasheet, explain why not 16 or 24 bits is important, and better in another thread, as it has nothing to do with analogread.
I think this one is very important bugfix for the original code. With the original code I had glitches on my charts. Here is the picture:
In the begining of each 256-samples block there are three samples "from the future", they are supposed to be 4 blocks ahead. There also was zero samples in the beginning of the chart:
I think what happens here is the buffer is being sent while ADC is writing in it.
After I've applied the fix from this comment the problem's gone.
Thank you, @madrang!
madrang:
ADC->ADC_RPR=(uint32_t)buf[0]; // DMA buffer
ADC->ADC_RCR=256;
ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
ADC->ADC_RNCR=256;
bufn=obufn=1;
I'm not sure, but it look like the Due is using buffer 0 for writing and reserving buffer 1 as the next buffer to be used.
If it is the case there is 2 buffer in use.
while(obufn==bufn); // wait for buffer to be full
This line should be
while((obufn + 1)%4==bufn); // wait for buffer to be full
Also why start at buffer 1 ??
bufn=obufn=1;
Would be better to start at 0.
bufn=1;
obufn=0;
Not sure if i understood the code properly, i hope someone can tell me more about this.
Hello! I'm very new in the Arduino world. I'm trying to adapt Stimmer's code to get data from two channels instead of one, but I'm a little bit confused. Can anyone help me?
#undef HID_ENABLED
// Arduino Due ADC->DMA->USB 1MSPS
// by stimmer
// Input: Analog in A0
// Output: Raw stream of uint16_t in range 0-4095 on Native USB Serial/ACM
// on linux, to stop the OS cooking your data:
// stty -F /dev/ttyACM0 raw -iexten -echo -echoe -echok -echoctl -echoke -onlcr
volatile int bufn,obufn;
uint16_t buf[4][256]; // 4 buffers of 256 readings
void ADC_Handler(){ // move DMA pointers to next buffer
int f=ADC->ADC_ISR;
if (f&(1<<27)){
bufn=(bufn+1)&3;
ADC->ADC_RNPR=(uint32_t)buf[bufn];
ADC->ADC_RNCR=256;
}
}
void setup(){
SerialUSB.begin(0);
while(!SerialUSB);
pmc_enable_periph_clk(ID_ADC);
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
ADC->ADC_MR |=0x80; // free running
ADC->ADC_CHER=0x80;
NVIC_EnableIRQ(ADC_IRQn);
ADC->ADC_IDR=~(1<<27);
ADC->ADC_IER=1<<27;
ADC->ADC_RPR=(uint32_t)buf[0]; // DMA buffer
ADC->ADC_RCR=256;
ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
ADC->ADC_RNCR=256;
bufn=obufn=1;
ADC->ADC_PTCR=1;
ADC->ADC_CR=2;
}
void loop(){
while(obufn==bufn); // wait for buffer to be full
SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
obufn=(obufn+1)&3;
}
I'm doing a project where I need at least 200 kHz of sample rate for each channel, but 100 kHz would be alright too.
I couldn't find anything that answers my questions.
Why not it is all there.
Can you be more specific?
OK.
The A/D will not go that fast.
If you could get it to go that fast then what are you going to do with the data, there is not enough memory to store very much and you can't get the SD card to read it at that rate. It is too fast to send it out of the serial port.
And I want to ask you if you know how to get data from two channels instead of one. I want to have the max speed achievable, if it's 100 khz per channel it would be great, but it would be useful too to have this code that connects to the PC and Python for 2 channels
I find this information quite useful! Thank you!
I tried sampling the input voltages to pins A0 and A8 of my Arduino DUE, and I needed 3 us to get both samples. Which is good enough for my application (> 300 kSa/s on 2 pins).
Now, the next I need to do is to sample 2 pins (A1, A9) just once, and then continuosly sample A0 and A8.
I tried two ways
I use analogRead(A1) , analogRead(A9), however, the sampling rate of A0 and A8 decreases (which I dont fully understand why)
I enable also A1 and A9
ADC->ADC_MR |= 0x80; //set free running mode on ADC
ADC->ADC_CHER = 0xcc0; //enable ADC on pins A0,1,8,9
However, of course also the sampling rate will decrease.
My question: Is there a way to "disable" pins A1 and A9 after reading them once?
Or do you have a better idea to keep above 300 kSa/s when reading both A0,A8?
I thouhg DUE
I'm an Arduino beginner and I would need your help with the code.
Could you please tell me how to get timestamps to the voltage values and send them over to the python script? as a bundle?
like
1ms , 0V
2ms, 0.1V
...
also I'm getting a sample rate of 660kHz only. Do you know how to speed it up?
Before that, I have a different problem. With stimmer's original code, I am only receiving zeros on python with a frequency generator. And that problem hasn't been there before. First it was all fine.
The line
ADC->ADC_PTCR=1
seems to let the Arduino crash. (I know that because when it is commented then the loop runs.)
The problem is, I don't receive any data from the frequency generator that I have connected to pin A0 of the due.
I have the following slightly altered code (for debugging purposes):
#undef HID_ENABLED
// Arduino Due ADC->DMA->USB 1MSPS
// by stimmer
// from http://forum.arduino.cc/index.php?topic=137635.msg1136315#msg1136315
// Input: Analog in A0
// Output: Raw stream of uint16_t in range 0-4095 on Native USB Serial/ACM
//fast@fast:~/Documents/IP$ nautilus ~/.arduino15/packages/arduino/hardware/sam/1.6.11/cores/arduino
// on linux, to stop the OS cooking your data:
// stty -F /dev/ttyACM0 raw -iexten -echo -echoe -echok -echoctl -echoke -onlcr
// screen /dev/ttyACM0^C
// changes and prints terminal line settings
volatile int bufn,obufn;
uint16_t buf[4][256]; // 4 buffers of 256 readings
void ADC_Handler(){ // move DMA pointers to next buffer
Serial.println("Start interrupt handler");
int f=ADC->ADC_ISR; // read the interrupt status register
if (f&(1<<27)){ // check the bit "endrx" in the status register, if endrx bit == 1 then execute body
// 1 = the receive counter register has reached 0 since the last write in ADC_RCR or ADC_RNCR
/// set up the "next pointer register"
bufn=(bufn+1)&3; // wht does this line do?
ADC->ADC_RNPR=(uint32_t)buf[bufn]; // RPNR = Receive Next Pointer Register points to
ADC->ADC_RNCR=256; // next count register is set to 256
}
}
void setup(){
pinMode(52, OUTPUT);
digitalWrite(52,HIGH);
Serial.begin(115200); // open a serialUSB connection
//Serial.begin(115200);
Serial.println("wait for SerialUSB");
while(!Serial); // wait for serialUSB, works only when connected to the native port
pmc_enable_periph_clk(ID_ADC);
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
ADC->ADC_MR |=0x80; // free running, set bit 8 to 1 in mode register
ADC->ADC_CHER=0x80; //channel enable register, set bit 8 to 1, rest 0, meaning enable pin A0
NVIC_EnableIRQ(ADC_IRQn); // interrupt controller set to enable adc.
ADC->ADC_IDR=~(1<<27); // interrupt disable register, disables all interrupts but ENDRX
ADC->ADC_IER=1<<27; // interrupt enable register, enables only ENDRX
ADC->ADC_RPR=(uint32_t)buf[0]; // DMA buffer
ADC->ADC_RCR=256;
ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
ADC->ADC_RNCR=256; // and next counter is set to 256
bufn=obufn=1;
ADC->ADC_PTCR=1; // transfer control register for the DMA is set to enable receiver channel requests
// now that all things are set up, it is safe to start the ADC.....
ADC->ADC_CR=2;
}
void loop(){
while(obufn==bufn)
{
Serial.println("wait for buffer to be full");// wait for buffer to be full
}
Serial.println("buffer full");
for(int i=0; i<256;i++)
{
Serial.println(buf[obufn][i]);
}
//SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
Serial.println("buffer sent");
//Serial.write((uint8_t *)buf[obufn],512);
//obufn=(obufn+1)&3;
}
I wanted to check if the buffer contains no values or if the serialusb interface is failing.
When I checked the Serial Monitor it only showed: