Browse Source

Ensure ADC conversion is complete before reading (#11336)

The current Marlin implementation relies on a timer interrupt to start the ADC conversion and read it. However in some circumstances the interrupt can be delayed resulting in insufficient time being available for the ADC conversion. This results in a bad reading and false temperature fluctuations. These changes make sure that the conversion is complete (by checking the ADC hardware via the HAL) before reading a value.

See: https://github.com/MarlinFirmware/Marlin/issues/11323
Andy Shaw 5 years ago
parent
commit
624986d423

+ 2
- 1
Marlin/src/HAL/HAL_AVR/HAL.h View File

@@ -345,7 +345,8 @@ inline void HAL_adc_init(void) {
345 345
   #define HAL_START_ADC(pin) ADCSRB = 0; SET_ADMUX_ADCSRA(pin)
346 346
 #endif
347 347
 
348
-#define HAL_READ_ADC ADC
348
+#define HAL_READ_ADC()  ADC
349
+#define HAL_ADC_READY() !TEST(ADCSRA, ADSC)
349 350
 
350 351
 #define GET_PIN_MAP_PIN(index) index
351 352
 #define GET_PIN_MAP_INDEX(pin) pin

+ 2
- 1
Marlin/src/HAL/HAL_DUE/HAL.h View File

@@ -141,7 +141,8 @@ void eeprom_update_block (const void *__src, void *__dst, size_t __n);
141 141
 inline void HAL_adc_init(void) {}//todo
142 142
 
143 143
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
144
-#define HAL_READ_ADC        HAL_adc_result
144
+#define HAL_READ_ADC()      HAL_adc_result
145
+#define HAL_ADC_READY()     true
145 146
 
146 147
 void HAL_adc_start_conversion(const uint8_t adc_pin);
147 148
 uint16_t HAL_adc_get_result(void);

+ 2
- 1
Marlin/src/HAL/HAL_ESP32/HAL.h View File

@@ -109,7 +109,8 @@ void eeprom_update_block (const void *__src, void *__dst, size_t __n);
109 109
 void HAL_adc_init(void);
110 110
 
111 111
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
112
-#define HAL_READ_ADC        HAL_adc_result
112
+#define HAL_READ_ADC()      HAL_adc_result
113
+#define HAL_ADC_READY()     true
113 114
 
114 115
 void HAL_adc_start_conversion (uint8_t adc_pin);
115 116
 

+ 3
- 1
Marlin/src/HAL/HAL_LPC1768/HAL.h View File

@@ -140,11 +140,13 @@ uint8_t spiRec(uint32_t chan);
140 140
 // ADC
141 141
 #define HAL_ANALOG_SELECT(pin) HAL_adc_enable_channel(pin)
142 142
 #define HAL_START_ADC(pin)     HAL_adc_start_conversion(pin)
143
-#define HAL_READ_ADC           HAL_adc_get_result()
143
+#define HAL_READ_ADC()         HAL_adc_get_result()
144
+#define HAL_ADC_READY()        HAL_adc_finished()
144 145
 
145 146
 void HAL_adc_init(void);
146 147
 void HAL_adc_enable_channel(int pin);
147 148
 void HAL_adc_start_conversion(const uint8_t adc_pin);
148 149
 uint16_t HAL_adc_get_result(void);
150
+bool HAL_adc_finished(void);
149 151
 
150 152
 #endif // _HAL_LPC1768_H_

+ 2
- 1
Marlin/src/HAL/HAL_STM32F1/HAL.h View File

@@ -224,7 +224,8 @@ void eeprom_update_block (const void *__src, void *__dst, size_t __n);
224 224
 void HAL_adc_init(void);
225 225
 
226 226
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
227
-#define HAL_READ_ADC        HAL_adc_result
227
+#define HAL_READ_ADC()      HAL_adc_result
228
+#define HAL_ADC_READY()     true
228 229
 
229 230
 void HAL_adc_start_conversion(const uint8_t adc_pin);
230 231
 

+ 2
- 1
Marlin/src/HAL/HAL_STM32F4/HAL.h View File

@@ -228,7 +228,8 @@ void eeprom_update_block (const void *__src, void *__dst, size_t __n);
228 228
 inline void HAL_adc_init(void) {}
229 229
 
230 230
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
231
-#define HAL_READ_ADC        HAL_adc_result
231
+#define HAL_READ_ADC()      HAL_adc_result
232
+#define HAL_ADC_READY()     true
232 233
 
233 234
 void HAL_adc_start_conversion(const uint8_t adc_pin);
234 235
 

+ 2
- 1
Marlin/src/HAL/HAL_STM32F7/HAL.h View File

@@ -214,7 +214,8 @@ void eeprom_update_block (const void *__src, void *__dst, size_t __n);
214 214
 inline void HAL_adc_init(void) {}
215 215
 
216 216
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
217
-#define HAL_READ_ADC        HAL_adc_result
217
+#define HAL_READ_ADC()      HAL_adc_result
218
+#define HAL_ADC_READY()     true
218 219
 
219 220
 void HAL_adc_start_conversion(const uint8_t adc_pin);
220 221
 

+ 2
- 1
Marlin/src/HAL/HAL_TEENSY35_36/HAL.h View File

@@ -142,7 +142,8 @@ uint8_t spiRec(uint32_t chan);
142 142
 void HAL_adc_init();
143 143
 
144 144
 #define HAL_START_ADC(pin)  HAL_adc_start_conversion(pin)
145
-#define HAL_READ_ADC        HAL_adc_get_result()
145
+#define HAL_READ_ADC()      HAL_adc_get_result()
146
+#define HAL_ADC_READY()     true
146 147
 
147 148
 #define HAL_ANALOG_SELECT(pin) NOOP;
148 149
 

+ 121
- 103
Marlin/src/module/temperature.cpp View File

@@ -1679,6 +1679,87 @@ void Temperature::set_current_temp_raw() {
1679 1679
   temp_meas_ready = true;
1680 1680
 }
1681 1681
 
1682
+void Temperature::readings_ready() {
1683
+  // Update the raw values if they've been read. Else we could be updating them during reading.
1684
+  if (!temp_meas_ready) set_current_temp_raw();
1685
+
1686
+  // Filament Sensor - can be read any time since IIR filtering is used
1687
+  #if ENABLED(FILAMENT_WIDTH_SENSOR)
1688
+    current_raw_filwidth = raw_filwidth_value >> 10;  // Divide to get to 0-16384 range since we used 1/128 IIR filter approach
1689
+  #endif
1690
+
1691
+  ZERO(raw_temp_value);
1692
+
1693
+  #if HAS_HEATED_BED
1694
+    raw_temp_bed_value = 0;
1695
+  #endif
1696
+
1697
+  #if HAS_TEMP_CHAMBER
1698
+    raw_temp_chamber_value = 0;
1699
+  #endif
1700
+
1701
+  #define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) > (HEATER_##N##_RAW_HI_TEMP) ? -1 : 1)
1702
+
1703
+  int constexpr temp_dir[] = {
1704
+    #if ENABLED(HEATER_0_USES_MAX6675)
1705
+       0
1706
+    #else
1707
+      TEMPDIR(0)
1708
+    #endif
1709
+    #if HOTENDS > 1
1710
+      , TEMPDIR(1)
1711
+      #if HOTENDS > 2
1712
+        , TEMPDIR(2)
1713
+        #if HOTENDS > 3
1714
+          , TEMPDIR(3)
1715
+          #if HOTENDS > 4
1716
+            , TEMPDIR(4)
1717
+          #endif // HOTENDS > 4
1718
+        #endif // HOTENDS > 3
1719
+      #endif // HOTENDS > 2
1720
+    #endif // HOTENDS > 1
1721
+  };
1722
+
1723
+  for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
1724
+    const int16_t tdir = temp_dir[e], rawtemp = current_temperature_raw[e] * tdir;
1725
+    const bool heater_on = 0 <
1726
+      #if ENABLED(PIDTEMP)
1727
+        soft_pwm_amount[e]
1728
+      #else
1729
+        target_temperature[e]
1730
+      #endif
1731
+    ;
1732
+    if (rawtemp > maxttemp_raw[e] * tdir && heater_on) max_temp_error(e);
1733
+    if (rawtemp < minttemp_raw[e] * tdir && !is_preheating(e) && heater_on) {
1734
+      #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
1735
+        if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
1736
+      #endif
1737
+          min_temp_error(e);
1738
+    }
1739
+    #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
1740
+      else
1741
+        consecutive_low_temperature_error[e] = 0;
1742
+    #endif
1743
+  }
1744
+
1745
+  #if HAS_HEATED_BED
1746
+    #if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP
1747
+      #define GEBED <=
1748
+    #else
1749
+      #define GEBED >=
1750
+    #endif
1751
+    const bool bed_on = 0 <
1752
+      #if ENABLED(PIDTEMPBED)
1753
+        soft_pwm_amount_bed
1754
+      #else
1755
+        target_temperature_bed
1756
+      #endif
1757
+    ;
1758
+    if (current_temperature_bed_raw GEBED bed_maxttemp_raw && bed_on) max_temp_error(-1);
1759
+    if (bed_minttemp_raw GEBED current_temperature_bed_raw && bed_on) min_temp_error(-1);
1760
+  #endif
1761
+}
1762
+
1682 1763
 /**
1683 1764
  * Timer 0 is shared with millies so don't change the prescaler.
1684 1765
  *
@@ -1996,6 +2077,12 @@ void Temperature::isr() {
1996 2077
    *
1997 2078
    * This gives each ADC 0.9765ms to charge up.
1998 2079
    */
2080
+  #define ACCUMULATE_ADC(var) do{ \
2081
+    if (!HAL_ADC_READY()) next_sensor_state = adc_sensor_state; \
2082
+    else var += HAL_READ_ADC(); \
2083
+  }while(0)
2084
+
2085
+  ADCSensorState next_sensor_state = adc_sensor_state < SensorsReady ? (ADCSensorState)(int(adc_sensor_state) + 1) : StartSampling;
1999 2086
 
2000 2087
   switch (adc_sensor_state) {
2001 2088
 
@@ -2005,21 +2092,30 @@ void Temperature::isr() {
2005 2092
       constexpr int8_t extra_loops = MIN_ADC_ISR_LOOPS - (int8_t)SensorsReady;
2006 2093
       static uint8_t delay_count = 0;
2007 2094
       if (extra_loops > 0) {
2008
-        if (delay_count == 0) delay_count = extra_loops;   // Init this delay
2009
-        if (--delay_count)                                 // While delaying...
2010
-          adc_sensor_state = (ADCSensorState)(int(SensorsReady) - 1); // retain this state (else, next state will be 0)
2095
+        if (delay_count == 0) delay_count = extra_loops;  // Init this delay
2096
+        if (--delay_count)                                // While delaying...
2097
+          next_sensor_state = SensorsReady;               // retain this state (else, next state will be 0)
2011 2098
         break;
2012 2099
       }
2013
-      else
2014
-        adc_sensor_state = (ADCSensorState)0; // Fall-through to start first sensor now
2100
+      else {
2101
+        adc_sensor_state = StartSampling;                 // Fall-through to start sampling
2102
+        next_sensor_state = (ADCSensorState)(int(StartSampling) + 1);
2103
+      }
2015 2104
     }
2016 2105
 
2106
+    case StartSampling:                                   // Start of sampling loops. Do updates/checks.
2107
+      if (++temp_count >= OVERSAMPLENR) {                 // 10 * 16 * 1/(16000000/64/256)  = 164ms.
2108
+        temp_count = 0;
2109
+        readings_ready();
2110
+      }
2111
+      break;
2112
+
2017 2113
     #if HAS_TEMP_ADC_0
2018 2114
       case PrepareTemp_0:
2019 2115
         HAL_START_ADC(TEMP_0_PIN);
2020 2116
         break;
2021 2117
       case MeasureTemp_0:
2022
-        raw_temp_value[0] += HAL_READ_ADC;
2118
+        ACCUMULATE_ADC(raw_temp_value[0]);
2023 2119
         break;
2024 2120
     #endif
2025 2121
 
@@ -2028,7 +2124,7 @@ void Temperature::isr() {
2028 2124
         HAL_START_ADC(TEMP_BED_PIN);
2029 2125
         break;
2030 2126
       case MeasureTemp_BED:
2031
-        raw_temp_bed_value += HAL_READ_ADC;
2127
+        ACCUMULATE_ADC(raw_temp_bed_value);
2032 2128
         break;
2033 2129
     #endif
2034 2130
 
@@ -2037,7 +2133,7 @@ void Temperature::isr() {
2037 2133
         HAL_START_ADC(TEMP_CHAMBER_PIN);
2038 2134
         break;
2039 2135
       case MeasureTemp_CHAMBER:
2040
-        raw_temp_chamber_value += HAL_READ_ADC;
2136
+        ACCUMULATE_ADC(raw_temp_chamber_value);
2041 2137
         break;
2042 2138
     #endif
2043 2139
 
@@ -2046,7 +2142,7 @@ void Temperature::isr() {
2046 2142
         HAL_START_ADC(TEMP_1_PIN);
2047 2143
         break;
2048 2144
       case MeasureTemp_1:
2049
-        raw_temp_value[1] += HAL_READ_ADC;
2145
+        ACCUMULATE_ADC(raw_temp_value[1]);
2050 2146
         break;
2051 2147
     #endif
2052 2148
 
@@ -2055,7 +2151,7 @@ void Temperature::isr() {
2055 2151
         HAL_START_ADC(TEMP_2_PIN);
2056 2152
         break;
2057 2153
       case MeasureTemp_2:
2058
-        raw_temp_value[2] += HAL_READ_ADC;
2154
+        ACCUMULATE_ADC(raw_temp_value[2]);
2059 2155
         break;
2060 2156
     #endif
2061 2157
 
@@ -2064,7 +2160,7 @@ void Temperature::isr() {
2064 2160
         HAL_START_ADC(TEMP_3_PIN);
2065 2161
         break;
2066 2162
       case MeasureTemp_3:
2067
-        raw_temp_value[3] += HAL_READ_ADC;
2163
+        ACCUMULATE_ADC(raw_temp_value[3]);
2068 2164
         break;
2069 2165
     #endif
2070 2166
 
@@ -2073,7 +2169,7 @@ void Temperature::isr() {
2073 2169
         HAL_START_ADC(TEMP_4_PIN);
2074 2170
         break;
2075 2171
       case MeasureTemp_4:
2076
-        raw_temp_value[4] += HAL_READ_ADC;
2172
+        ACCUMULATE_ADC(raw_temp_value[4]);
2077 2173
         break;
2078 2174
     #endif
2079 2175
 
@@ -2082,9 +2178,11 @@ void Temperature::isr() {
2082 2178
         HAL_START_ADC(FILWIDTH_PIN);
2083 2179
       break;
2084 2180
       case Measure_FILWIDTH:
2085
-        if (HAL_READ_ADC > 102) { // Make sure ADC is reading > 0.5 volts, otherwise don't read.
2181
+        if (!HAL_ADC_READY())
2182
+          next_sensor_state = adc_sensor_state; // redo this state
2183
+        else if (HAL_READ_ADC() > 102) { // Make sure ADC is reading > 0.5 volts, otherwise don't read.
2086 2184
           raw_filwidth_value -= (raw_filwidth_value >> 7); // Subtract 1/128th of the raw_filwidth_value
2087
-          raw_filwidth_value += ((unsigned long)HAL_READ_ADC << 7); // Add new ADC reading, scaled by 128
2185
+          raw_filwidth_value += ((unsigned long)HAL_READ_ADC() << 7); // Add new ADC reading, scaled by 128
2088 2186
         }
2089 2187
       break;
2090 2188
     #endif
@@ -2094,8 +2192,10 @@ void Temperature::isr() {
2094 2192
         HAL_START_ADC(ADC_KEYPAD_PIN);
2095 2193
         break;
2096 2194
       case Measure_ADC_KEY:
2097
-        if (ADCKey_count < 16) {
2098
-          raw_ADCKey_value = HAL_READ_ADC;
2195
+        if (!HAL_ADC_READY())
2196
+          next_sensor_state = adc_sensor_state; // redo this state
2197
+        else if (ADCKey_count < 16) {
2198
+          raw_ADCKey_value = HAL_READ_ADC();
2099 2199
           if (raw_ADCKey_value > 900) {
2100 2200
             //ADC Key release
2101 2201
             ADCKey_count = 0;
@@ -2113,94 +2213,12 @@ void Temperature::isr() {
2113 2213
 
2114 2214
   } // switch(adc_sensor_state)
2115 2215
 
2116
-  if (!adc_sensor_state && ++temp_count >= OVERSAMPLENR) { // 10 * 16 * 1/(16000000/64/256)  = 164ms.
2117
-
2118
-    temp_count = 0;
2119
-
2120
-    // Update the raw values if they've been read. Else we could be updating them during reading.
2121
-    if (!temp_meas_ready) set_current_temp_raw();
2122
-
2123
-    // Filament Sensor - can be read any time since IIR filtering is used
2124
-    #if ENABLED(FILAMENT_WIDTH_SENSOR)
2125
-      current_raw_filwidth = raw_filwidth_value >> 10;  // Divide to get to 0-16384 range since we used 1/128 IIR filter approach
2126
-    #endif
2127
-
2128
-    ZERO(raw_temp_value);
2129
-
2130
-    #if HAS_HEATED_BED
2131
-      raw_temp_bed_value = 0;
2132
-    #endif
2133
-
2134
-    #if HAS_TEMP_CHAMBER
2135
-      raw_temp_chamber_value = 0;
2136
-    #endif
2137
-
2138
-    #define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) > (HEATER_##N##_RAW_HI_TEMP) ? -1 : 1)
2139
-
2140
-    int constexpr temp_dir[] = {
2141
-      #if ENABLED(HEATER_0_USES_MAX6675)
2142
-         0
2143
-      #else
2144
-        TEMPDIR(0)
2145
-      #endif
2146
-      #if HOTENDS > 1
2147
-        , TEMPDIR(1)
2148
-        #if HOTENDS > 2
2149
-          , TEMPDIR(2)
2150
-          #if HOTENDS > 3
2151
-            , TEMPDIR(3)
2152
-            #if HOTENDS > 4
2153
-              , TEMPDIR(4)
2154
-            #endif // HOTENDS > 4
2155
-          #endif // HOTENDS > 3
2156
-        #endif // HOTENDS > 2
2157
-      #endif // HOTENDS > 1
2158
-    };
2159
-
2160
-    for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
2161
-      const int16_t tdir = temp_dir[e], rawtemp = current_temperature_raw[e] * tdir;
2162
-      const bool heater_on = 0 <
2163
-        #if ENABLED(PIDTEMP)
2164
-          soft_pwm_amount[e]
2165
-        #else
2166
-          target_temperature[e]
2167
-        #endif
2168
-      ;
2169
-      if (rawtemp > maxttemp_raw[e] * tdir && heater_on) max_temp_error(e);
2170
-      if (rawtemp < minttemp_raw[e] * tdir && !is_preheating(e) && heater_on) {
2171
-        #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
2172
-          if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
2173
-        #endif
2174
-            min_temp_error(e);
2175
-      }
2176
-      #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
2177
-        else
2178
-          consecutive_low_temperature_error[e] = 0;
2179
-      #endif
2180
-    }
2181
-
2182
-    #if HAS_HEATED_BED
2183
-      #if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP
2184
-        #define GEBED <=
2185
-      #else
2186
-        #define GEBED >=
2187
-      #endif
2188
-      const bool bed_on = 0 <
2189
-        #if ENABLED(PIDTEMPBED)
2190
-          soft_pwm_amount_bed
2191
-        #else
2192
-          target_temperature_bed
2193
-        #endif
2194
-      ;
2195
-      if (current_temperature_bed_raw GEBED bed_maxttemp_raw && bed_on) max_temp_error(-1);
2196
-      if (bed_minttemp_raw GEBED current_temperature_bed_raw && bed_on) min_temp_error(-1);
2197
-    #endif
2198
-
2199
-  } // temp_count >= OVERSAMPLENR
2216
+  // Go to the next state
2217
+  adc_sensor_state = next_sensor_state;
2200 2218
 
2201
-  // Go to the next state, up to SensorsReady
2202
-  adc_sensor_state = (ADCSensorState)(int(adc_sensor_state) + 1);
2203
-  if (adc_sensor_state > SensorsReady) adc_sensor_state = (ADCSensorState)0;
2219
+  //
2220
+  // Additional ~1KHz Tasks
2221
+  //
2204 2222
 
2205 2223
   #if ENABLED(BABYSTEPPING)
2206 2224
     LOOP_XYZ(axis) {

+ 2
- 0
Marlin/src/module/temperature.h View File

@@ -52,6 +52,7 @@
52 52
  * States for ADC reading in the ISR
53 53
  */
54 54
 enum ADCSensorState : char {
55
+  StartSampling,
55 56
   #if HAS_TEMP_ADC_0
56 57
     PrepareTemp_0,
57 58
     MeasureTemp_0,
@@ -328,6 +329,7 @@ class Temperature {
328 329
     /**
329 330
      * Called from the Temperature ISR
330 331
      */
332
+    static void readings_ready();
331 333
     static void isr();
332 334
 
333 335
     /**

Loading…
Cancel
Save