Browse Source

LPC1768: Increase ADC median filter from 3 values to 23

Clarify the HAL_adc_get_result method to make sure correct values enter the filters

HAL: Fix the PID control loop for non-AVR platforms
Christopher Pepper 7 years ago
parent
commit
14dcad6bbc

+ 114
- 34
Marlin/src/HAL/HAL_LPC1768/HAL.cpp View File

22
 
22
 
23
 #include "../../inc/MarlinConfig.h"
23
 #include "../../inc/MarlinConfig.h"
24
 
24
 
25
-extern "C" {
26
-  //#include <lpc17xx_adc.h>
27
-  //#include <lpc17xx_pinsel.h>
28
-}
29
-
30
 HalSerial usb_serial;
25
 HalSerial usb_serial;
31
 
26
 
32
 //u8glib required fucntions
27
 //u8glib required fucntions
112
   };
107
   };
113
 }
108
 }
114
 
109
 
115
-uint8_t active_adc = 0;
116
 void HAL_adc_start_conversion(const uint8_t ch) {
110
 void HAL_adc_start_conversion(const uint8_t ch) {
117
   if (analogInputToDigitalPin(ch) == -1) {
111
   if (analogInputToDigitalPin(ch) == -1) {
118
     MYSERIAL.printf("HAL: HAL_adc_start_conversion: invalid channel %d\n", ch);
112
     MYSERIAL.printf("HAL: HAL_adc_start_conversion: invalid channel %d\n", ch);
122
   LPC_ADC->ADCR &= ~0xFF; // Reset
116
   LPC_ADC->ADCR &= ~0xFF; // Reset
123
   SBI(LPC_ADC->ADCR, ch); // Select Channel
117
   SBI(LPC_ADC->ADCR, ch); // Select Channel
124
   SBI(LPC_ADC->ADCR, 24); // Start conversion
118
   SBI(LPC_ADC->ADCR, 24); // Start conversion
125
-  active_adc = ch;
126
 }
119
 }
127
 
120
 
128
 bool HAL_adc_finished(void) {
121
 bool HAL_adc_finished(void) {
130
 }
123
 }
131
 
124
 
132
 // possible config options if something similar is extended to more platforms.
125
 // possible config options if something similar is extended to more platforms.
133
-#define ADC_USE_MEDIAN_FILTER      // filter out erroneous readings
134
-#define ADC_USE_LOWPASS_FILTER     // filter out high frequency noise
135
-#define ADC_LOWPASS_K_VALUE 4      // how much to smooth out noise (1:8)
126
+#define ADC_USE_MEDIAN_FILTER          // Filter out erroneous readings
127
+#define ADC_MEDIAN_FILTER_SIZE    (23) // Higher values increase step delay (phase shift),
128
+                                       // (ADC_MEDIAN_FILTER_SIZE + 1) / 2 sample step delay (12 samples @ 500Hz: 24ms phase shift)
129
+                                       // Memory usage per ADC channel (bytes): (6 * ADC_MEDIAN_FILTER_SIZE) + 16
130
+                                       // 8 * ((6 * 23) + 16 ) = 1232 Bytes for 8 channels
131
+
132
+#define ADC_USE_LOWPASS_FILTER         // Filter out high frequency noise
133
+#define ADC_LOWPASS_K_VALUE       (6)  // Higher values increase rise time
134
+                                       // Rise time sample delays for 100% signal convergence on full range step
135
+                                       // (1 : 13, 2 : 32, 3 : 67, 4 : 139, 5 : 281, 6 : 565, 7 : 1135, 8 : 2273)
136
+                                       // K = 6, 565 samples, 500Hz sample rate, 1.13s convergence on full range step
137
+                                       // Memory usage per ADC channel (bytes): 4 (32 Bytes for 8 channels)
138
+
136
 
139
 
140
+// Sourced from https://embeddedgurus.com/stack-overflow/tag/median-filter/
137
 struct MedianFilter {
141
 struct MedianFilter {
138
-  uint16_t values[3];
139
-  uint8_t next_val;
140
-  MedianFilter() {
141
-    next_val = 0;
142
-    values[0] = values[1] = values[2] = 0;
142
+  #define STOPPER 0                // Smaller than any datum
143
+  struct Pair {
144
+    Pair   *point;                 // Pointers forming list linked in sorted order
145
+    uint16_t  value;               // Values to sort
146
+  };
147
+
148
+  Pair buffer[ADC_MEDIAN_FILTER_SIZE] = {}; // Buffer of nwidth pairs
149
+  Pair *datpoint = buffer;                  // Pointer into circular buffer of data
150
+  Pair small = {NULL, STOPPER};             // Chain stopper
151
+  Pair big = {&small, 0};                   // Pointer to head (largest) of linked list.
152
+
153
+  uint16_t update(uint16_t datum) {
154
+    Pair *successor;                        // Pointer to successor of replaced data item
155
+    Pair *scan;                             // Pointer used to scan down the sorted list
156
+    Pair *scanold;                          // Previous value of scan
157
+    Pair *median;                           // Pointer to median
158
+    uint16_t i;
159
+
160
+    if (datum == STOPPER) {
161
+      datum = STOPPER + 1;                  // No stoppers allowed.
162
+    }
163
+
164
+    if ( (++datpoint - buffer) >= ADC_MEDIAN_FILTER_SIZE) {
165
+      datpoint = buffer;                    // Increment and wrap data in pointer.
166
+    }
167
+
168
+    datpoint->value = datum;                // Copy in new datum
169
+    successor = datpoint->point;            // Save pointer to old value's successor
170
+    median = &big;                          // Median initially to first in chain
171
+    scanold = NULL;                         // Scanold initially null.
172
+    scan = &big;                            // Points to pointer to first (largest) datum in chain
173
+
174
+    // Handle chain-out of first item in chain as special case
175
+    if (scan->point == datpoint) {
176
+      scan->point = successor;
177
+    }
178
+    scanold = scan;                         // Save this pointer and
179
+    scan = scan->point ;                    // step down chain
180
+
181
+    // Loop through the chain, normal loop exit via break.
182
+    for (i = 0 ; i < ADC_MEDIAN_FILTER_SIZE; ++i) {
183
+      // Handle odd-numbered item in chain
184
+      if (scan->point == datpoint) {
185
+        scan->point = successor;            // Chain out the old datum
186
+      }
187
+
188
+      if (scan->value < datum) {            // If datum is larger than scanned value
189
+        datpoint->point = scanold->point;   // Chain it in here
190
+        scanold->point = datpoint;          // Mark it chained in
191
+        datum = STOPPER;
192
+      }
193
+
194
+      // Step median pointer down chain after doing odd-numbered element
195
+      median = median->point;               // Step median pointer
196
+      if (scan == &small) {
197
+        break;                              // Break at end of chain
198
+      }
199
+      scanold = scan;                       // Save this pointer and
200
+      scan = scan->point;                   // step down chain
201
+
202
+      // Handle even-numbered item in chain.
203
+      if (scan->point == datpoint) {
204
+        scan->point = successor;
205
+      }
206
+
207
+      if (scan->value < datum) {
208
+        datpoint->point = scanold->point;
209
+        scanold->point = datpoint;
210
+        datum = STOPPER;
211
+      }
212
+
213
+      if (scan == &small) {
214
+        break;
215
+      }
216
+
217
+      scanold = scan;
218
+      scan = scan->point;
219
+    }
220
+    return median->value;
143
   }
221
   }
222
+};
223
+
224
+struct LowpassFilter {
225
+  uint32_t data_delay = 0;
144
   uint16_t update(uint16_t value) {
226
   uint16_t update(uint16_t value) {
145
-    values[next_val++] = value;
146
-    next_val = next_val % 3;
147
-    return max(min(values[0], values[1]), min(max(values[0], values[1]), values[2]));     //median
227
+    data_delay = data_delay - (data_delay >> ADC_LOWPASS_K_VALUE) + value;
228
+    return (uint16_t)(data_delay >> ADC_LOWPASS_K_VALUE);
148
   }
229
   }
149
 };
230
 };
150
 
231
 
151
-uint16_t lowpass_filter(uint16_t value) {
152
-  const uint8_t k_data_shift = ADC_LOWPASS_K_VALUE;
153
-  static uint32_t data_delay[NUM_ANALOG_INPUTS] = { 0 };
154
-  uint32_t &active_filter = data_delay[active_adc];
155
-  active_filter = active_filter - (active_filter >> k_data_shift) + value;
156
-  return (uint16_t)(active_filter >> k_data_shift);
157
-}
158
-
159
 uint16_t HAL_adc_get_result(void) {
232
 uint16_t HAL_adc_get_result(void) {
160
-  uint32_t data = LPC_ADC->ADGDR;
161
-  CBI(LPC_ADC->ADCR, 24);    // Stop conversion
162
-  if (data & ADC_OVERRUN) return 0;
233
+  uint32_t adgdr = LPC_ADC->ADGDR;
234
+  CBI(LPC_ADC->ADCR, 24);                    // Stop conversion
235
+
236
+  if (adgdr & ADC_OVERRUN) return 0;
237
+  uint16_t data = (adgdr >> 4) & 0xFFF;      // copy the 12bit data value
238
+  uint8_t adc_channel = (adgdr >> 24) & 0x7; // copy the  3bit used channel
239
+
163
   #ifdef ADC_USE_MEDIAN_FILTER
240
   #ifdef ADC_USE_MEDIAN_FILTER
164
     static MedianFilter median_filter[NUM_ANALOG_INPUTS];
241
     static MedianFilter median_filter[NUM_ANALOG_INPUTS];
165
-    data = median_filter[active_adc].update((uint16_t)data);
242
+    data = median_filter[adc_channel].update(data);
166
   #endif
243
   #endif
244
+
167
   #ifdef ADC_USE_LOWPASS_FILTER
245
   #ifdef ADC_USE_LOWPASS_FILTER
168
-    data = lowpass_filter((uint16_t)data);
246
+    static LowpassFilter lowpass_filter[NUM_ANALOG_INPUTS];
247
+    data = lowpass_filter[adc_channel].update(data);
169
   #endif
248
   #endif
170
-  return ((data >> 6) & 0x3ff);    // 10bit
249
+
250
+  return ((data >> 2) & 0x3ff);    // return 10bit value as Marlin expects
171
 }
251
 }
172
 
252
 
173
 #define SBIT_CNTEN     0
253
 #define SBIT_CNTEN     0
187
   LPC_PWM1->TCR = _BV(SBIT_CNTEN) | _BV(SBIT_PWMEN);
267
   LPC_PWM1->TCR = _BV(SBIT_CNTEN) | _BV(SBIT_PWMEN);
188
   LPC_PWM1->PR  =  0x0;               // No prescalar
268
   LPC_PWM1->PR  =  0x0;               // No prescalar
189
   LPC_PWM1->MCR = _BV(SBIT_PWMMR0R);  // Reset on PWMMR0, reset TC if it matches MR0
269
   LPC_PWM1->MCR = _BV(SBIT_PWMMR0R);  // Reset on PWMMR0, reset TC if it matches MR0
190
-  LPC_PWM1->MR0 = 255;                /* set PWM cycle(Ton+Toff)=255) */
191
-  LPC_PWM1->MR5 = 0;                  /* Set 50% Duty Cycle for the channels */
270
+  LPC_PWM1->MR0 = 255;                // set PWM cycle(Ton+Toff)=255)
271
+  LPC_PWM1->MR5 = 0;                  // Set 50% Duty Cycle for the channels
192
   LPC_PWM1->MR6 = 0;
272
   LPC_PWM1->MR6 = 0;
193
 
273
 
194
   // Trigger the latch Enable Bits to load the new Match Values MR0, MR5, MR6
274
   // Trigger the latch Enable Bits to load the new Match Values MR0, MR5, MR6

+ 1
- 1
Marlin/src/HAL/HAL_LPC1768/HAL_LCD_pin_routines.c View File

34
 
34
 
35
 #include <LPC17xx.h>
35
 #include <LPC17xx.h>
36
 #include <lpc17xx_pinsel.h>
36
 #include <lpc17xx_pinsel.h>
37
-#include "src/core/macros.h"
37
+#include "../../src/core/macros.h"
38
 //#include "pinmapping.h"
38
 //#include "pinmapping.h"
39
 
39
 
40
 #define LPC_PORT_OFFSET         (0x0020)
40
 #define LPC_PORT_OFFSET         (0x0020)

+ 1
- 1
Marlin/src/module/temperature.h View File

90
 
90
 
91
 #if HAS_PID_HEATING
91
 #if HAS_PID_HEATING
92
   #define PID_K2 (1.0-PID_K1)
92
   #define PID_K2 (1.0-PID_K1)
93
-  #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (F_CPU / 64.0 / 256.0))
93
+  #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
94
 
94
 
95
   // Apply the scale factors to the PID values
95
   // Apply the scale factors to the PID values
96
   #define scalePID_i(i)   ( (i) * PID_dT )
96
   #define scalePID_i(i)   ( (i) * PID_dT )

Loading…
Cancel
Save