Go Down

Topic: optimizing USART communication on Arduino Due (Read 341 times) previous topic - next topic

dberezin

I'm writing a code in Arduino Due to generate a signal through the DAC as the input of a circuit, read through the ADC the output of the circuit and send through serial both the input and output values, so I can graph both signals on the Computer. I have the following:

Code: [Select]

#define __SAM3X8E__

// Stores data value read from ADC
int analog_data;
int wave = 1;
int i = 0;
String data;

void serialEvent(){
  while (Serial.available()){
    data = Serial.readString();
    if (data== "s"){
      wave = 0;
      }
    else if (data == "t"){
      wave=1;
      }
    }
  }

void setup(void) {
  Serial.begin(57600);   
  ADC->ADC_MR = 0x00000000 ; // ADC full speed
  ADC->ADC_IDR = 0xFFFFFFFF ; // disable ADC interrupts
 
  ADC->ADC_CHER = 0x00000001 << 7 ; // enable the ADC, just ch0
 
  pmc_enable_periph_clk (DACC_INTERFACE_ID) ; // start clocking DACC

  DACC->DACC_IDR = 0xFFFFFFFF ; // no interrupts
  DACC->DACC_CHER = 0x00000001 ; // enable DACC chan0
}

void loop(void) {
    // start first ADC conversion
    ADC->ADC_CR = 0x00000002 ;
   
    // Read the value from ADC last conversion data register.
    analog_data = ADC->ADC_LCDR & 0x00000FFF ;

    // Write the value just read to the DACC conversion data register.
    DACC->DACC_CDR = sintab[wave][i];
    i++;

    if (i>=512){
      i-=512;     
      }
}




I ommited the lookup tables, both for sine and triangle waves, but that's working fine. The code send lookup table values to DAC (512 value tables) and read the ADC. It is able of generating ~750Hz signals. The problem is that if I add
Code: [Select]
Serial.write(analog_data) the code slows down from 750 to a few hertz. Whats the efficient way to configure the USART registers of the Arduino Due? Should I gather the data in a buffer and send it every once in a while or send data by data?

Please, if possible, help me with code examples.

ard_newbie


The general rule to lower the CPU load  with a DUE (Sam3x8e) is to leverage its DMA feature. As you will see by reading Sam3x datasheet (page 504), both DAC and ADC PDC DMA are provided and relatively easy to implement (plus an UART PDC DMA).

In the DUE sub forum, you can find example sketches with ADC DMA and DAC DMA. Experiment step by step a DAC DMA code, then an ADC DMA code, then mix an ADC and a DAC DMA code once you have understood how to trigger a PDC DMA at the right pace with a timer.

dberezin

It will be good to optimize the DAC and ADC, but currently my bottleneck is adding the serial. Is there a way to program the UART throughDMA? I barely know what DMA is

FantomT

Quote
Additionally, there is a native USB-serial port on the SAM3X chip, SerialUSB'.
https://www.arduino.cc/reference/en/language/functions/communication/serial/

You may increase baud-rate, to 115200, 230400 or 460800:

  Serial.begin(57600);   
 

dberezin

https://www.arduino.cc/reference/en/language/functions/communication/serial/

You may increase baud-rate, to 115200, 230400 or 460800:

  Serial.begin(57600);   
 
The bottleneck is not the baudrate, but the time it takes to initialize the serial function. I am using a DMA serial library now and it is way faster at the same baudrate. The problem is that I don't manage to create RX driven interrupts for that library. Actually I'm just sending data, haven't managed to receive yet.

The library is https://github.com/rblilja/DmaSerial

FantomT

I don't think serial-dma is gonna to solve your problem. DMA is needed when data rate is higher than arduino could handle over interrupt driven function. For example, you need ADC->DMA when sampling rate is above 200-300 kHz, it's for 12-bits data about 3 Mega baud. Same with DAC. For very slow data rate (1 kHz - is very slow) arduino could run everything ( adc, dac, uart) in interrupt scheduled functions, w/o DMA. Serial even could never get 3 Mega baud, so arduino internal Serial.write() is more than sufficient.

 What  you need, is to correctly organize data flow. Two data array - one for adc, and another for dac. Than, Timer interrupt that trigger dac & adc conversion on regular bases, lets say 1 kHz. Inside timer interrupt subroutine - a few commands line - start adc/ start dac conversion, read last adc result to adc buffer, increment index and check for index overflow.
Serial is managed inside main loop, transferring data from adc array - to PC, and checking data available to write into dac buffer array. Serial could not interfere with timer interrupt in this case, dac would always be written - adc read in exact 1 kHz time frame. If serial link would have issue with baud-rate, than simply not all data would be transferred to PC or not all data get into DAC buffer.

Go Up