Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Fri Dec 27 20:14:23 2019 +0000
Revision:
104:6e06e0f4b476
Parent:
100:1ff35c07217c
AEAT-6012, TCD1103 updates

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 17:ab3cec0c8bf4 1 // Potentiometer plunger sensor
mjr 17:ab3cec0c8bf4 2 //
mjr 17:ab3cec0c8bf4 3 // This file implements our generic plunger sensor interface for a
mjr 43:7a6364d82a41 4 // potentiometer. The potentiometer resistance must be linear in
mjr 43:7a6364d82a41 5 // position. To connect physically, wire the fixed ends of the
mjr 43:7a6364d82a41 6 // potentiometer to +3.3V and GND (respectively), and connect the
mjr 43:7a6364d82a41 7 // wiper to an ADC-capable GPIO pin on the KL25Z. The wiper voltage
mjr 43:7a6364d82a41 8 // that we read on the ADC will vary linearly with the wiper position.
mjr 43:7a6364d82a41 9 // Mechanically attach the wiper to the plunger so that the wiper moves
mjr 43:7a6364d82a41 10 // in lock step with the plunger.
mjr 43:7a6364d82a41 11 //
mjr 100:1ff35c07217c 12 // In practice, the ADC readings from a potentiometer can be noisy,
mjr 100:1ff35c07217c 13 // varying by around 1% from reading to reading when the slider is
mjr 100:1ff35c07217c 14 // stationary. One way to improve this is to use longer sampling times
mjr 100:1ff35c07217c 15 // in the ADC to improve the accuracy of the sampling. We can tolerate
mjr 100:1ff35c07217c 16 // quite long ADC sampling times because even the slow modes are quite
mjr 100:1ff35c07217c 17 // a lot faster than the result rate we require. Another way to reduce
mjr 100:1ff35c07217c 18 // noise is to apply some low-pass filtering. The simplest low-pass
mjr 100:1ff35c07217c 19 // filter is to average a number of samples together. Since our ADC
mjr 100:1ff35c07217c 20 // sampling rate (even with long conversions) is quite a lot faster than
mjr 100:1ff35c07217c 21 // the needed output rate, we can simply average samples over the time
mjr 100:1ff35c07217c 22 // scale where we need discrete outputs.
mjr 100:1ff35c07217c 23 //
mjr 100:1ff35c07217c 24 // Note: even though this class is specifically for potentiometers, it
mjr 100:1ff35c07217c 25 // could also be used with any other type of sensor that represents its
mjr 100:1ff35c07217c 26 // position reading as a single analog voltage level that varies linearly
mjr 104:6e06e0f4b476 27 // with the position, such as an LVDT. Note that linearity is key here:
mjr 104:6e06e0f4b476 28 // this code wouldn't work well with a sensor that produces an analog
mjr 104:6e06e0f4b476 29 // voltage but has a NON-linear response curve with respect to measured
mjr 104:6e06e0f4b476 30 // position. For example, this code wouldn't work well with the old
mjr 104:6e06e0f4b476 31 // Sharp reflective IR proximity/distance sensors, since those have
mjr 104:6e06e0f4b476 32 // power-law response curves. To work with a non-linear sensor, you'd
mjr 104:6e06e0f4b476 33 // have to subclass this class, override readRaw(), and add processing
mjr 104:6e06e0f4b476 34 // that translates the non-linear sensor reading to a linear position
mjr 104:6e06e0f4b476 35 // measurement. Such processing is obviously a function of the physics
mjr 104:6e06e0f4b476 36 // of the particular sensor, so it would have to be crafted for each
mjr 104:6e06e0f4b476 37 // such sensor type.
mjr 100:1ff35c07217c 38 //
mjr 17:ab3cec0c8bf4 39
mjr 100:1ff35c07217c 40 #include "plunger.h"
mjr 100:1ff35c07217c 41 #include "AltAnalogIn.h"
mjr 17:ab3cec0c8bf4 42
mjr 35:e959ffba78fd 43 class PlungerSensorPot: public PlungerSensor
mjr 17:ab3cec0c8bf4 44 {
mjr 17:ab3cec0c8bf4 45 public:
mjr 86:e30a1f60f783 46 // Our native readings are taken as 16-bit ADC samples, so
mjr 86:e30a1f60f783 47 // our native scale is an unsigned 16-bit int, 0..65535.
mjr 100:1ff35c07217c 48 //
mjr 100:1ff35c07217c 49 // Initialize the ADC to take continuous samples, interrupting us
mjr 100:1ff35c07217c 50 // when each conversion finishes so that we can collect the result
mjr 100:1ff35c07217c 51 // in an ISR. For the sampling mode, use long conversions with
mjr 100:1ff35c07217c 52 // 24 ADCK cycles and 8x averaging; this gives us conversion times
mjr 100:1ff35c07217c 53 // of about 37.33us.
mjr 100:1ff35c07217c 54 //
mjr 100:1ff35c07217c 55 PlungerSensorPot(PinName ao) :
mjr 100:1ff35c07217c 56 PlungerSensor(65535),
mjr 100:1ff35c07217c 57 pot(ao, true, 24, 8) // continuous, 24-cycle long samples, 8x averaging -> 37.33us/sample
mjr 17:ab3cec0c8bf4 58 {
mjr 100:1ff35c07217c 59 // calibrate the ADC for best accuracy
mjr 100:1ff35c07217c 60 pot.calibrate();
mjr 100:1ff35c07217c 61
mjr 100:1ff35c07217c 62 // clear the timing statistics
mjr 100:1ff35c07217c 63 totalConversionTime = 0;
mjr 100:1ff35c07217c 64 nSamples = 0;
mjr 100:1ff35c07217c 65
mjr 100:1ff35c07217c 66 // start with everything zeroed
mjr 100:1ff35c07217c 67 history_write_idx = 0;
mjr 100:1ff35c07217c 68 running_sum = 0;
mjr 100:1ff35c07217c 69 for (int i = 0 ; i < countof(history); ++i)
mjr 100:1ff35c07217c 70 history[i] = 0;
mjr 100:1ff35c07217c 71
mjr 100:1ff35c07217c 72 // set the initial timestamp to the arbitrary epoch on the timer
mjr 100:1ff35c07217c 73 current_timestamp = 0;
mjr 100:1ff35c07217c 74
mjr 100:1ff35c07217c 75 // Set up an interrupt handler to collect the ADC results. The
mjr 100:1ff35c07217c 76 // ADC will trigger the interrupt on each completed sample.
mjr 100:1ff35c07217c 77 isrThis = this;
mjr 100:1ff35c07217c 78 NVIC_SetVector(ADC0_IRQn, (uint32_t)&irq_handler_static);
mjr 100:1ff35c07217c 79 NVIC_EnableIRQ(ADC0_IRQn);
mjr 100:1ff35c07217c 80 pot.enableInterrupts();
mjr 100:1ff35c07217c 81
mjr 100:1ff35c07217c 82 // Start the first asynchronous ADC sample. The ADC will run
mjr 100:1ff35c07217c 83 // continuously once started, and we'll collect samples in the ISR.
mjr 100:1ff35c07217c 84 pot.start();
mjr 48:058ace2aed1d 85 timer.start();
mjr 17:ab3cec0c8bf4 86 }
mjr 17:ab3cec0c8bf4 87
mjr 35:e959ffba78fd 88 virtual void init()
mjr 17:ab3cec0c8bf4 89 {
mjr 17:ab3cec0c8bf4 90 }
mjr 17:ab3cec0c8bf4 91
mjr 100:1ff35c07217c 92 // samples are always ready
mjr 100:1ff35c07217c 93 virtual bool ready() { return true; }
mjr 100:1ff35c07217c 94
mjr 48:058ace2aed1d 95 // read the sensor
mjr 86:e30a1f60f783 96 virtual bool readRaw(PlungerReading &r)
mjr 17:ab3cec0c8bf4 97 {
mjr 100:1ff35c07217c 98 // read the current sample components atomically
mjr 100:1ff35c07217c 99 __disable_irq();
mjr 48:058ace2aed1d 100
mjr 100:1ff35c07217c 101 // figure the current average reading over the history window
mjr 100:1ff35c07217c 102 r.pos = running_sum / countof(history);
mjr 100:1ff35c07217c 103 r.t = current_timestamp;
mjr 48:058ace2aed1d 104
mjr 100:1ff35c07217c 105 // done with the atomic read
mjr 100:1ff35c07217c 106 __enable_irq();
mjr 52:8298b2a73eb2 107
mjr 100:1ff35c07217c 108 // we always have a result available
mjr 17:ab3cec0c8bf4 109 return true;
mjr 17:ab3cec0c8bf4 110 }
mjr 52:8298b2a73eb2 111
mjr 100:1ff35c07217c 112 // Figure the average scan time in microseconds
mjr 53:9b2611964afc 113 virtual uint32_t getAvgScanTime()
mjr 53:9b2611964afc 114 {
mjr 100:1ff35c07217c 115 // The effective time per sample is the raw sampling interval
mjr 100:1ff35c07217c 116 // times the averaging window size.
mjr 100:1ff35c07217c 117 if (nSamples == 0)
mjr 100:1ff35c07217c 118 return 0;
mjr 100:1ff35c07217c 119 else
mjr 100:1ff35c07217c 120 return static_cast<uint32_t>(totalConversionTime/nSamples) * countof(history);
mjr 53:9b2611964afc 121 }
mjr 23:14f8c5004cd0 122
mjr 17:ab3cec0c8bf4 123 private:
mjr 48:058ace2aed1d 124 // analog input for the pot wiper
mjr 100:1ff35c07217c 125 AltAnalogIn_16bit pot;
mjr 48:058ace2aed1d 126
mjr 48:058ace2aed1d 127 // timer for input timestamps
mjr 48:058ace2aed1d 128 Timer timer;
mjr 52:8298b2a73eb2 129
mjr 100:1ff35c07217c 130 // total sampling time and number of samples, for computing scan times
mjr 100:1ff35c07217c 131 uint64_t totalConversionTime;
mjr 100:1ff35c07217c 132 uint32_t nSamples;
mjr 100:1ff35c07217c 133
mjr 100:1ff35c07217c 134 // interrupt handler
mjr 100:1ff35c07217c 135 static PlungerSensorPot *isrThis;
mjr 100:1ff35c07217c 136 static void irq_handler_static(void) { isrThis->irq_handler(); }
mjr 100:1ff35c07217c 137
mjr 100:1ff35c07217c 138 void irq_handler()
mjr 100:1ff35c07217c 139 {
mjr 100:1ff35c07217c 140 // read the next sample
mjr 100:1ff35c07217c 141 uint16_t sample = pot.read_u16();
mjr 100:1ff35c07217c 142
mjr 100:1ff35c07217c 143 // deduct the outgoing sample from the running sum
mjr 100:1ff35c07217c 144 running_sum -= history[history_write_idx];
mjr 100:1ff35c07217c 145
mjr 100:1ff35c07217c 146 // add the new sample into the running sum
mjr 100:1ff35c07217c 147 running_sum += sample;
mjr 100:1ff35c07217c 148
mjr 100:1ff35c07217c 149 // store the new sample in the history
mjr 100:1ff35c07217c 150 history[history_write_idx++] = sample;
mjr 100:1ff35c07217c 151
mjr 100:1ff35c07217c 152 // wrap the history index at the end of the window
mjr 100:1ff35c07217c 153 if (history_write_idx >= countof(history))
mjr 100:1ff35c07217c 154 history_write_idx = 0;
mjr 100:1ff35c07217c 155
mjr 100:1ff35c07217c 156 // calculate the elapsed time since the last sample
mjr 100:1ff35c07217c 157 uint32_t now = timer.read_us();
mjr 100:1ff35c07217c 158 totalConversionTime += now - current_timestamp;
mjr 100:1ff35c07217c 159 ++nSamples;
mjr 100:1ff35c07217c 160
mjr 100:1ff35c07217c 161 // update the reading timestamp
mjr 100:1ff35c07217c 162 current_timestamp = now;
mjr 100:1ff35c07217c 163 }
mjr 100:1ff35c07217c 164
mjr 100:1ff35c07217c 165 // Running sum of readings. This is the sum of the readings in the
mjr 100:1ff35c07217c 166 // rolling 5ms window.
mjr 100:1ff35c07217c 167 uint32_t running_sum;
mjr 100:1ff35c07217c 168
mjr 100:1ff35c07217c 169 // Rolling window of readings, for the averaging filter. Our
mjr 100:1ff35c07217c 170 // sampling time is about 37.33us; 128 of these add up to about
mjr 100:1ff35c07217c 171 // 4.8ms, which is a good interval between samples for our
mjr 100:1ff35c07217c 172 // internal tracking and sending USB data to the PC.
mjr 100:1ff35c07217c 173 uint16_t history[128];
mjr 100:1ff35c07217c 174 int history_write_idx;
mjr 100:1ff35c07217c 175
mjr 100:1ff35c07217c 176 // current average reading and scan time
mjr 100:1ff35c07217c 177 uint32_t current_timestamp;
mjr 17:ab3cec0c8bf4 178 };