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
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-Main.cpp --- 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; + } + } } }
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-Main.h --- 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
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-ScanInput.cpp --- 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
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-ScanInput.h --- 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
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-TEC.cpp --- /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 +
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-TEC.h --- /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 +
diff -r b9d4b9b8884c -r cbcf2695a4a1 LaserMon-TestOutput.cpp --- 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)