Motivation

Der STM32F411 (Blackpill) ist ein leistungsfähiger 32-Bit μC auf ARM-Cortex-M4-Basis mit einer Taktfrequenz von bis zu 100 MHz. Er besitzt einen schnellen 12-Bit-ADC, der nominal bis zu 2,4 MSPS schafft. Beim Blackpill sind 10 ADC-Kanäle heraus geführt. Es lassen sich Konvertierungssequenzen von bis zu 16 Kanälen vorprogrammieren, die kontinuierlich wiederholt werden können. Die Messwerte lassen sich per DMA ohne Zutun der CPU ablegen, die während der Wandlungszeiten schon mit de Datenauswertung beginnen kann. Also ein idealer Kandidat für schnelle Signalverarbeitung.

In der Arduino-Umgebung lassen sich die ADC-Kanäle jedoch nur einzeln ansprechen und man schafft max. 19 KSPS. Die im Folgenden beschriebene Bibliothek ermöglicht es, Konvertierungen mit der maximalen Frequenz durchzuführen.

Download

STM32F411 ADC

Hardware

Pinout

Präzision

Taktfrequenz (Clock)

Auflösung (Resolution)

Kanalspezifische Abtastzeit (Sampling Time)

Abtastzeit (Conversion Time) / Abtastrate (Sample Rate)

Abtastraten-Rechner

EOC (End of Conversion) Signal

Arduino-Umgebung

Klasse UrsAdcClass (UrsADC)

Verwendung

Einzel-Kanal-Abtastung

Mehr-Kanal-Abtastung (Abtast-Sequenz) mit DMA-Unterstützung

Test

Versuchsaufbau

Zusammenfassung

Performance-Tests

Arduino analogRead

UrsADC analogRead

UrsADC DMA Read

Auswirkung der kanalspezifischen Abtastzeit (Sampling TIme)


Versionshistorie

Version Anpassungen
1.0 (2022-06-24) Basis-Version

Download

Das ZIP-Archiv für Bibliothek UrsSTM32F411-fast-ADC zum Download. Die entpackten Dateien ins Verzeichnis <user>\Documents\Arduino\libraries kopieren (siehe Installing Additional Arduino Libraries).

STM32F411 ADC

Hardware

Allgemeine Informationen zum ADC findet man im Reference Manual und in der Application Note AN3116 "STM32’s ADC modes and their applications". In dieser Bibliothek werden die Modi Single-Channel-Single-Conversion und Multichannel-Continuous-Conversion (Sequenz) implementiert. Multichannel-Single-Conversion kann durch Angabe einer Wiederholung von eins erreicht werden.

Pinout

Beim Blackpill sind zehn ADC-Kanäle heraus geführt: ADC0 (PA0) .. ADC9 (PB1):

Blackpill Pinout

Präzision

In der Applikation Note How to get the best ADC accuracy in STM32 microcontrollers wird beschrieben, wie man die bestmögliche Präzision des ADC erreichen kann. Der CPU-Pin VREF+ ist leider nicht separat heraus geführt. Zu vermuten ist, dass er direkt mit der Versorgungsspannung verbunden ist. Man muss also auf eine niederohmige und sauber Versorgungspannung achten.

Taktfrequenz (Clock)

Der ADC wird über den APB2-Bus betrieben, der mit 100 MHz betrieben wird. Der Frequenzteiler kann auf 2 (ADCCLK = 50 MHz [0,02 μs]), 4 (25 MHz [0,04 μs]), 6 (16,7 MHz [0,06 μs]) und 8 (12,5 MHz [0,08 μs]) eingestellt werden.

Auflösung (Resolution)

Der ADC kann mit 6, 8, 10 und 12 Bit Auflösung betrieben werden. Die geringeren Auflösungen benötigen eine kleinere Umwandlungszeit.

Kanalspezifische Abtastzeit (Sampling Time)

Zum Wandlung werden intern mehrere Kondensatoren mit der zu messenden Spannung geladen. Bei hohen Impedanzen der Eingangsspannung und hohen Wandlungsraten führt dies zu einem Problem. Die Kondensatoren werden nicht vollständig geladen (s. unten Abschnitt Test).

Durch die Channel x sampling time selection im ADC sample time register kann man die Ladezeit der Kondensatoren kanalspezifisch anpassen.

Abtastzeit (Conversion Time) / Abtastrate (Sample Rate)

Die Abtastzeit wird bestimmt durch die ADC-Taktfrequenz ADCCLK (= 100 MHz / Clock Divider), dier eingestellten Auflösung (Resolution) und die für den Kanal festgelegte Konvertierungszeit (Sampling Time).

  • Stime: Kanalspezifische Konvertierungszyklen
  • Nres: Auflösungsabhängige Konvertierungszyklen
  • Div: Frequenzteiler
Auflösung Tconv Min (ST = 3, Div = 2) Max (ST = 480, Div = 8)
12 Bit Sampling Time + 12 ADCCLK Cycles 15 Cycles * 0,02 μs / Cycle
= 0,30 μs (3,3 MSPS)
492 (Cycles) * 0,08 μs / Cycle
39,4 μs (25,4 KSPS)
10 Bit Sampling Time + 10 ADCCLK Cycles 13 Cycles * 0,02 μs / Cycle
= 0,26 μs (3,8 MSPS)
490 (Cycles) * 0,08 μs / Cycle
39,2 μs (25,5 KSPS)
8 Bit Sampling Time + 8 ADCCLK Cycles 11 Cycles * 0,02 μs / Cycle
= 0,22 μs (4,5 MSPS)
488 (Cycles) * 0,08 μs / Cycle
39,0 μs (25,6 KSPS)
6 Bit Sampling Time + 6 ADCCLK Cycles 9 Cycles * 0,02 μs / Cycle
= 0,18 μs (5,6 MSPS)
486 (Cycles) * 0,08 μs / Cycle
38,9 μs (25,7 KSPS)

Abtastraten-Rechner

Clock Div CLK Duration Resulution Bit-Conversion SamplingTime Total Cycles Tconv Rate

EOC (End of Conversion) Signal

Der ADC generiert nach Abschluss einer Konvertierung ein EOC-Signal. Das EOC-Signal dient als Auslöser des ADC-Interrupts. Das Verhalten kann so eingestellt werden, dass das Signal entweder nach Durchführung einer einzelnen Konvertierung generiert wird oder nachdem eine Sequenz konvertiert wurde.

Arduino-Umgebung

Die im Folgenden beschrieben Klassen und Methoden basieren auf Arduino-Board-Library von STMicroelectronics. Die Arduino-Umgebung stellt die Methode analogRead zur Verfügung. Bei der Implementierung wird ein Schichtenmodell verwendet. Daten müssen durch mehrere Schichten durchgereicht werden. Dabei werden Parameterprüfungen mehrfach und redundant durchgeführt. Weitere Anweisungen dienen zu Einhaltung der Kompatibilität mit dem Arduino-Standard. All das kostet Rechenzeit und reduziert die Abtastrate (Sampling Rate) auf etwa 19 KSPS (Kilo-Samples-per-Second).

Im Folgenden werden Methoden beschrieben, die unter Verwendung der DMA Abtastraten von gut 3,17 MSPS in der Optimierungsstufe O3 (fastest)ermöglichen. Bei der Standard-Einstellung Os (smallest) reduziert sich diese kaum (3,16 MSPS).

Die beschriebene Klasse bietet nur einfache Methoden zum Auslesen eines einzelnen Kanals und einer Kanal-Sequenz. Sie nutzt die vielfältigen Möglichkeiten des ADC bei Weitem nicht aus.

Klasse UrsAdcClass (UrsADC)

Die Klasse UrsAdcClass kapselt die Methoden für die schnelle Analog-Digital-Konvertierung. Wie in der Arduino-Umgebung üblich, wird eine Instanz der Klasse (UrsADC) vordefiniert, über die der Zugriff auf die Methoden erfolgt.

Der STM32F411 besitzt nur einen ADC, es ist also nur eine Instanz der Klasse notwendig und sinnvoll. Sämtliche Methoden und Felder der Klasse können somit (und sind es auch) als statisch deklariert werden. Das spart im übersetzten Code die Übergabe des Zeigers auf die zugehörige Instanz.

Verwendung

Beim Reset des STM32F4 ist der ADC deaktiviert (Stromsparfunktion). Zur Benutzung muss er zunächst eingeschaltet werden (Methode enable). Er benötigt eine μs zur Stabilisierung. Mit der Methode disable wird der ADC wieder abgeschaltet. Wenn der ADC eingeschaltet ist, lässt er sich konfigurieren (Hinweis: enable versetzt den ADC zurück in den Grundzustand, Einstellungen gehen mit dem Aufruf verloren).

Die Voreinstellung des ADC erlaubt maximale Abtastraten und ein Auflösung von 12 Bit. Über die Methoden setClockDivider (Einstellung des Frequenzteilers), setResolution (Einstellung der Auflösung) und setChannelSampleTime (Einstellung der kanalspezifischen Abtastzeit) kann dies an das eigene Projekt angepasst werden.

Damit die Parameterprüfungen übergangen werden können, ist es notwendig, schon bei der Codierung sicher zu stellen, dass nur korrekte Parameter verwendet werden. Dies geschieht, indem sämtliche über Enumerationen (enum class) eingestellt werden müssen. Sie sind in der Datei UrsSTM32F411-fast-ADC-Definitions.h  hinterlegt.

Enumeration Verwendung Werte
UrsAdcClockDivider Konstanten für den Frequenzteiler. 2 (Default), 4, 6, 8
UrsAdcResolution Konstanten für die Auflösung. 12 (Default), 10, 8, 6 Bit
UrsAdcSampleTime Konstanten für die kanalspezifische Abtastzeit. 3 (Default), 15, 29, 56, 84, 112, 144, 480 ADC-Zyklen
UrsAdcChannel Konstanten für die Kanalauswahl. 0..9, Vbat
UrsAdcEocSelection Konstanten für die Auslösung des ADC-EOC-Interrupts. Sequence, Single

Einzel-Kanal-Abtastung

Mit der Funktion analogRead steht eine dem Anrduino-Standard entsprechende Abtastfunktion zur Verfügung. Sie liefert in der Voreinstellung Werte im Bereich vom 0..4095 (12 Bit). Um vollständig kompatibel zu sein, muss die Auflösung auf 10 Bit eingestellt werden. Dann ist der Wertebereich wie beim Arduino 0..1023.

Sind höhere Abtastraten für einen einzelnen Kanal erforderlich, kann die Methodenkombination setReadChannel und repeatRead genutzt werden. Hier sind Abtastraten von bis zu gut 1,3 MSPS möglich.

Referenz

Methode Funktion Anmerkung
void enable(bool waitForStabilisation) Initialisiert den ADC Die ADC-Register werden mit Grundkonfiguration versehen, der ADC wird aktiviert und auf die Stabilisierung gewartet. Der Default für waitForStabilisation ist true.
void disable() Deaktiviert den ADC Stromsparfunktion. Unterbricht die Abarbeitung des aktuellen Konvertierungsauftrags.
setClockDivider(UrsAdcClockDivider) Legt den Frequenzteiler fest. 2..8. Der Defaultwert ist 2. Muss nach enable eingestellt werden.
void setResolution(UrsAdcResolution) Legt die Auflösung fest. 6..12 Bit. Der Defaultwert ist 12 Bit. Muss nach enable eingestellt werden.
uint16_t analogRead(
   UrsAdcChannel channel,
   UrsAdcSampleTime sampleTime)
Führt eine einzelne Konvertierung durch. Wie: Arduino uint32_t analogRead(uint32_t ulPin).
Der Defaultwert für optionalen Parameter sampleTime ist 3 ADC-Cycles. Es lassen sich Abtastraten von knapp 290 KSPS erreichen.
void setReadChannel(
   UrsAdcChannel channel,
   UrsAdcSampleTime sampleTime)
Stellt den zu lesenden Kanal für repeatRead ein. Der Defaultwert für den optionalen Parameter sampleTime ist 3 ADC-Cycles.
uint16_t repeatRead() Den von setReadChannel eingestellten Kanal (erneut) auslesen. Deutlich schneller als analogRead, wenn der gleiche Kanal mehrfach direkt nacheinander ausgelesen werden soll. Es lassen sich Abtastraten von mehr als 1,3 MSPS erreichen.

Mehr-Kanal-Abtastung (Abtast-Sequenz) mit DMA-Unterstützung

Sollen die Kanäle mit einer sehr hohen Rate abgetastet werden, ist die CPU für das einzelne Auslesen der Abtastwerte zu langsam. Die Daten können aber per DMA abgelegt werden. startSequence übernimmt eine Sequenz von abzutastenden Kanälen, führt die Wandlung der Sequenz ggf. mehrfach aus und legt die Daten per DMA im RAM ab. Der Zielbereich muss bei einer Auflösung von 10 oder 12 Bit ein 16-Bit-Array (uint16_t[]) und bei einer Auflösung von 6 oder 8 Bit ein 8-Bit-Array (uint8_t[]) sein. Über getConversionsDone kann abgefragt werden, wie viele Konvertierungen bereits durchgeführt wurden und über isConversionComplete, ob der komplette Konvertierungsauftrag erledigt ist.

Die Abarbeitung des Konvertierungsauftrags kann vorzeitig durch den Aufruf von disable abgebrochen werden.

Interrupts

Alternativ können Interrupts ausgelöst werden, wenn eine einzelne Konvertierung, die Abtastung einer Sequenz, der Konvertierungsauftrag zur Hälfte oder komplett erledigt ist.

Die Installation der Interrupt-Handler erfolgt nicht automatisch. Sie muss über entsprechende Makros in der optional vorhandenen, projektspezifischen Header-Datei UrsAdc-Config.h angefordert werden:

#pragma once

#define INSTALL_ADC_ISR // Die ADC-ISR wird implementiert.
#define INSTALL_DMA_ISR // Die DMA-ISR wird implementiert.

Sollen die ISR installiert werden, muss die Datei vorhanden und die Makros INSTALL_ADC_ISR bzw. INSTALL_DMA_ISR definiert sein. Ist die Datei nicht vorhanden oder sind die Makros nicht definiert, werden keine ISRs angelegt. Projektspezifische Funktionalitäten können in den Callback-Funktionen implementiert werden, die als Parameter der Methode startSequence übergeben werden können.

Es stehen Interrupts für das ADC-EOC-Signal, für DMA-Half-Transfer-Complete und DMA-Transfer-Complete zur Verfügung. Der EOC-Interrupt wird, je nach Einstellung (setEocSelection), nach jeder einzelnen Konvertierung oder nach der Konvertierung einer kompletten Sequenz getriggert. Der Callback-Funktion wird die Anzahl der bereits einzelnen Abtastungen übergeben.

 Der Half-Transfer-Complete-Interrupt wird ausgelöst, wenn die Hälfte des Konvertierungsauftrags (Länge der Kanal-Sequenz * Anzahl Wiederholungen / 2) erledigt ist, der Transfer-Complete-Interrupt, wenn der komplette Konvertierungsauftrag ausgeführt wurde.

Die Callback-Funktionen haben den Prototyp:

// Prototypdefinition für die ISR (Transfer Complete und Half Transfer Complete).
typedef void (*UrsDmaISR)();
typedef void (*UrsAdcISR)(int count); // Liefert die Anzahl der bereits abgetasteten Sequenzen.

Referenz

Methode Funktion Anmerkung
void enable(bool waitForStabilisation) Initialisiert den ADC Die ADC-Register werden mit Grundkonfiguration versehen, der ADC wird aktiviert und auf die Stabilisierung gewartet. Der Default für waitForStabilisation ist true.
void disable() Deaktiviert den ADC  
setClockDivider(UrsAdcClockDivider) Legt den Frequenzteiler fest. 2..8. Der Defaultwert ist 2. Muss nach enable eingestellt werden.
void setResolution(UrsAdcResolution) Legt die Auflösung fest. 6..12 Bit. Der Defaultwert ist 12 Bit. Muss nach enable eingestellt werden.
setEocSelection(UrsAdcEocSelection) Legt fest, wann das End-Of-Connversion-Flag (EOC) gesetzt wird.  Sequence oder Single. Der Defaultwert ist Sequence. Der ADC-Interrupt wird nach Setzen dieses Bits augelöst.
void setChannelSampleTime(
   UrsAdcChannel channel,
   UrsAdcSampleTime sampleTime)
Legt die kanalspezifische Abtastzeit für startSequence fest. 3..480 ADC-Cycles. Der Defaultwert für sampleTime ist 3. Sie muss nach enable eingestellt werden.
void startSequence(
   std::initializer_list<UrsAdcChannel> channelList,
   void* dest, uint16_t count

   [, UrsDmaISR transferComplete]
   [, UrsDmaISR halfTransferComplete]
   [, UrsAdcISR adcConversionDone])
Startet die mehrfache Konvertierung einer Sequenz.

channelList: Liste der Kanäle einer einzelnen Sequenz [1..16].

dest: Zieladresse, die ermittelten Daten werden dorthin kopiert. Bei einer Auflösung von 10 oder 12 Bit werden pro Wandlung 2 Byte (16 Bit) kopiert. dest muss ein Zeiger auf uint16_t[] sein.
Bei einer Auflösung von 6 oder 8 Bit werden pro Wandlung 1 Byte (8 Bit) kopiert. dest muss ein Zeiger auf uint8_t[] sein.
Es werden conversionList.size * count * Wandlungen durchgeführt und die Ergebnisse abgelegt.

count: Anzahl Wiederholungen der Sequenz. Defaultwert ist 1. conversionList.size * count darf 65.535 nicht überschreiten!

transferComplete: ISR für den Transfer-Complete-Interrupt. Defaultwert ist nullptr. Der Parameter ist nur dann vorhanden, wenn der DMA-IRQ-Handler installiert ist.

halfTransferComplete: ISR für den Half-Transfer-Complete-Interrupt. Defaultwert ist nullptr. Der Parameter ist nur dann vorhanden, wenn der DMA-IRQ-Handler installiert ist.

adcConversionDone: ISR für den ADC-EOC-Interrupt. Der Parameter ist nur dann vorhanden, wenn der ADC-IRQ-Handler installiert ist.

bool isConversionComplete() Die eingestellte Anzahl Konvertierungen wurde ausgeführt.  
int getConversionsDone() Liefert die Anzahl der nach Ausführung von startSequence bereits durchgeführten Konvertierungen.  

Test

Versuchsaufbau

Eine Kette von sieben 1kΩ-Widerständen teilt die Versorgungsspannung von 3,3V in gleiche Intervalle. Die Einzelspannungen werden mit den Kanälen 0..7 gemessen. Die Erwartungswerte sind 0,000 V, 0,471 V, 0,943 V, 1,414 V, 1,885 V, 2,356 V, 2,827 V und 3,300 V. Differenzen ergeben sich u.a. aus der Ungenauigkeit der Versorgungsspannung und Unterschiede bei den Widerstandswerten (5% Toleranz).

Die Schaltung wurde auf einem Steckbrett (Breadboard) aufgebaut.

Zusammenfassung

Performance-Tests

Alle Tests wurden mit einer vorbereitenden Code-Sequenz versehen. In den einzelnen Test werden dann jeweils 8000 Konvertierungen durchgeführt und die benötigte Zeit einschl. evtl. benötigter Schleifen gemessen. Um die Wiederholbarkeit (Reproduzierbarkeit) zu begutachten wurden die ersten 10 Messungen/Messreihen auf der Konsole ausgegeben. Dazu wurden die ADC-Rohwerte in Volt mit 3 Nachkommastellen umgerechnet.

uint32_t start, end;

// =============================
// Arduino analogRead
// =============================
// Test vorbereiten
analogReadResolution(12);
clear();

start = micros();
testArduinoAnalogRead();
end = micros();
reportSequence("Arduino analogRead", end - start, 8);

Arduino analogRead

In einer Schleife wurden die acht angeschlossenen Kanäle 1000 mal mit der Standard-Arduino-Funktion analogRead ausgelesen und die benötigte Zeit gemessen. Um Vergleichbarkeit zu erzielen, wurde die Präzision auf 12 Bit eingestellt.

void testArduinoAnalogRead() {
   int m = 0;
   for (int k = 0; k < 1000; k++)
      for (int i = 0; i < 8; i++)
         buffer[m++] = analogRead(i);
}

Das Ergebnis:

Test: Arduino analogRead
t: 50.196 ns pro sample
f: 19 ksps
   c0    c1    c2    c3    c4    c5    c6    c7
0,000 0,471 0,943 1,414 1,885 2,356 2,827 3,300 Erwatungswert
0,002 0,472 0,945 1,416 1,890 2,361 2,828 3,298
0,002 0,472 0,946 1,416 1,890 2,361 2,828 3,298
0,002 0,472 0,946 1,416 1,890 2,362 2,829 3,298
0,002 0,471 0,945 1,416 1,893 2,361 2,828 3,299
0,002 0,472 0,944 1,416 1,889 2,361 2,829 3,299
0,002 0,471 0,945 1,416 1,890 2,361 2,827 3,299
0,002 0,472 0,945 1,416 1,890 2,361 2,829 3,299
0,002 0,472 0,946 1,416 1,892 2,361 2,829 3,299

Die ermittelten Werte stimmen gut mit den Erwartungswerten überein. Abweichungen treten nur in der dritten Nachkommastelle auf (± 2 Punkte). Die Abtastfrequenz liegt bei knapp 20 KSPS.

UrsADC analogRead

Statt der Arduino-Funktion wurde das Äquivalent aus der Klasse UrsADC verwendet. Die kanalspezifische Abtastzeit wurde auf den kleinstmöglichen Wert von 3 ADCCLK-Zyklen eingestellt.

Test: UrsADC analogRead
t: 3.472 ns pro sample
f: 288 ksps
   c0    c1    c2    c3    c4    c5    c6    c7
0,000 0,471 0,943 1,414 1,885 2,356 2,827 3,300 Erwatungswert
0,002 0,471 0.944 1,414 1,887 2,359 2,823 3,291
0,002 0,471 0,944 1,414 1,888 2,359 2,823 3,292
0,002 0,471 0,944 1,414 1,888 2,357 2,822 3,291
0,002 0,471 0,944 1,414 1,889 2,356 2,821 3,291
0,002 0,471 0,944 1,414 1,888 2,357 2,822 3,291
0,002 0,472 0,945 1,414 1,888 2,357 2,821 3,291
0,002 0,471 0,944 1,414 1,888 2,360 2,821 3,291
0,002 0,471 0,945 1,414 1,888 2,357 2,823 3,291

Die Werte sind ähnlich gut wie die mit der Arduino-Standardfunktion. Sie liegen jedoch erwartungsgemäß leicht darunter (s. Abschnitt Kanalspezifische Abtastzeit). Die Abtastfrequenz ist jedoch gut 15 mal höher als die der Standard-Arduino-Funktion. Jeder Kanal wurde mit ca. 36 KSPS abgetastet. Mit dieser Rate ließen sich schon Audio-Signale abtasten.

Der Nachteil ist jedoch, dass diese Funktion, wie auch die Arduino-Funktion, erst nach erfolgter Wandlung zurück kehrt. Die CPU ist also die ganze Zeit beschäftigt und die Auswertung kann erst nach der Wandlung vorgenommen werden.

UrsADC DMA Read

Bei diesem Test wurde die Methode UrsADC::startSequence benutzt, bei der die Wandlungsergebnisse ohne Zutun der CPU ins RAM geschrieben werden. Die CPU kann währen der Wandlung andere Dinge erledigen oder schon mit der Auswertung der Daten beginnen.

Test: UrsADC DMA read
t: 315 ns pro sample
f: 3.174 ksps
   c0    c1    c2    c3    c4    c5    c6    c7
0,000 0,471 0,943 1,414 1,885 2,356 2,827 3,300 Erwatungswert
0,001 0,456 0,910 1,359 1,820 2,301 2,797 3,298
0,005 0,457 0,910 1,362 1,820 2,299 2,800 3,298
0,005 0,458 0,908 1,362 1,822 2,301 2,799 3,299
0,004 0,457 0,910 1,362 1,821 2,300 2,800 3,298
0,003 0,457 0,910 1,360 1,821 2,299 2,800 3,298
0,005 0,458 0,907 1,362 1,822 2,301 2,798 3,299
0,005 0,457 0,910 1,361 1,821 2,299 2,799 3,299
0,004 0,457 0,910 1,359 1,823 2,303 2,798 3,298
0,004 0,456 0,910 1,363 1,823 2,303 2,800 3,298
0,005 0,458 0,907 1,362 1,822 2,299 2,799 3,299

Die Abtastfrequenz liegt bei über 3 MSPS. Jeder einzelne Kanal wird mit knapp 400 KSPS abgetastet.

Die Messwerte weichen jedoch deutlicher von den Erwartungswerten ab. Die größten Abweichungen liegen bei etwa 4%.

Noch höhere Abtastraten kann man durch Reduktion der Auflösung erreichen. Bei 8-Bit sind 4,3 MSPS möglich:

Test: UrsADC DMA read 8 Bit (3 cycles)
t: 232 ns pro sample
f: 4.310 ksps
   c0    c1    c2    c3    c4    c5    c6    c7
0,000 0,471 0,943 1,414 1,885 2,356 2,827 3,300 Erwatungswert
0,000 0,451 0,902 1,354 1,792 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287
0,000 0,451 0,902 1,354 1,818 2,295 2,797 3,287

Auswirkung der kanalspezifischen Abtastzeit (Sampling TIme)

In einem weiteren Versuch wurden die 1 kΩ-Widerstände durch solche mit 10 kΩ ersetzt. Bei den hohen Abtastraten macht sich die höhere Impedanz bei der Genauigkeit bemerkbar. Abgetastet wurde jeweils der Kanal 2. Der Erwartungswert ist 0,943 V.

Test: UrsADC repeatRead (3 cycles)
t: 736 ns pro sample
f: 1.358 ksps
0,943
0,933
0,932
0,932
0,933
0,933
0,933
0,933
0,935
0,932

Während der erste Wert noch mit dem Erwartungswert übereinstimmt, sind die Folgewerte um etwa 10 mV zu niedrig.

Bei Verlängerung der Sampling Time auf 29 Zyklen stimmen alle Messwerte mit dem Erwartungswert überein:

Test: UrsADC repeatRead 29 Cycles
t: 1246 ns pro sample
f: 802 ksps
0,942
0,941
0,941
0,941
0,941
0,941
0,941
0,941
0,941

Die Verlängerung auf 29 Zyklen bei der schnelleren DMA-gestützten Abtastung nicht ausreichend:

Test: UrsADC DMA read 29 Cycles
t: 836 ns pro sample
f: 1.196 ksps
   c0    c1    c2    c3    c4    c5    c6    c7
0,000 0,471 0,943 1,414 1,885 2,356 2,827 3,300 Erwatungswert
0,002 0,469 0,922 1,369 1,833 2,314 2,813 3,298
0,002 0,469 0,922 1,370 1,835 2,314 2,812 3,298
0,002 0,469 0,922 1,370 1,837 2,314 2,812 3,298
0,002 0,468 0,922 1,370 1,835 2,315 2,812 3,298
0,002 0,468 0,922 1,370 1,835 2,314 2,812 3,298
0,002 0,468 0,922 1,370 1,835 2,315 2,812 3,298
0,002 0,467 0,922 1,370 1,837 2,314 2,813 3,298
0,002 0,469 0,921 1,370 1,837 2,314 2,812 3,298
0,002 0,469 0,922 1,369 1,835 2,315 2,813 3,298
0,003 0,469 0,922 1,370 1,835 2,315 2,812 3,298

Besonders bei den Kanälen 3 und 4 macht sich der Effekt besonders bemerkbar. Hier ist der Gesamtwiderstand gegenüber Vcc bzw. Masse 40 kΩ.