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.

analogReadIntervalTimer.ino 8.3KB

преди 3 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. This example shows how to use the IntervalTimer library and the ADC library in the Teensy 3.0/3.1
  3. The three important objects are: the ADC, the (one or more) IntervalTimer and the same number of RingBuffer.
  4. The ADC sets up the internal ADC, you can change the settings as usual. Enable interrupts.
  5. The IntervalTimer (timerX) executes a function every 'period' microseconds.
  6. This function, timerX_callback, starts the desired ADC measurement, for example:
  7. startSingleRead, startSingleDifferential, startSynchronizedSingleRead, startSynchronizedSingleDifferential
  8. you can use the ADC0 or ADC1 (only for Teensy 3.1).
  9. When the measurement is done, the adc_isr is executed:
  10. - If you have more than one timer per ADC module you need to know which pin was measured.
  11. - Then you store/process the data
  12. - Finally, if you have more than one timer you can check whether the last measurement interruped a
  13. a previous one (using adc->adcX->adcWasInUse), and restart it if so.
  14. The settings of the interrupted measurement are stored in the adc->adcX->adc_config struct.
  15. */
  16. #include <ADC.h>
  17. // and IntervalTimer
  18. #include <IntervalTimer.h>
  19. const int ledPin = LED_BUILTIN;
  20. const int readPin0 = A10;
  21. const int period0 = 120; // us
  22. const int readPin1 = A11;
  23. const int period1 = 120; // us
  24. const int readPeriod = 100000; // us
  25. ADC *adc = new ADC(); // adc object
  26. IntervalTimer timer0, timer1; // timers
  27. #define BUFFER_SIZE 500
  28. uint16_t buffer_0[BUFFER_SIZE];
  29. uint16_t buffer_0_count = 0xffff;
  30. uint32_t delta_time_0 = 0;
  31. uint16_t buffer_1[BUFFER_SIZE];
  32. uint16_t buffer_1_count = 0xffff;
  33. uint32_t delta_time_1 = 0;
  34. elapsedMillis timed_read_elapsed;
  35. int startTimerValue0 = 0, startTimerValue1 = 0;
  36. void setup() {
  37. pinMode(ledPin, OUTPUT); // led blinks every loop
  38. pinMode(ledPin+1, OUTPUT); // timer0 starts a measurement
  39. pinMode(ledPin+2, OUTPUT); // timer1 starts a measurement
  40. pinMode(ledPin+3, OUTPUT); // adc0_isr, measurement finished for readPin0
  41. pinMode(ledPin+4, OUTPUT); // adc0_isr, measurement finished for readPin1
  42. pinMode(readPin0, INPUT);
  43. pinMode(readPin1, INPUT);
  44. Serial.begin(9600);
  45. delay(1000);
  46. ///// ADC0 ////
  47. adc->adc0->setAveraging(16); // set number of averages
  48. adc->adc0->setResolution(12); // set bits of resolution
  49. adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
  50. adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed
  51. Serial.println("Starting Timers");
  52. // start the timers, if it's not possible, startTimerValuex will be false
  53. startTimerValue0 = timer0.begin(timer0_callback, period0);
  54. // wait enough time for the first timer conversion to finish (depends on resolution and averaging),
  55. // with 16 averages, 12 bits, and ADC_MED_SPEED in both sampling and conversion speeds it takes about 36 us.
  56. delayMicroseconds(25); // if we wait less than 36us the timer1 will interrupt the conversion
  57. // initiated by timer0. The adc_isr will restart the timer0's measurement.
  58. // You can check with an oscilloscope:
  59. // Pin 14 corresponds to the timer0 initiating a measurement
  60. // Pin 15 the same for the timer1
  61. // Pin 16 is the adc_isr when there's a new measurement on readpin0
  62. // Pin 17 is the adc_isr when there's a new measurement on readpin1
  63. // Timer0 starts a comversion and 25 us later timer1 starts a new one, "pausing" the first, about 36 us later timer1's conversion
  64. // is done, and timer0's is restarted, 36 us later timer0's conversion finishes. About 14 us later timer0 starts a new conversion again.
  65. // (times don't add up to 120 us because the timer_callbacks and adc_isr take time to execute, about 2.5 us and 1 us, respectively)
  66. // so in the worst case timer0 gets a new value in about twice as long as it would take alone.
  67. // if you change the periods, make sure you don't go into a loop, with the timers always interrupting each other
  68. startTimerValue1 = timer1.begin(timer1_callback, period1);
  69. adc->adc0->enableInterrupts(adc0_isr);
  70. Serial.println("Timers started");
  71. delay(500);
  72. }
  73. int value = 0;
  74. char c=0;
  75. void loop() {
  76. if(startTimerValue0==false) {
  77. Serial.println("Timer0 setup failed");
  78. }
  79. if(startTimerValue1==false) {
  80. Serial.println("Timer1 setup failed");
  81. }
  82. // See if we have a timed read test that finished.
  83. if (delta_time_0) printTimedADCInfo(ADC_0, buffer_0, delta_time_0);
  84. if (delta_time_1) printTimedADCInfo(ADC_0, buffer_1, delta_time_1);
  85. if (Serial.available()) {
  86. c = Serial.read();
  87. if(c=='s') { // stop timer
  88. Serial.println("Stop timer1");
  89. timer1.end();
  90. } else if(c=='r') { // restart timer
  91. Serial.println("Restart timer1");
  92. startTimerValue1 = timer1.begin(timer1_callback, period1);
  93. } else if(c=='p') { // restart timer
  94. Serial.print("isContinuous: ");
  95. Serial.println(adc->adc0->isContinuous());
  96. }
  97. }
  98. //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
  99. delayMicroseconds(readPeriod);
  100. }
  101. void printTimedADCInfo(uint8_t adc_num, uint16_t *buffer, uint32_t &delta_time) {
  102. uint32_t min_value = 0xffff;
  103. uint32_t max_value = 0;
  104. uint32_t sum = 0;
  105. for (int i = 0; i < BUFFER_SIZE; i++) {
  106. if (buffer[i] < min_value) min_value = buffer[i];
  107. if (buffer[i] > max_value) max_value = buffer[i];
  108. sum += buffer[i];
  109. }
  110. float average_value = (float)sum / BUFFER_SIZE; // get an average...
  111. float sum_delta_sq = 0;
  112. for (int i = 0; i < BUFFER_SIZE; i++) {
  113. int delta_from_center = (int)buffer[i] - average_value;
  114. sum_delta_sq += delta_from_center * delta_from_center;
  115. }
  116. int rms = sqrt(sum_delta_sq / BUFFER_SIZE);
  117. Serial.printf("ADC:%d delta time:%d freq:%d - min:%d max:%d avg:%d rms:%d\n", adc_num,
  118. delta_time, (1000 * BUFFER_SIZE) / delta_time,
  119. min_value, max_value, (int)average_value, rms);
  120. delta_time = 0;
  121. }
  122. // This function will be called with the desired frequency
  123. // start the measurement
  124. // in my low-res oscilloscope this function seems to take 1.5-2 us.
  125. void timer0_callback(void) {
  126. digitalWriteFast(ledPin+1, HIGH);
  127. adc->adc0->startSingleRead(readPin0); // also: startSingleDifferential, analogSynchronizedRead, analogSynchronizedReadDifferential
  128. digitalWriteFast(ledPin+1, LOW);
  129. //digitalWriteFast(ledPin+1, !digitalReadFast(ledPin+1));
  130. }
  131. // This function will be called with the desired frequency
  132. // start the measurement
  133. void timer1_callback(void) {
  134. digitalWriteFast(ledPin+2, HIGH);
  135. adc->adc0->startSingleRead(readPin1);
  136. digitalWriteFast(ledPin+2, LOW);
  137. }
  138. // when the measurement finishes, this will be called
  139. // first: see which pin finished and then save the measurement into the correct buffer
  140. void adc0_isr() {
  141. #if defined(__IMXRT1062__) // Teensy 4.0
  142. uint8_t pin = ADC::sc1a2channelADC0[ADC1_HC0&0x1f]; // the bits 0-4 of ADC0_SC1A have the channel
  143. #else
  144. uint8_t pin = ADC::sc1a2channelADC0[ADC0_SC1A&ADC_SC1A_CHANNELS]; // the bits 0-4 of ADC0_SC1A have the channel
  145. #endif
  146. // add value to correct buffer
  147. if(pin==readPin0) {
  148. digitalWriteFast(ledPin+3, HIGH);
  149. uint16_t adc_val = adc->adc0->readSingle();
  150. if (buffer_0_count < BUFFER_SIZE) {
  151. buffer_0[buffer_0_count++] = adc_val;
  152. if (buffer_0_count == BUFFER_SIZE) delta_time_0 = timed_read_elapsed;
  153. }
  154. digitalWriteFast(ledPin+3, LOW);
  155. } else if(pin==readPin1) {
  156. digitalWriteFast(ledPin+4, HIGH);
  157. uint16_t adc_val = adc->adc0->readSingle();
  158. if (buffer_1_count < BUFFER_SIZE) {
  159. buffer_1[buffer_1_count++] = adc_val;
  160. if (buffer_1_count == BUFFER_SIZE) delta_time_1 = timed_read_elapsed;
  161. }
  162. digitalWriteFast(ledPin+4, LOW);
  163. } else { // clear interrupt anyway
  164. adc->readSingle();
  165. }
  166. // restore ADC config if it was in use before being interrupted by the analog timer
  167. if (adc->adc0->adcWasInUse) {
  168. // restore ADC config, and restart conversion
  169. adc->adc0->loadConfig(&adc->adc0->adc_config);
  170. // avoid a conversion started by this isr to repeat itself
  171. adc->adc0->adcWasInUse = false;
  172. }
  173. //digitalWriteFast(ledPin+2, !digitalReadFast(ledPin+2));
  174. #if defined(__IMXRT1062__) // Teensy 4.0
  175. asm("DSB");
  176. #endif
  177. }