The ADC is a "Successive Approximation" type ADC. It works by:
- Taking a snapshot of the incoming voltage in a small capacitor
- Generating a reference voltage
- Comparing the voltage in the capacitor to that reference voltage
- Refining the reference voltage
- Go back to 3 until you have the accuracy you desire.
There's lots of "time" involved there:
- The capacitor can only store the voltage accurately for so long before the self-discharge (leakage current) causes the voltage to drop (this defines the maximum amount of time you can take to do a reading)
- Each refining of the reference voltage and comparison thereof takes one ADC clock tick. There are a few "setup" clock ticks as well. This defines the minimum number of ADC clocks that you need to take a reading (13)
- The DAC and comparator take a certain amount of time to operate each clock tick - this limits the maximum clock frequency the ADC can run at.
So you have a "sweet spot" of speed (like the "goldilocks zone" of the solar system). Set the ADC too slow or try and get too high a resolution out of it and you lose accuracy due to voltage droop on the capacitor. Set it too fast and the DAC can't keep up and you lose accuracy due to the comparison voltage not being right.
Well, that's the internals. Then on top of that you have the Arduino API. That adds an entire other layer of complication.
analogRead() is a blocking operation. It:
- Congfigures the IO pin (if needed)
- Turns on the ADC (if needed)
- Configures the ADC MUX to the right channel
- Starts a conversion
- Sits there twiddling its thumbs for a while
- Reads the conversion result
- Returns it to you
And it does that (except maybe 1 and 2) every time you take a reading. That's fine for reading a potentiometer, or an LDR, etc. But rubbish when you want to do fast, time-based, readings.
Instead you need to push the envelope a little and step away from the Arduino API. Much of what the ADC does is done without intervention of the CPU. Manually configuring the ADC to read continuously and trigger an interrupt when the conversion is done, and then using that interrupt to grab the result of the comparison and start a new one (or use a timer interrupt to read the previous result and trigger a new reading) will give you much more control over the ADC and exactly when things happen.
So, now to answer your main question of "when during that 8us interval the actual reading takes place.", in the context of how the ADC works:
At the moment the SAH capacitor is detached from the MUX to start the comparison sequence.
When exactly is, though, is subjective. If you use the Arduino API (
analogRead()) then it's at some point near the start of the function call, but not at the start of it.
If you configure it manually and trigger it from within a timer interrupt, it's on the second (out of 13) falling edge of the ADC clock after ADSC has been set HIGH.
There are also "Free Running" and "Auto Trigger" modes whose timing is the same as for a single conversion. Note that the first conversion performed in any mode imposes a "run-in" clock sequence where the ADC MUX and reference voltage DAC are initialised.
All this timing can be found in figures 23-4 and 23-5 on page 209 of the ATMega328P datasheet. On page 210 there is a handy table that gives you how many ADC cycles from the start of a conversion the Sample And Hold occurs and how long the conversion takes in clock cycles.
For best throughput you want to use "Free Running" mode and read and store the ADC result in the interrupt the ADC triggers. For most accurate and controllable timing you want to use Auto Triggered mode with a timer for the trigger source, and again read the result in the ADC interrupt.