System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Revision 36:0afc0fc8f86b, committed 2015-01-22
- Comitter:
- pspatel321
- Date:
- Thu Jan 22 07:58:51 2015 +0000
- Parent:
- 35:9337ac9f4e1b
- Child:
- 37:2207b58b9a7f
- Commit message:
- Tested in car with other systems. Most features are good to go. Except xbees need work. The DC-DC protection features were giving problems due to spurious current measurements. They have been edited to reduce glitchy errors.
Changed in this revision
--- a/Constants.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Constants.h Thu Jan 22 07:58:51 2015 +0000 @@ -1,10 +1,10 @@ #ifndef CONSTANTS_H #define CONSTATNS_H -#define BAUD 460800 // Serial port baud rate -#define CHAR_TIME 0.00002 // Time to send 1 char @ above baud +#define BAUD 230400 // Serial port baud rate +#define CHAR_TIME 0.00005 // Time to send 1 char @ above baud #define TX_SIZE 1000 // Serial buffer TX size -#define RX_SIZE 100 // Serial buffer RX size +#define RX_SIZE 60 // Serial buffer RX size #define XBEE_BAUD 250000 // 250k baud serial for xbees #define XBEE_TX_SIZE 1000 // Serial buffer TX size for xbees @@ -13,7 +13,7 @@ #define START_DELAY 10 // Startup delay for latch monitor circuits #define FAST_LOOP 0.01 // Period (seconds) for fast loop (sampling, filters) #define GATHER_LOOP 0.1 // Period (seconds) for main data processing loop -#define WDT_TIME 0.1 // Normal, running mode WDT timeout +#define WDT_TIME 0.5 // Normal, running mode WDT timeout #define CAN_LOOP 0.1 // Output period for CAN transmissions #endif \ No newline at end of file
--- a/IOobjects/CAN_RxIDs.h Wed Jan 07 03:36:43 2015 +0000 +++ b/IOobjects/CAN_RxIDs.h Thu Jan 22 07:58:51 2015 +0000 @@ -4,15 +4,15 @@ #define BASE_ID 0x500 // Start at 0x500 for this device // Receive IDs -#define FAN_CONTROL_ID BASE_ID + 80 -#define PUMP_CONTROL_ID BASE_ID + 81 -#define DCDC_CONTROL_ID BASE_ID + 82 +#define FAN_CONTROL_ID BASE_ID + 0x80 +#define PUMP_CONTROL_ID BASE_ID + 0x81 +#define DCDC_CONTROL_ID BASE_ID + 0x82 -#define GLVBAT_CLEARSOC_ID BASE_ID + 90 -#define GLVBAT_CLEARAH_ID BASE_ID + 91 -#define GLVBAT_SETCAPAC_ID BASE_ID + 92 +#define GLVBAT_SETSOC_ID BASE_ID + 0x90 +#define GLVBAT_SETAH_ID BASE_ID + 0x91 +#define GLVBAT_SETCAPAC_ID BASE_ID + 0x92 -#define AMS_RELAYS_ID 0x303 +#define AMS_MODE_ID 0x301 #define STEERING_RESET_ID 0x602 #endif \ No newline at end of file
--- a/IOobjects/CAN_TxIDs.h Wed Jan 07 03:36:43 2015 +0000 +++ b/IOobjects/CAN_TxIDs.h Thu Jan 22 07:58:51 2015 +0000 @@ -5,34 +5,34 @@ // Transmit IDs - System Mgmt Specific // Operating diagnostics -#define SYS_ERROR_ID BASE_ID + 00 // Error frame - critical errors that require shutdown -#define SYS_XBEE1_ID BASE_ID + 01 // Message in/out counter for xbee1 -#define SYS_XBEE2_ID BASE_ID + 02 // Message in/out counter for xbee2 -#define SYS_TEMP_ID BASE_ID + 03 // Internal temperature of the glv battery chargerFET +#define SYS_ERROR_ID BASE_ID + 0x00 // Error frame - critical errors that require shutdown +#define SYS_XBEE1_ID BASE_ID + 0x01 // Message in/out counter for xbee1 +#define SYS_XBEE2_ID BASE_ID + 0x02 // Message in/out counter for xbee2 +#define SYS_TEMP_ID BASE_ID + 0x03 // Internal temperature of the glv battery chargerFET // GLV Battery -#define SYS_GLV_CURRENT_ID BASE_ID + 10 // GLV battery current -#define SYS_GLV_CAPACITY_ID BASE_ID + 11 // GLV battery capacity setting -#define SYS_GLV_AH_ID BASE_ID + 12 // GLV battery amphours -#define SYS_GLV_SOC_ID BASE_ID + 13 // GLV battery SOC +#define SYS_GLV_CURRENT_ID BASE_ID + 0x10 // GLV battery current +#define SYS_GLV_CAPACITY_ID BASE_ID + 0x11 // GLV battery capacity setting +#define SYS_GLV_AH_ID BASE_ID + 0x12 // GLV battery amphours +#define SYS_GLV_SOC_ID BASE_ID + 0x13 // GLV battery SOC // DC-DC Converter -#define SYS_DCDC_CURRENT_ID BASE_ID + 20 // DC-DC current -#define SYS_DCDC_STATUS_ID BASE_ID + 21 // DC-DC status byte +#define SYS_DCDC_CURRENT_ID BASE_ID + 0x20 // DC-DC current +#define SYS_DCDC_STATUS_ID BASE_ID + 0x21 // DC-DC status byte // PWM Channels -#define SYS_PWM_FAN_ID BASE_ID + 30 // FAN1 actual pwm -#define SYS_PWM_PUMP_ID BASE_ID + 31 // PUMP1 actual pwm +#define SYS_PWM_FAN_ID BASE_ID + 0x30 // FAN1 actual pwm +#define SYS_PWM_PUMP_ID BASE_ID + 0x31 // PUMP1 actual pwm // IMD -#define SYS_IMD_STATUS_ID BASE_ID + 40 // IMD status byte -#define SYS_IMD_RESIST_ID BASE_ID + 41 // IMD resistance measurement +#define SYS_IMD_STATUS_ID BASE_ID + 0x40 // IMD status byte +#define SYS_IMD_RESIST_ID BASE_ID + 0x41 // IMD resistance measurement // Latch Supervisor states -#define SYS_IMD_LATCH_ID BASE_ID + 50 // IMD Latch circuit error byte -#define SYS_AMS_LATCH_ID BASE_ID + 51 // AMS Latch circuit error byte +#define SYS_IMD_LATCH_ID BASE_ID + 0x50 // IMD Latch circuit error byte +#define SYS_AMS_LATCH_ID BASE_ID + 0x51 // AMS Latch circuit error byte // Shutdown Switches -#define SYS_SWITCHES_ID BASE_ID + 60 // Shutdown Switch State +#define SYS_SWITCHES_ID BASE_ID + 0x60 // Shutdown Switch State #endif \ No newline at end of file
--- a/IOobjects/IOobjects.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/IOobjects/IOobjects.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,29 +1,29 @@ #include "IOobjects.h" -Watchdog wdt(1); // Watchdog timer (TIMEOUT (sec)) -LPCDigitalIn sw[]={ // Shutdown switch sense lines - LPCDigitalIn(p1_0, PullUp), // Sense0 - fuse power - LPCDigitalIn(p1_1, PullUp), // Sense1 - AMS latch - LPCDigitalIn(p1_4, PullUp), // Sense2 - IMD latch - LPCDigitalIn(p1_8, PullUp), // Sense3 - PCM relay - LPCDigitalIn(p1_9, PullUp), // Sense4 - Brake plausibility relay - LPCDigitalIn(p1_10, PullUp), // Sense5 - Left e-stop - LPCDigitalIn(p1_14, PullUp), // Sense6 - Brake over-travel - LPCDigitalIn(p1_15, PullUp), // Sense7 - Inertia switch - LPCDigitalIn(p1_16, PullUp), // Sense8 - Cockpit e-stop - LPCDigitalIn(p1_17, PullUp), // Sense9 - Right e-stop - LPCDigitalIn(p1_27, PullUp), // Sense10 - HVD/Charger - LPCDigitalIn(p1_28, PullUp), // Sense11 - TSMS/tractive enable +Watchdog wdt; // Watchdog timer (TIMEOUT (sec)) +DigitalIn sw[]={ // Shutdown switch sense lines + DigitalIn(P1_0, PullDown), // Sense0 - fuse power + DigitalIn(P1_1, PullDown), // Sense1 - AMS latch + DigitalIn(P1_4, PullDown), // Sense2 - IMD latch + DigitalIn(P1_8, PullDown), // Sense3 - PCM relay + DigitalIn(P1_9, PullDown), // Sense4 - Brake plausibility relay + DigitalIn(P1_10, PullDown), // Sense5 - Left e-stop + DigitalIn(P1_14, PullDown), // Sense6 - Brake over-travel + DigitalIn(P1_15, PullDown), // Sense7 - Inertia switch + DigitalIn(P1_16, PullDown), // Sense8 - Cockpit e-stop + DigitalIn(P1_17, PullDown), // Sense9 - Right e-stop + DigitalIn(P1_27, PullDown), // Sense10 - HVD/Charger + DigitalIn(P1_28, PullDown), // Sense11 - TSMS/tractive enable }; -CANBuffer can(CAN2, MEDIUM, p4_28); // Buffered CAN interface (PORT, SPEED, SILENT PIN) +PollSwitch switches(sw, sizeof(sw)/sizeof(sw[0])); // Shutdown switch sense pins (SWITCH PIN ARRAY, NUM PINS) +CANBuffer can(CAN2, MEDIUM, P4_28); // Buffered CAN interface (PORT, SPEED, SILENT PIN) CoulombCounter glvBat(p19, FAST_LOOP*1000); // Coulomb counter battery monitor for GLV Battery (CURRENT SENSE PIN, INTEGRATION TIME) -DC_DC dcdc(p18, p20, p26, p25, p24, p23, 0.01, 1); // DC-DC converter & high-current load control (CONTROL PIN< CURRENT SENSE PIN, FAN1 PIN, FAN2 PIN, PUMP1 PIN, PUMP2 PIN, PWM PERIOD (sec), FULL-SCALE SLEW (sec)) -IMD imd(p1_26); // IMD PWM sense channel to read status and resistance (IMD PWM PIN) -LatchMonitor AMSlatch(p0_18, p0_22, START_DELAY*1000); // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) -LatchMonitor IMDlatch(p0_17, p0_21, START_DELAY*1000); // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) +IMD imd(P1_26); // IMD PWM sense channel to read status and resistance (IMD PWM PIN) +LatchMonitor AMSlatch(P0_18, P0_22, START_DELAY*1000); // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) +LatchMonitor IMDlatch(P0_17, P0_21, START_DELAY*1000); // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) MODSERIAL pc(USBTX, USBRX, TX_SIZE, RX_SIZE); // Serial to computer for diagnostics, 3kB output buffer, 256 byte input buffer +DC_DC dcdc(p18, p20, p26, p25, p24, p23, 0.01, 1); // DC-DC converter & high-current load control (CONTROL PIN, CURRENT SENSE PIN, FAN1 PIN, FAN2 PIN, PUMP1 PIN, PUMP2 PIN, PWM PERIOD (sec), FULL-SCALE SLEW (sec)) Temperature internalTmp(&NXFT15XH103_TABLE, p15); // Temperature conversion look-up table for internal temperature on the GLV bat charger FET (TABLE PTR, PIN) -PollSwitch switches(sw, sizeof(sw)/sizeof(sw[0])); // Shutdown switch sense pins (SWITCH PIN ARRAY, NUM PINS) XbeeManager xbeeRelay(p9, p10, p13, p14, XBEE_BAUD, XBEE_TX_SIZE, XBEE_RX_SIZE); //XbeeRelay xbee;
--- a/IOobjects/IOobjects.h Wed Jan 07 03:36:43 2015 +0000 +++ b/IOobjects/IOobjects.h Thu Jan 22 07:58:51 2015 +0000 @@ -2,6 +2,7 @@ #define _IO_OBJECTS_H #include "mbed.h" +#include "rtos.h" #include "Constants.h" #include "CAN_RxIDs.h" #include "CAN_TxIDs.h" @@ -17,9 +18,6 @@ #include "XbeeManager.h" //#include "XbeeRelay.h" -#define OS_TIMERPRIO 6 -#include "rtos.h" - extern CANBuffer can; extern CoulombCounter glvBat; extern DC_DC dcdc; @@ -81,6 +79,7 @@ public: char inputStr[RX_SIZE+1]; char parseGoodChar; + void* wdtThreadId; }; extern CANinputs CANdata;
--- a/Libs/CANBuffer.lib Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/CANBuffer.lib Thu Jan 22 07:58:51 2015 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#533722a1a6cf +http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#b2b886bdb080
--- a/Libs/CoulombCounter/CoulombCounter.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/CoulombCounter/CoulombCounter.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,8 +1,8 @@ #include "CoulombCounter.h" const float MSEC_HRS = 2.77778e-7; // Multiplier to convert milliseconds to hours -const float BAT_ISENSE_MULTIPLIER = 6.2299; // Multiplier to convert float to amps -const float BAT_ISENSE_OFFSET = -0.5*BAT_ISENSE_MULTIPLIER; // Offset to convert float to amps +const float BAT_ISENSE_MULTIPLIER = /*6.2299*/6.640114; // Multiplier to convert float to amps, calibrated using 3 points with Fluke 87V meter and code on 1/9/15 +const float BAT_ISENSE_OFFSET = /*-0.5*BAT_ISENSE_MULTIPLIER*/-3.344968; // Offset to convert float to amps, calibrated using 3 points with Fluke 87V meter and code on 1/9/15 const float BAT_ISENSE_LIMS = 3.0; // Over-current limit = +/- 3A CoulombCounter::CoulombCounter(PinName _pin, int _mSec) : BatISense(_pin) { @@ -22,18 +22,15 @@ // Take the initial readings, fill the buffer for (int i = 0; i < CC_FILTER_TAPS; i++) { - buffArr[i] = BatISense.read() * BAT_ISENSE_MULTIPLIER + BAT_ISENSE_OFFSET; + buffArr[i] = BatISense.read()*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET; } - current(); // Get avg and fill out overCurrent flag + updateAvg(); // Get avg and fill out overCurrent flag tracker=0; - - // Start counting - // sampler.attach_us(this, &CoulombCounter::sample, mSec*1000); } void CoulombCounter::sample() { // Take the reading - currentSample = BatISense.read()*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET; + float currentSample = BatISense.read()*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET; // Integrate float f = ampHours()-currentSample*mSec*MSEC_HRS; @@ -50,16 +47,17 @@ buffArr[tracker] = currentSample; tracker++; if (tracker >= CC_FILTER_TAPS) tracker = 0; + updateAvg(); } -float CoulombCounter::current() { +void CoulombCounter::updateAvg() { float avg = 0; for (int i = 0; i < CC_FILTER_TAPS; i++) { avg += buffArr[i]; } avg /= CC_FILTER_TAPS; if (abs(avg) > BAT_ISENSE_LIMS) overCurrent = true; - return avg; + currentFiltered = avg; } bool CoulombCounter::overCurrentDetected() {
--- a/Libs/CoulombCounter/CoulombCounter.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/CoulombCounter/CoulombCounter.h Thu Jan 22 07:58:51 2015 +0000 @@ -7,20 +7,21 @@ const float defaultAh = 1.5; // Default amphours of battery, in case store read is bad/empty const float defaultSOC = 0.5; -const int CC_FILTER_TAPS = 10; +const int CC_FILTER_TAPS = 50; // Nominal current draw with only Sys.Mgmt plugeed in should be 0.182A for calibration const int rtcGPREG_counter = 0; // rtc GPREG offset for the coulomb counter const int rtcGPREG_capacity = 1; // rtc GPREG offset for the capacity spec -const float MIN_CAPACITY_SETTING = 0.5; // Lowest allowable capacity setting -const float MAX_CAPACITY_SETTING = 10; // Largest allowable capacity setting +const float MIN_CAPACITY_SETTING = 0.5; // Lowest allowable capacity setting +const float MAX_CAPACITY_SETTING = 10; // Largest allowable capacity setting class CoulombCounter { + public: // Configures for a certain pin, millisecond sample period, and which GPREG in store to use to store the ampHours CoulombCounter(PinName _pin, int _mSec); bool overCurrentDetected(); // Sensor above range - float current(); // Last current reading in Amps + float current() { return currentFiltered; } // Last current reading in Amps void sample(); float capacity() { return store.read(rtcGPREG_capacity); } @@ -47,8 +48,9 @@ //Ticker sampler; // Used to capture next sample and coulomb count RTCStore store; volatile bool overCurrent; + void updateAvg(); // Used to get average current and update flags int mSec; - volatile float currentSample; + volatile float currentFiltered; AnalogIn BatISense; // Analog input pin volatile float buffArr[CC_FILTER_TAPS];
--- a/Libs/DC_DC/DC_DC.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/DC_DC/DC_DC.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,22 +1,23 @@ #include "DC_DC.h" #include <math.h> -#define OFF 1 -#define ON 0 +#define TURN_OFF dcdcControl = 1; isControlPinOn = false; +#define TURN_ON dcdcControl = 0; isControlPinOn = true; const float CURRENT_MULTIPLIER_DEFAULT = 41.35338345864663; // Full scale amps const float CURRENT_OFFSET_DEFAULT = 0.0909090909090909; // Float adc reading for 0 amps -const float DC_DC_ON_THRESHOLD = 0.5; // Current draw required in order to declare it as ON -const int STARTUP_DELAY_MS = 500; // DC-DC converter startup time in milliseconds -const float OVER_CURRENT_THRESHOLD = 25; // Overcurrent threshold -const float CURRENT_SENSOR_LLIM = -0.5; // Lowest allowable reading before declaring sensor broken -const int ZEROING_SAMPLES = 50; // Number of samples to average for zeroing -const int STOP_DELAY_MS = 500; // Amount of time given to turn-off before flagging error +const float DC_DC_ON_THRESHOLD = 0.5; // Current draw required in order to declare it as on +const int STARTUP_DELAY_MS = 1000; // DC-DC converter startup time in milliseconds +const float OVER_CURRENT_THRESHOLD = 25; // Overcurrent threshold +const float CURRENT_SENSOR_LLIM = -1.0; // Lowest allowable reading before declaring sensor broken +const float CURRENT_SENSOR_ULIM = 33; // Sensor is at 5V rail, broken +const int STOP_DELAY_MS = 1000; // Amount of time given to turn-off before flagging error -DC_DC::DC_DC(PinName _dcdcPin, PinName _dcdcCurrent, PinName _fan1, PinName _fan2, PinName _pump1, PinName _pump2, float period, float slew) : - dcdcControl(_dcdcPin, OFF), dcdcCurrent(_dcdcCurrent), fan1(_fan1, period, slew), fan2(_fan2, period, slew), pump1(_pump1, period, slew), pump2(_pump2, period, slew) { - +DC_DC::DC_DC(PinName _dcdcPin, PinName _dcdcCurrent, PinName _fan1, PinName _fan2, PinName _pump1, PinName _pump2, float period, float slew) : + dcdcControl(_dcdcPin, 1), dcdcCurrent(_dcdcCurrent), fan1(_fan1, period, slew), fan2(_fan2, period, slew), pump1(_pump1, period, slew), pump2(_pump2, period, slew) +{ + TURN_OFF currentOffset = CURRENT_OFFSET_DEFAULT; starting = false; stopping = false; @@ -29,23 +30,23 @@ // Fill up the buffer for (int i = 0; i < DC_DC_FILTER_TAPS; i++) { filterBuff[i] = (dcdcCurrent - currentOffset) * CURRENT_MULTIPLIER_DEFAULT; + wait_ms(10); } - updateCurrent(); - sample(); - if (!critError) zeroCurrent(); + updateCurrent(); // Compute avg + sample(); // Use sample() function to check for errors + + if (!critError) { // If no errors, zero the sensor + currentOffset = (current / CURRENT_MULTIPLIER_DEFAULT) + CURRENT_OFFSET_DEFAULT; + } + + // Correct the buffer for the new zero + for (int i = 0; i < DC_DC_FILTER_TAPS; i++) { + filterBuff[i] = ((CURRENT_OFFSET_DEFAULT - currentOffset) * CURRENT_MULTIPLIER_DEFAULT) + filterBuff[i]; + } } -void DC_DC::zeroCurrent() { - float avg=0; - for (int i = 0; i < ZEROING_SAMPLES; i++) { - avg+=dcdcCurrent; - wait_ms(1); - } - avg /= ZEROING_SAMPLES; - currentOffset = avg; -} - -void DC_DC::updateCurrent() { +void DC_DC::updateCurrent() +{ float avg=0; for (int i = 0; i < DC_DC_FILTER_TAPS; i++) { avg += filterBuff[i]; @@ -54,28 +55,32 @@ current = avg; } -void DC_DC::set(bool on) { +void DC_DC::set(bool on) +{ // Do nothing if already on - if (on && dcdcControl == ON) return; + if (on && isControlPinOn) return; + // Do nothing if already off + if (!on && !isControlPinOn) return; + // If start requested and no error if (on && !critError) { - dcdcControl = ON; starting = true; + TURN_ON startTimer.reset(); startTimer.start(); stopTimer.stop(); stopTimer.reset(); stopping = false; - - // If stop requested + + // If stop requested } else { - stopping=true; + stopping = true; fan1.directOff(); fan2.directOff(); pump1.directOff(); pump2.directOff(); - dcdcControl = OFF; + TURN_OFF stopTimer.reset(); stopTimer.start(); startTimer.stop(); @@ -84,26 +89,25 @@ } } -void DC_DC::sample() { - +void DC_DC::sample() +{ // Get next current sample - float curr = (dcdcCurrent - currentOffset) * CURRENT_MULTIPLIER_DEFAULT; - if (curr < CURRENT_SENSOR_LLIM) curr = -INFINITY; // Check if sensor out of range - else if (curr < 0) curr = 0; // Floor to zero - filterBuff[buffTracker] = curr; // Add to buffer filter + float curr = (dcdcCurrent.read() - currentOffset) * CURRENT_MULTIPLIER_DEFAULT; + + filterBuff[buffTracker] = curr; // Add to buffer filter buffTracker++; if (buffTracker >= DC_DC_FILTER_TAPS) buffTracker = 0; - updateCurrent(); // Compute average + updateCurrent(); // Compute average // Update status - register char stat = status & 0xF0; // The the upper 4 bits (locking errors) - if (current >= DC_DC_ON_THRESHOLD) stat |= ConvOn; // The converter is actually on (positive current) - if (dcdcControl == ON) stat |= SetOn; // The converter is set on - + register char stat = status & 0xF0; // The upper 4 bits (locking errors) + if (current >= DC_DC_ON_THRESHOLD) stat |= ConvOn; // The converter is actually on (positive current) + if (isControlPinOn) stat |= SetOn; // The converter is set on + // During Timed Startup Phase if (starting) { stat |= PowerUp; // Indicate state in status byte - if (startTimer.read_us() >= STARTUP_DELAY_MS*1000) { // Start time elapsed + if (startTimer.read_ms() >= STARTUP_DELAY_MS) { // Start time elapsed if (stat & ConvOn) { // Positive current detected startTimer.stop(); // Stop timer startTimer.reset(); // Reset to zero @@ -114,35 +118,37 @@ stat |= FailStart; // Failed to start } } - } - + } else stat &= ~PowerUp; + // During Timed Stopping Phase if (stopping) { - stat |= PowerDown; // Indicate state in status byte - if (stopTimer.read_us() >= STOP_DELAY_MS*1000) { // Stop time elapsed - if (stat & ConvOn) { // Converter still on + stat |= PowerDown; // Indicate state in status byte + if (stopTimer.read_ms() >= STOP_DELAY_MS) { // Stop time elapsed + if (stat & ConvOn) { // Converter still on stopTimer.stop(); stopTimer.reset(); stat |= FailStop; // It didn't turn off even after timer expired! } else { // Its actually off stopping = false; stopTimer.stop(); - stopTimer.reset(); + stopTimer.reset(); } } + } else stat &= ~PowerDown; + + // While in steady state + if (!stopping && !starting) { + if ((stat & SetOn) && !(stat & ConvOn)) stat |= FailStart; // Should be running but its not + else stat &= ~FailStart; + if (!(stat & SetOn) && (stat & ConvOn)) stat |= FailStop; // Should be stopped but its not + else stat &= ~FailStop; } - if (current > OVER_CURRENT_THRESHOLD) stat |= OverCurrent; // Over current - if (current == -INFINITY) stat |= SensorFault; // Sensor out of range - - // While in steady state - if (!stopping && !starting) { - if ((stat & SetOn) && !(stat & 1)) stat |= FailStart; // Should be running but its not - if (!(stat & SetOn) && (stat & 1)) stat |= FailStop; // Should be stopped but its not - } - + if (current < CURRENT_SENSOR_LLIM || current > CURRENT_SENSOR_ULIM) stat |= SensorFault; // Sensor out of range + else if (current > OVER_CURRENT_THRESHOLD) stat |= OverCurrent; // Over current + // Process critical error conditions - if (stat & 0xF0) critError = true; + if (stat & (SensorFault | OverCurrent)) critError = true; else critError = false; status = stat; @@ -152,25 +158,27 @@ fan2.directOff(); pump1.directOff(); pump2.directOff(); - dcdcControl = OFF; + TURN_OFF startTimer.stop(); startTimer.reset(); starting = false; } } -void DC_DC::setPwm(enum Channel_T chan, float duty) { +void DC_DC::setPwm(enum Channel_T chan, float duty) +{ // Do nothing if error present, starting in startup, or DC-DC not actually on, or not set on - if (critError || starting || stopping || !(status & 1) || dcdcControl == OFF) return; - + if (critError || starting || stopping || !(status & ConvOn) || !isControlPinOn) return; + else { if (chan == FAN1) fan1.write(duty); if (chan == FAN2) fan2.write(duty); if (chan == PUMP1) pump1.write(duty); - if (chan == PUMP2) pump2.write(duty); + if (chan == PUMP2) pump2.write(duty); } } -float DC_DC::readPwm(enum Channel_T chan) { +float DC_DC::readPwm(enum Channel_T chan) +{ if (chan == FAN1) return fan1.readRaw(); if (chan == FAN2) return fan2.readRaw(); if (chan == PUMP1) return pump1.readRaw();
--- a/Libs/DC_DC/DC_DC.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/DC_DC/DC_DC.h Thu Jan 22 07:58:51 2015 +0000 @@ -20,13 +20,12 @@ FailStart=64, FailStop=128, }; -const int DC_DC_FILTER_TAPS = 10; +const int DC_DC_FILTER_TAPS = 50; class DC_DC{ public: DC_DC(PinName _dcdcPin, PinName _dcdcCurrent, PinName _fan1, PinName _fan2, PinName _pump1, PinName _pump2, float period, float slew); float getCurrent() { return current; } - void zeroCurrent(); void set(bool on); void setPwm(enum Channel_T chan, float duty); float readPwm(enum Channel_T chan); @@ -50,7 +49,7 @@ Timer stopTimer; volatile bool starting; volatile bool stopping; - + volatile bool isControlPinOn; DigitalOut dcdcControl; AnalogIn dcdcCurrent; volatile float currentOffset;
--- a/Libs/DC_DC/FanPump/FanPump.cpp Wed Jan 07 03:36:43 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -#include "FanPump.h" - -static FanPump* instance[6] = { NULL }; // Access pwm object by channel# -const int PCLK = 24e6; // 24Mhz clock - -// Interrupt handler, must be called from static context, calls all the slew functions -void pwmIRQ() { - int sum = 0; - int items = 0; - if (LPC_PWM1->IR & 1) { - for (int i = 0; i < 6; i++) { - if (instance[i] != NULL) { - items++; - sum += instance[i]->slew(); - } - } - } - LPC_PWM1->IR = 0x73F; // Clear interrupts - if (items == sum) { - LPC_PWM1->MCR = 0; // Detach all the interrupts, every pin is already where it needs to be - } -} - -// Called on each timer expire for each pwm object -int FanPump::slew() { - uint32_t currPulseT = *MR_base; // Get the current pulsewidth ticks - uint32_t setPointT = setPoint_us * (PCLK/1e6); // Convert us into ticks - if (currPulseT == setPointT) return 1; // Nothing to slew here, already at its setpoint - - uint32_t currPulse_us = currPulseT / (PCLK/1e6); // Convert to us - if (currPulseT < setPointT) { - if (setPoint_us - currPulse_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us); // Close to the setpoint, write it directly - else pwm.pulsewidth_us(currPulse_us + maxChange_us); - } else { - if (currPulse_us - setPoint_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us); // Close to the setpoint, write it directly - else pwm.pulsewidth_us(currPulse_us - maxChange_us); - } - return 0; -} - -FanPump::FanPump(PinName pin, float period, float slew) : pwm(pin) { - - // Match the pin# to the PWM object for the interrupt - int channel = 0; - if (pin == p26 || pin == LED1) channel = 1; - if (pin == p25 || pin == LED2) channel = 2; - if (pin == p24 || pin == LED3) channel = 3; - if (pin == p23 || pin == LED4) channel = 4; - if (pin == p22) channel = 5; - if (pin == p21) channel = 6; - if (channel == 0) return; // Invalid pin - instance[channel-1] = this; // Attach this object to an instance pointer to access from interrupt - - // Set the match register address, gap between MR3 and MR4 - if (channel <= 3) MR_base = (uint32_t*)(&LPC_PWM1->MR0)+channel; - else MR_base = (uint32_t*)(&LPC_PWM1->MR4)+(channel-4); - - setPoint_us = 0; - period_us = period * 1.0e6; - pwm.period_us(period_us); - maxChange_us = (period / slew) * period_us; - - LPC_PWM1->IR = 0x73F; // Clear interrupts - NVIC_SetVector(PWM1_IRQn, (uint32_t)&pwmIRQ); - NVIC_SetPriority(PWM1_IRQn, 0); - NVIC_EnableIRQ(PWM1_IRQn); - LPC_PWM1->MCR = 1; // Enable interrupt on MR0 (when the pwm period expires) -} -void FanPump::write(float duty) { - if (duty < 0) duty = 0; - if (duty > 1) duty = 1; - setPoint_us = duty * period_us; - LPC_PWM1->MCR = 1; // Enable interrupt on MR0 (when the pwm period expires) -} -void FanPump::directOff() { - __disable_irq(); - pwm.pulsewidth_us(0); - setPoint_us = 0; - __enable_irq(); -} -float FanPump::read() { - return (float)(setPoint_us)/(float)(period_us); -} -float FanPump::readRaw() { - uint32_t currPulseT = *MR_base; // Get the current pulsewidth ticks - return ((float)(currPulseT) / (float)(PCLK/1e6)) / (float)(period_us); -} \ No newline at end of file
--- a/Libs/DC_DC/FanPump/FanPump.h Wed Jan 07 03:36:43 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -#ifndef _FILE_FANPUMP_H -#define _FILE_FANPUMP_H - -#include "mbed.h" - -class FanPump{ -public: - // Takes Pwmout pin, period (seconds), duty cycle slew rate in second^-1 (1 means duty 0 to 1 occurs over 1 second, 0 means no slew) - // Use slew rate to implement soft start - FanPump(PinName pin, float period, float slew); - void write(float duty); - float read(); // Read the last setpoint - float readRaw(); // Read the raw current duty (may be mid-transition) - void directOff(); // Turn off the channel immediately (no slew) - - int slew(); // Slew rate callback function -private: - PwmOut pwm; // mbed PWM out - uint32_t* MR_base; // pwm channel# match register pointer - volatile uint32_t period_us; // pwm period in us, shared by all channels - volatile uint32_t setPoint_us; - volatile uint32_t maxChange_us; // Max pulsewidth change allowed to achieve the slew rate -}; - -#endif \ No newline at end of file
--- a/Libs/IMD/IMD.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/IMD/IMD.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,5 +1,6 @@ #include "IMD.h" #include <math.h> +#include "pinmap.h" static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects) @@ -29,42 +30,37 @@ LPC_TIM3->IR=0x3F; // Clear interrupt flags } -bool cmpPin(LPC_pin p1, LPC_pin p2) { - if (p1.gpio_addr == p2.gpio_addr && p1.gpio_num == p2.gpio_num) return true; - else return false; -} - -IMD::IMD(LPC_pin _pin) { +IMD::IMD(PinName _pin) { // Setup the timer/pin access variables - if (cmpPin(_pin, p1_26)) { // CAP0.0 + if (_pin == P1_26) { // CAP0.0 timer=0; pin=0; timerBase=LPC_TIM0; - } else if (cmpPin(_pin, p1_27)) { // CAP0.1 + } else if (_pin == P1_27) { // CAP0.1 timer=0; pin=1; timerBase=LPC_TIM0; - } else if (cmpPin(_pin, p1_18)) { // CAP1.0 + } else if (_pin == P1_18) { // CAP1.0 timer=1; pin=0; timerBase=LPC_TIM1; - } else if (cmpPin(_pin, p1_19)) { // CAP1.1 + } else if (_pin == P1_19) { // CAP1.1 timer=1; pin=1; timerBase=LPC_TIM1; - } else if (cmpPin(_pin, p0_4)) { // CAP2.0 + } else if (_pin == P0_4) { // CAP2.0 timer=2; pin=0; timerBase=LPC_TIM2; - } else if (cmpPin(_pin, p0_5)) { // CAP2.1 + } else if (_pin == P0_5) { // CAP2.1 timer=2; pin=1; timerBase=LPC_TIM2; - } else if (cmpPin(_pin, p0_23)) { // CAP3.0 + } else if (_pin == P0_23) { // CAP3.0 timer=3; pin=0; timerBase=LPC_TIM3; - } else if (cmpPin(_pin, p0_24)) { // CAP3.1 + } else if (_pin == P0_24) { // CAP3.1 timer=3; pin=1; timerBase=LPC_TIM3; @@ -97,9 +93,9 @@ LPC_SC->PCLKSEL1 &= ~(3<<14); } - *(_pin.pinsel_addr) |= 3 << _pin.selmode_num; // Set pin as capture pin - *(_pin.pinmode_addr) |= 3 << _pin.selmode_num; // Pull down - + pin_function(_pin, 3); // Capture input + pin_mode(_pin, PullDown); // Pull-down + timerBase->TCR=2; // Stop counter and hold at 0, for configuration timerBase->IR=0x3F; // Clear any interrupt flags timerBase->CTCR=0; // Use pclk, not external pin @@ -125,7 +121,7 @@ uint32_t capTime = pin?timerBase->CR1:timerBase->CR0; // Get the time of the capture event timerBase->MR0 = capTime + TIMEOUT_TICKS; // Move the zero timeout ahead - // Special case - on first pulse after a timeout or on startup, period cannot be calculated + // Special case - on first pulse after a timeout or on startup == Period cannot be calculated // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1) if (first) { first = false;
--- a/Libs/IMD/IMD.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/IMD/IMD.h Thu Jan 22 07:58:51 2015 +0000 @@ -4,7 +4,6 @@ #define _FILE_IMD_H #include "mbed.h" -#include "LPCDigitalIn.h" const float ZERO_HZ_TIMEOUT = 0.15; // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width @@ -20,7 +19,7 @@ class IMD{ public: - IMD(LPC_pin _pin); + IMD(PinName _pin); char status(); // Gets the insulation resistance reading
--- a/Libs/LPCDigitalIn.lib Wed Jan 07 03:36:43 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://mbed.org/teams/Penn-Electric-Racing/code/LPCDigitalIn/#963ce3b85931
--- a/Libs/LatchMonitor/LatchMonitor.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/LatchMonitor/LatchMonitor.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,6 +1,6 @@ #include "LatchMonitor.h" -LatchMonitor::LatchMonitor(LPC_pin _ok, LPC_pin _fault, unsigned int startupDelay_ms):okPin(_ok, PullDown), faultPin(_fault, PullDown) { +LatchMonitor::LatchMonitor(PinName _ok, PinName _fault, unsigned int startupDelay_ms):okPin(_ok, PullDown), faultPin(_fault, PullDown) { // Power-on reset detected if (LPC_SC->RSID & 1) {
--- a/Libs/LatchMonitor/LatchMonitor.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/LatchMonitor/LatchMonitor.h Thu Jan 22 07:58:51 2015 +0000 @@ -2,7 +2,6 @@ #define __LATCH_MONITOR_H #include "mbed.h" -#include "LPCDigitalIn.h" enum LatchMon_Status_Bits { okPinF=1, @@ -15,7 +14,7 @@ public: // Make this startup delay longer than the actual hardware circuit delay so that it can catch errors in the circuit - LatchMonitor(LPC_pin _ok, LPC_pin _fault, unsigned int startupDelay_ms); + LatchMonitor(PinName _ok, PinName _fault, unsigned int startupDelay_ms); /* char update() returns status encoded in a char bit0 = okPinFault - equals 1 when the OK pin from the monitored device is LOW indicating device fault @@ -28,8 +27,8 @@ Timeout startup; void startupDelay(); bool started; - LPCDigitalIn okPin; - LPCDigitalIn faultPin; + DigitalIn okPin; + DigitalIn faultPin; }; #endif \ No newline at end of file
--- a/Libs/PollSwitch/PollSwitch.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/PollSwitch/PollSwitch.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,6 +1,6 @@ #include "PollSwitch.h" -PollSwitch::PollSwitch(LPCDigitalIn *swArr, int numSw){ +PollSwitch::PollSwitch(DigitalIn *swArr, int numSw){ numSwitches = numSw; sw = swArr; } @@ -8,10 +8,11 @@ char PollSwitch::poll(){ char i = 0; - // if a low signal is detected, previous switch is broken + // If a low signal is detected, previous switch is broken for (i = 0; i < numSwitches; i++) { - if (!sw[i].read()) break; + if (sw[i].read() == 0) break; } if (i >= numSwitches) i = 0; - return i+1; + else i++; + return i; } \ No newline at end of file
--- a/Libs/PollSwitch/PollSwitch.h Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/PollSwitch/PollSwitch.h Thu Jan 22 07:58:51 2015 +0000 @@ -1,17 +1,17 @@ #ifndef _FILE_POLLSWITCH_H #define _FILE_POLLSWITCH_H -#include "LPCDigitalIn.h" +#include "mbed.h" class PollSwitch{ public: - PollSwitch(LPCDigitalIn *sw, int numSwitches); + PollSwitch(DigitalIn *sw, int numSwitches); // Returns new state, 0 means all Closed, 1=first sense line (fuse), 12=last (TSMS) char poll(); private: - LPCDigitalIn *sw; + DigitalIn *sw; int numSwitches; }; #endif \ No newline at end of file
--- a/Libs/Watchdog.lib Wed Jan 07 03:36:43 2015 +0000 +++ b/Libs/Watchdog.lib Thu Jan 22 07:58:51 2015 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#cb296650f43e +http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#339e2407baaa
--- a/inCommands/inCommands.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/inCommands/inCommands.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -32,9 +32,9 @@ else dcdc.set(0); break; - case AMS_RELAYS_ID: + case AMS_MODE_ID: if (msg.len != sizeof(char)) break; - if ((msg.data[0] & (1<<3|1<<4|1<<5)) == (1<<3|1<<4|1<<5)) { // AIRs closed? 1<<3=posAIR, 1<<4=negAIR, 1<<5=tractiveEnable signal + if (msg.data[0] & 1<<2) { // AIRs closed? CANdata.airsClosed = true; dcdc.set(1); } else { @@ -43,12 +43,12 @@ } break; - case GLVBAT_CLEARSOC_ID: + case GLVBAT_SETSOC_ID: if (msg.len != sizeof(float)) break; glvBat.resetToSOC(*((float*)(&msg.data[0]))); break; - case GLVBAT_CLEARAH_ID: + case GLVBAT_SETAH_ID: if (msg.len != sizeof(float)) break; glvBat.resetToAh(*((float*)(&msg.data[0]))); break; @@ -80,14 +80,16 @@ // Compare string to a word in the serial input, shorter to type #define CMP(w, string) if (!strcasecmp(word[w-1], string)) -static char word[3][RX_SIZE+1]; + // Serial input int inCommands::serviceSerial() { + static int end = 0; // End of string position - static int end = 0; // End of string position - int c = pc.getcNb(); // Get char from RX buffer (returns an int) + int c=0; + if (pc.readable()) c = pc.getc(); if (c == -1) return -2; // Invalid char, no char available + char b = c; // Casted to char type bool process = false; // Is string complete (ready to parse)? @@ -101,22 +103,20 @@ tempData.inputStr[end] = 0; // Erase char } else if (b > 31 && b < 127) { // New valid displayable char - tempData.inputStr[end] = b; // Add to buffer - end++; // Increment end + tempData.inputStr[end++] = b; // Add to buffer tempData.inputStr[end] = 0; // Add null terminator if (end >= RX_SIZE) { end = 0; // Reset end location process = true; // Flag for processing } } - // Continue to parsing section only if flagged as complete and string not empty - if (!process || strlen(tempData.inputStr) == 0) return 0; - + if (!process || strlen((char*)tempData.inputStr) == 0) return 0; + + static char word[3][RX_SIZE+1]; // Hold 3 words int pieces = sscanf(tempData.inputStr, "%s %s %s", word[0], word[1], word[2]); // Populate words tempData.inputStr[0] = 0; // Empty the string displayed on screen - - char *next; // Used by strtod and strtoul + char *next; // Used by strtof and strtoul // One word commands if (pieces == 1) { @@ -125,8 +125,8 @@ NVIC_SystemReset(); return 1; } - // Two word commands } + // Two word commands if (pieces == 2) { // Manual DC-DC on/off control CMP(1, "dcdc") { @@ -170,9 +170,10 @@ if (*next == 0) { if (glvBat.changeCapacity(cap)) return 1; } - return -1; + return -1; } } + // Three word commands if (pieces == 3) { // Fan Duty CMP(1, "Fan") { @@ -203,4 +204,17 @@ } } return -1; +} + +void inCommands::thread_getInputs(void const* args) +{ + while(1) { + inCommands::serviceCAN(); + inCommands::receiveMsgXbee(); + + int ret = inCommands::serviceSerial(); + if (ret == -1) tempData.parseGoodChar = 'x'; + if (ret == 1) tempData.parseGoodChar = 251; + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<2); // Signal watchdog thread + } } \ No newline at end of file
--- a/inCommands/inCommands.h Wed Jan 07 03:36:43 2015 +0000 +++ b/inCommands/inCommands.h Thu Jan 22 07:58:51 2015 +0000 @@ -9,6 +9,7 @@ bool serviceCAN(CANMessage* fromXbee=0); bool receiveMsgXbee(); int serviceSerial(); + void thread_getInputs(void const* args); } #endif \ No newline at end of file
--- a/main.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/main.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -3,18 +3,33 @@ #include "outDiagnostics.h" #include "inCommands.h" +//#define DEBUG_MODE + +void thread_watchDog(void const* args) { + tempData.wdtThreadId = Thread::gettid(); +#ifdef DEBUG_MODE + wdt.kick(); +#else + wdt.kick(WDT_TIME); +#endif + while(1) { + Thread::signal_wait(0x1F); + wdt.kick(); + } +} + int main() { - wdt.kick(); // Kick the watchdog timer pc.baud(BAUD); - pc.format(8, SerialBase::None, 2); // 2 Stop bits, reduce bad serial packets + pc.format(8, SerialBase::None, 2); // 2 Stop bits, reduce bad serial packets + pc.printf("\033[2J\033[2J\r\n"); // Clear screen can.mode(FIFO); + NVIC_SetPriority(TIMER0_IRQn, 0); + NVIC_SetPriority(PWM1_IRQn, 1); + NVIC_SetPriority(CAN_IRQn, 2); + NVIC_SetPriority(UART0_IRQn, 3); NVIC_SetPriority(TIMER3_IRQn, 4); - NVIC_SetPriority(UART0_IRQn, 0); - NVIC_SetPriority(CAN_IRQn, 3); - NVIC_SetPriority(TIMER0_IRQn, 1); - NVIC_SetPriority(PWM1_IRQn, 2); - + bool normalReset = true; // Did a watchdog reset occur since last power cycle? if (wdt.checkFlag()) { @@ -31,28 +46,25 @@ } // Print normal reset string if (normalReset) pc.printf("Sys Mgmt Reset\r\n"); - - // Start the 10Hz data thread - Thread gather(runTime::thread_gather, 0, osPriorityHigh, 512); - - // Start the 100Hz data timer (more time critical than thread) + + // Start the watchdog check-in thread + Thread watchdogCheck(thread_watchDog, 0, osPriorityRealtime, 128); + + // Start the 100Hz data timer (priotity high) RtosTimer sample(runTime::thread_sample, osTimerPeriodic); sample.start(FAST_LOOP*1000); // Start the serial, CAN threads - Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityAboveNormal, 2000); // Allocate 6kB RAM stack - Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal, 512); // Allocate 256B RAM stack + Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityBelowNormal); + Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityBelowNormal, 512); - wdt.kick(1); // Startup complete, normal timeout - // Background task + // Start the input polling thread + Thread getInputs(inCommands::thread_getInputs, 0, osPriorityLow); + + // Main task while(1) { - // Service CAN and Xbee logic - inCommands::serviceCAN(); - inCommands::receiveMsgXbee(); - - int ret = inCommands::serviceSerial(); - if (ret == -1) tempData.parseGoodChar = 'x'; - if (ret == 1) tempData.parseGoodChar = 251; - wdt.kick(); + runTime::gather(0); + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<0); // Signal watchdog thread + Thread::wait(GATHER_LOOP*1000); } } \ No newline at end of file
--- a/outDiagnostics/outDiagnostics.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/outDiagnostics/outDiagnostics.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -1,59 +1,42 @@ #include "outDiagnostics.h" -osThreadId Serialthread_id = 0; // RTOS thread ID of thread_serialOut +osThreadId serialID = 0; // RTOS thread ID of thread_serialOut const int max_charsPerLine = 80; // Max chars per line of printed information -const int max_lines = TX_SIZE / (max_charsPerLine+2); // Lines per printing chunk (write chunk to MODSERIAL Buffer every x lines) -// Interrupt function called when the MODSERIAL TX buffer is empty -// The functions signals RTOS to unblock to serial thread and allow it -// to produce the chunk of serial output data -void empty(MODSERIAL_IRQ_INFO *q) -{ - osSignalSet(Serialthread_id, 1); // Set signal 1 for serial thread +// Use the txEmpty interrupt from MODSERIAL to pace the thread so it always runs as fast as possible +void empty(MODSERIAL_IRQ_INFO *q) { + osSignalSet(serialID, 1); } -// Add a line of text to the printing queue. -// Actually gets added to another local buffer, which gets copied into the MODSERIAL TX buffer when it -// empties. Provides double-buffered output stream so inflow and outflow rates can be different. -// Char *str NEEDS to be NULL terminated string! bool newline determines whether newline characters \r\n are appended to the line -void AddToChunk (char *str, bool newline=true) +// Output a string to the MODSERIAL tx buffer, wait when buffer full +void AddtoBuffer(char *str, bool newline=true) { - static char chunk[(max_charsPerLine+5)*max_lines]; // The chunk buffer, holds one chunk= max_charsPerLine*max_lines characters - static int pos = 0; // The position to load next character - static int lines = 0; // Number of lines currently stored in the chunk - static int wait = pc.txBufferGetSize(0) * (CHAR_TIME*1000); // Max wait time to empty the tx buffer = max time to send out all chars - - pos += sprintf(chunk+pos, "%s%s", str, newline?"\r\n":""); // Append to working array - lines++; // New line added to array - - if (lines >= max_lines) { // Time to print the block - // Is buffer free enough to accept the block? - if (pc.txBufferGetCount() - pc.txBufferGetSize(0) > pos+5) { - for (int i = 0; i < pos; i++) pc.putc(chunk[i]); // Add the string to the buffer - } else { - // No, it is not free enough to hold the string - osSignalClear(Serialthread_id, 1); // Clear signal if it was set - Thread::signal_wait(1, wait); // RTOS wait for empty signal, max wait if it never occurs - for (int i = 0; i < pos; i++) pc.putc(chunk[i]); // Add into the output buffer + const int waitT = TX_SIZE * CHAR_TIME*1000; // Max wait time to empty the tx buffer = max time to send out all chars + int len = strlen(str); + int times = newline ? (len + 2) : (len); // If newline requested, add 2 chars for "\r\n" + for (int i = 0; i < times; i++) { + if (!pc.writeable()) { // Keep writing till it fills + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<3); // Check-in with watchdog thread + Thread::signal_wait(1, waitT); // Wait for empty signal from MODSERIAL tx empty interrupt, timeout in waitT ms } - lines = 0; // Chunk added, reset line counter - pos = 0; // Chunk added, reset position + if (i < len) pc.putc(str[i]); // Print the string + else if (i == len) pc.putc('\r'); // Add carriage return + else if (i > len) pc.putc('\n'); // Add newline } } // Print to internal string buffer, pad to maxLen chars and center it with char pad, str must be null terminated! void padCenter(int LineLen, char *str, char pad) { - static char line[max_charsPerLine+5]; // String buffer to work with one line at a time + static char line[max_charsPerLine+5]; // String buffer to work with one line at a time + int len = strlen(str); // Length of input string + int padL = (LineLen-len)/2; // How many pad chars needed on left side? + for (int i=0; i<padL; i++) line[i] = pad; // Fill in the left padding chars + strcpy(line+padL, str); // Copy to line string + for (int i = padL+len; i<LineLen; i++) line[i] = pad; // Fill remaining with padding chars + line[LineLen-1] = '\0'; // Add null terminator - int len = strlen(str); // Length of input string - int padL = (LineLen-len)/2; // How many pad chars needed on left side? - for (int i=0; i<padL; i++) line[i] = pad; // Fill in the left padding chars - strcpy(line+padL, str); // Copy to line string - for (int i = padL+len; i<LineLen; i++) line[i] = pad; // Fill remaining with padding chars - line[LineLen-1] = '\0'; // Add null terminator - - AddToChunk(line); + AddtoBuffer(line); } @@ -67,11 +50,10 @@ // Generates the serial dashboard, uses MODSERIAL, self-paced (thread yields when buffer is full, resumes when empty) void outDiagnostics::thread_serialOut(void const *args) { - Serialthread_id = Thread::gettid(); // Record thread ID so empty() can signal this thread + serialID = Thread::gettid(); // Record thread ID so empty() can signal this thread char temp[max_charsPerLine+5]; // String buffer to sprintf into, max 1 line pc.attach(&empty, MODSERIAL::TxEmpty); // Attach the tx empty interrupt which paces this thread - pc.printf("\033[2J"); // Clear the screen to get rid of reset message tempData.parseGoodChar = ' '; tempData.inputStr[0] = 0; @@ -89,7 +71,7 @@ serialLoop.reset(); sprintf(temp, "\033[0;0H\033[0;0H"); - AddToChunk(temp, false); // Move to 0,0, do not append newline + AddtoBuffer(temp, false); // Move to 0,0, do not append newline DIVIDER_LINE TITLE(" Penn Electric Racing - REV0 System Management Controller Dashboard ") @@ -97,10 +79,10 @@ int tempLength=0; tempLength += sprintf(temp, "Command Input:%c %s%c", tempData.parseGoodChar, tempData.inputStr, 176); // Command input: print header, reply, input string, and cursor marker - for (int i = 0; i < max_charsPerLine - strlen(temp)- 1; i++) { // Fill in the rest of the line with blanks + for (int i = 0; i < max_charsPerLine - tempLength - 1; i++) { // Fill in the rest of the line with blanks tempLength += sprintf(temp+tempLength, " "); // Append spaces } - AddToChunk(temp); // Add this to the chunk + AddtoBuffer(temp); // Add this to the chunk TITLE(" GLV Battery ") BLANK_LINE @@ -121,7 +103,7 @@ else if (!(DCDC & SetOn)) dcdcMode = 4; sprintf(temp, "Active: %3s Mode: %10s AIRS: %6s StatusByte: 0x%02x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC); ADD_SPRINTF_LINE - sprintf(temp, "Current: %5.3fA Overcurrent: %3s SensorFault: %3s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); + sprintf(temp, "Current: %5.2fA Overcurrent: %3s SensorFault: %3s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); ADD_SPRINTF_LINE sprintf(temp, "StartFault: %3s StopFault: %3s CritErrors: %3s", BOOL(DCDC & FailStart), BOOL(DCDC & FailStop), BOOL(data.dcdcError)); ADD_SPRINTF_LINE @@ -146,9 +128,9 @@ BLANK_LINE char AMSerr = data.AMSlatchError; char IMDerr = data.IMDlatchError; - sprintf(temp, "AMS: OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (AMSerr & 1)?"LOW":"HIGH", BOOL(AMSerr & 2), BOOL(AMSerr & 4), BOOL(AMSerr & 8)); + sprintf(temp, "AMS - OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (AMSerr & 1)?"LOW":"HIGH", BOOL(AMSerr & 2), BOOL(AMSerr & 4), BOOL(AMSerr & 8)); ADD_SPRINTF_LINE - sprintf(temp, "IMD: OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (IMDerr & 1)?"LOW":"HIGH", BOOL(IMDerr & 2), BOOL(IMDerr & 4), BOOL(IMDerr & 8)); + sprintf(temp, "IMD - OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (IMDerr & 1)?"LOW":"HIGH", BOOL(IMDerr & 2), BOOL(IMDerr & 4), BOOL(IMDerr & 8)); ADD_SPRINTF_LINE BLANK_LINE @@ -163,15 +145,15 @@ BLANK_LINE TITLE(" Telemetry ") BLANK_LINE - sprintf(temp, "Channel 1: MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX1in, xbeeRelay.counterX1out); + sprintf(temp, "Channel 1 - MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX1in, xbeeRelay.counterX1out); ADD_SPRINTF_LINE - sprintf(temp, "Channel 2: MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX2in, xbeeRelay.counterX2out); + sprintf(temp, "Channel 2 - MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX2in, xbeeRelay.counterX2out); ADD_SPRINTF_LINE BLANK_LINE TITLE(" Miscellaneous ") BLANK_LINE - sprintf(temp, "Temp: %5.1fC %3s canFault: %3s Watchdog: %3s ErrorCode: 0x%02x SerailTime: %3dms", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame, serialTime_ms); + sprintf(temp, "Temp: %5.1fC %3s canFault: %3s Watchdog: %3s ErrorCode: 0x%02x SerialTime: %3dms", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame, serialTime_ms); ADD_SPRINTF_LINE // Erase screen every 5sec to remove glitches @@ -232,7 +214,8 @@ // Shutdown Switches CHAR(data.switchState, SYS_SWITCHES_ID) - + + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<4); // Signal watchdog thread Thread::wait(CAN_LOOP*1000); } } \ No newline at end of file
--- a/runTime/runTime.cpp Wed Jan 07 03:36:43 2015 +0000 +++ b/runTime/runTime.cpp Thu Jan 22 07:58:51 2015 +0000 @@ -2,48 +2,48 @@ const float INTERNAL_OVER_TEMP_THRES = 60; // Overtemp at 60C -void runTime::thread_gather(void const* args) { - while(1) { - - // GLV battery coulomb counter - data.glvCurrent = glvBat.current(); - data.glvSOC = glvBat.SOC(); - data.glvAmphours = glvBat.ampHours(); - data.glvCapacity = glvBat.capacity(); - data.glvOverCurrent = glvBat.overCurrentDetected(); - - // DC-DC converter & PWM channels - data.dcdcStatus = dcdc.getStatus(); - data.dcdcError = dcdc.hasCritError(); - data.dcdcCurrent = dcdc.getCurrent(); - data.dcdcFan1Duty = dcdc.readPwm(FAN1); - data.dcdcFan2Duty = dcdc.readPwm(FAN2); - data.dcdcPump1Duty = dcdc.readPwm(PUMP1); - data.dcdcPump2Duty = dcdc.readPwm(PUMP2); - - // IMD PWM - data.imdStatus = imd.status(); - data.imdResistance = imd.resistance(); - data.imdError = ((data.imdStatus != NORMAL) && (data.imdStatus != SPEEDSTART)) || (isnan(data.imdResistance)); - - // Reset latches - data.AMSlatchError = AMSlatch.update(); - data.IMDlatchError = IMDlatch.update(); +void runTime::gather(void const* args) +{ + // GLV battery coulomb counter + data.glvCurrent = glvBat.current(); + data.glvSOC = glvBat.SOC(); + data.glvAmphours = glvBat.ampHours(); + data.glvCapacity = glvBat.capacity(); + data.glvOverCurrent = glvBat.overCurrentDetected(); + + // DC-DC converter & PWM channels + data.dcdcStatus = dcdc.getStatus(); + data.dcdcError = dcdc.hasCritError(); + data.dcdcCurrent = dcdc.getCurrent(); + data.dcdcFan1Duty = dcdc.readPwm(FAN1); + data.dcdcFan2Duty = dcdc.readPwm(FAN2); + data.dcdcPump1Duty = dcdc.readPwm(PUMP1); + data.dcdcPump2Duty = dcdc.readPwm(PUMP2); - // Switches - data.switchState = switches.poll(); - - // Temperaure - data.internalTemp = internalTmp.read(); - if (data.internalTemp > INTERNAL_OVER_TEMP_THRES) data.internalOverTemp = true; - else data.internalOverTemp = false; - - // Error frame - data.errorFrame = data.canFault<<0 | data.watchdogReset<<1 | data.internalOverTemp<<2 | (data.IMDlatchError!=0)<<3 | (data.AMSlatchError!=0)<<4 | data.imdError<<5 | data.dcdcError<<6 | data.glvOverCurrent<<7; - Thread::wait(GATHER_LOOP*1000); - } + // IMD PWM + data.imdStatus = imd.status(); + data.imdResistance = imd.resistance(); + data.imdError = ((data.imdStatus != NORMAL) && (data.imdStatus != SPEEDSTART)) || (isnan(data.imdResistance)); + + // Reset latches + data.AMSlatchError = AMSlatch.update(); + data.IMDlatchError = IMDlatch.update(); + + // Switches + data.switchState = switches.poll(); + + // Temperaure + data.internalTemp = internalTmp.read(); + if (data.internalTemp > INTERNAL_OVER_TEMP_THRES) data.internalOverTemp = true; + else data.internalOverTemp = false; + + // Error frame + data.errorFrame = data.canFault<<0 | data.watchdogReset<<1 | data.internalOverTemp<<2 | (data.IMDlatchError!=0)<<3 | (data.AMSlatchError!=0)<<4 | data.imdError<<5 | data.dcdcError<<6 | data.glvOverCurrent<<7; } -void runTime::thread_sample(void const* args) { + +void runTime::thread_sample(void const* args) +{ + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<1); // Signal watchdog thread glvBat.sample(); // Integrate next sample in GLV Battery coulomb counter dcdc.sample(); // Handle dc-dc filter and errors } \ No newline at end of file
--- a/runTime/runTime.h Wed Jan 07 03:36:43 2015 +0000 +++ b/runTime/runTime.h Thu Jan 22 07:58:51 2015 +0000 @@ -5,7 +5,7 @@ namespace runTime { - void thread_gather(void const* args); + void gather(void const* args); void thread_sample(void const* args); }