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
LaserMon-ScanInput.cpp
- Committer:
- Damotclese
- Date:
- 2019-06-17
- Revision:
- 2:cbcf2695a4a1
- Parent:
- 1:b9d4b9b8884c
File content as of revision 2:cbcf2695a4a1:
// ----------------------------------------------------------------------
// LaserMon-ScanInput.cpp
//
// Fredric L. Rice, June 2019
//
// ----------------------------------------------------------------------
#include "mbed.h" // The mbed operating system
#include "LCD_DISCO_F429ZI.h" // For controlling the LCD
#include "TS_DISCO_F429ZI.h" // For controlling the touch screen
#include "LaserMon-Main.h" // For data exported to us
#include "LaserMon-TestOutput.h" // For test signal
// ----------------------------------------------------------------------
// Options, defined constants, and MACROs
//
// ----------------------------------------------------------------------
#define WANT_TEST_SIGNAL 0
// ----------------------------------------------------------------------
// Local data storage
//
// ----------------------------------------------------------------------
// We create an analog input
static AnalogIn st_scanInput(LASER_SCAN_IN);
// For diagnostic purposes to show that the Laser Scan is operating
static DigitalOut st_scanInputLED(LED2);
// There are LCD_HEIGHT possible scan lines with a height of
// LCD_WIDTH -- yes, the defined constant names are swapped
// because we plot sideways.
//
// This value contains the next scan line number to plot
static uint16_t u16_nextScanLine;
// We store the last pixel's height so we may plot
static uint16_t u16_lastHeight = 0;
// Flag indicates whether we believe we are receiving porch or not
static bool b_inPorch;
// We keep track of how many times we have had to search for porch.
// Typically we could expect not to have to search for it when the
// plot goes beyond the end of the screen, however we may need to
// search on power-up and when the scan frequency changes
static uint16_t u16_resyncCount;
// For no reason at all we keep track of how many scans we detect
static uint32_t u32_scanCount;
// When we are searching for porch, we use this flag to indicate that
static bool b_waitingForPorch;
// We keep track of how many milliseconds there are between porch
// detections. This indicates a fairly close timing of the scan
// frequency.
static uint16_t u16_scanFrequency;
static uint16_t u16_msFromPorchToPorch;
// ----------------------------------------------------------------------
// ScanInputPlotThisValue()
//
// What percentage of LCD_HEIGHT is the voltage? We need to scale 0 to
// 3.3 volts across LCD_HEIGHT, with 0 being zero, and 3.3 volts being
// LCD_HEIGHT.
//
// We compute the percentage of 3.3 volts that the input signal is
// currently showing, then we compute that percentage of LCD_HEIGHT to
// determine how many pixels on a scan line that percentage is. That
// gives us the height of the plot line while u16_nextScanLine gives
// us the line to plot it on.
//
// This is easy because the value passed to this function is a value
// from 0.0 to 1.0 which is a percentage of 3.3 volts, so we use the
// value against LCD_HEIGHT to yield the percentage of height.
//
// ----------------------------------------------------------------------
static void ScanInputPlotThisValue(float f_analogValue)
{
// Compute the percentage of LCD height
uint16_t u16_pixelHeight = ((f_analogValue / 3.3f) * ((float)LCD_HEIGHT - 10.0f));
u16_pixelHeight /= 2;
u16_pixelHeight += 10;
// Clear the entire current scan line to plot
st_lcd.SetTextColor(LCD_COLOR_WHITE);
st_lcd.DrawLine(1, u16_nextScanLine, LCD_WIDTH, u16_nextScanLine);
// Plot from the previous pixel to the new one
st_lcd.SetTextColor(LCD_COLOR_BLUE);
// Are we currently in porch? We plot differently if so
if (false == b_inPorch)
{
// We plot ramp from the previous scan line's height to the current scan line and height
st_lcd.DrawLine(u16_lastHeight, u16_nextScanLine - 1, u16_pixelHeight, u16_nextScanLine);
}
else
{
// We plot the porch at a height of 10 pixels
st_lcd.DrawLine(10, u16_nextScanLine - 1, 10, u16_nextScanLine);
}
// Keep track of the last height so we may plot
u16_lastHeight = u16_pixelHeight;
}
// ----------------------------------------------------------------------
//
//
// ----------------------------------------------------------------------
static float ScanInputGetInputVoltage(void)
{
// Get the current analog input value and convert to volts
float f_analogValue = st_scanInput.read() * 3.3f;
#if WANT_TEST_SIGNAL
// Use the test output signal voltage instead
f_analogValue = f_rampVoltage;
#endif
// Return either the actual analog in or test voltage
return f_analogValue;
}
static void ScanInputUpdateScanFrequency(void)
{
// Store the last porch to porch counter
u16_scanFrequency = u16_msFromPorchToPorch;
// Restart the porch to porch counter
u16_msFromPorchToPorch = 0;
}
// ----------------------------------------------------------------------
// ScanInputWaitForPorch()
//
// ----------------------------------------------------------------------
static void ScanInputWaitForPorch(void)
{
float f_analogValue = 5.0f;
// While we're not seeing porch, loop
if (f_analogValue > 0.5f)
{
return;
}
// Flag the fact that we're in porch
b_inPorch = true;
b_waitingForPorch = false;
// Keep track of our scan frequency
ScanInputUpdateScanFrequency();
// Since we detected porch, start the plot over from the beginning
u16_nextScanLine = 50;
// The last height we consider to be 1 pixel on porch
u16_lastHeight = 1;
// Keep track of how many times we had to wait for locating porch
// again after loosing it. Note that on power-up, if we are using
// the test signal output, it is driven to porch co-incident with
// the input test, so we start up with porch as the first sample
++u16_resyncCount;
}
// ----------------------------------------------------------------------
// ScanInputGetNextValue()
//
//
// ----------------------------------------------------------------------
static void ScanInputGetNextValue(bool b_allowPlotting)
{
float f_analogValue = ScanInputGetInputVoltage();
// Dows the input indicate that we are in porch?
if (f_analogValue < 1.0f)
{
// Did we previously know that we were in porch?
if (false == b_inPorch)
{
float f_plusFourPercent = 0.0f;
// Flag the fact that we're in porch now
b_inPorch = true;
// Since we detected a new porch, start the plot over
u16_nextScanLine = 49;
// The last height we consider to be 1 pixel on porch
u16_lastHeight = 1;
// Update our scan frequency
ScanInputUpdateScanFrequency();
// Since our timing in this device is off, we add a correction
f_plusFourPercent = (((float)u16_scanFrequency / 100.0f) * 4.3f);
// Let the main module know what the scan rate is for display
// and for testing and evaluating
LaserMonMainInformScanInformation((uint16_t)((float)u16_scanFrequency + f_plusFourPercent), ++u32_scanCount);
}
}
else
{
// We are in the ramp so flag the fact even if we already know
b_inPorch = false;
// Keep track of the scan frequency
u16_msFromPorchToPorch++;
}
// Indicate the next line to plot this reading on to
u16_nextScanLine++;
// The display may be in use for other functionality so we
// check to ensure that we are permitted to plot the input
if (true == b_allowPlotting)
{
// Call the function which plots this value
(void)ScanInputPlotThisValue(f_analogValue);
}
// Are we about to exceed the display?
if (u16_nextScanLine >= (LCD_HEIGHT - 10))
{
// We have lost track of porch so we must search for it again
b_waitingForPorch = true;
}
// Set the LED with whether we are at porch or not
st_scanInputLED = b_inPorch;
}
// ----------------------------------------------------------------------
// ScanInputThread()
//
// This is called once a millisecond however it is not a thread, the
// thread class on this board ended up with timing that could not be
// controlled so the main() loop calls us once a millisecond.
//
// ----------------------------------------------------------------------
void ScanInputThread(bool b_allowPlotting)
{
// Are we waiting for porch synchronization?
if (true == b_waitingForPorch)
{
// Start out searching for porch
ScanInputWaitForPorch();
}
// Scan the signal coming in and optionally plot it
ScanInputGetNextValue(b_allowPlotting);
}
// ----------------------------------------------------------------------
// ScanInputInit()
//
// Initialize this module's locally-held data
//
// ----------------------------------------------------------------------
void ScanInputInit(void)
{
// Start out with the LED turned ON
st_scanInputLED = 1;
// Initialize loc ally-held variables
u16_nextScanLine = 50;
b_inPorch = false;
b_waitingForPorch = true;
u16_scanFrequency = 0;
u16_resyncCount = 0;
u32_scanCount = 0;
u16_msFromPorchToPorch = 0;
}
// End of file