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:
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:
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
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:
header:
cpp:
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
Post a Comment