Playing with analog sequencer on DUE


hi.
trying more performance project, star playing analog sequencer on due base on:arduino-due-adc-channel-sequence.

i wrote little library simplify use (in attachement).

it work well, can access data of 12 inputs in 7 usec. take around 56 usec  using analogread. tried example:

code: [select]


#include <adc_seqr.h>

adc_seqr adc;
int reading[12];

void setup() {
  serial.begin(9600);
  adc.begin(0);
}

void loop() {
  unsigned long = micros();
  (int = 0; < 12 ; i++){
    reading[i] = adc.read(i);
  }
  unsigned long cronos = micros()-now;
  serial.println(cronos);
  delay(1000);
}

///////        sequencer data 12 analog input in 7 micro sec

//////          analogread()  take 56 micro sec

/*
int reading[12];

void setup() {
  serial.begin(9600);
}

void loop() {
  unsigned long = micros();
  (int = 0; < 12 ; i++){
    reading[i] = analogread(i);
  }
  unsigned long cronos = micros()-now;
  serial.println(cronos);
  delay(1000);
}*/



but now, go further, want add more feature. using master timer mck, interrupt call @ 164.0625khz using prescaler. smaller prescaler, faster sampling.

but if want go slower? in app, should plenty enough @ 100hz, slower.
it save again mcu usage , interrupt conflict.

i saw timmer0, pwm timer used...(sam3x data sheet, page 1333, adc_mr, trgsel) not explain how using or calculate it.

also, access data trough or loop, time consuming.. there shortcut possible copy entire array in buffer memory buffer ? like:

code: [select]

int buffer[12];
memcpy(global_adcounts_array,buffer*);



finnaly, should disalbe interrup while reading buffer, or somme other thing? change interrupt priority? idea... ?

and better understand mcu resource involved, there way evaluate time of adc interrupt request?

thanks .

nitrof

ok.

still working on library.

i not find way trigger sequencer other trough master clk... have go little bit slower...

anyway, keep working , add couple feature , add comment understand want i've done , other make comments upgrade code.

new add:
 -enable , disable sequencer
 -set prescaler
 -support read input a0 or 0

example:
code: [select]


#include <adc_seqr.h>

adc_seqr adc;
int reading[12];

void setup() {
  serial.begin(9600);
  adc.begin();
  //  set prescaler : adcclock = mck / ( (prescal+1) * 2 ), mck = 84mhz, range = 0-255, default = 255.
  adc.prescaler(150); //optionnal !
  
  //turn on , off sequencer if wanted (do no other change on settings in adc configuration...)
  adc.disable();  //optionnal !
  adc.enable(); //optionnal !
}

void loop() {
  unsigned long = micros();
  for (int = 0; < 12 ; i++){
    reading[i] = adc.read(i);
  }
  unsigned long cronos = micros()-now;

  for (int = 0; < 12 ; i++){
    serial.print(reading[i]);
    serial.println(" bits");
  }
  
  serial.print("get data in ");
  serial.println(cronos);
  delay(1000);
}

///////        sequencer data 12 analog input in 7 micro sec

//////          analogread()  take 56 micro sec

/*
int reading[12];

void setup() {
  serial.begin(9600);
}

void loop() {
  unsigned long = micros();
  for (int = 0; < 12 ; i++){
    reading[i] = analogread(i);
  }
  unsigned long cronos = micros()-now;
  serial.println(cronos);
  delay(1000);
}*/


header:
code: [select]
#ifndef adc_seqr_h
#define adc_seqr_h

#if (arduino >= 100)
    #include "arduino.h"
#else
    #include "wprogram.h"
#endif

#include <streaming.h>
  
class adc_seqr  {
private:
 static const int num_channels=12; //number of analog channel active
 static uint16_t global_adcounts_array[12];  // holds raw data analog digital
 
public:
 static void begin();
 static void adchandler();
 static uint16_t read(uint8_t pin);

 static void prescaler(uint32_t prsc);
 static void printsetup();
 static void enable();
 static void disable();
};

#endif


cpp:
code: [select]
#include "arduino.h"
#include "adc_seqr.h"

  
uint16_t adc_seqr::global_adcounts_array[] = {0};

/*sam3x adc_mr register, refer data sheet:43.7.2 adc mode register

 31 | 30 | 29 28 | 27 26 25 24
useq -  transfer  tracktim

 23 | 22 | 21 20 | 19 18 17 16
  anach -  settling   startup

| 15 14 13 12 11 10 9 8 |
 prescal

 7 | 6 | 5 | 4 | 321 | 0
freerun fwup  sleep   lowres  trgsel  trgen
*/

void adc_seqr::begin(){
  pmc_enable_periph_clk(id_adc);   //power management controller told turn on adc
  adc->adc_cr |=1; //reset adc
  adc->adc_mr= 0x9038ff00;  //default setting  adc_mr register :
  //useq = 1;
  //transfer = 1;
  //tracktim = 0;
  //anach = 0;
  //settling = 3;
  //startup = 8;
  //prescal = 255;
  //freerun = 0;
  //fwup = 0;
  //sleep = 0;
  //lowres = 0;
  //trgsel = 0;
  //trgen = 0;

  adc->adc_chdr=0xffffffff;   // disable channels  
  adc->adc_cher=0x3cff;       //   use channels a0 a11 //

  adc->adc_mr |=0x80000000;   //useq bit set, saying use sequence

  adc->adc_seqr1=0x01234567;  // use a0 a7 in order array
  adc->adc_seqr2=0x00dcba00;      //use a8 a11 following in order array
  
  nvic_enableirq(adc_irqn); // interrupt controller set enable adc.
  adc->adc_idr=~((1<<27)); // interrupt disable register, disables interrupts endrx
  adc->adc_ier=(1<<27);   // interrupt enable register, enables endrx
 
 // following dma controller registers peripheral
 // "receive buffer address"
 adc->adc_rpr=(uint32_t) global_adcounts_array;   // dma receive pointer register  points beginning of global_adcount
 // "receive count"
 adc->adc_rcr=num_channels;  //  receive counter set 12
 // "next-buffer address"
 adc->adc_rnpr=(uint32_t)global_adcounts_array; // next receive pointer register dma global_adcounts_arrayfer  points second set of data
 // , "next count"
 adc->adc_rncr=num_channels;   //  and next counter set 12
 // "transmit control register"
 adc->adc_ptcr=1;  // transfer control register dma set enable receiver channel requests
 // things set up, safe start adc.....
 adc->adc_mr |=0x80; // mode register of adc bit seven, free run, set free running. starts adc
 delay(2000); //for stability
}

void adc_seqr::printsetup(){
 serial << "mode register =            " << _hex(reg_adc_mr) << endl;
 serial << "channel enabled register = " << _hex(reg_adc_chsr) << endl;
 serial << "sequence register1 =       " << _hex(reg_adc_seqr1) << endl;
 serial << "sequence register2 =       " << _hex(reg_adc_seqr2) << endl;
 serial << "interrupts =               " << _hex(reg_adc_imr) << endl;
}

uint16_t adc_seqr::read(uint8_t pin){
 switch (pin) { //handle 0-11 , a0 a11 pin, if invalid return 0
 case 0:;
 case 1:;
 case 2:;
 case 3:;
 case 4:;
 case 5:;
 case 6:;
 case 7:;
 case 8:;
 case 9:;
 case 10:;
 case 11: break;
 case 54:;
 case 55:;
 case 56:;
 case 58:;
 case 59:;
 case 60:;
 case 61:;
 case 62:;
 case 63:;
 case 64:;
 case 65:;
 case 66 : pin = pin-54; break;
 default : return 0;
 }

   uint16_t result = 0;
 result = global_adcounts_array[pin];
 return result;
}

void adc_seqr::adchandler(){     // atod: re-initialize dma pointers , count
 
 int f=adc->adc_isr;  //   read interrupt status register
 if (f & (1<<27)){ /// check bit "endrx"  in status register
 /// set "next pointer register"
 adc->adc_rnpr=(uint32_t)global_adcounts_array;  // "receive next pointer" register set global_adcounts_array
 // set "next count"
 adc->adc_rncr=num_channels;  // "receive next" counter set 12
 }
}

void adc_seqr::prescaler(uint32_t prsc){
 adc->adc_mr &=0xffff00ff;   //mode register "prescale" zeroed out.
 adc->adc_mr |= prsc << 8;  //setup prescale frequency
}

void adc_seqr::enable(){
 adc->adc_mr |= 0x80000000; //turn on bit 32, sequencer enable
}

void adc_seqr::disable(){
 adc->adc_mr &= 0x7fffffff; //turn off bit 32, sequencer disable
}

  //interrupt handler
void adc_handler(){
    adc_seqr::adchandler();
}


Arduino Forum > Products > Arduino Due (Moderator: fabioc84) > Playing with analog sequencer on DUE


arduino

Comments

Popular posts from this blog

DHT11 Time out error using v0.4.1library

Sketch upload fails with Java error (___REMOVE___/bin/avrdude)!

Arduino Uno + KTY81/210 temperature sensor