user46514: I want to get meteo sensors values, and turn avr based 16mhz arduino (i have mega, but that seems not matter alot vs uno) into multichannel oscilloscope.
Task details. Desired data rate is 8(uno) to 16(mega) analog channels divide by 4 to 16 reads per second. Extra adc "speed capacity" must be spent on summing up on arduino. Prescale is almost not needed. Each reading is 32bit, lsb is always zeroed. Plus there is 0xffffffff between packets (easiest binary proto, i really hate those ascii low-quality slow shit, but this is personal and offtopic). So now you got the setup and purpose, lest get down to my simple sketch
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


// packet starts after indicator and goes before next such indicator.
const long packetStartIndicator = 0xFFFFFFFFl;

// values are fixed point ints 0..65534 (with LSB always cleared)
// such descision is made because least significant bit almast always == noise;
// also its just easist pck splitting scheme
const long packetValueMask = 0xFFFFFFFEl;

const int numPins = 8;

long sensorValues[numPins+1];

// TODO: configure this from host via serial (inside setup)
int pinNumbers[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8};
//int pinNumbers[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15};


// 1 reading is 10 bit. we can make 2^6==64 readings and sum them up (to top up to full 16 bit, to make kind of digital expoure)
// upd. 1 reading is counted as 16 bit, for host convenience (no matter or real adc)
// sum up like 256 of 16-bit readings to get 24bit value. send as 32bit long variable.
const int adcOrder = 10;
const int readingsOrder = 8;
const int targetOrder = 24;
const int numReadings = 1 << readingsOrder; //64;


void setup() {
  // TODO: reset ADCSRA, or it would not work. Also: get clue on free run mode
// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
// for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
//ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
//ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
//ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz


//sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); sbi(ADCSRA,ADPS0); // set prescale to 32 for 38.5 KHz
//sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); cbi(ADCSRA,ADPS0); // set prescale to 16 for 76.9 KHz
//cbi(ADCSRA,ADPS2); sbi(ADCSRA,ADPS1); sbi(ADCSRA,ADPS0); // set prescale to 8 for 153.8 KHz


  sensorValues[numPins] = packetStartIndicator;
  //analogReadResolution(10);
  Serial.begin(115200, SERIAL_8N1);
  //Serial.begin(250000, SERIAL_8N1);
  //Serial.begin(500000, SERIAL_8N1); 
}


void zero_values() {
  int i;
  for(i=0; i<numPins; i++) {
    sensorValues[i] = 0;
  }
}

void clear_lsb() {
  int i;
  int shiftOrder = targetOrder - (adcOrder + readingsOrder);
  for(i=0; i<numPins; i++) {
    sensorValues[i] <<= shiftOrder;
    sensorValues[i] &= packetValueMask;
  }
}

void serial_write() {
  Serial.write( (uint8_t*)sensorValues, sizeof(long)*(numPins+1) );
}

void loop() {
  int i, j; 
  zero_values();
  for(i=0; i<numPins; i++) {
    for (j=0;j<numReadings; j++) {
      sensorValues[i] += analogRead(pinNumbers[i]);
    }
  }
  clear_lsb();
  serial_write();
}

I am weak with reading avr datasheets and lacking of knowledge on internals. My question is tied with my desire to switch it to freerun mode. I really dislike analogRead, seems it was written by real juniors, and is real slow. AFAIK free run mode is something when you have interrupt function running when conversion is done. I feel (dont know but really feel) that working with serial inside interrupt is a bad idea. How, in somple words, this can be reworked to event-based ISR with sending over serial when you would encounter inside your interrupt following: currentPin == lastPin && currentReading == numReading means you have summed up desired bumber of readings, and this is last pin, so its time to post it over serial.

user4143: In the Arduino environment sending data over serial inside an interrupt is seldom a good idea. That's not to say it's impossible, you just need to keep certain caveats in mind.
The chief of which is that when the TX buffer fills up everything will lock up.
So with that in mind, if you can guarantee that all your data from one interrupt will be completely sent out before the next interrupt occurs then sending serial in an interrupt can be used.
And yes, analogRead(), like many things in the Arduino API, is not fast. It's not intended to be fast. It is, though, intended to be simple.  And also like many things in the Arduino API it's easy to out-grow them.
I am not familiar with the Atmel ADC registers (preferring PIC32 to AVR any day...) but looking at the datasheet I can see a few points of interest.

First set the trigger source to "free running" (ADCSRB):



Bit 2:0 – ADTS2:0: ADC Auto Trigger Source

If ADATE in ADCSRA is written to one, the value of these bits selects which source will trigger an ADC conversion. If ADATE is cleared, the ADTS2:0 settings will have no effect. A conversion will be triggered by the rising edge of
  the selected Interrupt Flag. Note that switching from a trigger source that is cleared to a trigger source that is set, will generate a positive edge on the trigger signal. If ADEN in ADCSRA is set, this will start a conversion. Switching
  to Free Running mode (ADTS[2:0]=0) will not cause a trigger event, even if the ADC Interrupt Flag is set.

Then set it to use the trigger source for starting conversions (ADCSRA):


Bit 5 – ADATE: ADC Auto Trigger Enable

When this bit is written to one, Auto Triggering of the ADC is enabled. The ADC will start a conversion on a positive
  edge of the selected trigger signal. The trigger source is selected by setting the ADC Trigger Select bits, ADTS in
  ADCSRB.

And enable interrupts (ADCSRA):


Bit 3 – ADIE: ADC Interrupt Enable

When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Interrupt is activated

Alternatively you could set it to use a timer for the trigger source so you have finer control over when a conversion is performed. That will help you to ensure that all of the previous data set has been sent over serial before the next interrupt occurs.

46514: <p>I want to get meteo sensors values, and turn avr based 16mhz arduino (i have mega, but that seems not matter alot vs uno) into multichannel oscilloscope.</p>

<p>Task details. Desired data rate is 8(uno) to 16(mega) analog channels divide by 4 to 16 reads per second. Extra adc "speed capacity" must be spent on summing up on arduino. Prescale is almost not needed. Each reading is 32bit, lsb is always zeroed. Plus there is 0xffffffff between packets (easiest binary proto, i really hate those ascii low-quality slow shit, but this is personal and offtopic). So now you got the setup and purpose, lest get down to my simple sketch</p>

<pre><code>// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &amp;= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


// packet starts after indicator and goes before next such indicator.
const long packetStartIndicator = 0xFFFFFFFFl;

// values are fixed point ints 0..65534 (with LSB always cleared)
// such descision is made because least significant bit almast always == noise;
// also its just easist pck splitting scheme
const long packetValueMask = 0xFFFFFFFEl;

const int numPins = 8;

long sensorValues[numPins+1];

// TODO: configure this from host via serial (inside setup)
int pinNumbers[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8};
//int pinNumbers[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15};


// 1 reading is 10 bit. we can make 2^6==64 readings and sum them up (to top up to full 16 bit, to make kind of digital expoure)
// upd. 1 reading is counted as 16 bit, for host convenience (no matter or real adc)
// sum up like 256 of 16-bit readings to get 24bit value. send as 32bit long variable.
const int adcOrder = 10;
const int readingsOrder = 8;
const int targetOrder = 24;
const int numReadings = 1 &lt;&lt; readingsOrder; //64;


void setup() {
  // TODO: reset ADCSRA, or it would not work. Also: get clue on free run mode
// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
// for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
//ADCSRA |= (1 &lt;&lt; ADPS2) | (1 &lt;&lt; ADPS0);    // 32 prescaler for 38.5 KHz
//ADCSRA |= (1 &lt;&lt; ADPS2);                     // 16 prescaler for 76.9 KHz
//ADCSRA |= (1 &lt;&lt; ADPS1) | (1 &lt;&lt; ADPS0);    // 8 prescaler for 153.8 KHz


//sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); sbi(ADCSRA,ADPS0); // set prescale to 32 for 38.5 KHz
//sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); cbi(ADCSRA,ADPS0); // set prescale to 16 for 76.9 KHz
//cbi(ADCSRA,ADPS2); sbi(ADCSRA,ADPS1); sbi(ADCSRA,ADPS0); // set prescale to 8 for 153.8 KHz


  sensorValues[numPins] = packetStartIndicator;
  //analogReadResolution(10);
  Serial.begin(115200, SERIAL_8N1);
  //Serial.begin(250000, SERIAL_8N1);
  //Serial.begin(500000, SERIAL_8N1); 
}


void zero_values() {
  int i;
  for(i=0; i&lt;numPins; i++) {
    sensorValues[i] = 0;
  }
}

void clear_lsb() {
  int i;
  int shiftOrder = targetOrder - (adcOrder + readingsOrder);
  for(i=0; i&lt;numPins; i++) {
    sensorValues[i] &lt;&lt;= shiftOrder;
    sensorValues[i] &amp;= packetValueMask;
  }
}

void serial_write() {
  Serial.write( (uint8_t*)sensorValues, sizeof(long)*(numPins+1) );
}

void loop() {
  int i, j; 
  zero_values();
  for(i=0; i&lt;numPins; i++) {
    for (j=0;j&lt;numReadings; j++) {
      sensorValues[i] += analogRead(pinNumbers[i]);
    }
  }
  clear_lsb();
  serial_write();
}
</code></pre>

<p>I am weak with reading avr datasheets and lacking of knowledge on internals. My question is tied with my desire to switch it to freerun mode. I really dislike analogRead, seems it was written by real juniors, and is real slow. AFAIK free run mode is something when you have interrupt function running when conversion is done. I feel (dont know but really feel) that working with serial inside interrupt is a bad idea. How, in somple words, this can be reworked to event-based ISR with sending over serial when you would encounter inside your interrupt following: <code>currentPin == lastPin &amp;&amp; currentReading == numReading</code> means <em>you have summed up desired bumber of readings, and this is last pin, so its time to post it over serial</em>.</p>
 4143: <p>In the Arduino environment sending data over serial inside an interrupt is seldom a good idea. That's not to say it's impossible, you just need to keep certain caveats in mind.</p>

<p>The chief of which is that when the TX buffer fills up everything will lock up.</p>

<p>So with that in mind, if you can <em>guarantee</em> that all your data from one interrupt will be completely sent out before the next interrupt occurs then sending serial in an interrupt can be used.</p>

<p>And yes, <code>analogRead()</code>, like many things in the Arduino API, is not fast. It's not intended to be fast. It is, though, intended to be simple.  And also like many things in the Arduino API it's easy to out-grow them.</p>

<p>I am not familiar with the Atmel ADC registers (preferring PIC32 to AVR any day...) but looking at the datasheet I can see a few points of interest.</p>

<ul>
<li>First set the trigger source to "free running" (ADCSRB):</li>
</ul>

<blockquote>
  <ul>
  <li>Bit 2:0 – ADTS2:0: ADC Auto Trigger Source</li>
  </ul>
  
  <p>If ADATE in ADCSRA is written to one, the value of these bits selects which source will trigger an ADC conversion. If ADATE is cleared, the ADTS2:0 settings will have no effect. A conversion will be triggered by the rising edge of
  the selected Interrupt Flag. Note that switching from a trigger source that is cleared to a trigger source that is set, will generate a positive edge on the trigger signal. If ADEN in ADCSRA is set, this will start a conversion. Switching
  to Free Running mode (ADTS[2:0]=0) will not cause a trigger event, even if the ADC Interrupt Flag is set.</p>
</blockquote>

<p>Then set it to use the trigger source for starting conversions (ADCSRA):</p>

<blockquote>
  <ul>
  <li>Bit 5 – ADATE: ADC Auto Trigger Enable</li>
  </ul>
  
  <p>When this bit is written to one, Auto Triggering of the ADC is enabled. The ADC will start a conversion on a positive
  edge of the selected trigger signal. The trigger source is selected by setting the ADC Trigger Select bits, ADTS in
  ADCSRB.</p>
</blockquote>

<p>And enable interrupts (ADCSRA):</p>

<blockquote>
  <ul>
  <li>Bit 3 – ADIE: ADC Interrupt Enable</li>
  </ul>
  
  <p>When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Interrupt is activated</p>
</blockquote>

<p>Alternatively you could set it to use a timer for the trigger source so you have finer control over when a conversion is performed. That will help you to ensure that all of the previous data set has been sent over serial before the next interrupt occurs.</p>
