System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Revision 30:91af74a299e1, committed 2014-11-13
- Comitter:
- pspatel321
- Date:
- Thu Nov 13 10:53:10 2014 +0000
- Parent:
- 24:f58a3c0071c3
- Child:
- 31:7eaa5e881b56
- Commit message:
- Parth's edits for the week.; DC-DC completed and fixed, IMD updated, LatchMonitor and Temperature added. Serial dashboard updated. File structure changed Everything tested. Compiles and runs.; Still need to write CAN in/out interface.
Changed in this revision
--- a/CANBuffer.lib Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#110f268af846
--- a/CANController/CANController.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-#include "CANController.h"
-
-CANController::CANController(){
-
-};
-
-bool CANController::dc_on(){
- return dc.is_on();
-};
-
-void CANController::set_dc(bool status){
- dc.set(status);
-};
-
-bool CANController::write_contrl(ContrlPinName name, float duty){
- if(dc.is_on()){
-
- return true;
- }
- return false;
-};
-
-void CANController::direct_off(ContrlPinName name, float duty){
-
-};
-
-float *CANController::read_control(){
- return NULL;
-}
\ No newline at end of file
--- a/CANController/CANController.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#ifndef _FILE_CANCONTRL_H
-#define _FILE_CANCONTRL_H
-
-#include "DC_DC.h"
-#include "FanPump.h"
-
-enum ContrlPinName{
- FAN1, FAN2, FAN3, PUMP
-};
-
-class CANController{
-public:
- CANController();
- bool dc_on();
- void set_dc(bool status);
- bool write_contrl(ContrlPinName name, float duty);
- void direct_off(ContrlPinName name, float duty);
- float *read_control();
-
-private:
- FanPump *contrl_pins[6];
- DC dc;
-};
-
-#endif
\ No newline at end of file
--- a/CANController/DC_DC/DC_DC.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#include "mbed.h"
-#include "DC_DC.h"
-
-DigitalOut dc_pin(p20);
-DigitalOut dc_control(p18);
-
-#define OFF 1
-#define ON 0
-
-DC::DC(){
- dc_control = OFF;
-}
-
-bool DC::is_on(){
- return dc_pin;
-}
-
-void DC::set(bool s){
- if(s)
- dc_control = ON;
- else
- dc_control = OFF;
-}
\ No newline at end of file
--- a/CANController/DC_DC/DC_DC.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#ifndef _FILE_DC_DC_H
-#define _FILE_DC_DC_H
-
-#include "CANBuffer.h"
-#include "FanPump.h"
-#include "rtos.h"
-
-const int TX_DC_DC_ID = ((0x4 << 8) | 0x01);
-const int RX_DC_DC_ID = ((0x4 << 8) | 0x90);
-
-class DC{
- public:
- DC(); //constructor takes function to shut down certain processes when off
- bool is_on();
- void set(bool status);
-};
-
-#endif
\ No newline at end of file
--- a/CANController/FanPump/FanPump.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#include "FanPump.h"
-
-static FanPump* instance[6] = { NULL }; // Access pwm object by channel#
-const int PCLK = 24e6; // 24Mhz clock
-uint32_t FanPump::period_us = 0.0;
-
-// 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 = *((uint32_t*)(&LPC_PWM1->MR0)+chan); // 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 chan=0;
- if (pin == p26 || pin == LED1) chan = 1;
- if (pin == p25 || pin == LED2) chan = 2;
- if (pin == p24 || pin == LED3) chan = 3;
- if (pin == p23 || pin == LED4) chan = 4;
- if (pin == p22) chan = 5;
- if (pin == p21) chan = 6;
- if (chan == 0) return; // Invalid pin
- instance[chan-1] = this;
-
- 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 = *((uint32_t*)(&LPC_PWM1->MR0)+chan); // Get the current pulsewidth ticks
- return ((float)(currPulseT) / (float)(PCLK/1e6)) / (float)(period_us);
-}
\ No newline at end of file
--- a/CANController/FanPump/FanPump.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +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
- volatile int chan; // pwm channel#
- static uint32_t period_us; // Period in microseconds (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/CAN_Filter_LUT.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
-Code by Parth Patel, Penn Electric Racing 2014, 9/23/2014
-
-This library provides an easy to use, buffered, hardware-filtered CAN interface for
-high performance CAN applications. Provides automatic reception of messages via CAN RX interrupt
-into a rx ring buffer. Provides automatic transmission of messages via CAN TX interrupt.
-
-@File CAN_Filter_LUT.h: Contains the formatted lookup tables to program the onboard CAN acceptance filters
-
-*/
-#ifndef _FILE_CAN_FILTER_LUT_H
-#define _FILE_CAN_FILTER_LUT_H
-
-#define STDMASK 0x7FF
-#define EXTMASK 0x1FFFFFFF
-
-// These arrays defines the CAN Controller Acceptance Filter Lookup Table.
-// Follow notes below or else the chip's behaviour will be undefined
-// MAX SIZE PERMITTED = 512 32bit ints total across all tables
-// Note that AF_LUT_SEI is 16bit, divide #entries by 2 for this one
-// Note that AF_LUT_EIR is 64bit, multipy #entries by 2 for this one
-
-const uint16_t AF_LUT_SEI[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
-
-// STANDARD EXPLICIT IDs - CAN CONTROLLER 1
-//( 0xID & STDMASK),
-
-// STANDARD EXPLICIT IDs - CAN CONTROLLER 2
-//( 0xID & STDMASK) | 1<<13,
-};
-
-const uint32_t AF_LUT_SIR[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
-
-// STANDARD ID RANGES - CAN CONTROLLER 1
-//( 0xLOWERBOUND & STDMASK) << 16 | ( 0xUPPERBOUND & STDMASK), lower/upperbounds are inclusive
-
-// STANDARD ID RANGES - CAN CONTROLLER 2
-//( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13), lower/upperbounds are inclusive
- ( 0x400 & STDMASK | 1<<13) << 16 | ( 0x4FF & STDMASK | 1<<13), // Index1
-};
-
-const uint32_t AF_LUT_EEI[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
-
-// EXTENDED EXPLICIT IDs - CAN CONTROLLER 1
-//( 0xID & EXTMASK),
-
-// EXTENDED EXPLICIT IDs - CAN CONTROLLER 2
-//( 0xID & EXTMASK) | 1<<29,
-};
-
-const uint64_t AF_LUT_EIR[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
-
-// EXTENDED ID RANGES - CAN CONTROLLER 1
-//( 0xLOWERBOUND & EXTMASK) << 32 | ( 0xUPPERBOUND & EXTMASK), lower/upperbounds are inclusive
-
-// EXTENDED ID RANGES - CAN CONTROLLER 2
-//( 0xLOWERBOUND & EXTMASK | 1<<29) << 32 | ( 0xUPPERBOUND & EXTMASK | 1<<29), lower/upperbounds are inclusive
-
-};
-
-#endif
\ No newline at end of file
--- a/CoulombCounter/CoulombCounter.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#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_LIMS = 3.0; // Over-current limit = +/- 3A
-
-CoulombCounter::CoulombCounter(int _mSec, int _rtcGPREG_counter, int _rtcGPREG_capacity) : BatISense(p19) {
- mSec = _mSec;
- rtcGPREG_counter = _rtcGPREG_counter;
- rtcGPREG_capacity = _rtcGPREG_capacity;
-
- // Take the initial reading
- currentSample = BatISense*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET;
- if (currentSample < -BAT_ISENSE_LIMS || currentSample > BAT_ISENSE_LIMS) overCurrent = true;
- else overCurrent = false;
-
- // 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;
-
- // Signal error on over current
- if (abs(currentSample) > BAT_ISENSE_LIMS) {
- overCurrent = true;
- } else overCurrent = false;
-
- // Integrate
- float f = ampHours()+currentSample*mSec*MSEC_HRS;
- store.write(f, rtcGPREG_counter);
-}
\ No newline at end of file
--- a/CoulombCounter/CoulombCounter.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#ifndef _FILE_CURRENTMONITOR_H
-#define _FILE_CURRENTMONITOR_H
-
-#include "mbed.h"
-#include "CANBuffer.h"
-#include "RTCStore.h"
-
-class CoulombCounter {
-public:
-
- // Configures for a certain pin, millisecond sample period, and which GPREG in RTC to use to store the ampHours
- CoulombCounter(int _mSec, int _rtcGPREG_counter, int _rtcGPREG_capacity);
-
- // Allow zeroing the SOC when the battery is fully charged/dead, SOC in % from 0 to 1
- void resetToSOC(float SOC) { store.write(SOC*capacity(), rtcGPREG_counter); }
-
- // Allow zeroing the SOC (via zeroing the Ah) when the battery is fully charged/dead
- void resetToAh(float Ah) { store.write(Ah, rtcGPREG_counter); }
-
- // Allow change of capacity spec (changes SOC)
- void changeCapacity(float capAh) {store.write(capAh, rtcGPREG_capacity); }
-
- bool overCurrent; // Sensor above range
- float current() { return currentSample; } // Last current reading in Amps
- float ampHours() { return store.read(rtcGPREG_counter); }
- float capacity() { return store.read(rtcGPREG_capacity); }
- float SOC() { return ampHours()/capacity(); }
-
-private:
- Ticker sampler; // Used to capture next sample and coulomb count
- void sample();
- RTCStore store;
-
- volatile int mSec;
- volatile float currentSample;
- volatile int rtcGPREG_counter;
- volatile int rtcGPREG_capacity;
- AnalogIn BatISense; // Analog input pin
-};
-#endif
\ No newline at end of file
--- a/CoulombCounter/RTCStore.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/* Test Code
- #include "Battery_Status.h"
- #include"mbed.h"
- BatteryStatus battery;
-
- int main()
- {
- //battery.write(6.92,0);
- printf("LPC_RTC->GPREG0:%f\n\r",battery.read(0));
- //battery.write(7.92,1);
- printf("LPC_RTC->GPREG1:%f\n\r",battery.read(1));
- //battery.write(8.92,2);
- printf("LPC_RTC->GPREG2:%f\n\r",battery.read(2));
- //battery.write(9.92,3);
- printf("LPC_RTC->GPREG3:%f\n\r",battery.read(3));
- //battery.write(10.92,4);
- printf("LPC_RTC->GPREG4:%f\n\r",battery.read(4));
- }
-*/
-
-#ifndef _RTC_STORE_H
-#define _RTC_STORE_H
-#include "mbed.h"
-
-class RTCStore {
-public:
- RTCStore() {
- LPC_SC->PCONP |= (1<<9); // Enable RTC Peripheral
- }
- void write(float data, int block) {
- *((float*)(&LPC_RTC->GPREG0)+block) = data;
- }
- float read(int block) {
- return *((float*)(&LPC_RTC->GPREG0)+block);
- }
-};
-#endif
-
\ No newline at end of file
--- a/IMD/IMD.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-#include "IMD.h"
-#include <math.h>
-
-static IMD* instance;
-
-const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz
-const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK
-const float EXTRA = 0.01; // Margin on the IMD PWM limits
-
-// Interrupt function, must be static context
-void tim0_IRQ() {
- // Capture event was found
- if (LPC_TIM0->IR & 1<<4) instance->edgeIRQ();
-
- // MR0 (zero Hz timeout) event was found
- if (LPC_TIM0->IR & 1) instance->zeroIRQ();
- LPC_TIM0->IR=0x3F; // Clear interrupt flags
-}
-
-IMD::IMD() {
- instance = this;
- first = true;
- startTime = 0;
- widthTicks = 0; // Zero low, so that duty = 0/1 = 0%
- periodTicks = 1;
-
- LPC_SC->PCONP |= (1<<1); // Power on timer0
- LPC_SC->PCLKSEL0 &= ~(3<<2); // Clock at 24MHz
-
- *(p1_26.pinsel_addr) |= 3 << p1_26.selmode_num; // Set pin as capture pin
- *(p1_26.pinmode_addr) |= 3 << p1_26.selmode_num; // Pull down
-
- LPC_TIM0->TCR=2; // Stop counter and hold at 0, for configuration, set to 1 to start operation
- LPC_TIM0->IR=0x3F; // Clear any interrupt flags
- LPC_TIM0->CTCR=0; // Use pclk, not external pin
- LPC_TIM0->PR=0; // No prescale value, clock at full pclk=24Mhz
- LPC_TIM0->EMR=0; // Do not use external match pins
-
- NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Point to the interrupt handler
- NVIC_SetPriority(TIMER0_IRQn, 0); // Highest Priority
- NVIC_EnableIRQ(TIMER0_IRQn); // Enable IRQ
- LPC_TIM0->CCR = RISING; // Generate interrupt on capture, capture on rising edge to start
- LPC_TIM0->MCR = 1; // Interrupt on Match0 to establish the zero speed timeout
- LPC_TIM0->MR0 = LPC_TIM0->TC+TIMEOUT_TICKS;
- LPC_TIM0->TCR = 1; // Start counting, GO!
-}
-
-void IMD::edgeIRQ() {
- uint32_t type = LPC_TIM0->CCR;
- uint32_t capTime = LPC_TIM0->CR0;
- LPC_TIM0->MR0 = capTime+TIMEOUT_TICKS; // Set the next zeroing timeout
-
- // 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;
- startTime = capTime - 1;
- }
- if (type == RISING) {
- periodTicks = capTime - startTime; // Get the period on Rising edge
- startTime = capTime; // Set the start of the next pulse
- }
- if (type == FALLING) {
- widthTicks = capTime - startTime; // Get the pulse width on Falling edge
- }
-
- // Switch interrupt types to capture the next edge
- if (type == RISING) LPC_TIM0->CCR = FALLING;
- if (type == FALLING) LPC_TIM0->CCR = RISING;
-}
-
-void IMD::zeroIRQ() {
- uint32_t type = LPC_TIM0->CCR;
- periodTicks = 1;
- first = true;
-
- // Timeout occurred after FALLING edge, now looking for RISING edge
- if (type == RISING) {
- widthTicks = 0; // Signal is low = 0/1 = 0% duty
- }
- if (type == FALLING) {
- widthTicks = 1; // Signal is high = 1/1 = 100% duty
- }
-}
-float IMD::frequency() {
- // Handle the case where we want to say 0Hz not infinity Hz
- if (periodTicks == 1 || periodTicks == 0) return 0;
- else return (float)(PCLK)/(float)(periodTicks);
-}
-float IMD::duty() {
- return (float)(widthTicks)/(float)(periodTicks);
-}
-
-char IMD::status() {
- float freq = frequency();
- if (freq == 0) return OFF; // IMD off
- else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode
- else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode
- else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode
- else if (45 < freq && freq <= 55) return ERROR; // 40Hz IMD error
- else if (55 < freq && freq <= 65) return GROUNDERR; // 50Hz Ground error
- else return INVALID; // Invalid
-}
-
-float IMD::resistance() {
- char stat = status();
- float dut = duty();
-
- // In normal or undervoltage mode, where Rf is available
- if (stat == 1 || stat == 2) {
- if (0.05-EXTRA <= dut && dut >= 0.95+EXTRA) {
- float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
- if (rf < 0) rf = 0;
- if (rf > 50e6) rf = 50e6;
- return rf;
- }
- else return -1;
- }
- // In speed start, where only good/bad estimate is available
- if (stat == 3) {
- if (0.05-EXTRA <= dut && dut >= 0.10+EXTRA) return 50e6; // Good
- else if (0.90-EXTRA <= dut && dut >= 0.95+EXTRA) return 0; // Bad
- else return -1;
- }
- return NAN; // Measurement not available in this mode
-}
\ No newline at end of file
--- a/IMD/IMD.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-// copied idea from http://developer.mbed.org/forum/mbed/topic/466/?page=1#comment-2457
-
-#ifndef _FILE_IMD_H
-#define _FILE_IMD_H
-
-#include "mbed.h"
-#include "LPCDigitalIn.h"
-
-const float ZERO_HZ_TIMEOUT = 0.1; // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width
-
-enum EdgeT {
- RISING=5,
- FALLING=6,
- BOTH=7,
-};
-
-enum IMDstatus {
- OFF=0,
- NORMAL=1,
- UNDERVOLT=2,
- SPEEDSTART=3,
- ERROR=4,
- GROUNDERR=5,
- INVALID=6,
-};
-
-class IMD{
-public:
- IMD();
-
- char status();
- // Gets the insulation resistance reading
- // Returns 0 to 50,000,000 in normal/UV modes
- // Returns 0 or 50,000,000 in speed start (good/bad only)
- // -1 for invalid measurement (out of permissible range)
- // and NaN for not applicable mode
- float resistance();
-
- // Interrupt function for the edge type detected
- void edgeIRQ();
- // Used to zero (reset) the data on timeout
- void zeroIRQ();
-
-private:
- float frequency();
- float duty();
- volatile uint32_t startTime;
- volatile uint32_t widthTicks;
- volatile uint32_t periodTicks;
- volatile bool first;
-};
-
-#endif
\ No newline at end of file
--- a/IOobjects.cpp Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#include "IOobjects.h" - -// I/O objects -MODSERIAL pc(USBTX, USBRX, 4096, 256); // Software buffered serial, 4kB buffer -CANBuffer can(CAN2, MEDIUM, p0_6); // Software buffered CAN -Watchdog wdt(0.11); // Watchdog timer set to 110ms -PollSwitch pollSwitch; -IMD imd; -CoulombCounter coulombCounter(10, 0, 0); -DC dc; \ No newline at end of file
--- a/IOobjects.h Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -#ifndef _IO_OBJECTS_H -#define _IO_OBJECTS_H - -#include "mbed.h" -#include "MODSERIAL.h" -#include "CANBuffer.h" -#include "Watchdog.h" - -#include "PollSwitch.h" -#include "IMD.h" -#include "CoulombCounter.h" -#include "DC_DC.h" - -extern CANBuffer can; -extern MODSERIAL pc; -extern Watchdog wdt; -extern PollSwitch pollSwitch; -extern IMD imd; -extern CoulombCounter coulombCounter; -extern DC dc; - -#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/CAN_Filter_LUT.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,65 @@
+/*
+Code by Parth Patel, Penn Electric Racing 2014, 9/23/2014
+
+This library provides an easy to use, buffered, hardware-filtered CAN interface for
+high performance CAN applications. Provides automatic reception of messages via CAN RX interrupt
+into a rx ring buffer. Provides automatic transmission of messages via CAN TX interrupt.
+
+@File CAN_Filter_LUT.h: Contains the formatted lookup tables to program the onboard CAN acceptance filters
+
+*/
+#ifndef _FILE_CAN_FILTER_LUT_H
+#define _FILE_CAN_FILTER_LUT_H
+#include "CAN_RxIDs.h"
+
+#define STDMASK 0x7FF
+#define EXTMASK 0x1FFFFFFF
+
+// These arrays defines the CAN Controller Acceptance Filter Lookup Table.
+// Follow notes below or else the chip's behaviour will be undefined
+// MAX SIZE PERMITTED = 512 32bit ints total across all tables
+// Note that AF_LUT_SEI is 16bit, divide #entries by 2 for this one
+// Note that AF_LUT_EIR is 64bit, multipy #entries by 2 for this one
+
+const uint16_t AF_LUT_SEI[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
+
+// STANDARD EXPLICIT IDs - CAN CONTROLLER 1
+//( 0xID & STDMASK),
+
+// STANDARD EXPLICIT IDs - CAN CONTROLLER 2
+//( 0xID & STDMASK) | 1<<13,
+};
+
+const uint32_t AF_LUT_SIR[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
+
+// STANDARD ID RANGES - CAN CONTROLLER 1
+//( 0xLOWERBOUND & STDMASK) << 16 | ( 0xUPPERBOUND & STDMASK), lower/upperbounds are inclusive
+
+// STANDARD ID RANGES - CAN CONTROLLER 2
+//( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13), lower/upperbounds are inclusive
+};
+
+const uint32_t AF_LUT_EEI[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
+
+// EXTENDED EXPLICIT IDs - CAN CONTROLLER 1
+//( 0xID & EXTMASK),
+
+// EXTENDED EXPLICIT IDs - CAN CONTROLLER 2
+//( 0xID & EXTMASK) | 1<<29,
+};
+
+const uint64_t AF_LUT_EIR[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
+
+// EXTENDED ID RANGES - CAN CONTROLLER 1
+//( 0xLOWERBOUND & EXTMASK) << 32 | ( 0xUPPERBOUND & EXTMASK), lower/upperbounds are inclusive
+
+// EXTENDED ID RANGES - CAN CONTROLLER 2
+//( 0xLOWERBOUND & EXTMASK | 1<<29) << 32 | ( 0xUPPERBOUND & EXTMASK | 1<<29), lower/upperbounds are inclusive
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IOobjects/CAN_RxIDs.h Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,6 @@ +#ifndef CAN_RXIDS_H +#define CAN_RXIDS_H + +// Receive IDs + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IOobjects/CAN_TxIDs.h Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,6 @@ +#ifndef CAN_TXIDS_H +#define CAN_TXIDS_H + + + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/IOobjects.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,32 @@
+#include "IOobjects.h"
+
+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
+};
+
+CANBuffer can(CAN2, MEDIUM, p4_28); // Buffered CAN interface (PORT, SPEED, SILENT PIN)
+CoulombCounter glvBat(p19, 10); // 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, 5000); // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms))
+LatchMonitor IMDlatch(p0_17, p0_21, 5000); // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms))
+MODSERIAL pc(USBTX, USBRX); // Serial to computer for diagnostics
+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)
+Watchdog wdt(0.25); // Watchdog timer (TIMEOUT (sec))
+Xbee xbee1(p9, p10, 250000, 1000, '\n'); // Software buffered Xbee 1 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR)
+Xbee xbee2(p9, p10, 250000, 1000, '\n'); // Software buffered Xbee 2 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR)
+DigitalOut extras[] = {(p16), (p17)}; // Unused analog pins driven low
+Inputs data;
+CANinputs CANdata;
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/IOobjects.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,83 @@
+#ifndef _IO_OBJECTS_H
+#define _IO_OBJECTS_H
+
+#include "mbed.h"
+#include "rtos.h"
+#include "CANBuffer.h"
+#include "CoulombCounter.h"
+#include "DC_DC.h"
+#include "IMD.h"
+#include "LatchMonitor.h"
+#include "MODSERIAL.h"
+#include "PollSwitch.h"
+#include "Temperature.h"
+#include "Watchdog.h"
+#include "Xbee.h"
+
+extern CANBuffer can;
+extern CoulombCounter glvBat;
+extern DC_DC dcdc;
+extern IMD imd;
+extern LatchMonitor AMSlatch;
+extern LatchMonitor IMDlatch;
+extern MODSERIAL pc;
+extern PollSwitch switches;
+extern Temperature internalTmp;
+extern Watchdog wdt;
+extern Xbee xbee1;
+extern Xbee xbee2;
+
+// Shared data updated by producer threads
+class Inputs {
+public:
+ volatile float glvCurrent;
+ volatile float glvAmphours;
+ volatile float glvSOC;
+ volatile float glvCapacity;
+ volatile bool glvOverCurrent; // Error bit, turn off car
+
+ volatile char dcdcStatus;
+ volatile bool dcdcError; // Error bit, turn off car
+ volatile float dcdcCurrent;
+ volatile float dcdcFan1Duty;
+ volatile float dcdcFan2Duty;
+ volatile float dcdcPump1Duty;
+ volatile float dcdcPump2Duty;
+
+ volatile char imdStatus;
+ volatile float imdResistance;
+ volatile bool imdError; // Error bit, turn off car
+
+ volatile char AMSlatchError; // Error bit, turn off car
+ volatile char IMDlatchError; // Error bit, turn off car
+
+ volatile char switchState;
+
+ volatile float internalTemp;
+ volatile bool internalOverTemp; // Error bit, turn off car
+
+ volatile unsigned int xbee1MessagesIn;
+ volatile unsigned int xbee2MessagesIn;
+ volatile unsigned int xbee1MessagesOut;
+ volatile unsigned int xbee2MessagesOut;
+
+ volatile bool watchdogReset; // Error bit, turn off car
+ volatile bool canFault; // Error bit, turn off car
+
+ volatile char errorFrame;
+};
+
+// Shared data updated by CAN messeges
+class CANinputs {
+public:
+ volatile bool airsClosed;
+ volatile float dcdcFan1Duty;
+ volatile float dcdcFan2Duty;
+ volatile float dcdcPump1Duty;
+ volatile float dcdcPump2Duty;
+};
+
+extern CANinputs CANdata;
+extern Inputs data;
+
+#endif
\ No newline at end of file
--- a/LPCDigitalIn.lib Fri Nov 07 21:26:46 2014 +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/CANBuffer.lib Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#4baa7251c6c0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,87 @@
+#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_LIMS = 3.0; // Over-current limit = +/- 3A
+
+const int rtcGPREG_counter = 0; // RTC GPREG offset for the coulomb counter
+const int rtcGPREG_capacity = 1; // RTC GPREG offset for the capacity spec
+
+CoulombCounter::CoulombCounter(PinName _pin, int _mSec) : BatISense(_pin) {
+ mSec = _mSec;
+
+ // Default capacity if blank or corrupted
+ float capReg = store.read(rtcGPREG_capacity);
+ if (capReg < 1.0 || capReg > 5.0) { // Bad, write default
+ store.write(defaultAh, rtcGPREG_capacity);
+ }
+ capReg = store.read(rtcGPREG_capacity);
+
+ // Default SOC if blank or corrupted
+ float Ah = store.read(rtcGPREG_counter);
+ if (Ah < 0 || Ah > capReg) { // Bad, write default
+ store.write(defaultSOC*capReg, rtcGPREG_counter);
+ }
+
+ // 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;
+ }
+ current(); // 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;
+
+ // Integrate
+ float f = ampHours()-currentSample*mSec*MSEC_HRS;
+
+ // Bound to valid range
+ float cap = capacity();
+ if (f > cap) f = cap;
+ if (f < 0) f = 0;
+
+ // Write
+ store.write(f, rtcGPREG_counter);
+
+ // Add to filter
+ buffArr[tracker] = currentSample;
+ tracker++;
+ if (tracker >= CC_FILTER_TAPS) tracker = 0;
+}
+void CoulombCounter::resetToSOC(float SOC) {
+ store.write(SOC*capacity(), rtcGPREG_counter);
+}
+void CoulombCounter::resetToAh(float Ah) {
+ store.write(Ah, rtcGPREG_counter);
+}
+void CoulombCounter::changeCapacity(float capAh) {
+ store.write(capAh, rtcGPREG_capacity);
+}
+float CoulombCounter::current() {
+ 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;
+}
+float CoulombCounter::ampHours() {
+ return store.read(rtcGPREG_counter);
+}
+float CoulombCounter::capacity() {
+ return store.read(rtcGPREG_capacity);
+}
+float CoulombCounter::SOC() {
+ return ampHours()/capacity();
+}
+bool CoulombCounter::overCurrentDetected() {
+ return overCurrent;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,45 @@
+#ifndef _FILE_CURRENTMONITOR_H
+#define _FILE_CURRENTMONITOR_H
+
+#include "mbed.h"
+#include "CANBuffer.h"
+#include "RTCStore.h"
+
+const float defaultAh = 1.5; // Default amphours of battery, in case RTC read is bad/empty
+const float defaultSOC = 0.5;
+const int CC_FILTER_TAPS = 10;
+
+class CoulombCounter {
+public:
+
+ // Configures for a certain pin, millisecond sample period, and which GPREG in RTC to use to store the ampHours
+ CoulombCounter(PinName _pin, int _mSec);
+
+ // Allow zeroing the SOC when the battery is fully charged/dead, SOC in % from 0 to 1
+ void resetToSOC(float SOC);
+
+ // Allow zeroing the SOC (via zeroing the Ah) when the battery is fully charged/dead
+ void resetToAh(float Ah);
+
+ // Allow change of capacity spec (changes SOC)
+ void changeCapacity(float capAh);
+
+ bool overCurrentDetected(); // Sensor above range
+ float current(); // Last current reading in Amps
+ float ampHours();
+ float capacity();
+ float SOC();
+ void sample();
+
+private:
+ //Ticker sampler; // Used to capture next sample and coulomb count
+ RTCStore store;
+ volatile bool overCurrent;
+ int mSec;
+ volatile float currentSample;
+ AnalogIn BatISense; // Analog input pin
+
+ volatile float buffArr[CC_FILTER_TAPS];
+ volatile unsigned int tracker;
+};
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/RTCStore.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,38 @@
+/* Test Code
+ #include "Battery_Status.h"
+ #include"mbed.h"
+ BatteryStatus battery;
+
+ int main()
+ {
+ //battery.write(6.92,0);
+ printf("LPC_RTC->GPREG0:%f\n\r",battery.read(0));
+ //battery.write(7.92,1);
+ printf("LPC_RTC->GPREG1:%f\n\r",battery.read(1));
+ //battery.write(8.92,2);
+ printf("LPC_RTC->GPREG2:%f\n\r",battery.read(2));
+ //battery.write(9.92,3);
+ printf("LPC_RTC->GPREG3:%f\n\r",battery.read(3));
+ //battery.write(10.92,4);
+ printf("LPC_RTC->GPREG4:%f\n\r",battery.read(4));
+ }
+*/
+
+#ifndef _RTC_STORE_H
+#define _RTC_STORE_H
+#include "mbed.h"
+
+class RTCStore {
+public:
+ RTCStore() {
+ LPC_SC->PCONP |= (1<<9); // Enable RTC Peripheral
+ }
+ void write(float data, int block) {
+ *((float*)(&LPC_RTC->GPREG0)+block) = data;
+ }
+ float read(int block) {
+ return *((float*)(&LPC_RTC->GPREG0)+block);
+ }
+};
+#endif
+
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/DC_DC.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,181 @@
+#include "DC_DC.h"
+#include <math.h>
+
+#define OFF 1
+#define ON 0
+
+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
+
+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) {
+
+ currentOffset = CURRENT_OFFSET_DEFAULT;
+ starting = false;
+ stopping = false;
+ buffTracker = 0;
+ wait_ms(10); // Make sure Hall effect IC is ready
+ startTimer.reset();
+ stopTimer.reset();
+ status=0;
+
+ // Fill up the buffer
+ for (int i = 0; i < DC_DC_FILTER_TAPS; i++) {
+ filterBuff[i] = (dcdcCurrent - currentOffset) * CURRENT_MULTIPLIER_DEFAULT;
+ }
+ updateCurrent();
+ sample();
+ if (!critError) zeroCurrent();
+}
+
+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() {
+ float avg=0;
+ for (int i = 0; i < DC_DC_FILTER_TAPS; i++) {
+ avg += filterBuff[i];
+ }
+ avg /= DC_DC_FILTER_TAPS;
+ current = avg;
+}
+
+void DC_DC::set(bool on) {
+ // Do nothing if already on
+ if (on && dcdcControl == ON) return;
+
+ // Do nothing if error present
+ if (critError) return;
+
+ // If start requested
+ if (on) {
+ dcdcControl = ON;
+ starting = true;
+ startTimer.reset();
+ startTimer.start();
+ stopTimer.stop();
+ stopTimer.reset();
+ stopping = false;
+ // If stop requested
+ } else {
+ stopping=true;
+ fan1.directOff();
+ fan2.directOff();
+ pump1.directOff();
+ pump2.directOff();
+ dcdcControl = OFF;
+ stopTimer.reset();
+ stopTimer.start();
+ startTimer.stop();
+ startTimer.reset();
+ starting = false;
+ }
+}
+
+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
+ buffTracker++;
+ if (buffTracker >= DC_DC_FILTER_TAPS) buffTracker = 0;
+ 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
+
+ // 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 (stat & ConvOn) { // Positive current detected
+ startTimer.stop(); // Stop timer
+ startTimer.reset(); // Reset to zero
+ starting = false; // Indicate running
+ } else {
+ startTimer.stop();
+ startTimer.reset();
+ stat |= FailStart; // Failed to start
+ }
+ }
+ }
+
+ // 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
+ 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();
+ }
+ }
+ }
+
+ 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
+ }
+
+ // Process critical error conditions
+ if (stat & 0xF0) critError = true;
+ else critError = false;
+ status = stat;
+
+ // Arrest error, all channels off, DC-DC off
+ if (critError) {
+ fan1.directOff();
+ fan2.directOff();
+ pump1.directOff();
+ pump2.directOff();
+ dcdcControl = OFF;
+ startTimer.stop();
+ startTimer.reset();
+ starting = false;
+ }
+}
+
+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;
+
+ 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);
+ }
+}
+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();
+ if (chan == PUMP2) return pump2.readRaw();
+ else return 0;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/DC_DC.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,71 @@
+#ifndef _FILE_DC_DC_H
+#define _FILE_DC_DC_H
+
+#include "mbed.h"
+#include "FanPump.h"
+
+enum Channel_T {
+ FAN1=0,
+ FAN2,
+ PUMP1,
+ PUMP2,
+};
+enum Status_Bits_T {
+ ConvOn=1,
+ SetOn=2,
+ PowerUp=4,
+ PowerDown=8,
+ OverCurrent=16,
+ SensorFault=32,
+ FailStart=64,
+ FailStop=128,
+};
+const int DC_DC_FILTER_TAPS = 10;
+
+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);
+ /*
+ char status =
+ bit0 - 1 = DC-DC converter is actually on
+ bit1 - 1 = DC-DC converter is set to on
+ bit2 - 1 = DC-DC Startup, its use is currently blocked until ready
+ bit3 - 1 = DC-DC Power-down, its use is currently blocked until ready
+ bit4 - 1 = DC-DC over current (drawing more current than allowed according to sensor)
+ bit5 - 1 = DC-DC current sensor out of range (broken)
+ bit6 - 1 = DC-DC failed to start
+ bit7 - 1 = DC-DC failed to stop
+ */
+ char getStatus() { return status; }
+ bool hasCritError() { return critError; } // An error exists according to status above
+ void sample(); // Attach this function in a 10ms RTOS timer
+
+private:
+ Timer startTimer;
+ Timer stopTimer;
+ volatile bool starting;
+ volatile bool stopping;
+
+ DigitalOut dcdcControl;
+ AnalogIn dcdcCurrent;
+ volatile float currentOffset;
+ volatile float filterBuff[DC_DC_FILTER_TAPS];
+ volatile int buffTracker;
+ void updateCurrent();
+
+ volatile float current;
+ volatile char status;
+ volatile bool critError;
+
+ FanPump fan1;
+ FanPump fan2;
+ FanPump pump1;
+ FanPump pump2;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/FanPump/FanPump.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,87 @@
+#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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/FanPump/FanPump.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/IMD/IMD.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,201 @@
+#include "IMD.h"
+#include <math.h>
+
+static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects)
+
+const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz
+const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK
+const float EXTRA = 0.01; // Margin on the IMD PWM limits
+
+// Interrupt functions, must be static context
+void tim0_IRQ() {
+ if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ(); // Capture pin interrupt
+ if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ(); // MR0 interrupt
+ LPC_TIM0->IR=0x3F; // Clear interrupt flags
+}
+void tim1_IRQ() {
+ if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ();
+ if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ();
+ LPC_TIM1->IR=0x3F; // Clear interrupt flags
+}
+void tim2_IRQ() {
+ if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ();
+ if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ();
+ LPC_TIM2->IR=0x3F; // Clear interrupt flags
+}
+void tim3_IRQ() {
+ if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ();
+ if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ();
+ 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) {
+ // Setup the timer/pin access variables
+ if (cmpPin(_pin, p1_26)) { // CAP0.0
+ timer=0;
+ pin=0;
+ timerBase=LPC_TIM0;
+ } else if (cmpPin(_pin, p1_27)) { // CAP0.1
+ timer=0;
+ pin=1;
+ timerBase=LPC_TIM0;
+ } else if (cmpPin(_pin, p1_18)) { // CAP1.0
+ timer=1;
+ pin=0;
+ timerBase=LPC_TIM1;
+ } else if (cmpPin(_pin, p1_19)) { // CAP1.1
+ timer=1;
+ pin=1;
+ timerBase=LPC_TIM1;
+ } else if (cmpPin(_pin, p0_4)) { // CAP2.0
+ timer=2;
+ pin=0;
+ timerBase=LPC_TIM2;
+ } else if (cmpPin(_pin, p0_5)) { // CAP2.1
+ timer=2;
+ pin=1;
+ timerBase=LPC_TIM2;
+ } else if (cmpPin(_pin, p0_23)) { // CAP3.0
+ timer=3;
+ pin=0;
+ timerBase=LPC_TIM3;
+ } else if (cmpPin(_pin, p0_24)) { // CAP3.1
+ timer=3;
+ pin=1;
+ timerBase=LPC_TIM3;
+ } else { // Invalid pin
+ timerBase=0;
+ pin=0;
+ timer=0;
+ return;
+ }
+
+ instance[timer] = this;
+ first = true;
+
+ startTime = 0;
+ widthTicks = 0; // Zero low, so that duty = 0/1 = 0%
+ periodTicks = 1;
+
+ // Enable power and set pclk at 24Mhz
+ if (timer==0) {
+ LPC_SC->PCONP |= (1<<1);
+ LPC_SC->PCLKSEL0 &= ~(3<<2);
+ } if (timer==1) {
+ LPC_SC->PCONP |= (1<<2);
+ LPC_SC->PCLKSEL0 &= ~(3<<4);
+ } if (timer==2) {
+ LPC_SC->PCONP |= (1<<22);
+ LPC_SC->PCLKSEL1 &= ~(3<<12);
+ } if (timer==3) {
+ LPC_SC->PCONP |= (1<<23);
+ 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
+
+ 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
+ timerBase->PR=0; // No prescale value, clock at full pclk=24Mhz
+ timerBase->EMR=0; // Do not use external match pins
+
+ if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Set irq handler for timer0
+ if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ); // Set irq handler for timer1
+ if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ); // Set irq handler for timer2
+ if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ); // Set irq handler for timer3
+
+ NVIC_EnableIRQ((IRQn_Type)(timer+1));
+ NVIC_SetPriority((IRQn_Type)(timer+1), 0); // Highest priority (default)
+
+ timerBase->CCR = pin?5<<3:5; // Generate interrupt on rising edge of capture pin
+ timerBase->MCR = 1; // Interrupt on MR0 to establish the zero speed timeout
+ zeroIRQ(); // Zero the values
+ timerBase->TCR = 1; // Start counting, GO!
+}
+
+void IMD::edgeIRQ() {
+ bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
+ 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
+ // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1)
+ if (first) {
+ first = false;
+ startTime = capTime - 1;
+ }
+ if (rising) {
+ periodTicks = capTime - startTime; // Get the period on Rising edge
+ startTime = capTime; // Set the start of the next pulse
+ } else {
+ widthTicks = capTime - startTime; // Get the pulse width on Falling edge
+ }
+
+ // Switch interrupt types to capture the next edge
+ if (rising) timerBase->CCR = pin?6<<3:6;
+ else timerBase->CCR = pin?5<<3:5;
+}
+
+void IMD::zeroIRQ() {
+ periodTicks = 1;
+ first = true; // Reset the first edge detection case
+
+ bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
+ // Timeout occurred after FALLING edge, RISING edge never happened
+ if (rising) {
+ widthTicks = 0; // Signal is low = 0/1 = 0% duty
+ } else {
+ widthTicks = 1; // Signal is high = 1/1 = 100% duty
+ }
+}
+float IMD::frequency() {
+ // Handle the case where we want to say 0Hz not infinity Hz
+ if (periodTicks == 1 || periodTicks == 0) return 0;
+ else return (float)(PCLK)/(float)(periodTicks);
+}
+float IMD::duty() {
+ return (float)(widthTicks)/(float)(periodTicks);
+}
+
+char IMD::status() {
+ float freq = frequency();
+ if (freq == 0) return OFF; // IMD off
+ else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode
+ else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode
+ else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode
+ else if (35 < freq && freq <= 45) return ERROR; // 40Hz IMD error
+ else if (45 < freq && freq <= 55) return GROUNDERR; // 50Hz Ground error
+ else return INVALID; // Invalid
+}
+
+float IMD::resistance() {
+ char stat = status();
+ float dut = duty();
+
+ // In normal or undervoltage mode, where Rf is available
+ if (stat == NORMAL || stat == UNDERVOLT) {
+ if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) {
+ if (dut > 0.95) dut = 0.95; // Ceiling
+ if (dut < 0.05) dut = 0.05; // Floor so it doesnt mess up the equation below
+ float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
+ if (rf < 1000) rf = 0; // Floor to hit 0
+ if (rf > 50e6) rf = 50e6; // Ceil to stay at 50e6
+ return rf;
+ }
+ else return NAN;
+ }
+ // In speed start, where only good/bad estimate is available
+ if (stat == SPEEDSTART) {
+ if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA) return 50e6; // Good
+ else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA) return 0; // Bad
+ else return NAN;
+ }
+ return NAN; // Measurement not available in this mode
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/IMD/IMD.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,52 @@
+// copied idea from http://developer.mbed.org/forum/mbed/topic/466/?page=1#comment-2457
+
+#ifndef _FILE_IMD_H
+#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
+
+enum IMDstatus {
+ OFF=0,
+ NORMAL=1,
+ UNDERVOLT=2,
+ SPEEDSTART=3,
+ ERROR=4,
+ GROUNDERR=5,
+ INVALID=6,
+};
+
+class IMD{
+public:
+ IMD(LPC_pin _pin);
+
+ char status();
+ // Gets the insulation resistance reading
+ // Returns 0 to 50,000,000 in normal/UV modes
+ // Returns 0 or 50,000,000 in speed start (good/bad only)
+ // Nan for invalid measurement (out of permissible range)
+ // Nan for not avail. in this mode
+ float resistance();
+
+ // Interrupt function for the edge type detected
+ void edgeIRQ();
+ // Used to zero (reset) the data on timeout
+ void zeroIRQ();
+
+private:
+ float frequency();
+ float duty();
+
+ volatile uint32_t startTime;
+ volatile uint32_t widthTicks;
+ volatile uint32_t periodTicks;
+ volatile bool first;
+
+ LPC_TIM_TypeDef *timerBase; // Base address of the active timer module
+ int pin; // Capture pin#, 0 or 1
+ int timer;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/LPCDigitalIn.lib Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/teams/Penn-Electric-Racing/code/LPCDigitalIn/#963ce3b85931
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/LatchMonitor/LatchMonitor.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,30 @@
+#include "LatchMonitor.h"
+
+LatchMonitor::LatchMonitor(LPC_pin _ok, LPC_pin _fault, unsigned int startupDelay_ms):okPin(_ok, PullDown), faultPin(_fault, PullDown) {
+
+ // Power-on reset detected
+ if (LPC_SC->RSID & 1) {
+ LPC_SC->RSID = 1; // Clear POR flag
+ started = false; // Use the blocking startup timer
+ startup.attach_us(this, &LatchMonitor::startupDelay, startupDelay_ms*1000);
+ } else {
+ started = true; // Not a power-cycle, do not use the timer
+ }
+}
+
+void LatchMonitor::startupDelay() {
+ started = true;
+}
+char LatchMonitor::update() {
+ char ret = 0;
+ ret |= (!okPin << 0); // Mirror the ok pin
+ ret |= (faultPin << 1); // Copy the fault pin
+
+ if (started) {
+ ret |= !okPin << 2; // Mirror the ok pin when started only
+ if (!okPin && !faultPin) { // If started && okFault but not caught in hardware
+ ret |= 1 << 3;
+ }
+ }
+ return ret;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/LatchMonitor/LatchMonitor.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,35 @@
+#ifndef __LATCH_MONITOR_H
+#define __LATCH_MONITOR_H
+
+#include "mbed.h"
+#include "LPCDigitalIn.h"
+
+enum LatchMon_Status_Bits {
+ okPinF=1,
+ faultPinF=2,
+ softwareF=4,
+ hardwareF=8,
+};
+
+class LatchMonitor {
+
+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);
+ /*
+ 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
+ bit1 = faultPinFault - equals 1 when the sys. mgmt. latch circuit is faulted with startup timer in hardware
+ bit2 = softwareFault - equals 1 when the LatchMonitor fault occurs with startup timer in software
+ bit3 = hardwareFault - the circuit is supposed to signal fault on the hardware pin but its not doing so!
+ */
+ char update();
+private:
+ Timeout startup;
+ void startupDelay();
+ bool started;
+ LPCDigitalIn okPin;
+ LPCDigitalIn faultPin;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL.lib Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/PollSwitch/PollSwitch.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,17 @@
+#include "PollSwitch.h"
+
+PollSwitch::PollSwitch(LPCDigitalIn *swArr, int numSw){
+ numSwitches = numSw;
+ sw = swArr;
+}
+
+char PollSwitch::poll(){
+ char i = 0;
+
+ // if a low signal is detected, previous switch is broken
+ for (i = 0; i < numSwitches; i++) {
+ if (!sw[i].read()) break;
+ }
+ if (i >= numSwitches) i = 0;
+ return i+1;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/PollSwitch/PollSwitch.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,17 @@
+#ifndef _FILE_POLLSWITCH_H
+#define _FILE_POLLSWITCH_H
+
+#include "LPCDigitalIn.h"
+
+class PollSwitch{
+ public:
+ PollSwitch(LPCDigitalIn *sw, int numSwitches);
+
+ // Returns new state, 0 means all Closed, 1=first sense line (fuse), 12=last (TSMS)
+ char poll();
+
+ private:
+ LPCDigitalIn *sw;
+ int numSwitches;
+};
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Temperature/Temperature.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,33 @@
+#include "Temperature.h"
+
+float NXFT15XH103_TABLE_IN[] = { 0.050512723, 0.056425741, 0.06305631, 0.07054559, 0.079189687, 0.088921283, 0.100071994, 0, 0.127018769, 0.143322197, 0.161706765, 0.182539034, 0.205908044, 0.232186732, 0.261393013, 0.293785311, 0.329354168, 0.368048534, 0.409646378, 0.453820525, 0.5, 0.547490837, 0.595469256, 0.642984648, 0.689103062, 0.732941648, 0.77373518, 0.810924767, 0.844154225, 0.873281379, 0.898354357, 0.919578592, 0.937262775, 0.951781202 };
+float NXFT15XH103_TABLE_OUT[] = { 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0, -5, -10, -15, -20, -25, -30, -35, -40 };
+
+LOOKUP_TABLE_T NXFT15XH103_TABLE = {
+ NXFT15XH103_TABLE_IN,
+ NXFT15XH103_TABLE_OUT,
+ sizeof(NXFT15XH103_TABLE)/sizeof(float)
+};
+
+Temperature::Temperature(LOOKUP_TABLE_T *_table, PinName _pin) : pin(_pin) {
+ table = _table;
+}
+float Temperature::convert(float reading) {
+ float in = reading;
+ if (in < table->input[0]) return INFINITY; // Out of range of the table
+ if (in > table->input[table->numEntries-1]) return -INFINITY; // Out of range of the table
+ int lowerIndex = 0;
+ int upperIndex = table->numEntries-1;
+ for (int i = 0; i < table->numEntries; i++) { // Converge on the entries that surround the input
+ if (in >= table->input[lowerIndex]) { lowerIndex = i; }
+ if (in <= table->input[upperIndex]) { upperIndex = table->numEntries-1 - i; }
+ }
+ // Interpolate and return
+ return table->output[lowerIndex] + (table->output[upperIndex] - table->output[lowerIndex]) * ((in - table->input[lowerIndex]) / (table->input[upperIndex] - table->input[lowerIndex]));
+}
+float Temperature::readRaw() {
+ return pin.read();
+}
+float Temperature::read() {
+ return convert(pin.read());
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Temperature/Temperature.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,30 @@
+#ifndef __TEMPERATURE_H
+#define __TEMPERATURE_H
+
+#include "mbed.h"
+
+typedef struct LOOKUP_TABLE_T {
+ float *input;
+ float *output;
+ int numEntries;
+} LOOKUP_TABLE_T;
+
+extern LOOKUP_TABLE_T NXFT15XH103_TABLE;
+
+class Temperature {
+public:
+ Temperature(LOOKUP_TABLE_T *_table, PinName _pin);
+ float readRaw();
+ float read();
+#ifdef MBED_OPERATORS
+ operator float() {
+ return read();
+ }
+#endif
+private:
+ float convert(float reading);
+ LOOKUP_TABLE_T *table;
+ AnalogIn pin;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/Watchdog.lib Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#cb296650f43e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Xbee/Xbee.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,57 @@
+#include "Xbee.h"
+
+Xbee::Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char _delim) : xbee(tx, rx, bufferSize) {
+ xbee.baud(baudrate);
+ charCounter = 0;
+ numMessagesIn = 0;
+ numMessagesOut = 0;
+ delim = _delim;
+
+ // Attach callback when a new message delimiter character arrives
+ xbee.autoDetectChar(delim);
+ xbee.attach(this, &Xbee::newMsg, MODSERIAL::RxAutoDetect);
+}
+bool Xbee::send(CANMessage& msg) {
+ if (!xbee.writeable()) return false; // Exit, txBuffer full
+
+ // Format as string
+ char str[100];
+
+ // Will it fit?
+ if (xbee.txBufferGetSize(0) - xbee.txBufferGetCount() > strlen(str)){
+ xbee.printf("%s\n", str);
+ numMessagesOut++;
+ return true;
+
+ // Don't send
+ } else {
+ return false;
+ }
+}
+bool Xbee::receive(CANMessage& msg) {
+ char str[100];
+ unsigned int i = 0;
+
+ if (charCounter == 0) return false; // No messages yet
+ else {
+ while (xbee.readable()) { // Build string until buffer is empty or delimiter char is found
+ char c = xbee.getc();
+ str[i] = c;
+ i++;
+ if (c == delim) {
+ charCounter--;
+ str[i-1] = '\0'; // Null terminator in place of delimiter char
+ break;
+ }
+ }
+ }
+
+ // Process string into CAN Message
+ int len = strlen(str);
+
+ numMessagesIn++;
+ return true;
+}
+void Xbee::newMsg(MODSERIAL_IRQ_INFO *q) {
+ charCounter++;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Xbee/Xbee.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#ifndef __XBEE_FILE_H
+#define __XBEE_FILE_H
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+class Xbee {
+public:
+ Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char delim='\n');
+ bool send(CANMessage& msg);
+ bool receive(CANMessage& msg);
+ unsigned int messagesProcessedOut() { return numMessagesOut; }
+ unsigned int messagesProcessedIn() { return numMessagesIn; }
+private:
+ MODSERIAL xbee;
+ volatile unsigned int numMessagesIn;
+ volatile unsigned int numMessagesOut;
+
+ // Interrupt function called on receipt of message delimitter char
+ void newMsg(MODSERIAL_IRQ_INFO *q);
+ char delim; // Delimitter char that ends each message
+ volatile unsigned int charCounter; // Number of messages received so far in the serial buffer
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/mbed-rtos.lib Thu Nov 13 10:53:10 2014 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/mbed_official/code/mbed-rtos/#a3452b867ec3
--- a/MODSERIAL.lib Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- a/PollSwitch/PollSwitch.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#include "PollSwitch.h"
-
-LPCDigitalIn sw[]={ LPCDigitalIn(p1_0, PullDown),
- LPCDigitalIn(p1_1, PullDown),
- LPCDigitalIn(p1_4, PullDown),
- LPCDigitalIn(p1_8, PullDown),
- LPCDigitalIn(p1_9, PullDown),
- LPCDigitalIn(p1_10, PullDown),
- LPCDigitalIn(p1_14, PullDown),
- LPCDigitalIn(p1_15, PullDown),
- LPCDigitalIn(p1_16, PullDown),
- LPCDigitalIn(p1_17, PullDown),
- LPCDigitalIn(p1_27, PullDown),
- LPCDigitalIn(p1_28, PullDown)
- };
-
-PollSwitch::PollSwitch(){
- switchState = 0;
-}
-
-uint16_t PollSwitch::poll(){
- int i = 0;
-
- // if a low signal is detected, previous switch is broken
- for(i = 1; i < sizeof(sw)/sizeof(sw[0]); i++){
- if(!sw[i].read())
- break;
- }
-
- // bit on: switch may be broken
- switchState = (1 << i);
- return (1 << i);
-}
\ No newline at end of file
--- a/PollSwitch/PollSwitch.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-#ifndef _FILE_POLLSWITCH_H
-#define _FILE_POLLSWITCH_H
-
-#include "LPCDigitalIn.h"
-
-class PollSwitch{
- public:
- PollSwitch();
-
- // Returns new state, updates last known
- uint16_t poll();
-
- // Stores the last known state
- uint16_t switchState;
-};
-#endif
\ No newline at end of file
--- a/SerialDiagnostics/SerialDiagnostics.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-#include "SerialDiagnostics.h"
-
-// Macros for working with the string
-// Add newlines, add it to the working buffer
-#define ADD_LINE len+=sprintf(buff+len,"%s\r\n",line);
-#define ADD_SPRINTF_LINE padCenter(line,max_charsPerLine-2,temp,' '); len+=sprintf(buff+len,"%s\r\n",line);
-
-// Print to a string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
-void padCenter(char *buff, int LineLen, char *str, char pad) {
- int len = strlen(str);
- int padL = (LineLen-len)/2; // -1 to save room for the null terminator
- for (int i=0; i<padL; i++) buff[i] = pad; // Fill in the left padding chars
- strcpy(buff+padL, str);
- for (int i = padL+len; i<LineLen; i++) buff[i] = pad; // Fill remaining with padding chars
- buff[LineLen-1] = '\0'; // Add null terminator
-}
-
-void SerialDiagnostics::thread_serialOut(void const* args){
-
- const int max_charsPerLine = 81; // Max chars per line
- const int max_lines = 30; // Max lines that the layout prints out
- pc.printf("\033[2J"); // Clear the screen to get rid of reset message
-
- char buff[max_charsPerLine*max_lines]; // Giant string to store the printout
- char line[max_charsPerLine]; // String buffer to work with one line at a time
- char temp[max_charsPerLine]; // String buffer to sprintf into
-
- while(1){
-
- int len = 0;
- len += sprintf(buff+len, "\033[0;0H"); // Home the cursor
- padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE // Generate a line full of 80 -'s
- padCenter(line, max_charsPerLine-2, " Penn Electric Racing - REV0 System Management Module Serial Dashboard ", '-'); ADD_LINE
- padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE // Generate a line full of 80 -'s
-
-
- // Polling Switches -----------------------------------------------------------------------------------------------//
-
- padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
- padCenter(line, max_charsPerLine-2, " Poll Switches ", '*'); ADD_LINE
-
- char binary_out[12];
- uint16_t poll = pollSwitch.poll();
-
- for(int i = 0; i < 10; i++){
- binary_out[i] = (poll & 0x1) ? '1' : '0';
- poll = poll >> 1;
- }
- binary_out[11] = '\0';
-
- sprintf(temp, "Switch Bits: %s", binary_out); ADD_SPRINTF_LINE
-
- // Reading IMD status and resistance -------------------------------------------------------------------------------//
-
- padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
- padCenter(line, max_charsPerLine-2, " IMD ", '*'); ADD_LINE
-
- char status = imd.status();
-
- switch(status){
- case OFF:
- sprintf(temp, "IMD Status: OFF"); ADD_SPRINTF_LINE break;
- case NORMAL:
- sprintf(temp, "IMD Status: NORMAL"); ADD_SPRINTF_LINE break;
- case UNDERVOLT:
- sprintf(temp, "IMD Status: UNDERVOLT"); ADD_SPRINTF_LINE break;
- case SPEEDSTART:
- sprintf(temp, "IMD Status: SPEEDSTART"); ADD_SPRINTF_LINE break;
- case ERROR:
- sprintf(temp, "IMD Status: ERROR"); ADD_SPRINTF_LINE break;
- case GROUNDERR:
- sprintf(temp, "IMD Status: GROUNDERR"); ADD_SPRINTF_LINE break;
- case INVALID:
- sprintf(temp, "IMD Status: INVALID"); ADD_SPRINTF_LINE break;
- default:
- sprintf(temp, "IMD Status: UNKNOWN STATUS ERROR"); ADD_SPRINTF_LINE break;
- }
-
- // Reading Coulomb Counter
- padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
- padCenter(line, max_charsPerLine-2, " CoulombCounter ", '*'); ADD_LINE
-
- sprintf(temp, "Current: %f ampHours: %f ", coulombCounter.current(), coulombCounter.ampHours()); ADD_SPRINTF_LINE
- sprintf(temp, "Capacity: %f SOC: %f ", coulombCounter.capacity(), coulombCounter.SOC()); ADD_SPRINTF_LINE
-
- // Reading DC_DC
- padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
- padCenter(line, max_charsPerLine-2, " DC-DC Converter ", '*'); ADD_LINE
-
- sprintf(temp, "DC Converter on: %d ", dc.is_on()); ADD_SPRINTF_LINE
-
- // Reading FanPump
- padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
- padCenter(line, max_charsPerLine-2, " ", '*'); ADD_LINE
-
- // Write it all at once to output tx buffer
- for (int i = 0; i < strlen(buff); i++) {
- pc.putc(buff[i]);
- }
-
- Thread::wait(100);
- }
-}
-
-/*
- Testing Notes
-
- Oct 25
- Tested PollSwitch:
-
- Wasn't able to access pins p1_x, but tried out pollswitch with pins p0_x
- Logic seems to work
-*/
\ No newline at end of file
--- a/SerialDiagnostics/SerialDiagnostics.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#ifndef _SERIAL_DIAGNOSTICS_H
-#define _SERIAL_DIAGNOSTICS_H
-
-#include "MODSERIAL.h"
-#include "rtos.h"
-#include "IOobjects.h"
-
-namespace SerialDiagnostics {
- void thread_serialOut(void const *args);
-
-}
-
-#endif
\ No newline at end of file
--- a/SysMngmt.cpp Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#include "mbed.h"
-#include "rtos.h"
-#include "IOobjects.h"
-#include "SerialDiagnostics.h"
-
-int main() {
- wdt.kick(); // Kick the watchdog timer
- pc.baud(921600);
- pc.printf("\r\n\r\nPCM Reset\r\n");
-
- // Did a watchdog reset occur since last power cycle?
- if (wdt.checkFlag()) {
- pc.printf("Watchdog Reset\r\n");
- }
-
- Thread serialThread(SerialDiagnostics::thread_serialOut, 0, osPriorityNormal, 6000);
-
- while(1) {
- wdt.kick();
- }
-}
--- a/SysMngmt.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#ifndef _SYSMNGMT_
-#define _SYSMNGMT_
-#include "mbed.h"
-
-#define MSEC_HRS 2.77778e-7
-#define DC_DC_ISENSE_OFFSET_V 0.5
-#define DC_DC_ISENSE_INCREMENT 0.133
-
-#define BAT_ISENSE_OFFSET_V 1.65
-#define BAT_ISENSE_INCREMENT 0.5297
-
-Serial pc(USBTX,USBRX);
-CAN CAN_SysM(p30,p29);
-
-//Temperature Input
-AnalogIn Coolant1(p17); //Brass ones
-AnalogIn Coolant2(p16); //Brass ones
-AnalogIn DC_DC(p18); //Murata
-AnalogIn ChargerFET(p15);//Murata
-AnalogIn BatISense(p19);
-AnalogIn DCSense(p20);
-
-typedef union convert{
- float FLOAT;
- char C_FLOAT[4];
- }ftc;
-
-// Call function at reccuring interval
-Ticker ReadIMD, PollSDSwitch, ReadTemperature, ReadBatteryState;
-
-double BATmA_Hr;
-float DCA_msec,BATA_msec;
-float Bat_I_Ratio,DC_I_Ratio;
-CANMessage RxBuffer[10]={};
-
-/*
-PwmOut Pump(p26);
-PwmOut Fan1(p25);
-PwmOut Fan2(p24);
-PwmOut Fan3(p23);
-*/
-#endif /* _SYSMNGMT_ */
\ No newline at end of file
--- a/Watchdog.lib Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#cb296650f43e
--- a/XBee/XBee_Lib.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
-Test Code
-//#include "XBee_Lib.h"
-#include "mbed.h"
-#include<sstream>
-#include <cstring>
-#include <string>
-Serial xbee(p28,p27);
-Serial pc(USBTX,USBRX);
-DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-DigitalOut reset(p5);
-DigitalIn CTS(p6, PullNone);
-DigitalIn in(p21, PullDown);
-
-int main()
-{
- //char a[]="Hello.....";
- //int i=0;
- //while(a[i]!='\0')
- xbee.baud(250000);
- char a[63];
- char b[100];
-
- a[0]='\x31';
- for(int j=1; j<=60; j++)
- {
- if(a[j-1]=='\x39')
- {
- a[j]='\x41';
- }
- else if(a[j-1]=='\x5A')
- {
- a[j]='\x61';
- }
- else
- a[j]=a[j-1]+1;
- }
- a[61]='\n';
- a[62]='\r';
- char data[8]="";
- data[0]='a';
- data[1]='b';
- data[2]='c';
- string stri;
-
- //pc.printf("%s",a);
- reset=0;
- wait_ms(1);
- reset=1;
- wait_ms(1);
-
-
- std::ostringstream ostr;
- ostr<<data;
- stri=ostr.str();
- std::strcpy (b, (ostr.str()).c_str());
- pc.printf("%s",b);
- while(1)
- {
- while(in.read())
- {
- pc.printf("Sending Data...\n\r");
- xbee.printf("%s",b);
-
- if(CTS.read()==1)
- {
- pc.printf("DI buffer full\n\r");
- led2=1;
- //break;
- while(CTS.read()){}
- pc.printf("DI buffer has place\n\r");
- led2=0;
- //i=0;
- }
-
- //wait_ms(1000);
- led1=!led1;
- //++i;
- }
- }
-}
-*/
-#ifndef XBEE_LIB_H
-#define XBEE_LIB_H
-
-#include"LPCDigitalOut.h"
-#include"mbed.h"
-#include<sstream>
-
-Serial Xbee_e1(p9,p10);
-Serial Xbee_e2(p13,p14);
-
-// Used for wireless communications with Xbee
-
-//Include the send function only in the main code.
-class XBee250x
-{
- public:
- XBee250x()
- {
- Xbee_e1.baud(250000);
- Xbee_e2.baud(250000);
- }
-
- void send(CANMessage Rxmsg)
- {
- Xbee_e1.printf("%c \t %d \t %s \n\r",Rxmsg.id, Rxmsg.len, Rxmsg.data);
- Xbee_e2.printf("%c \t %d \t %s \n\r",Rxmsg.id, Rxmsg.len, Rxmsg.data);
- }
-};
-#endif /*XBEE_LIB_H*/
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,33 @@
+#include "IOobjects.h"
+#include "runTime.h"
+#include "outDiagnostics.h"
+
+int main() {
+ wdt.kick(0.11); // Kick the watchdog timer, set the timeout to 110ms
+ pc.baud(921600);
+ pc.printf("\r\n\r\nSys Mgmt Reset\r\n");
+ can.mode(FIFO); // Use FIFO mode
+ NVIC_SetPriority(TIMER3_IRQn, 2); // Decrease timer3 priority (mbed timer, rtos)
+ NVIC_SetPriority(UART0_IRQn, 1); // Decrease serial priority to give CAN higher priority
+
+ // Did a watchdog reset occur since last power cycle?
+ if (wdt.checkFlag()) {
+ data.watchdogReset = true;
+ pc.printf("Watchdog Reset\r\n");
+ }
+
+ // Start the 10Hz data thread
+ Thread gather_10Hz(runTime::thread_gather_10Hz, 0, osPriorityHigh);
+
+ // Start the 100Hz data timer (more time critical than thread)
+ Thread gather_100Hz(runTime::thread_gather_100Hz, 0, osPriorityRealtime);
+
+ // Start the serial, CAN threads
+ Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityAboveNormal, 6000); // Allocate 6kB RAM stack
+ Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal, 256); // Allocate 256B RAM stack
+
+ // Background task
+ while(1) {
+ // Service CAN and Xbee logic
+ }
+}
\ No newline at end of file
--- a/mbed-rtos.lib Fri Nov 07 21:26:46 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed-rtos/#e2da1b20a6d5
--- a/mbed.bld Fri Nov 07 21:26:46 2014 +0000 +++ b/mbed.bld Thu Nov 13 10:53:10 2014 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1 \ No newline at end of file +http://mbed.org/users/mbed_official/code/mbed/builds/031413cf7a89 \ No newline at end of file
--- a/mbed_error.h Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef MBED_ERROR_H
-#define MBED_ERROR_H
-
-/** To generate a fatal compile-time error, you can use the pre-processor #error directive.
- *
- * @code
- * #error "That shouldn't have happened!"
- * @endcode
- *
- * If the compiler evaluates this line, it will report the error and stop the compile.
- *
- * For example, you could use this to check some user-defined compile-time variables:
- *
- * @code
- * #define NUM_PORTS 7
- * #if (NUM_PORTS > 4)
- * #error "NUM_PORTS must be less than 4"
- * #endif
- * @endcode
- *
- * Reporting Run-Time Errors:
- * To generate a fatal run-time error, you can use the mbed error() function.
- *
- * @code
- * error("That shouldn't have happened!");
- * @endcode
- *
- * If the mbed running the program executes this function, it will print the
- * message via the USB serial port, and then die with the blue lights of death!
- *
- * The message can use printf-style formatting, so you can report variables in the
- * message too. For example, you could use this to check a run-time condition:
- *
- * @code
- * if(x >= 5) {
- * error("expected x to be less than 5, but got %d", x);
- * }
- * #endcode
- */
-
-// for some reason, the rtos library can't access mbed_error.h from the mbed library
-// This is a pretty recent bug as of Oct 5, 2014
-// If they fix the bug, remove this file
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void error(const char* format, ...);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/outDiagnostics/outDiagnostics.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,101 @@
+#include "outDiagnostics.h"
+
+// Macros for working with the string
+#define ADD_LINE len+=sprintf(buff+len,"%s\r\n",line); // Add newlines, add it to the working buffer
+#define ADD_SPRINTF_LINE padCenter(line,max_charsPerLine-2,temp,' '); len+=sprintf(buff+len,"%s\r\n",line); // Add newlines, add it to the working buffer
+#define BOOL(VAR) (VAR)?"ERR":"OK"
+
+// Print to a string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
+void padCenter(char *buff, int LineLen, char *str, char pad) {
+ int len = strlen(str);
+ int padL = (LineLen-len)/2; // -1 to save room for the null terminator
+ for (int i=0; i<padL; i++) buff[i] = pad; // Fill in the left padding chars
+ strcpy(buff+padL, str);
+ for (int i = padL+len; i<LineLen; i++) buff[i] = pad; // Fill remaining with padding chars
+ buff[LineLen-1] = '\0'; // Add null terminator
+}
+
+// Generates the serial dashboard, uses MODDMA MODSERIAL to speed up printing
+void outDiagnostics::thread_serialOut(void const *args) {
+ const int max_charsPerLine = 81; // Max chars per line
+ const int max_lines = 35; // Max lines that the layout prints out
+ pc.printf("\033[2J"); // Clear the screen to get rid of reset message
+
+ char buff[max_charsPerLine*max_lines]; // Giant string to store the printout
+ char line[max_charsPerLine]; // String buffer to work with one line at a time
+ char temp[max_charsPerLine]; // String buffer to sprintf into
+ while(1) {
+
+ int len = 0;
+ len += sprintf(buff+len, "\033[0;0H"); // Home the cursor
+ padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE // Generate a line full of -'s
+ padCenter(line, max_charsPerLine-2, " Penn Electric Racing - REV0 System Management Controller Serial Dashboard ", '-'); ADD_LINE
+ padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE // Generate a line full of -'s
+
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " GLV Battery ", '*'); ADD_LINE
+ sprintf(temp, "Current: %4.3fA Capacity: %4.3fAh", data.glvCurrent, data.glvCapacity); ADD_SPRINTF_LINE
+ sprintf(temp, "Amphours: %4.3fAh SOC: %5.1f%% Overcurrent: %s", data.glvAmphours, data.glvSOC*100.0, BOOL(data.glvOverCurrent)); ADD_SPRINTF_LINE
+
+ char DCDC = data.dcdcStatus;
+ char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","ON","OFF"};
+ int dcdcMode = 0;
+ if (DCDC & PowerUp) dcdcMode = 1;
+ else if (DCDC & PowerDown) dcdcMode = 2;
+ else if (DCDC & SetOn) dcdcMode = 3;
+ else if (!(DCDC & SetOn)) dcdcMode = 4;
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " DC-DC Converter ", '*'); ADD_LINE
+ sprintf(temp, "Current: %5.3fA Overcurrent: %s SensorFault: %s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); ADD_SPRINTF_LINE
+ sprintf(temp, "Active: %s Mode: %s AIRS: %s StatusByte: 0x%x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC); ADD_SPRINTF_LINE
+ sprintf(temp, "StartFault: %s StopFault: %s CritErrors: %s", BOOL(DCDC & FailStart), BOOL(DCDC & FailStop), BOOL(data.dcdcError)); ADD_SPRINTF_LINE
+
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " PWM Channels ", '*'); ADD_LINE
+ sprintf(temp, "Actual: FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", data.dcdcFan1Duty*100.0, data.dcdcFan2Duty*100.0, data.dcdcPump1Duty*100.0, data.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE
+ sprintf(temp, "Requestd: FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", CANdata.dcdcFan1Duty*100.0, CANdata.dcdcFan2Duty*100.0, CANdata.dcdcPump1Duty*100.0, CANdata.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE
+
+ const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDFLT","INVALID"};
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " IMD ", '*'); ADD_LINE
+ sprintf(temp, "Status: %s Resistance: %7.0fkohm CritError: %s",IMDstr[data.imdStatus], data.imdResistance/1e3, BOOL(data.imdError)); ADD_SPRINTF_LINE
+
+ char AMSerr = data.AMSlatchError;
+ char IMDerr = data.IMDlatchError;
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " Latch Circuits ", '*'); ADD_LINE
+ sprintf(temp, "AMS: OK: %s Latch: %s SoftFault: %s HardFault: %s", (AMSerr & 1)?"LOW":"HIGH", (AMSerr & 2)?"OPEN":"OK", BOOL(AMSerr & 4), BOOL(AMSerr & 8)); ADD_SPRINTF_LINE
+ sprintf(temp, "IMD: OK: %s Latch: %s SoftFault: %s HardFault: %s", (IMDerr & 1)?"LOW":"HIGH", (IMDerr & 2)?"OPEN":"OK", BOOL(IMDerr & 4), BOOL(IMDerr & 8)); ADD_SPRINTF_LINE
+
+ char switches = data.switchState;
+ const char switchNames[12][26] = {"FUSE","AMS LATCH","IMD LATCH","PCM RELAY","BRAKE PLAUSIBILITY RELAY","LEFT E-STOP","INERTIA SWITCH","BRAKE OVER-TRAVEL SWITCH","COCKPIT E-STOP","RIGHT E-STOP","HVD","TSMS"};
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " Shutdown Switches ", '*'); ADD_LINE
+ if (switches == 0) sprintf(temp, "All switches are CLOSED.");
+ else sprintf(temp, "%s is OPEN.", switchNames[switches-1]);
+ ADD_SPRINTF_LINE
+
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " Telemetry ", '*'); ADD_LINE
+ sprintf(temp, "Channel 1: MessagesIn: %d MessagesOut: %d", data.xbee1MessagesIn, data.xbee1MessagesOut); ADD_SPRINTF_LINE
+ sprintf(temp, "Channel 2: MessagesIn: %d MessagesOut: %d", data.xbee2MessagesIn, data.xbee2MessagesOut); ADD_SPRINTF_LINE
+
+ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line
+ padCenter(line, max_charsPerLine-2, " Miscellaneous ", '*'); ADD_LINE
+ sprintf(temp, "Temp: %5.1fC OverTemp: %s canFault: %s WatchdogReset: %s ErrorFrame: 0x%x", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame); ADD_SPRINTF_LINE
+
+ // Write it all at once to output tx buffer
+ for (int i = 0; i < strlen(buff); i++) {
+ pc.putc(buff[i]);
+ }
+ Thread::wait(100);
+ }
+}
+
+void outDiagnostics::thread_canOut(void const *args) {
+ while(1) {
+ CANMessage msg;
+
+ Thread::wait(100);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/outDiagnostics/outDiagnostics.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,14 @@
+#ifndef _OUT_DIAGNOSTICS_H
+#define _OUT_DIAGNOSTICS_H
+
+#include "IOobjects.h"
+#include "rtos.h"
+
+namespace outDiagnostics {
+
+ void thread_canOut(void const *args);
+ void thread_serialOut(void const *args);
+
+}
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runTime/runTime.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,58 @@
+#include "runTime.h"
+
+const float INTERNAL_OVER_TEMP_THRES = 60; // Overtemp at 60C
+
+void runTime::thread_gather_10Hz(void const* args) {
+ while(1) {
+ wdt.kick();
+
+ // 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();
+
+ // Switches
+ data.switchState = switches.poll();
+
+ // Temperaure
+ data.internalTemp = internalTmp.read();
+ if (data.internalTemp > INTERNAL_OVER_TEMP_THRES) data.internalOverTemp = true;
+ else data.internalOverTemp = false;
+
+ // Xbees
+ data.xbee1MessagesIn = xbee1.messagesProcessedIn();
+ data.xbee2MessagesIn = xbee2.messagesProcessedIn();
+ data.xbee1MessagesOut = xbee1.messagesProcessedOut();
+ data.xbee2MessagesOut = xbee2.messagesProcessedOut();
+
+ 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(100);
+ }
+}
+void runTime::thread_gather_100Hz(void const* args) {
+ while(1) {
+ glvBat.sample(); // Integrate next sample in GLV Battery coulomb counter
+ dcdc.sample(); // Handle dc-dc filter and errors
+ Thread::wait(10);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runTime/runTime.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,12 @@
+#ifndef __RUNTIME_H
+#define __RUNTIME_H
+
+#include "IOobjects.h"
+
+
+namespace runTime {
+ void thread_gather_10Hz(void const* args);
+ void thread_gather_100Hz(void const* args);
+}
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/serviceCAN/serviceCAN.cpp Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#include "serviceCAN.h"
+
+// MACRO to setup handling of timeouts
+#define TIMEOUT(VAR) Timeout timer_##VAR; void timeout_##VAR(){ flags.VAR = false; }
+#define REFRESH_TIMEOUT(VAR) timer_##VAR.detach(); timer_##VAR.attach(&timeout_##VAR, DEVICE_CAN_TIMEOUT/100.0);
+#define CHECK_ERRORS(VAR, MSG) if (hasErrors(MSG)) { flags.VAR = false; } else { flags.VAR = true; }
+
+// Timeouts to handle cases where CAN messages stop coming in
+
+
+// Check every byte of the message for an error bit
+bool hasErrors(CANMessage& msg) {
+ bool errorPresent = false;
+ for (int i = 0; i < msg.len; i++) {
+ if (i >= 8) { errorPresent = true; break; } // out of bounds, bad CAN message
+ if (msg.data[i]) errorPresent = true;
+ }
+ return errorPresent;
+}
+
+bool canbus::serviceCAN() {
+ CANMessage msg;
+
+ return false;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/serviceCAN/serviceCAN.h Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,13 @@
+#ifndef _SERVICE_CAN_H
+#define _SERVICE_CAN_H
+
+#include "mbed.h"
+#include "IOobjects.h"
+
+const int DEVICE_CAN_TIMEOUT = 0.25; // Comms. lost to external device if a message is not received within 200 ms
+
+namespace canbus {
+ bool serviceCAN();
+}
+
+#endif
\ No newline at end of file
