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
Revision 2:cbcf2695a4a1, committed 2019-06-17
- Comitter:
- Damotclese
- Date:
- Mon Jun 17 17:11:07 2019 +0000
- Parent:
- 1:b9d4b9b8884c
- Commit message:
- Added average TEC history;
Changed in this revision
--- a/LaserMon-Main.cpp Fri Jun 14 21:11:31 2019 +0000
+++ b/LaserMon-Main.cpp Mon Jun 17 17:11:07 2019 +0000
@@ -11,6 +11,7 @@
#include "TS_DISCO_F429ZI.h" // For controlling the touch screen
#include "LaserMon-TestOutput.h" // For generating test output signal
#include "LaserMon-ScanInput.h" // For monitoring laser power pin
+#include "LaserMon-TEC.h" // For monitoring the TEC output
#include "LaserMon-Main.h" // Always include ourself
// ----------------------------------------------------------------------
@@ -19,8 +20,30 @@
// ----------------------------------------------------------------------
const char * pch_firstMessage = "Test signal on PA_5";
- const char * pch_secondMessage = "Laser Scan on PC_1";
+ const char * pch_secondMessage = "Laser Scan on PC_1";
+ const char * pch_thirdMessage = "TEC signal on PC_3";
+
+ // Instantiate a digitial input mapped as our push button
+ static DigitalIn st_pushButton(PA_0);
+ // We must see the button down for a period of time, we
+ // do a debounce even though the class may do one already
+ static uint16_t u16_buttonDownCount;
+
+ // This flag informs the laser scan input module whether
+ // it is permitted to plot the scan input or not
+ static bool b_allowPlotting;
+
+ // We store the scan length in milliseconds offered to this
+ // module by the laser scanner, and we store the TEC voltage
+ // offered by the TEC scanner
+ static uint16_t u16_scanLength;
+ static uint16_t u16_TECVoltage;
+ static uint16_t u16_scanCount;
+
+ // We talk to Jenkins through an RS232 serial interface
+ static Serial st_Serial1(USE_SERIAL_TX, USE_SERIAL_RX);
+
// ----------------------------------------------------------------------
// Define global data storage which we will export
//
@@ -38,6 +61,13 @@
// ----------------------------------------------------------------------
static void MainInit(void)
{
+ // Initialize locally-held data
+ u16_buttonDownCount = 0;
+ b_allowPlotting = true;
+ u16_scanLength = 0;
+ u16_TECVoltage = 0;
+ u16_scanCount = 0;
+
// Bring the LCD up
st_lcd.Clear(LCD_COLOR_WHITE);
@@ -49,6 +79,168 @@
// Set the default font size
BSP_LCD_SetFont(&Font16);
+
+ // Set the push button to not have an internal pull-up or down
+ st_pushButton.mode(PullNone);
+
+ // We configure the serial interface
+ st_Serial1.baud(115200);
+ st_Serial1.format(8, SerialBase::None, 1);
+}
+
+// ----------------------------------------------------------------------
+//
+//
+// ----------------------------------------------------------------------
+static void MainCheckInbound(void)
+{
+ // See if there is inbound serial data
+ if (st_Serial1.readable())
+ {
+
+ }
+}
+
+// ----------------------------------------------------------------------
+//
+//
+// ----------------------------------------------------------------------
+static void MainTransmitOutput(uint8_t * pu8_thisFrame, uint16_t u16_thisCount)
+{
+ st_Serial1.write(pu8_thisFrame, u16_thisCount, NULL);
+}
+
+// ----------------------------------------------------------------------
+// LaserMonMainInformScanInformation()
+//
+//
+// ----------------------------------------------------------------------
+void LaserMonMainInformScanInformation(uint16_t u16_thisScanLength, uint16_t u16_thisScanCount)
+{
+ // If we arte displaying information, the scan gets slowed down
+ // while we print the information to the screen, making the scan
+ // information inaccurate. To avoid displaying inaccurate values
+ // we refrain from storing the scan rate while displaying the
+ // information
+ if (true == b_allowPlotting)
+ {
+ // Allow the scan information to get updated
+ u16_scanLength = u16_thisScanLength;
+ }
+
+ // Always store the scan counter value
+ u16_scanCount = u16_thisScanCount;
+}
+
+// ----------------------------------------------------------------------
+// LaserMonMainInformTECVoltage()
+//
+// ----------------------------------------------------------------------
+void LaserMonMainInformTECVoltage(uint16_t u16_thisVoltage)
+{
+ u16_TECVoltage = u16_thisVoltage;
+}
+
+// ----------------------------------------------------------------------
+// MainReportValues()
+//
+// ----------------------------------------------------------------------
+static void MainReportValues(void)
+{
+ char pch_holdMessage[101] = { 0 };
+
+ (void)sprintf(pch_holdMessage, "Scan duration %u", u16_scanLength);
+ st_lcd.DisplayStringAt(1, LINE(1), (uint8_t *)pch_holdMessage, LEFT_MODE);
+
+ (void)sprintf(pch_holdMessage, "Scan count %u", u16_scanCount);
+ st_lcd.DisplayStringAt(1, LINE(2), (uint8_t *)pch_holdMessage, LEFT_MODE);
+
+ (void)sprintf(pch_holdMessage, "TEC voltage %1.02f", (float)u16_TECVoltage / 100.0f);
+ st_lcd.DisplayStringAt(1, LINE(3), (uint8_t *)pch_holdMessage, LEFT_MODE);
+
+ (void)sprintf(pch_holdMessage, "TEC average %1.02f", (float)TECGetLastTenAverage() / 100.0f);
+ st_lcd.DisplayStringAt(1, LINE(4), (uint8_t *)pch_holdMessage, LEFT_MODE);
+
+ // Build a report for Jenkins or anything else to monitor
+ (void)sprintf(pch_holdMessage, "%u,%1.02f,%1.02f,%u%c%c",
+ u16_scanLength,
+ ((float)u16_TECVoltage / 100.0f),
+ ((float)TECGetLastTenAverage() / 100.0f),
+ u16_scanCount,
+ 0x0d, 0x0a);
+
+ // Send that report out the serial interface
+ MainTransmitOutput((uint8_t *)pch_holdMessage, (uint16_t)strlen(pch_holdMessage));
+}
+
+// ----------------------------------------------------------------------
+// MainHandleButtonDown()
+//
+// ----------------------------------------------------------------------
+static void MainHandleButtonDown(void)
+{
+ // Are we currently allowing the laser scan input to be plotted?
+ if (true == b_allowPlotting)
+ {
+ // Flag the fact that we are not allowing the plot
+ b_allowPlotting = false;
+
+ // Make sure that the display is cleared
+ st_lcd.Clear(LCD_COLOR_WHITE);
+
+ // Report the lasr scan and TEC voltage values
+ MainReportValues();
+ }
+ else
+ {
+ // Clear the display
+ st_lcd.Clear(LCD_COLOR_WHITE);
+
+ // Clear the flag so that the plot of the scan may be displayed
+ b_allowPlotting = true;
+ }
+}
+
+// ----------------------------------------------------------------------
+// MainThread()
+//
+// ----------------------------------------------------------------------
+static bool MainThread(void)
+{
+ bool b_restartOneSecondTimer = false;
+
+ // Acquire / poll the state of the push button
+ int i_buttonState = st_pushButton.read();
+
+ // Is the button down?
+ if (1 == i_buttonState)
+ {
+ // The button is not down, was the button down before?
+ // We need to see if the button is down for 10 milliseconds
+ // before we agree that the button is down
+ if (u16_buttonDownCount < 10)
+ {
+ if (10 == ++u16_buttonDownCount)
+ {
+ // The button has been held down long enough
+ MainHandleButtonDown();
+
+ // We want to have the one second timer restarted
+ b_restartOneSecondTimer = true;
+ }
+ }
+ }
+ else
+ {
+ // The button is not down so clear the down counter
+ u16_buttonDownCount = 0;
+ }
+
+ // See if there is inbouns serial data to be processed
+ MainCheckInbound();
+
+ // Indicate whether we are displaying the running information or not
+ return b_restartOneSecondTimer;
}
// ----------------------------------------------------------------------
@@ -58,26 +250,65 @@
// ----------------------------------------------------------------------
int main(void)
{
+ uint16_t u16_oneSecondCounter = 0;
+ bool b_restartOneSecondTimer = false;
+
// Perform local module initialization, if any
MainInit();
- // Start generating the putput test signal
+ // Initialize the generating of the output test signal module
TestOutputInit();
- // Start scanning the laser drive power
+ // Initialize the scanning of the the laser drive power module
ScanInputInit();
+ // Initialize the scanning of the TEC input and launch thread
+ TECInit();
+
// Display information about what signal pigs have what
- st_lcd.DisplayStringAt(1, LINE(1), (uint8_t *)pch_firstMessage, LEFT_MODE);
- st_lcd.DisplayStringAt(1, LINE(2), (uint8_t *)pch_secondMessage, LEFT_MODE);
+ st_lcd.DisplayStringAt(1, LINE(0), (uint8_t *)pch_firstMessage, LEFT_MODE);
+ st_lcd.DisplayStringAt(1, LINE(1), (uint8_t *)pch_secondMessage, LEFT_MODE);
+ st_lcd.DisplayStringAt(1, LINE(2), (uint8_t *)pch_thirdMessage, LEFT_MODE);
// Go in to a forever loop for the main thread which does nothing
while(true)
{
// Wait for 1 millisecond
wait_us(899);
+
+ // Instead of launching threads whose timing is a problem,
+ // we merely call the once-a-millisecond "thread" functions
+ // to drive the test signal out and the laser scan signal in
TestOutputThread();
- ScanInputThread();
+ ScanInputThread(b_allowPlotting);
+ b_restartOneSecondTimer = MainThread();
+ TECThread();
+
+ // Have we just started displaying collected information?
+ if (true == b_restartOneSecondTimer)
+ {
+ // Yes, so we will count down the timer
+ u16_oneSecondCounter = 1000;
+ }
+ else
+ {
+ // In case the one second timer is running, stop it
+ b_restartOneSecondTimer = 0;
+ }
+
+ // Is the one second counter running?
+ if (u16_oneSecondCounter > 0 && false == b_allowPlotting)
+ {
+ // Count down the one second timer and see if it's expired
+ if (0 == --u16_oneSecondCounter)
+ {
+ // Report the current values again
+ MainReportValues();
+
+ // Restart the one second timer
+ u16_oneSecondCounter = 1000;
+ }
+ }
}
}
--- a/LaserMon-Main.h Fri Jun 14 21:11:31 2019 +0000 +++ b/LaserMon-Main.h Mon Jun 17 17:11:07 2019 +0000 @@ -8,6 +8,9 @@ #define TEST_SIGNAL_OUT PA_5 #define LASER_SCAN_IN PC_1 +#define TEC_VOLTAGE_IN PC_3 +#define USE_SERIAL_TX PA_9 +#define USE_SERIAL_RX PA_10 // ---------------------------------------------------------------------- // Defined constants and MACROs @@ -37,6 +40,8 @@ // // ---------------------------------------------------------------------- +extern void LaserMonMainInformScanInformation(uint16_t u16_scanLength, uint16_t u16_scanCount); +extern void LaserMonMainInformTECVoltage(uint16_t u16_thisVoltage); // End of file
--- a/LaserMon-ScanInput.cpp Fri Jun 14 21:11:31 2019 +0000
+++ b/LaserMon-ScanInput.cpp Mon Jun 17 17:11:07 2019 +0000
@@ -17,7 +17,7 @@
//
// ----------------------------------------------------------------------
-#define WANT_TEST_SIGNAL 1
+#define WANT_TEST_SIGNAL 0
// ----------------------------------------------------------------------
// Local data storage
@@ -43,10 +43,23 @@
// 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()
@@ -115,6 +128,15 @@
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()
//
@@ -134,12 +156,19 @@
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;
}
@@ -148,7 +177,7 @@
//
//
// ----------------------------------------------------------------------
-static void ScanInputGetNextValue(void)
+static void ScanInputGetNextValue(bool b_allowPlotting)
{
float f_analogValue = ScanInputGetInputVoltage();
@@ -158,7 +187,7 @@
// Did we previously know that we were in porch?
if (false == b_inPorch)
{
- char pch_testMessage[21] = { 0 };
+ float f_plusFourPercent = 0.0f;
// Flag the fact that we're in porch now
b_inPorch = true;
@@ -169,21 +198,36 @@
// The last height we consider to be 1 pixel on porch
u16_lastHeight = 1;
- (void)sprintf(pch_testMessage, "Resync %u, Scans %u", u16_resyncCount, ++u32_scanCount);
- st_lcd.DisplayStringAt(1, LINE(0), (uint8_t *)pch_testMessage, LEFT_MODE);
+ // 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++;
- // Call the function which plots this value
- (void)ScanInputPlotThisValue(f_analogValue);
+ // 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))
@@ -199,41 +243,43 @@
// ----------------------------------------------------------------------
// ScanInputThread()
//
-// This thread wakes up every 1 millisecond to drive the input of the
-// signal coming in on the analog input -- or if it's enabled, to drive
-// the input based on the test signal for diagnostic and software
-// development use.
+// 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(void)
+void ScanInputThread(bool b_allowPlotting)
{
+ // Are we waiting for porch synchronization?
if (true == b_waitingForPorch)
{
// Start out searching for porch
ScanInputWaitForPorch();
}
- ScanInputGetNextValue();
+ // 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 locally-held variables
- u16_nextScanLine = 50;
-
- // Flag the fact that we don't believe that we are seeing porch
- b_inPorch = false;
- b_waitingForPorch = true;
-
- u16_resyncCount = 0;
- u32_scanCount = 0;
+ // 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
--- a/LaserMon-ScanInput.h Fri Jun 14 21:11:31 2019 +0000 +++ b/LaserMon-ScanInput.h Mon Jun 17 17:11:07 2019 +0000 @@ -12,7 +12,7 @@ // ---------------------------------------------------------------------- extern void ScanInputInit(void); -extern void ScanInputThread(void); +extern void ScanInputThread(bool b_allowPlotting); // End of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LaserMon-TEC.cpp Mon Jun 17 17:11:07 2019 +0000
@@ -0,0 +1,104 @@
+
+// ----------------------------------------------------------------------
+// LaserMon-TEC.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-TEC.h" // Always include ourself
+
+// ----------------------------------------------------------------------
+// Local data storage
+//
+// ----------------------------------------------------------------------
+
+ // We bring in the TEC voltage to scan what it is
+ static AnalogIn st_TECInput(TEC_VOLTAGE_IN);
+
+ // We store the last ten TEC readings and keep a running average
+ // of the last ten so that the main module may find out what the
+ // average is and display it
+ static uint16_t u16_TECHistory[TEC_HISTORY_COUNT_MAX];
+ static uint8_t u8_TECHistoryCount;
+ static uint16_t u16_TECHistoryRunningAverage;
+
+// ----------------------------------------------------------------------
+// TECGetLastTenAverage()
+//
+// ----------------------------------------------------------------------
+uint16_t TECGetLastTenAverage(void)
+{
+ return u16_TECHistoryRunningAverage;
+}
+
+// ----------------------------------------------------------------------
+//
+//
+// ----------------------------------------------------------------------
+void TECThread(void)
+{
+ uint16_t u16_TECVoltage = 0;
+ float f_rawTECVoltage = 0.0f;
+
+ // Get the current voltage
+ f_rawTECVoltage = st_TECInput.read() * 3.3f;
+
+ // The TEC voltage is converted from a floating point in to
+ // 16 bit value with the value after the decimal moved to
+ // the right by two decimal place
+ u16_TECVoltage = (uint16_t)(f_rawTECVoltage * 100.0f);
+
+ // Inform the main module what the TEC voltage is
+ LaserMonMainInformTECVoltage(u16_TECVoltage);
+
+ // Do we have lessd than our TEC history values stored so far?
+ if (u8_TECHistoryCount < TEC_HISTORY_COUNT_MAX)
+ {
+ // Since we have fewer than our maximum history, store it
+ u16_TECHistory[u8_TECHistoryCount++] = u16_TECVoltage;
+ }
+ else
+ {
+#if 1
+ // Discard the oldest history value that we have
+ for (uint8_t u8_thisValue = 1; u8_thisValue < TEC_HISTORY_COUNT_MAX; u8_thisValue++)
+ {
+ // Move the history value over to the left once
+ u16_TECHistory[u8_thisValue] = u16_TECHistory[u8_thisValue - 1];
+ }
+
+ // Now store the latest value in to the history array
+ u16_TECHistory[TEC_HISTORY_COUNT_MAX - 1] = u16_TECVoltage;
+#endif
+ }
+
+ // Compute the average TEC value
+ u16_TECHistoryRunningAverage = 0;
+
+ for (uint8_t u8_thisValue = 0; u8_thisValue < u8_TECHistoryCount; u8_thisValue++)
+ {
+ u16_TECHistoryRunningAverage += u16_TECHistory[u8_thisValue];
+ }
+
+ // Compute the average
+ u16_TECHistoryRunningAverage /= u8_TECHistoryCount;
+}
+
+// ----------------------------------------------------------------------
+//
+//
+// ----------------------------------------------------------------------
+void TECInit(void)
+{
+ // Initialize locally-held data
+ u8_TECHistoryCount = 0;
+ u16_TECHistoryRunningAverage = 0;
+}
+
+// End of file
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LaserMon-TEC.h Mon Jun 17 17:11:07 2019 +0000 @@ -0,0 +1,26 @@ + +// ---------------------------------------------------------------------- +// LaserMon-TEC.h +// +// Fredric L. Rice, June 2019 +// +// ---------------------------------------------------------------------- + +// ---------------------------------------------------------------------- +// Defined constants and MACROs we may use +// +// ---------------------------------------------------------------------- + +#define TEC_HISTORY_COUNT_MAX 10 + +// ---------------------------------------------------------------------- +// External function prototype that we will export +// +// ---------------------------------------------------------------------- + +extern void TECInit(void); +extern void TECThread(void); +extern uint16_t TECGetLastTenAverage(void); + +// End of file +
--- a/LaserMon-TestOutput.cpp Fri Jun 14 21:11:31 2019 +0000
+++ b/LaserMon-TestOutput.cpp Mon Jun 17 17:11:07 2019 +0000
@@ -36,7 +36,7 @@
// We create an analog output
static AnalogOut st_testSignalOut(TEST_SIGNAL_OUT);
-
+
// For diagnostic purposes to show that the test output is working
static DigitalOut st_testSignalLED(LED1);
@@ -64,11 +64,15 @@
// ----------------------------------------------------------------------
// TestOutputThread()
//
+// 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 TestOutputThread(void)
{
static uint8_t u8_ledTimeoutTimer = 0;
-
+
// Do we need to turn the scan-completed LED off?
if (u8_ledTimeoutTimer > 0)
{
@@ -143,7 +147,7 @@
// ----------------------------------------------------------------------
// TestOutputInit()
//
-// This function initializes this module and then launches the thread
+// This function initializes this module's locally-held data
//
// ----------------------------------------------------------------------
void TestOutputInit(void)