Rivian Irvine Team
/
TCTF_Control_Main
Control Code with I/O and ADC working
main.cpp
- Committer:
- jrodenburg
- Date:
- 2018-07-18
- Revision:
- 21:f87464a7e7c6
- Parent:
- 20:cdeed4dad690
File content as of revision 21:f87464a7e7c6:
// MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF) // DATE: SEPTEMBER 2017 //CHANGE THE PYTHON CODE TO REFLECT ERROR STATE ENTERED #include "mbed.h" #include "MODSERIAL.h" #include "MCP23008.h" #include "LTC2487.h" #include <string> //DEFINITIVE VARIABLES #define DEBUG_LOOP_TIME 0x00000001 #define RXDATA_PRINT 0x00000002 #define UID_PRINT 0x00000004 #define ERROR_PRINT 0x00000008 #define ADC_VAL_PRINT 0x00000010 #define HEATER_CHILLER_PRINT 0x00000020 #define HEATER_ON_TIME_PRINT 0x00000040 #define LED_PRINT 0x00000080 #define TEMP_PRINT 0x00000100 #define I2C_PRINT 0x00000200 #define IO_I2C_LINE 1 #define ADC_I2C_LINE 2 #define CHAN_COUNT 8 #define ERROR_COUNT 6 #define MIN_TEMP 10 #define MAX_TEMP 65 #define TEMP_MARGIN 10 #define HYST_LOW 0.3 #define HYST_HIGH 1 #define VALVE_ON 1 #define HEATER_ON 2 #define GREEN_STATUS_ON 3 #define RED_STATUS_ON 4 #define ERROR_STATUS_ON 5 #define ALL_OFF 6 #define sizeLUT 34 #define BACK_THERM 0 #define FRONT_THERM 1 #define HEAT_FET_AMP 2 #define VALVE_FET_AMP 3 #define NUM_EMAIL_SEND 2 #define STATUS_COOLING 1 #define STATUS_HEATING 2 #define STATUS_INACTIVE 3 #define STATUS_STANDBY 4 #define MIN_AD_COUNT 10428 //65C #define MAX_AD_COUNT 49169 //10C #define MAX_TIME_TO_SP 60 //allow 60 minutes for channel to reach set point #define READ_TEMP_TASK_TIME .300f //300ms to read one A/D value #define I2C_READ_WAIT_TIME 0.08f // Defines for use with Serial communication #pragma pack (1) #define RX_SOF 0x7B #define RX_EOF 0x7D #define TX_SOF 0x7B #define TX_EOF 0x7D #define DELIMETER 0x2E #define SET_TEMPERATURE 0xB0 #define SELECT_CHANNEL 0xB1 #define READ_UID 0xB2 #define READ_FW_VERSION 0xB3 #define DEBUG_CONTROL 0xB4 #define RESPONSE_DATA 0xD0 #define TEMP_DATA 0xD1 #define UID_DATA 0xD2 #define FW_VERSION_DATA 0xD3 #define ERROR_DATA 0xDF // Defines for errors #define ERR_OVER_TEMP 0 #define ERR_UNDER_TEMP 1 #define ERR_TEMP_DIFF 2 #define ERR_ACK_LTC 3 #define ERR_ACK_MCP 4 #define ERR_SP_TIME 5 #define MAX_ERROR_CNT 8 #define PRINT_ERROR_CHECK_VALS 0 #define PRINT_ERRORS 0 const char FW_Version[8] = "V0.01D"; unsigned int chanSel_SendTemp = 0; unsigned int chanSel_SetTemp = 0; // Default to chan 0 int currChan = 0; bool newTempSet = false; bool readFrontThermistor = true; bool newTempData = false; bool newTempDataAvailable = false; unsigned int UID_print_count = 0; unsigned int debug_control = 0x80; //*********************************************** // Timers //*********************************************** Ticker frontTempDoneTicker; Ticker backTempDoneTicker; Ticker readThermistorTicker; Ticker frontTempInProgTicker; Ticker backTempInProgTicker; Ticker setPointTimeTicker; //*********************************************** // LEDs //*********************************************** DigitalOut rLed(LED1); DigitalOut gLed(LED2); //*********************************************** // Functions Declarations //*********************************************** void sendUID (); void sendFWVersion(); void read_front_temp(); void read_back_temp(); void update_front_temp_data(); void update_back_temp_data(); void temperatureDataReady(); //*********************************************** // Serial Rx Packet Format //*********************************************** typedef struct { unsigned char SOF_flag; unsigned char cmd_type; unsigned char len; unsigned char Delim; } HOST_CMD_HEADER; typedef struct { HOST_CMD_HEADER cmd_header; unsigned char chanID; unsigned char tempDelim; float setTemp; unsigned char chanStatDelim; unsigned char chanStat; } SET_TEMPERATURE_CMD; typedef struct { HOST_CMD_HEADER cmd_header; unsigned char chanIDSel; unsigned char chanDelim; unsigned char chanStat; } SELECT_CHANNEL_CMD; typedef struct { unsigned char SOF_flag; unsigned char cmd_type; unsigned char len; unsigned char Delim; uint32_t channel; float data; unsigned char EOF_flag; } RESPONSE_CMD; typedef struct { unsigned char SOF_flag; unsigned char cmd_type; unsigned char len; unsigned char Delim; float chTemp[CHAN_COUNT]; unsigned char EOF_flag; } RESPONSE_TEMP_CMD; typedef struct { HOST_CMD_HEADER cmd_header; unsigned char chanIDSel; unsigned char chanDelim; unsigned char chanStat; } READ_UID_CMD; typedef struct { HOST_CMD_HEADER cmd_header; unsigned char chanIDSel; unsigned char chanDelim; uint32_t commandData; } GUI_STANDARD_CMD; typedef struct { unsigned char SOF_flag; unsigned char cmd_type; unsigned char len; unsigned char Delim; unsigned char FW_Version[8]; unsigned char EOF_flag; } FW_VERSION_RESPONSE; typedef struct { unsigned char SOF_flag; unsigned char cmd_type; unsigned char len; unsigned char Delim; uint32_t UIDMH; uint32_t UIDML; uint32_t UIDL; unsigned char EOF_flag; } UID_RESPONSE; //TCTF CHANNEL DATA struct CHNL_DATA{ bool status; float setTemp; bool error; int state; int LTCi2cAckRxed; int MCPi2cAckRxed; bool SPReached; int SPTime; }; CHNL_DATA chnlStatus[] = { {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0}, {0, NULL, false, 0, 0, 0, false, 0} }; //I2C AADRESS LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP) struct I2C_ADDR_LUT{ int adc; int io; }; I2C_ADDR_LUT addrLUT[] = { {0x23, 0x10}, {0x53, 0x60}, {0x43, 0x70}, {0x73, 0x40}, {0x63, 0x50}, {0x22, 0x11}, {0x52, 0x61}, {0x42, 0x71} }; //THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP) struct THERM_LUT{ int adc; int temp; }; THERM_LUT thermLUT[] = { {113779,-40}, {109152,-35}, {103830,-30}, {97855,-25}, {91319,-20}, {84352,-15}, {77124,-10}, {69820,-5}, {62621,0}, {55693,5}, {49169,10}, {43144,15}, {37669,20}, {32768,25}, {28429,30}, {24622,35}, {21309,40}, {18439,45}, {15962,50}, {13831,55}, {12002,60}, {10428,65}, {9080,70}, {7919,75}, {6923,80}, {6063,85}, {5323,90}, {4685,95}, {4130,100}, {3653,105}, {3234,110}, {2876,115}, {2563,120}, {2284,125} }; //TCTF CHANNEL TEMPERATURE typedef struct{ float currADCFront; float currADCBack; float currTempFront; float currTempBack; }CHNL_TEMP; CHNL_TEMP channelTempData[CHAN_COUNT]; //SERIAL COMMUNICATION SETUP MODSERIAL pc(USBTX, USBRX); //DEFINE PINS DigitalOut myled(LED2); //I2C FOR MCP23008 (I/O Control) MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl //I2C FOR LTC2487 (ADC Control) LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl //GLOBAL VARIABLES volatile bool dataReceived = false; //used to check if data has been received volatile bool dataTxReady = false; char rxBuf[50]; int chnlSel; bool standbyLED[CHAN_COUNT] = {false,false,false,false,false,false,false,false}; int errorCount[CHAN_COUNT][ERROR_COUNT] = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0} }; int errorEmailSent[CHAN_COUNT][ERROR_COUNT] = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0} }; void resetErrorCount(){ for(int i = 0; i < CHAN_COUNT; i++){ for(int i = 0; i < ERROR_COUNT; i++){ errorCount[CHAN_COUNT][ERROR_COUNT] = 0; errorEmailSent[CHAN_COUNT][ERROR_COUNT] = 0; } } } /* Function: turnOffChannel ************************************************************** Description: Turns off a channel Recieves: chnl: channel to turn off Returns: N/A */ void turnOffChannel(int chnl){ io_control.setAddress(addrLUT[chnl].io); io_control.init(); io_control.writeOutput(0,0,0,0); } /* Function: rxInterrupt ************************************************************** Description: serial rx interupt handler Receives: N/A Returns: N/A */ //*********************************************** // Rx Interrupt from serial Host interface //*********************************************** void rxInterrupt(MODSERIAL_IRQ_INFO *info) { gLed = 0; dataReceived = true; //wait(.5); gLed = 1; } //*************************************************************** // Tx Interrupt from serial Host interface //*************************************************************** void txInterrupt(MODSERIAL_IRQ_INFO *info) { gLed = 1; dataTxReady = true; gLed = 1; } /* Function: parseRXData ************************************************************** Description: The parse received data into Receives: chn: The channel we want to put into the channel Returns: N/A */ void processRxUARTData() { HOST_CMD_HEADER *pRxPktHdr; string data = ""; pRxPktHdr = (HOST_CMD_HEADER *)rxBuf; if (debug_control & RXDATA_PRINT) { pc.printf("DBG: SOF=%02x, Len=%02x, CMD=%02x\r\n", pRxPktHdr->SOF_flag, pRxPktHdr->len, pRxPktHdr->cmd_type); pc.printf("DBG: "); for (int i=0; i <5; i++) pc.printf("%02x ", rxBuf[i]); pc.printf("\n"); } // Exit if the packet does not contain correct header // Maybe send NAK? if ((pRxPktHdr->SOF_flag != RX_SOF) || (pRxPktHdr->Delim != DELIMETER)) return; switch (pRxPktHdr->cmd_type) { case SET_TEMPERATURE: // Process set temp for specified channel { SET_TEMPERATURE_CMD *pRxPkt = (SET_TEMPERATURE_CMD *)(rxBuf); if (debug_control & RXDATA_PRINT) pc.printf("DBG: SETTEMP: ch = %02x, tempSet = %f, chanStat = %02x\r\n", pRxPkt->chanID, pRxPkt->setTemp, pRxPkt->chanStat); if ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) { // Send NAK back pc.printf("DBG: Error\n"); } else { if((pRxPkt->setTemp < MAX_TEMP) && (pRxPkt->setTemp > MIN_TEMP)){ chanSel_SetTemp = pRxPkt->chanID; chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat; chnlStatus[pRxPkt->chanID].state = STATUS_INACTIVE; chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp; chnlStatus[pRxPkt->chanID].error = false; chnlStatus[pRxPkt->chanID].LTCi2cAckRxed = 0; chnlStatus[pRxPkt->chanID].MCPi2cAckRxed = 0; chnlStatus[pRxPkt->chanID].SPReached = false; chnlStatus[pRxPkt->chanID].SPTime = 0; memset(errorCount[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT); memset(errorEmailSent[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT); newTempSet = true; } } } break; case SELECT_CHANNEL: // Select channel to send temp data to { SELECT_CHANNEL_CMD *pRxPkt = (SELECT_CHANNEL_CMD *)(rxBuf); chanSel_SendTemp = pRxPkt->chanIDSel; // Send back FW version for each select channel sendFWVersion(); if (debug_control & RXDATA_PRINT) pc.printf("DBG: CHAN_SEL: chan=%02x, chanStat = %02x\r\n", pRxPkt->chanIDSel, pRxPkt->chanStat); } break; case READ_UID: { READ_UID_CMD *pRxPkt = (READ_UID_CMD *)(rxBuf); if (debug_control & RXDATA_PRINT) pc.printf("DBG: Read UID: chan%02x\n", pRxPkt->chanIDSel); sendUID(); } break; case READ_FW_VERSION: { sendFWVersion(); if (debug_control & RXDATA_PRINT) pc.printf("DBG: Read SW Version\r\n"); } break; case DEBUG_CONTROL: { GUI_STANDARD_CMD *pRxPkt = (GUI_STANDARD_CMD *)rxBuf; debug_control = pRxPkt->commandData; if (debug_control & RXDATA_PRINT) pc.printf ("DBG: Rx'd DEBUG CMD: %04x\r\n", pRxPkt->commandData); } break; default: // Error break; } } /* Function: get_temp ************************************************************** Description: Convert A/D count to temperature value Receives: ADC_val: the count from the A/D reading Returns: the temp. of the A/D reading */ float get_temp(float ADC_val){ myled = 1; //ltc2487.setAddress(addrLUT[chn].adc); //float ADC_val = ltc2487.readOutput(port); //(65536*1.334)/2.5 int i = 0; while((i < sizeLUT) && (thermLUT[i].adc > ADC_val)){ i++; } //find the temp. above therm temp //Point slope formula extrapolation: // m = (y1-y0)/(x1-x0)+ y0 , y = temp. value, x = adc value // y1 = thermLUT[i-1].temp y0 = thermLUT[i].temp // x1 = thermLUT[i-1].adc x0 =thermLUT[i].adc float a = float(thermLUT[i-1].temp - thermLUT[i].temp); //slope of temp between points where therm temp is between (Tmax - Tmin) float b = float(thermLUT[i-1].adc - thermLUT[i].adc); //slope of adc between points where therm adc is between (Amax - Amin) float m = a/b; float y = (m*(ADC_val-thermLUT[i].adc))+thermLUT[i].temp; if (debug_control & ADC_VAL_PRINT) pc.printf("DBG: ADC VAL: %f TEMP: %f \r\n", ADC_val, y); return y; } /* Function: get_front_temp_DATA ************************************************************** Description: Read A/D data from LTC2487 and set array with front temp. Save values in CHNL_TEMP data struct Receives: N/A Returns: int If the write recieved an ACK */ void read_front_temp_data() { readThermistorTicker.detach(); //Write to all 8 channels selecting the front port to read for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ chnlStatus[chnl].LTCi2cAckRxed = 0; ltc2487.setAddress(addrLUT[chnl].adc); //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(FRONT_THERM); } //wait until next clock cycle on LTC //wait(I2C_READ_WAIT_TIME); frontTempInProgTicker.attach(&update_front_temp_data, I2C_READ_WAIT_TIME); } void update_front_temp_data(){ float countVal; frontTempInProgTicker.detach(); for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ ltc2487.setAddress(addrLUT[chnl].adc); countVal = ltc2487.read(); channelTempData[chnl].currADCFront = countVal; channelTempData[chnl].currTempFront = get_temp(countVal); } //wait until next clock cycle on LTC //wait(0.08); frontTempDoneTicker.attach(&read_back_temp, I2C_READ_WAIT_TIME); } /* Function: get_back_temp_DATA ************************************************************** Description: Read A/D data from LTC2487 and set array with back temp. Save values in CHNL_TEMP data struct Receives: N/A Returns: N/A */ void read_back_temp() { frontTempDoneTicker.detach(); //Write to all 8 channels selecting the front port to read for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ chnlStatus[chnl].LTCi2cAckRxed = 0; ltc2487.setAddress(addrLUT[chnl].adc); //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(BACK_THERM); } //wait until next clock cycle on LTC //wait(I2C_READ_WAIT_TIME); backTempInProgTicker.attach(&update_back_temp_data, I2C_READ_WAIT_TIME); } void update_back_temp_data(){ float countVal; backTempInProgTicker.detach(); for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ ltc2487.setAddress(addrLUT[chnl].adc); countVal = ltc2487.read(); channelTempData[chnl].currADCBack = countVal; channelTempData[chnl].currTempBack = get_temp(countVal); } //wait until next clock cycle on LTC //wait(0.08); backTempDoneTicker.attach(&temperatureDataReady, I2C_READ_WAIT_TIME); } /* Function: temperatureDataReady ************************************************************** Description: Flag that temperature data is ready to be processed Restart task timer Receives: N/A Returns: N/A */ void temperatureDataReady() { backTempDoneTicker.detach(); newTempDataAvailable = true; readThermistorTicker.attach(&read_front_temp_data, READ_TEMP_TASK_TIME); } /* Function: get_heater_current ************************************************************** Description: Retrieve current into heater control MOSFET Receives: chn: the channel of the fixture to read current from Returns: the current into the heater control MOSFET */ void get_heater_current(int chn, int port){ ltc2487.setAddress(addrLUT[chn].adc); ltc2487.writePort(HEAT_FET_AMP); wait(0.08); ltc2487.read(); wait(0.08); } /* Function: get_valve_current ************************************************************** Description: Retrieve current into valve control MOSFET Receives: chn: the channel of the fixture to read current from Returns: the current into the valve control MOSFET */ void get_valve_current(int chn, int port){ ltc2487.setAddress(addrLUT[chn].adc); ltc2487.writePort(VALVE_FET_AMP); wait(0.08); ltc2487.read(); wait(0.08); } /* Function: MCP_Control ************************************************************** Description: Controls valves/status LEDs Receives: chn: the channel of the fixture status: the status of channel (good (1) or bad (0)) Returns: N/A */ void Chn_Control(int chn, int status){ //writeOutput(VALVE, HEATER, GREEN STATUS LED, RED STATUS LED) pc.printf("[%i] CHANNEL CONTROL \r\n", chn); if(status == VALVE_ON){ //valve ON, heater OFF, green status LED ON, red status led OFF if(debug_control & LED_PRINT) pc.printf("VALVE ON %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,1,0); } if(status == HEATER_ON){ //valve ON, heater ON, green status LED ON, red status led OFF if(debug_control & LED_PRINT) pc.printf("HEATER ON %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,1,1,0); } if(status == GREEN_STATUS_ON){ //valve OFF, heater OFF, green status LED ON, red status led OFF if(debug_control & LED_PRINT) pc.printf("GREEN LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,1,0); } if(status == RED_STATUS_ON){ //valve OFF, heater OFF, green status LED OFF, red status led ON if(debug_control & LED_PRINT) pc.printf("RED LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,1); } if(status == ERROR_STATUS_ON){ //valve ON, heater OFF, green status LED OFF, red status led ON if(debug_control & LED_PRINT) pc.printf("RED AND BLUE LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,0,1); } if(status == ALL_OFF){ //valve OFF, heater OFF, green status LED OFF, red status led OFF if(debug_control & LED_PRINT) pc.printf("ALL OFF %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); chnlStatus[chn].MCPi2cAckRxed = 0; //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,0); } } //*************************************************************** // Build packet with temperature readings to send to GUI //*************************************************************** void processTxUARTData() { RESPONSE_TEMP_CMD response; unsigned char *ptr = (unsigned char *)&response; int i; response.SOF_flag = TX_SOF; response.cmd_type = TEMP_DATA; response.len = 5+(sizeof(response.chTemp)); response.Delim = DELIMETER; response.chTemp[0] = channelTempData[0].currTempBack; response.chTemp[1] = channelTempData[1].currTempBack; response.chTemp[2] = channelTempData[2].currTempBack; response.chTemp[3] = channelTempData[3].currTempBack; response.chTemp[4] = channelTempData[4].currTempBack; response.chTemp[5] = channelTempData[5].currTempBack; response.chTemp[6] = channelTempData[6].currTempBack; response.chTemp[7] = channelTempData[7].currTempBack; // Send Errors Count/Info /*float *dst = (float *)&response.chTemp[0]; float *src = (float *)&channelTempData[0]; memcpy(dst, src, sizeof(channelTempData));*/ response.EOF_flag = TX_EOF; // Send response to GUI for (i=0; i < response.len; i++, ptr++) pc.printf("%02x", *ptr); pc.printf("\n"); } //*************************************************************** // Build packet with Board UID (Unique Identification) //*************************************************************** void sendUID () { UID_RESPONSE response; unsigned char *ptr = (unsigned char *)&response; int i; response.SOF_flag = TX_SOF; response.cmd_type = UID_DATA; response.len = 17; response.Delim = DELIMETER; response.UIDMH = (uint32_t)SIM->UIDMH; response.UIDML = (uint32_t)SIM->UIDML; response.UIDL = (uint32_t)SIM->UIDL; response.EOF_flag = TX_EOF; // Send response to GUI for (i=0; i < response.len; i++, ptr++) pc.printf("%02x", *ptr); pc.printf("\n"); } //*************************************************************** // Build packet with SW Version //*************************************************************** void sendFWVersion() { FW_VERSION_RESPONSE response; unsigned char *ptr = (unsigned char *)&response; int i; rLed = 1; for (i=0; i < 20; i++) rLed = 0; rLed = 1; response.SOF_flag = TX_SOF; response.cmd_type = FW_VERSION_DATA; response.len = 13; response.Delim = DELIMETER; memcpy(response.FW_Version, FW_Version, 8); response.FW_Version[7] = '\0'; response.EOF_flag = TX_EOF; // Send response to GUI for (i=0; i < response.len; i++, ptr++) pc.printf("%02x", *ptr); pc.printf("\n"); } //*************************************************************** // Build packet with errors to send to GUI //*************************************************************** void sendError (int chan, float error) { RESPONSE_CMD response; unsigned char *ptr = (unsigned char *)&response; int i; response.SOF_flag = TX_SOF; response.cmd_type = ERROR_DATA; response.len = 13; response.Delim = DELIMETER; response.channel = chan; response.data = (float)error; response.EOF_flag = TX_EOF; // Send response to GUI for (i=0; i < response.len; i++, ptr++) pc.printf("%02x", *ptr); pc.printf("\n"); } /* Function: toggleI2C ************************************************************** Description: Toggle the I2C line in an attempt to unfreeze it Receives: N/A Returns: N/A */ void toggleI2C(){ DigitalOut ioSDAIn(PTC9); DigitalOut adcSDAIn(PTC11); DigitalOut ioSCLIn(PTC8); DigitalOut adcSCLIn(PTC10); ioSDAIn = 1; adcSDAIn = 1; ioSCLIn = 1; adcSCLIn = 1; wait(0.5); ioSDAIn = 0; adcSDAIn = 0; ioSCLIn = 0; adcSCLIn = 0; wait(0.5); ioSDAIn = 1; adcSDAIn = 1; ioSCLIn = 1; adcSCLIn = 1; wait(0.5); ioSDAIn = 0; adcSDAIn = 0; ioSCLIn = 0; adcSCLIn = 0; wait(0.5); MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl } /* Function: sendErrorEmail ************************************************************** Description: sends error email Receives: chn: channel to check error on Returns: N/A */ void sendErrorEmail(int chn){ int error; for (error=0; error < ERROR_COUNT; error++){ if((errorCount[chn][error] == MAX_ERROR_CNT) && (!errorEmailSent[chn][error])){ sendError(chn, error); errorEmailSent[chn][error] = 1; } } } /* Function: errorCheck ************************************************************** Description: Updates error count for the channel Receives: chn: channel to update errorFlag: if the error was encountered errorNum: number of error encountered Returns: N/A */ void errorCheck(int chn, bool errorFlag, int errorNum){ if(errorFlag){ if(errorCount[chn][errorNum] < MAX_ERROR_CNT){ //increase error count errorCount[chn][errorNum]++; pc.printf("[%i] ERROR ENCOUNTERED: %i %i \r\n", chn, errorNum, errorCount[chn][errorNum]); } else{ //this is an error, set error flag chnlStatus[chn].error = true; //pc.printf("[%i] ERROR FLAGGED: %i %i\r\n", chn, errorNum, errorCount[chn][errorNum]); } } else{ if(errorCount[chn][errorNum] > 0){ //decrease error count errorCount[chn][errorNum]--; } //pc.printf("[%i] NO ERROR FLAGGED: %i \r\n\n", chn, errorNum); } } /* Function: softwareReset ************************************************************** Description: soft reset Recieves: N/A Returns: N/A */ void softwareReset(void){ SCB->AIRCR = (0x5FA<<SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk; for(;;){} } /* Function: SP_Time_Check ************************************************************** Description: Reset the SP time for each channel every minute (minutes since SP has been set and SP hasn't been reach) Recieves: N/A Returns: N/A */ void SP_Time_Check(){ int chan; for (chan=0; chan < CHAN_COUNT; chan++){ if(chnlStatus[chan].status == 1){ if(!chnlStatus[chan].SPReached){ if(chnlStatus[chan].SPTime != MAX_TIME_TO_SP){ chnlStatus[chan].SPTime++; } } } } } /* Function: read I2C Line ************************************************************** Description: Read the I2C line to check if pulled high Receives: N/A Returns: N/A */ int readI2CLine(int line) { if(line == IO_I2C_LINE){ DigitalIn ioSDAIn(PTC9); int ioSDA = ioSDAIn.read(); if(I2C_PRINT) pc.printf("DBG: TEMPERATURE SDA LINE: %d \r\n", ioSDA); MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl return ioSDA; } if(line == ADC_I2C_LINE){ DigitalIn adcSDAIn(PTC11); int adcSDA = adcSDAIn.read(); if(I2C_PRINT) pc.printf("DBG: IO SDA LINE: %d \r\n", adcSDA); LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl return adcSDA; } return 0; } /* Function: systemLogic ************************************************************** Description: Sets setting for fixture needed to maintain temperature at SP Receives: N/A Returns: N/A */ void systemLogic(){ int chan; float currTemp; for (chan=0; chan < CHAN_COUNT; chan++) { if(chnlStatus[chan].status == 1){ //Current Temperature currTemp = channelTempData[chan].currTempBack; if(currTemp > ((chnlStatus[chan].setTemp)+HYST_HIGH)){ //TURN COOLING ON chnlStatus[chan].state = STATUS_COOLING; } else if(currTemp < ((chnlStatus[chan].setTemp)-HYST_LOW)){ //TURN HEATER ON chnlStatus[chan].state = STATUS_HEATING; } else{ //FIXTURE INACTIVE chnlStatus[chan].state = STATUS_INACTIVE; } } else{ //FIXTURE STANDBY pc.printf("FIXTURE IN STANDBY \r\n"); chnlStatus[chan].state = STATUS_STANDBY; } } } /* Function: systemControl ************************************************************** Description: Changes fixture setting in accordance to logic set in systemLOGIC function Receives: N/A Returns: N/A */ void systemControl() { int chan; for (chan=0; chan < CHAN_COUNT; chan++){ pc.printf("[%i] CHANNEL ERRORS: %d \r\n", chan, chnlStatus[chan].error); if(!chnlStatus[chan].error){ //pc.printf("[%i] CHANNEL NO ERRORS \r\n", chan); if(errorCount[chan][ERR_ACK_LTC] == 0){ if(chnlStatus[chan].state == STATUS_INACTIVE){ //FIXTURE INACTIVE Chn_Control(chan, GREEN_STATUS_ON); //SP reached chnlStatus[chan].SPReached = true; } else if(chnlStatus[chan].state == STATUS_COOLING){ //TURN COOLING ON Chn_Control(chan, VALVE_ON); } else if(chnlStatus[chan].state == STATUS_HEATING){ //TURN HEATER ON (have to toggle bc of charge pump in circuit) Chn_Control(chan, GREEN_STATUS_ON); //turn heater off Chn_Control(chan, HEATER_ON); } else if(chnlStatus[chan].state == STATUS_STANDBY){ //FIXTURE IN STANDBY (i.e. off) if(standbyLED[chan]){ Chn_Control(chan, GREEN_STATUS_ON); standbyLED[chan] = !standbyLED[chan]; } else{ Chn_Control(chan, ALL_OFF); standbyLED[chan] = !standbyLED[chan]; } } } } else{ sendErrorEmail(chan); } } } /* Function: systemDiagnostic ************************************************************** Description: Checks for any system errors Receives: chn: Channel to modify Returns: N/A */ void systemDiagnostic(){ int chan; float backCount; float frontCount; float backTemp; float frontTemp; bool errorFlag; float tempDiff; int LTC_Ack; int MCP_Ack; int timeToSP; bool reachedSP; for (chan=0; chan < CHAN_COUNT; chan++){ backCount = channelTempData[chan].currADCBack; frontCount = channelTempData[chan].currADCFront; frontTemp = channelTempData[chan].currTempFront; backTemp = channelTempData[chan].currTempBack; LTC_Ack = chnlStatus[chan].LTCi2cAckRxed; MCP_Ack = chnlStatus[chan].MCPi2cAckRxed; timeToSP = chnlStatus[chan].SPTime; reachedSP = chnlStatus[chan].SPReached; if(PRINT_ERROR_CHECK_VALS){ pc.printf("BAKC COUNT: %f \r\n", backCount); pc.printf("FRONT COUNT: %f \r\n", frontCount); pc.printf("TEMP DIFF: %f \r\n", abs(frontTemp-backTemp)); pc.printf("LTC ACK: %f \r\n", LTC_Ack); pc.printf("MCP ACK: %f \r\n", MCP_Ack); } //Check if the ADC temperature is too high (low ADC count) errorFlag = false; if((backCount < MIN_AD_COUNT) || (frontCount < MIN_AD_COUNT)) errorFlag = true; errorCheck(chan, errorFlag, ERR_OVER_TEMP); //Check if the ADC temperature is too low (high ADC count), valve stuck on errorFlag = false; if((backCount > MAX_AD_COUNT) || (frontCount > MAX_AD_COUNT)) errorFlag = true; errorCheck(chan, errorFlag, ERR_UNDER_TEMP); //Check for a substantial temp. diff. |b| the front & back of the fixture errorFlag = false; tempDiff = abs(frontTemp-backTemp); if(tempDiff > TEMP_MARGIN) errorFlag = true; errorCheck(chan, errorFlag, ERR_TEMP_DIFF); //Check for ACK from the LTC2487 chip (temperature reading) errorFlag = false; if(!LTC_Ack) errorFlag = true; errorCheck(chan, errorFlag, ERR_ACK_LTC); //Check for ACK from the MCP23008 chip (valve/heater controller) /*errorFlag = false; if(!MCP_Ack) errorFlag = true; errorCheck(chan, errorFlag, ERR_ACK_MCP);*/ //Check if the fixture has not reached SP in X amount of time errorFlag = false; if(!reachedSP && (timeToSP == MAX_TIME_TO_SP)) errorFlag = true; errorCheck(chan, errorFlag, ERR_SP_TIME); } } /*************************************************************/ /* NEW MAIN FUNCTION */ /*************************************************************/ int main(){ /* INITIALIZATION CODE */ // Setup serial port // Look for RX_EOF uint32_t UIDMH, UIDML, UIDL; int UID_print_count = 0; //resetErrorCount(); //********************************* // Initial thermistors readings // Kick of SP time updates // Kick off temperature reading // state machine //********************************* readThermistorTicker.attach(&read_front_temp_data, .0001); //setPointTimeTicker.attach(&SP_Time_Check, 60); pc.baud(9600); pc.autoDetectChar(RX_EOF); pc.attach(&rxInterrupt, MODSERIAL::RxAutoDetect); UIDMH = (uint32_t)SIM->UIDMH; UIDML = (uint32_t)SIM->UIDML; UIDL = (uint32_t)SIM->UIDL; //print UID three times on start-up to ID Mbed board if(UID_print_count++ < 3) pc.printf("DBG: [UID: %04X%08X%08X]\n", UIDMH, UIDML, UIDL); while(1) { //********************************* // Process Rx UART data from GUI //********************************* //pc.printf("LOOP \r\n"); if (dataReceived) { dataReceived = false; if (debug_control & RXDATA_PRINT) pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount()); pc.move(rxBuf, 50); processRxUARTData(); pc.rxBufferFlush(); } //********************************* // Logic Loop //********************************* // System Logic/Control if (newTempDataAvailable) systemLogic(); //********************************* // System Diagnostic & Error Check //********************************* systemDiagnostic(); //********************************* // Process Tx UART data // Send Temperature Data/Error to GUI //********************************* if (newTempDataAvailable) { processTxUARTData(); //********************************* //Actuate Loop //********************************* systemControl(); newTempDataAvailable = false; } } }