Rivian Irvine Team
/
TCTF_Control_Main
Control Code with I/O and ADC working
main.cpp
- Committer:
- jrodenburg
- Date:
- 2018-07-16
- Revision:
- 20:cdeed4dad690
- Parent:
- 19:0946665b37c7
- Child:
- 21:f87464a7e7c6
File content as of revision 20:cdeed4dad690:
// MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF) // DATE: SEPTEMBER 2017 #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 MIN_TEMP 10 #define MAX_TEMP 65 #define MEGA_MAX_TEMP 75 #define TEMP_MARGIN 10 #define HYST_LOW 0.3 #define HYST_HIGH 1 #define SAMPLES 5 #define I2C_Freq 2000 #define VALVE 1 #define HEATER 2 #define GREEN_STATUS_ON 3 #define RED_STATUS_ON 0 #define ERROR_STATUS_ON 1 #define STATUS_OFF 4 #define sizeLUT 34 #define BACK_THERM 0 #define FRONT_THERM 1 #define HEAT_FET_AMP 2 #define VALVE_FET_AMP 3 #define FET_ON_CURRENT 1.12 #define ROOM_TEMP 22 #define MAX_HEATER_ON_TIME 25 #define MAX_CHILL_TIME 10 //10sec #define MIN_ERROR_CNT_1 4 //ALL SAFETY RELATEDD CHECKS #define MIN_ERROR_CNT_2 600 //PEFORMANCE TIME (HAVE TO GIVE FIXTURE TIME TO SETTLE) #define MIN_ERROR_CNT_3 60 #define NUM_EMAIL_SEND 2 #define STATUS_COOLING 1 #define STATUS_HEATING 2 #define STATUS_INACTIVE 3 #define STATUS_STANDBY 4 #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 const char FW_Version[8] = "V0.01C"; 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 = 0x2; //*********************************************** // Timers //*********************************************** Ticker frontTempDoneTicker; Ticker backTempDoneTicker; Ticker readThermistorTicker; Ticker frontTempInProgTicker; Ticker backTempInProgTicker; //*********************************************** // 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; int error; int state; int errorEmailSent; int i2cRxed; }; CHNL_DATA chnlStatus[] = { {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1}, {0, NULL, 0, 0, 0, 1} }; //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 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}; /* 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 { 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 = 0; chnlStatus[pRxPkt->chanID].errorEmailSent = 0; chnlStatus[pRxPkt->chanID].i2cRxed = 0; 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].i2cRxed = 0; ltc2487.setAddress(addrLUT[chnl].adc); //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chnl].i2cRxed = !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() { frontTempInProgTicker.detach(); for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ ltc2487.setAddress(addrLUT[chnl].adc); channelTempData[chnl].currTempFront = get_temp(ltc2487.read()); } //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].i2cRxed = 0; ltc2487.setAddress(addrLUT[chnl].adc); //Check if write was ack'ed (0 = ACK, (non)0 = NACK) chnlStatus[chnl].i2cRxed = !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() { backTempInProgTicker.detach(); for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ ltc2487.setAddress(addrLUT[chnl].adc); channelTempData[chnl].currTempBack = get_temp(ltc2487.read()); } //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: turn_valve_on ************************************************************** Description: Turn valve on and green status LED on Receives: chn: the channel of the fixture Returns: N/A */ void turn_valve_on(int chn){ io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(1,0,1,0); } /* Function: turn_valve_off ************************************************************** Description: Turn valve off and green status LED on Receives: chn: the channel of the fixture Returns: N/A */ void turn_valve_off(int chn){ io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,0,1,0); } /* Function: turn_heater_on ************************************************************** Description: Turn heater on and green status LED on Receives: chn: the channel of the fixture Returns: N/A */ void turn_heater_on(int chn){ io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,1,1,0); } /* Function: turn_heater_off ************************************************************** Description: Turn heater off and green status LED on Receives: chn: the channel of the fixture Returns: N/A */ void turn_heater_off(int chn){ io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,0,1,0); } /* Function: status_led ************************************************************** Description: Turn status LED on (turns on green or red) Receives: chn: the channel of the fixture status: the status of channel (good (1) or bad (0)) Returns: N/A */ void status_led(int chn, int status){ if(status == GREEN_STATUS_ON){ //green LED if(debug_control & LED_PRINT) pc.printf("GREEN LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,0,1,0); } if(status == RED_STATUS_ON){ //red LED if(debug_control & LED_PRINT) pc.printf("RED LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,0,0,1); } if(status == ERROR_STATUS_ON){ //turn valve on too if(debug_control & LED_PRINT) pc.printf("RED AND BLUE LED %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(1,0,0,1); } if(status == STATUS_OFF){ //turn valve on too if(debug_control & LED_PRINT) pc.printf("ALL OFF %d \r\n", chn); io_control.setAddress(addrLUT[chn].io); io_control.init(); io_control.writeOutput(0,0,0,0); } } /* Function: test_mcp23008 ************************************************************** Description: Test each output of the MCP23009 Receives: N/A Returns: N/A */ void test_mcp23008(int chn){ turn_valve_on(chn); wait(0.5); turn_valve_off(chn); wait(0.5); turn_heater_on(chn); wait(0.5); turn_heater_off(chn); wait(0.5); status_led(chn, 0); wait(0.5); status_led(chn, 1); } /* Function: test_ltc2487 ************************************************************** Description: Test the reading from LTC2487 Receives: N/A Returns: N/A */ void test_ltc2487(){ for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ float frontTemp = channelTempData[chnl].currTempFront; float backTemp = channelTempData[chnl].currTempBack; pc.printf("TEMPERATURE READING [%i]:: BACK: %f FRONT: %f \r\n", chnl, backTemp, frontTemp); } } //*************************************************************** // 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; if(chnlStatus[chan].errorEmailSent >= NUM_EMAIL_SEND) return; 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"); chnlStatus[chan].errorEmailSent++; } /* 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: 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: 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: error_check ************************************************************** Description: Checks for any system errors Recieves: frontTemp: temp. of front thermistor backTemp: temp. of back thermistor currTimeMin: currentTime in minutes ioSDA: voltage on the SDA line adcSDA: voltage on the SDA line Returns: N/A */ int error_check(int chnl, float currentTempFront, float currentTempBack, int currTimeMin, int ioSDA, int adcSDA){ //check if the thermistors are disconnected if((currentTempFront == 0) || (currentTempBack == 0)){ if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){ sendError(chnl, 2); status_led(chnl, RED_STATUS_ON); } else{ chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 2 \r\n", chnl); return 1; } //check if the channels are disconnected if(currentTempBack == currentTempFront){ if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){ sendError(chnl, 8); status_led(chnl, RED_STATUS_ON); } else{ chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 2A \r\n", chnl); return 1; } //check if there is a temperature difference |b| front and back if((abs(currentTempBack - currentTempFront) >= TEMP_MARGIN)){ if(chnlStatus[chnl].error >= MIN_ERROR_CNT_2){ sendError(chnl, 3); status_led(chnl, RED_STATUS_ON); } else{ chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 3 \r\n", chnl); return 1; } //check if channels are over the MAX temperature if((currentTempFront >= MAX_TEMP) || (currentTempBack >= MAX_TEMP)){ //if fixture over 65C for more than ~60s if(chnlStatus[chnl].error >= MIN_ERROR_CNT_3){ sendError(chnl, 1); status_led(chnl, RED_STATUS_ON); if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1 SOFTWARE RESET %d \r\n", chnl, chnlStatus[chnl].error); softwareReset(); } //if fixture over 65C for more than ~1s else if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){ sendError(chnl, 1); status_led(chnl, RED_STATUS_ON); if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1.9 SOFTWARE RESET %d \r\n", chnl, chnlStatus[chnl].error); chnlStatus[chnl].error++; } else{ chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1 \r\n", chnl); return 1; } //check if the valves are stuck open if(((currentTempFront <= MIN_TEMP) && (currentTempBack <= MIN_TEMP))){ if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){ sendError(chnl, 4); status_led(chnl, RED_STATUS_ON ); } else{ chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 4 \r\n", chnl); return 1; } //check that the SDA lines aren't stuck low if((ioSDA != 1) || (adcSDA != 1)){ if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){ sendError(chnl, 6); status_led(chnl, RED_STATUS_ON ); softwareReset(); } else{ toggleI2C(); chnlStatus[chnl].error++; } if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 6 \r\n", chnl); return 1; } //no errors return 0; } /* Function: systemLogic ************************************************************** Description: Checks for any system errors Receives: Channel to modify 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 chnlStatus[chan].state = STATUS_STANDBY; } } } /* Function: systemControl ************************************************************** Description: Checks for any system errors Receives: chn: Channel to modify Returns: N/A */ void systemControl() { int chan; for (chan=0; chan < CHAN_COUNT; chan++){ if(chnlStatus[chan].status == 1){ if(chnlStatus[chan].state == STATUS_COOLING){ //TURN COOLING ON turn_valve_on(chan); } else if(chnlStatus[chan].state == STATUS_HEATING){ //TURN HEATER ON turn_heater_off(chan); turn_heater_on(chan); } else{ //FIXTURE INACTIVE status_led(chan, GREEN_STATUS_ON ); } } else { //FIXTURE INACTIVE if(standbyLED[chan]){ status_led(chan, GREEN_STATUS_ON); standbyLED[chan] = !standbyLED[chan]; } else{ status_led(chan, STATUS_OFF); standbyLED[chan] = !standbyLED[chan]; } } } } void systemDiagnostic() { } /*************************************************************/ /* NEW MAIN FUNCTION */ /*************************************************************/ int main(){ /* INITIALIZATION CODE */ // Setup serial port // Look for RX_EOF uint32_t UIDMH, UIDML, UIDL; int UID_print_count = 0; //********************************* // Initial thermistors readings // Kick off temperature reding // state machine //********************************* readThermistorTicker.attach(&read_front_temp_data, .0001); 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 //********************************* 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; } } }