PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.0KB

  1. /* Example for using DMA with ADC
  2. This example uses DMA object to do the sampling. It does not use a timer so it runs
  3. at whatever speed the ADC will run at with current settings.
  4. It should work for Teensy LC, 3.x and T4
  5. DMA: using AnalogBufferDMA with two buffers, this runs in continuous mode and when one buffer fills
  6. an interrupt is signaled, which sets flag saying it has data, which this test application
  7. scans the data, and computes things like a minimum, maximum, average values and an RMS value.
  8. For the RMS it keeps the average from the previous set of data.
  9. */
  10. #ifdef ADC_USE_DMA
  11. #include <ADC.h>
  12. #include <AnalogBufferDMA.h>
  13. // This version uses both ADC1 and ADC2
  14. #if defined(KINETISL)
  15. const int readPin_adc_0 = A0;
  16. #elif defined(KINETISK)
  17. const int readPin_adc_0 = A0;
  18. const int readPin_adc_1 = A2;
  19. #else
  20. const int readPin_adc_0 = A0;
  21. const int readPin_adc_1 = 26;
  22. #endif
  23. ADC *adc = new ADC(); // adc object
  24. const uint32_t initial_average_value = 2048;
  25. // Going to try two buffers here using 2 dmaSettings and a DMAChannel
  26. #ifdef KINETISL
  27. const uint32_t buffer_size = 500;
  28. #else
  29. const uint32_t buffer_size = 1600;
  30. #endif
  31. DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
  32. DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
  33. AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);
  34. #ifdef ADC_DUAL_ADCS
  35. DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
  36. DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff2[buffer_size];
  37. AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size, dma_adc2_buff2, buffer_size);
  38. #endif
  39. void setup() {
  40. while (!Serial && millis() < 5000) ;
  41. pinMode(LED_BUILTIN, OUTPUT);
  42. pinMode(readPin_adc_0, INPUT); //pin 23 single ended
  43. #ifdef ADC_DUAL_ADCS
  44. pinMode(readPin_adc_1, INPUT);
  45. #endif
  46. Serial.begin(9600);
  47. Serial.println("Setup ADC_0");
  48. // reference can be ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
  49. //adc->setReference(ADC_REFERENCE::REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
  50. adc->adc0->setAveraging(8); // set number of averages
  51. adc->adc0->setResolution(12); // set bits of resolution
  52. // always call the compare functions after changing the resolution!
  53. //adc->enableCompare(1.0/3.3*adc->getMaxValue(ADC_0), 0, ADC_0); // measurement will be ready if value < 1.0V
  54. //adc->enableCompareRange(1.0*adc->getMaxValue(ADC_1)/3.3, 2.0*adc->getMaxValue(ADC_1)/3.3, 0, 1, ADC_1); // ready if value lies out of [1.0,2.0] V
  55. // enable DMA and interrupts
  56. Serial.println("before enableDMA"); Serial.flush();
  57. // setup a DMA Channel.
  58. // Now lets see the different things that RingbufferDMA setup for us before
  59. abdma1.init(adc, ADC_0);
  60. abdma1.userData(initial_average_value); // save away initial starting average
  61. #ifdef ADC_DUAL_ADCS
  62. Serial.println("Setup ADC_1");
  63. adc->adc1->setAveraging(8); // set number of averages
  64. adc->adc1->setResolution(12); // set bits of resolution
  65. abdma2.init(adc, ADC_1);
  66. abdma2.userData(initial_average_value); // save away initial starting average
  67. adc->adc1->startContinuous(readPin_adc_1);
  68. #endif
  69. // Start the dma operation..
  70. adc->adc0->startContinuous(readPin_adc_0);
  71. Serial.println("End Setup");
  72. }
  73. char c = 0;
  74. void loop() {
  75. // Maybe only when both have triggered?
  76. #ifdef ADC_DUAL_ADCS
  77. if ( abdma1.interrupted() && abdma2.interrupted()) {
  78. if (abdma1.interrupted()) ProcessAnalogData(&abdma1, 0);
  79. if (abdma2.interrupted()) ProcessAnalogData(&abdma2, 1);
  80. Serial.println();
  81. }
  82. #else
  83. if ( abdma1.interrupted()) {
  84. ProcessAnalogData(&abdma1, 0);
  85. Serial.println();
  86. }
  87. #endif
  88. }
  89. void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
  90. uint32_t sum_values = 0;
  91. uint16_t min_val = 0xffff;
  92. uint16_t max_val = 0;
  93. uint32_t average_value = pabdma->userData();
  94. volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
  95. volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
  96. float sum_delta_sq = 0.0;
  97. if ((uint32_t)pbuffer >= 0x20200000u) arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
  98. while (pbuffer < end_pbuffer) {
  99. if (*pbuffer < min_val) min_val = *pbuffer;
  100. if (*pbuffer > max_val) max_val = *pbuffer;
  101. sum_values += *pbuffer;
  102. int delta_from_center = (int) * pbuffer - average_value;
  103. sum_delta_sq += delta_from_center * delta_from_center;
  104. pbuffer++;
  105. }
  106. int rms = sqrt(sum_delta_sq / buffer_size);
  107. average_value = sum_values / buffer_size;
  108. Serial.printf(" %d - %u(%u): %u <= %u <= %u %d ", adc_num, pabdma->interruptCount(), pabdma->interruptDeltaTime(), min_val,
  109. average_value, max_val, rms);
  110. pabdma->clearInterrupt();
  111. pabdma->userData(average_value);
  112. }
  113. #else // make sure the example can run for any boards (automated testing)
  114. void setup() {}
  115. void loop() {}
  116. #endif // ADC_USE_DMA