Solved: ADCs on Teensy 4.0 are way too fast?!

Status
Not open for further replies.
Hello together!

I have a question regarding the maximum ADC Speed of the teensy 4.0. According to the datasheet of the IMXRT1060 the minimal total conversion time is ~750nS,
but with the code below I'm way too fast for that and getting conversion times of about ~200nS!!! (For 12Bit!!!)

The highest possible clock for the ADCs should be 40Mhz, so the values I'm measuring can't be accurate!
Does anyone know where these strange measurements come from?
Have I set any of the registers wrong, or is the measurement itself done wrong?

Thank you in advance for any help :D

Measurements:

adcspeedquestion.PNG
(for getting Nanoseconds: 10^9/ticks)

Code:

Code:
//Verwendetes Datenblatt: IMXRT1060 Reference Manual
#include <DMAChannel.h>
#define PrintRegister(x) Serial.print(#x" 0x"); Serial.println(x, BIN); //bequeme Schreib-Definition für seriellen Monitor (zur Ausgabe von Registerwerten)
#define BufferSize 1 //Größe aller DMA-Buffer
/*  ADC Muxing Options (für ADC1-Inputs (auch mit ADC2 messbar!) S. 289):
    ADC1_IN7 GPIO_AD_B1_02 (A0) // ADC1_IN8 GPIO_AD_B1_03 (A1) // ADC1_IN12 GPIO_AD_B1_07 (A2)
    ADC1_IN11 GPIO_AD_B1_06 (A3) // ADC1_IN6 GPIO_AD_B1_01 (A4) // ADC1_IN5 GPIO_AD_B1_00 (A5)
    ADC1_IN15 GPIO_AD_B1_10 (A6) // ADC1_IN0 GPIO_AD_B1_11 (A7) // ADC1_IN13 GPIO_AD_B1_08 (A8)
    ADC1_IN14 GPIO_AD_B1_09 (A9) // ADC1_IN1 GPIO_AD_B0_12 (A10) // ADC1_IN2 GPIO_AD_B0_13 (A11)  */
#define pinMessungA 7 //A0 --> langsamer => Strom!
#define pinMessungB 14 //A9 --> schneller => Spannung! (wird als 2. initialisiert => Priorität pinMessungB > Priorität pinMessungA

//ADC General Status-Register S. 3494
bool ADACT1;  bool ADACT2; //Conversion Active Flag
bool CALF1;   bool CALF2;  //Calibration Failed Flag
bool AWKST1;  bool AWKST2; //Asynchronous wakeup interrupt status (0 = no asynchronous interrupt)

DMAMEM static uint16_t SpannungBufferDMA[BufferSize]; //Buffer für Spannung im DMA-Speicher
DMAChannel dma1(false);
DMAMEM static uint16_t StromBufferDMA[BufferSize]; //Buffer für Strom im DMA-Speicher
DMAChannel dma2(false);
volatile uint32_t ticks = 0;
volatile uint32_t ticks2 = 0;

void setup() {
  Serial.begin(115200); //Baudrate einstellen für serielle Verbindung
  while (!Serial);
  
  setupADCs(pinMessungA, pinMessungB);
  if (checkADCs()) { //Laufen beide ADCs fehlerfrei?
    Serial.println("\nBeide ADCs erfolgreich initialisiert!");
  } else {
    Serial.println("\nBeide ADCs laufen nicht! (INIT FEHLER)\n");
  }
  delay(1000);
}

void loop() {
  printReadings(); //Speed in nS = (10^9/ticks)
  arm_dcache_delete(SpannungBufferDMA, BufferSize + 1); //Cache leeren + 1?
  arm_dcache_delete(StromBufferDMA, BufferSize + 1); //Cache leeren
  delay(1000);
}

bool checkADCs() {
  /*                         AWKST | CALF | ADACT
    ADCx_GS = 3Bit...          1       0      1
    Maske mit & für ADACT:     0       0      1  */
  ADACT1 = ADC1_GS & 001;   ADACT2 = ADC2_GS & 001;
  CALF1 =  ADC1_GS & 010;   CALF2 =  ADC2_GS & 010;
  AWKST1 =  ADC1_GS & 100;  AWKST2 =  ADC2_GS & 100;
  if (ADACT1 && ADACT2 && !CALF1 && !CALF2 && !AWKST1 && !AWKST2) return 1;
  return 0;
}

void setupADCs(int pin1, int pin2) {
  //Datasheet Seite 3449 (i.MX RT1064)
  cli(); //Interrupts deaktivieren
  Serial.println("Setup ADCs...\n");
  //ADC-1:
  ADC1_GC = 0x42; //1000010
  ADC1_CFG = 0x408; //10000001000
  ADC1_HC0 = pin1; //Kanal 7 = A0
  PrintRegister(ADC1_GC);
  PrintRegister(ADC1_CFG);
  PrintRegister(ADC1_HC0);
  //DMA für ADC1 initialisieren:
  dma1.begin(true); //Speicher für DMA-Kanal allozieren
  dma1.source((uint16_t &) ADC1_R0); //ADC1 als Triggerquelle wählen
  dma1.destinationBuffer(SpannungBufferDMA, BufferSize + 1); //Ziel wählen
  dma1.interruptAtCompletion();
  dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1); //DMA durch ADC1 triggern lassen!
  //ADC-2:
  ADC2_GC = 0x42; //11000010
  ADC2_CFG = 0x408; //10000001000
  ADC2_HC0 = pin2; //Kanal 14 = A9
  PrintRegister(ADC2_GC);
  PrintRegister(ADC2_CFG);
  PrintRegister(ADC2_HC0);
  //DMA für ADC2 initialisieren:
  dma2.begin(true); //Speicher für DMA-Kanal allozieren
  dma2.source((uint16_t &) ADC2_R0); //ADC2 als Triggerquelle wählen
  dma2.destinationBuffer(StromBufferDMA, BufferSize + 1);
  dma2.interruptAtCompletion();
  dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC2);
  //Direct Memory Access Interrupts aktivieren:
  dma1.attachInterrupt(dma1_isr);
  dma1.enable();
  dma2.attachInterrupt(dma2_isr);
  dma2.enable();
  sei(); //Interrupts wieder aktivieren
}

void dma1_isr(void) { //ADC
  dma1.clearInterrupt();
  ticks++; //Sample-Counter
  asm volatile ("dsb"); //Inline Assembler Anweisung
  /* https://developer.arm.com/docs/dui0646/a/the-cortex-m7-instruction-set/instruction-set-summary
     DSB acts as a special data synchronization memory barrier.
     Instructions that come after the DSB, in program order, do not execute until the DSB instruction completes.
     The DSB instruction completes when all explicit memory accesses before it complete. */
}

void dma2_isr(void) { //ADC
  dma2.clearInterrupt();
  ticks2++; //Sample-Counter
  asm volatile ("dsb");
}

void printReadings() { //Debugging
  static int prev;
  static int prev2;
  Serial.printf("%d ticks A0 = %d \n", ticks - prev, SpannungBufferDMA[0]);
  prev = ticks;
  Serial.printf("%d ticks A9 = %d \n", ticks2 - prev2, StromBufferDMA[0]);
  prev2 = ticks2;
}
 
Last edited by a moderator:
[CASE SOLVED]

I simply overclocked the ADC with the ipg_clock (150Mhz)
=> Divider (ADIV = 2) gives me 37,5Mhz @ which I'm getting exacly the result the datasheet claims!

BUT: It can be overclocked!!! Currently at 75Mhz and ADSTS(1) for getting Results @ constant 400nS! :D

Q: How can I edit the Thread's title to "solved" ???
 
Hello Marty Brown. I am in need of doing AD conversions of around 100 ns and then store the number in RAM within ~50 ns after that. Your code does not look much like Arduino code to my untrained eye and having the comments in German makes it much harder. Any possibility you could translate the comments to English. Thanks!
 
Status
Not open for further replies.
Back
Top