Generates a test signal on an AnalogOut and monitors a signal on an AnalogIn, plotting the test signal or the actual signal depending on a conditional compile. The wait() and wait_ms() library calls for this board are highly inaccurate so a new function is provided to wait for X number of milliseconds -- which is not very accurate.

Dependencies:   LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI mbed-os BSP_DISCO_F429ZI

Committer:
Damotclese
Date:
Mon Jun 17 17:11:07 2019 +0000
Revision:
2:cbcf2695a4a1
Parent:
1:b9d4b9b8884c
Added average TEC history;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Damotclese 0:1ebe7d222470 1
Damotclese 0:1ebe7d222470 2 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 3 // LaserMon-ScanInput.cpp
Damotclese 0:1ebe7d222470 4 //
Damotclese 0:1ebe7d222470 5 // Fredric L. Rice, June 2019
Damotclese 0:1ebe7d222470 6 //
Damotclese 0:1ebe7d222470 7 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 8
Damotclese 0:1ebe7d222470 9 #include "mbed.h" // The mbed operating system
Damotclese 0:1ebe7d222470 10 #include "LCD_DISCO_F429ZI.h" // For controlling the LCD
Damotclese 0:1ebe7d222470 11 #include "TS_DISCO_F429ZI.h" // For controlling the touch screen
Damotclese 0:1ebe7d222470 12 #include "LaserMon-Main.h" // For data exported to us
Damotclese 0:1ebe7d222470 13 #include "LaserMon-TestOutput.h" // For test signal
Damotclese 0:1ebe7d222470 14
Damotclese 0:1ebe7d222470 15 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 16 // Options, defined constants, and MACROs
Damotclese 0:1ebe7d222470 17 //
Damotclese 0:1ebe7d222470 18 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 19
Damotclese 2:cbcf2695a4a1 20 #define WANT_TEST_SIGNAL 0
Damotclese 0:1ebe7d222470 21
Damotclese 0:1ebe7d222470 22 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 23 // Local data storage
Damotclese 0:1ebe7d222470 24 //
Damotclese 0:1ebe7d222470 25 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 26
Damotclese 0:1ebe7d222470 27 // We create an analog input
Damotclese 0:1ebe7d222470 28 static AnalogIn st_scanInput(LASER_SCAN_IN);
Damotclese 1:b9d4b9b8884c 29
Damotclese 0:1ebe7d222470 30 // For diagnostic purposes to show that the Laser Scan is operating
Damotclese 0:1ebe7d222470 31 static DigitalOut st_scanInputLED(LED2);
Damotclese 0:1ebe7d222470 32
Damotclese 0:1ebe7d222470 33 // There are LCD_HEIGHT possible scan lines with a height of
Damotclese 0:1ebe7d222470 34 // LCD_WIDTH -- yes, the defined constant names are swapped
Damotclese 0:1ebe7d222470 35 // because we plot sideways.
Damotclese 0:1ebe7d222470 36 //
Damotclese 0:1ebe7d222470 37 // This value contains the next scan line number to plot
Damotclese 0:1ebe7d222470 38 static uint16_t u16_nextScanLine;
Damotclese 0:1ebe7d222470 39
Damotclese 1:b9d4b9b8884c 40 // We store the last pixel's height so we may plot
Damotclese 0:1ebe7d222470 41 static uint16_t u16_lastHeight = 0;
Damotclese 0:1ebe7d222470 42
Damotclese 1:b9d4b9b8884c 43 // Flag indicates whether we believe we are receiving porch or not
Damotclese 1:b9d4b9b8884c 44 static bool b_inPorch;
Damotclese 0:1ebe7d222470 45
Damotclese 2:cbcf2695a4a1 46 // We keep track of how many times we have had to search for porch.
Damotclese 2:cbcf2695a4a1 47 // Typically we could expect not to have to search for it when the
Damotclese 2:cbcf2695a4a1 48 // plot goes beyond the end of the screen, however we may need to
Damotclese 2:cbcf2695a4a1 49 // search on power-up and when the scan frequency changes
Damotclese 1:b9d4b9b8884c 50 static uint16_t u16_resyncCount;
Damotclese 2:cbcf2695a4a1 51
Damotclese 2:cbcf2695a4a1 52 // For no reason at all we keep track of how many scans we detect
Damotclese 1:b9d4b9b8884c 53 static uint32_t u32_scanCount;
Damotclese 1:b9d4b9b8884c 54
Damotclese 2:cbcf2695a4a1 55 // When we are searching for porch, we use this flag to indicate that
Damotclese 1:b9d4b9b8884c 56 static bool b_waitingForPorch;
Damotclese 2:cbcf2695a4a1 57
Damotclese 2:cbcf2695a4a1 58 // We keep track of how many milliseconds there are between porch
Damotclese 2:cbcf2695a4a1 59 // detections. This indicates a fairly close timing of the scan
Damotclese 2:cbcf2695a4a1 60 // frequency.
Damotclese 2:cbcf2695a4a1 61 static uint16_t u16_scanFrequency;
Damotclese 2:cbcf2695a4a1 62 static uint16_t u16_msFromPorchToPorch;
Damotclese 1:b9d4b9b8884c 63
Damotclese 0:1ebe7d222470 64 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 65 // ScanInputPlotThisValue()
Damotclese 0:1ebe7d222470 66 //
Damotclese 0:1ebe7d222470 67 // What percentage of LCD_HEIGHT is the voltage? We need to scale 0 to
Damotclese 0:1ebe7d222470 68 // 3.3 volts across LCD_HEIGHT, with 0 being zero, and 3.3 volts being
Damotclese 0:1ebe7d222470 69 // LCD_HEIGHT.
Damotclese 0:1ebe7d222470 70 //
Damotclese 0:1ebe7d222470 71 // We compute the percentage of 3.3 volts that the input signal is
Damotclese 0:1ebe7d222470 72 // currently showing, then we compute that percentage of LCD_HEIGHT to
Damotclese 0:1ebe7d222470 73 // determine how many pixels on a scan line that percentage is. That
Damotclese 0:1ebe7d222470 74 // gives us the height of the plot line while u16_nextScanLine gives
Damotclese 0:1ebe7d222470 75 // us the line to plot it on.
Damotclese 0:1ebe7d222470 76 //
Damotclese 0:1ebe7d222470 77 // This is easy because the value passed to this function is a value
Damotclese 0:1ebe7d222470 78 // from 0.0 to 1.0 which is a percentage of 3.3 volts, so we use the
Damotclese 0:1ebe7d222470 79 // value against LCD_HEIGHT to yield the percentage of height.
Damotclese 0:1ebe7d222470 80 //
Damotclese 0:1ebe7d222470 81 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 82 static void ScanInputPlotThisValue(float f_analogValue)
Damotclese 0:1ebe7d222470 83 {
Damotclese 0:1ebe7d222470 84 // Compute the percentage of LCD height
Damotclese 1:b9d4b9b8884c 85 uint16_t u16_pixelHeight = ((f_analogValue / 3.3f) * ((float)LCD_HEIGHT - 10.0f));
Damotclese 0:1ebe7d222470 86
Damotclese 0:1ebe7d222470 87 u16_pixelHeight /= 2;
Damotclese 0:1ebe7d222470 88 u16_pixelHeight += 10;
Damotclese 0:1ebe7d222470 89
Damotclese 1:b9d4b9b8884c 90 // Clear the entire current scan line to plot
Damotclese 1:b9d4b9b8884c 91 st_lcd.SetTextColor(LCD_COLOR_WHITE);
Damotclese 1:b9d4b9b8884c 92 st_lcd.DrawLine(1, u16_nextScanLine, LCD_WIDTH, u16_nextScanLine);
Damotclese 1:b9d4b9b8884c 93
Damotclese 1:b9d4b9b8884c 94 // Plot from the previous pixel to the new one
Damotclese 1:b9d4b9b8884c 95 st_lcd.SetTextColor(LCD_COLOR_BLUE);
Damotclese 1:b9d4b9b8884c 96
Damotclese 1:b9d4b9b8884c 97 // Are we currently in porch? We plot differently if so
Damotclese 1:b9d4b9b8884c 98 if (false == b_inPorch)
Damotclese 0:1ebe7d222470 99 {
Damotclese 1:b9d4b9b8884c 100 // We plot ramp from the previous scan line's height to the current scan line and height
Damotclese 1:b9d4b9b8884c 101 st_lcd.DrawLine(u16_lastHeight, u16_nextScanLine - 1, u16_pixelHeight, u16_nextScanLine);
Damotclese 0:1ebe7d222470 102 }
Damotclese 0:1ebe7d222470 103 else
Damotclese 0:1ebe7d222470 104 {
Damotclese 1:b9d4b9b8884c 105 // We plot the porch at a height of 10 pixels
Damotclese 1:b9d4b9b8884c 106 st_lcd.DrawLine(10, u16_nextScanLine - 1, 10, u16_nextScanLine);
Damotclese 0:1ebe7d222470 107 }
Damotclese 1:b9d4b9b8884c 108
Damotclese 1:b9d4b9b8884c 109 // Keep track of the last height so we may plot
Damotclese 0:1ebe7d222470 110 u16_lastHeight = u16_pixelHeight;
Damotclese 1:b9d4b9b8884c 111 }
Damotclese 1:b9d4b9b8884c 112
Damotclese 1:b9d4b9b8884c 113 // ----------------------------------------------------------------------
Damotclese 1:b9d4b9b8884c 114 //
Damotclese 1:b9d4b9b8884c 115 //
Damotclese 1:b9d4b9b8884c 116 // ----------------------------------------------------------------------
Damotclese 1:b9d4b9b8884c 117 static float ScanInputGetInputVoltage(void)
Damotclese 1:b9d4b9b8884c 118 {
Damotclese 1:b9d4b9b8884c 119 // Get the current analog input value and convert to volts
Damotclese 1:b9d4b9b8884c 120 float f_analogValue = st_scanInput.read() * 3.3f;
Damotclese 0:1ebe7d222470 121
Damotclese 1:b9d4b9b8884c 122 #if WANT_TEST_SIGNAL
Damotclese 1:b9d4b9b8884c 123 // Use the test output signal voltage instead
Damotclese 1:b9d4b9b8884c 124 f_analogValue = f_rampVoltage;
Damotclese 1:b9d4b9b8884c 125 #endif
Damotclese 1:b9d4b9b8884c 126
Damotclese 1:b9d4b9b8884c 127 // Return either the actual analog in or test voltage
Damotclese 1:b9d4b9b8884c 128 return f_analogValue;
Damotclese 1:b9d4b9b8884c 129 }
Damotclese 1:b9d4b9b8884c 130
Damotclese 2:cbcf2695a4a1 131 static void ScanInputUpdateScanFrequency(void)
Damotclese 2:cbcf2695a4a1 132 {
Damotclese 2:cbcf2695a4a1 133 // Store the last porch to porch counter
Damotclese 2:cbcf2695a4a1 134 u16_scanFrequency = u16_msFromPorchToPorch;
Damotclese 2:cbcf2695a4a1 135
Damotclese 2:cbcf2695a4a1 136 // Restart the porch to porch counter
Damotclese 2:cbcf2695a4a1 137 u16_msFromPorchToPorch = 0;
Damotclese 2:cbcf2695a4a1 138 }
Damotclese 2:cbcf2695a4a1 139
Damotclese 1:b9d4b9b8884c 140 // ----------------------------------------------------------------------
Damotclese 1:b9d4b9b8884c 141 // ScanInputWaitForPorch()
Damotclese 1:b9d4b9b8884c 142 //
Damotclese 1:b9d4b9b8884c 143 // ----------------------------------------------------------------------
Damotclese 1:b9d4b9b8884c 144 static void ScanInputWaitForPorch(void)
Damotclese 1:b9d4b9b8884c 145 {
Damotclese 1:b9d4b9b8884c 146 float f_analogValue = 5.0f;
Damotclese 1:b9d4b9b8884c 147
Damotclese 1:b9d4b9b8884c 148 // While we're not seeing porch, loop
Damotclese 1:b9d4b9b8884c 149 if (f_analogValue > 0.5f)
Damotclese 0:1ebe7d222470 150 {
Damotclese 1:b9d4b9b8884c 151 return;
Damotclese 1:b9d4b9b8884c 152 }
Damotclese 0:1ebe7d222470 153
Damotclese 1:b9d4b9b8884c 154 // Flag the fact that we're in porch
Damotclese 1:b9d4b9b8884c 155 b_inPorch = true;
Damotclese 1:b9d4b9b8884c 156
Damotclese 1:b9d4b9b8884c 157 b_waitingForPorch = false;
Damotclese 1:b9d4b9b8884c 158
Damotclese 2:cbcf2695a4a1 159 // Keep track of our scan frequency
Damotclese 2:cbcf2695a4a1 160 ScanInputUpdateScanFrequency();
Damotclese 2:cbcf2695a4a1 161
Damotclese 1:b9d4b9b8884c 162 // Since we detected porch, start the plot over from the beginning
Damotclese 1:b9d4b9b8884c 163 u16_nextScanLine = 50;
Damotclese 1:b9d4b9b8884c 164
Damotclese 1:b9d4b9b8884c 165 // The last height we consider to be 1 pixel on porch
Damotclese 1:b9d4b9b8884c 166 u16_lastHeight = 1;
Damotclese 1:b9d4b9b8884c 167
Damotclese 2:cbcf2695a4a1 168 // Keep track of how many times we had to wait for locating porch
Damotclese 2:cbcf2695a4a1 169 // again after loosing it. Note that on power-up, if we are using
Damotclese 2:cbcf2695a4a1 170 // the test signal output, it is driven to porch co-incident with
Damotclese 2:cbcf2695a4a1 171 // the input test, so we start up with porch as the first sample
Damotclese 1:b9d4b9b8884c 172 ++u16_resyncCount;
Damotclese 0:1ebe7d222470 173 }
Damotclese 0:1ebe7d222470 174
Damotclese 0:1ebe7d222470 175 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 176 // ScanInputGetNextValue()
Damotclese 0:1ebe7d222470 177 //
Damotclese 0:1ebe7d222470 178 //
Damotclese 0:1ebe7d222470 179 // ----------------------------------------------------------------------
Damotclese 2:cbcf2695a4a1 180 static void ScanInputGetNextValue(bool b_allowPlotting)
Damotclese 0:1ebe7d222470 181 {
Damotclese 1:b9d4b9b8884c 182 float f_analogValue = ScanInputGetInputVoltage();
Damotclese 0:1ebe7d222470 183
Damotclese 1:b9d4b9b8884c 184 // Dows the input indicate that we are in porch?
Damotclese 1:b9d4b9b8884c 185 if (f_analogValue < 1.0f)
Damotclese 1:b9d4b9b8884c 186 {
Damotclese 1:b9d4b9b8884c 187 // Did we previously know that we were in porch?
Damotclese 1:b9d4b9b8884c 188 if (false == b_inPorch)
Damotclese 1:b9d4b9b8884c 189 {
Damotclese 2:cbcf2695a4a1 190 float f_plusFourPercent = 0.0f;
Damotclese 1:b9d4b9b8884c 191
Damotclese 1:b9d4b9b8884c 192 // Flag the fact that we're in porch now
Damotclese 1:b9d4b9b8884c 193 b_inPorch = true;
Damotclese 1:b9d4b9b8884c 194
Damotclese 1:b9d4b9b8884c 195 // Since we detected a new porch, start the plot over
Damotclese 1:b9d4b9b8884c 196 u16_nextScanLine = 49;
Damotclese 1:b9d4b9b8884c 197
Damotclese 1:b9d4b9b8884c 198 // The last height we consider to be 1 pixel on porch
Damotclese 1:b9d4b9b8884c 199 u16_lastHeight = 1;
Damotclese 1:b9d4b9b8884c 200
Damotclese 2:cbcf2695a4a1 201 // Update our scan frequency
Damotclese 2:cbcf2695a4a1 202 ScanInputUpdateScanFrequency();
Damotclese 2:cbcf2695a4a1 203
Damotclese 2:cbcf2695a4a1 204 // Since our timing in this device is off, we add a correction
Damotclese 2:cbcf2695a4a1 205 f_plusFourPercent = (((float)u16_scanFrequency / 100.0f) * 4.3f);
Damotclese 2:cbcf2695a4a1 206
Damotclese 2:cbcf2695a4a1 207 // Let the main module know what the scan rate is for display
Damotclese 2:cbcf2695a4a1 208 // and for testing and evaluating
Damotclese 2:cbcf2695a4a1 209 LaserMonMainInformScanInformation((uint16_t)((float)u16_scanFrequency + f_plusFourPercent), ++u32_scanCount);
Damotclese 1:b9d4b9b8884c 210 }
Damotclese 1:b9d4b9b8884c 211 }
Damotclese 1:b9d4b9b8884c 212 else
Damotclese 1:b9d4b9b8884c 213 {
Damotclese 1:b9d4b9b8884c 214 // We are in the ramp so flag the fact even if we already know
Damotclese 1:b9d4b9b8884c 215 b_inPorch = false;
Damotclese 2:cbcf2695a4a1 216
Damotclese 2:cbcf2695a4a1 217 // Keep track of the scan frequency
Damotclese 2:cbcf2695a4a1 218 u16_msFromPorchToPorch++;
Damotclese 1:b9d4b9b8884c 219 }
Damotclese 0:1ebe7d222470 220
Damotclese 1:b9d4b9b8884c 221 // Indicate the next line to plot this reading on to
Damotclese 1:b9d4b9b8884c 222 u16_nextScanLine++;
Damotclese 1:b9d4b9b8884c 223
Damotclese 2:cbcf2695a4a1 224 // The display may be in use for other functionality so we
Damotclese 2:cbcf2695a4a1 225 // check to ensure that we are permitted to plot the input
Damotclese 2:cbcf2695a4a1 226 if (true == b_allowPlotting)
Damotclese 2:cbcf2695a4a1 227 {
Damotclese 2:cbcf2695a4a1 228 // Call the function which plots this value
Damotclese 2:cbcf2695a4a1 229 (void)ScanInputPlotThisValue(f_analogValue);
Damotclese 2:cbcf2695a4a1 230 }
Damotclese 1:b9d4b9b8884c 231
Damotclese 1:b9d4b9b8884c 232 // Are we about to exceed the display?
Damotclese 1:b9d4b9b8884c 233 if (u16_nextScanLine >= (LCD_HEIGHT - 10))
Damotclese 1:b9d4b9b8884c 234 {
Damotclese 1:b9d4b9b8884c 235 // We have lost track of porch so we must search for it again
Damotclese 1:b9d4b9b8884c 236 b_waitingForPorch = true;
Damotclese 1:b9d4b9b8884c 237 }
Damotclese 1:b9d4b9b8884c 238
Damotclese 1:b9d4b9b8884c 239 // Set the LED with whether we are at porch or not
Damotclese 1:b9d4b9b8884c 240 st_scanInputLED = b_inPorch;
Damotclese 0:1ebe7d222470 241 }
Damotclese 0:1ebe7d222470 242
Damotclese 0:1ebe7d222470 243 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 244 // ScanInputThread()
Damotclese 0:1ebe7d222470 245 //
Damotclese 2:cbcf2695a4a1 246 // This is called once a millisecond however it is not a thread, the
Damotclese 2:cbcf2695a4a1 247 // thread class on this board ended up with timing that could not be
Damotclese 2:cbcf2695a4a1 248 // controlled so the main() loop calls us once a millisecond.
Damotclese 0:1ebe7d222470 249 //
Damotclese 0:1ebe7d222470 250 // ----------------------------------------------------------------------
Damotclese 2:cbcf2695a4a1 251 void ScanInputThread(bool b_allowPlotting)
Damotclese 0:1ebe7d222470 252 {
Damotclese 2:cbcf2695a4a1 253 // Are we waiting for porch synchronization?
Damotclese 1:b9d4b9b8884c 254 if (true == b_waitingForPorch)
Damotclese 0:1ebe7d222470 255 {
Damotclese 1:b9d4b9b8884c 256 // Start out searching for porch
Damotclese 1:b9d4b9b8884c 257 ScanInputWaitForPorch();
Damotclese 0:1ebe7d222470 258 }
Damotclese 1:b9d4b9b8884c 259
Damotclese 2:cbcf2695a4a1 260 // Scan the signal coming in and optionally plot it
Damotclese 2:cbcf2695a4a1 261 ScanInputGetNextValue(b_allowPlotting);
Damotclese 0:1ebe7d222470 262 }
Damotclese 0:1ebe7d222470 263
Damotclese 0:1ebe7d222470 264 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 265 // ScanInputInit()
Damotclese 0:1ebe7d222470 266 //
Damotclese 2:cbcf2695a4a1 267 // Initialize this module's locally-held data
Damotclese 2:cbcf2695a4a1 268 //
Damotclese 0:1ebe7d222470 269 // ----------------------------------------------------------------------
Damotclese 0:1ebe7d222470 270 void ScanInputInit(void)
Damotclese 0:1ebe7d222470 271 {
Damotclese 0:1ebe7d222470 272 // Start out with the LED turned ON
Damotclese 0:1ebe7d222470 273 st_scanInputLED = 1;
Damotclese 0:1ebe7d222470 274
Damotclese 2:cbcf2695a4a1 275 // Initialize loc ally-held variables
Damotclese 2:cbcf2695a4a1 276 u16_nextScanLine = 50;
Damotclese 2:cbcf2695a4a1 277 b_inPorch = false;
Damotclese 2:cbcf2695a4a1 278 b_waitingForPorch = true;
Damotclese 2:cbcf2695a4a1 279 u16_scanFrequency = 0;
Damotclese 2:cbcf2695a4a1 280 u16_resyncCount = 0;
Damotclese 2:cbcf2695a4a1 281 u32_scanCount = 0;
Damotclese 2:cbcf2695a4a1 282 u16_msFromPorchToPorch = 0;
Damotclese 0:1ebe7d222470 283 }
Damotclese 0:1ebe7d222470 284
Damotclese 0:1ebe7d222470 285 // End of file
Damotclese 0:1ebe7d222470 286