Dual CANbus monitor and instrumentation cluster supporting ILI9341 display controller
Dependencies: SPI_TFTx2_ILI9341 TOUCH_TFTx2_ILI9341 TFT_fonts mbed
Fork of CANary by
Revision 12:8e42d7ba8468, committed 2013-03-03
- Comitter:
- TickTock
- Date:
- Sun Mar 03 15:50:54 2013 +0000
- Parent:
- 11:e9d155aad4e2
- Child:
- 13:62e0f7f39ff5
- Commit message:
- Repartitioned display and utility functions
Changed in this revision
--- a/CANary.h Wed Feb 27 03:47:06 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -//CANary - -#include "mbed.h" -#include "CAN.h" -#include "beep.h" -#include "MSCFileSystem.h" -#include "SPI_TFTx2.h" -#include "Arial12x12.h" -#include "Arial12x12_prop.h" -#include "Arial28x28.h" -#include "Neu42x35.h" -#include "SCProSB31x55.h" -#include "TOUCH_TFTx2.h" -#include "PowerControl.h" -#include "EthernetPowerControl.h" -#define upLine "\033[1A" -#define maxBufLen 768 -#define canTimeout 500 -#define userTimeout 10 -#define maxModes 7 -#define offMode 0 -#define logMode 1 -#define dteMode 2 -#define brakeMode 3 -#define powerMode 4 -#define monitorMode 5 -#define changedMode 6 -#define cpMode 7 -#define btn31x1 12 -#define btn31x2 101 -#define btn32x1 115 -#define btn32x2 204 -#define btn33x1 218 -#define btn33x2 307 -#define btn11y1 180 -#define btn11y2 229 - -//LEAF OBD -//1: -//2: -//3: AVCAN-L White/Blue -//4: VSS-Shield -//5: VSS Brown,White/Brown -//6: CARCAN-H Green -//7: -//8: 12V-SW Orange,White/Orange -//9: -//10: -//11: AVCAN-H Blue -//12: EVCAN-L White/Grey -//13: EVCAN-H Grey -//14: CARCAN-L White/Green -//15: -//16: 12V-AON Red/Blue,Blue/Red - -//VP230 -//1:D -//2:GND -//3:VCC -//4:R -//5:Vref -//6:CANL -//7:CANH -//8:RS - -//LPC1768 -//1: VSS -//2: NC:VIN (4.5-9V supply) -//3: NC:VB -//4: NC:nR -//5: SPI:CS0 -//6: SPI:CS1 -//7: SPI:Reset -//8: CAN1:Sleep --> 8:CAN1:RS -//9: CAN1:RX --> 4:CAN1:R -//10: CAN1:TX --> 1:CAN1:D -//11: SPI:MOSI -//12: SPI:MISO -//13: SPI:SCLK -//14: NC:Ain -//15: MON12V --> 4K to 12V, 1K to VSS (To be implemented) -//16: TOUCH_X+ -//17: TOUCH_X- -//18: NC:Aout -//19: TOUCH_Y+ -//20: TOUCH_Y- -//21: Spkr+ -//22: Spkr- (optional complimentary output for more volume) -//23: NC:pwm -//24: LED -//25: NC:pwm -//26: NC:pwm -//27: NC -//28: CAN2:Sleep --> 8:CAN2:RS -//29: CAN2:TX --> 1:CAN2:D -//30: CAN2:RX --> 4:CAN2:R -//31: USB_D+ -//32: USB_D- -//33: NC:Eth_TD+ -//34: NC:Eth_TD- -//35: NC:Eth_RD+ -//36: NC:Eth_RD- -//37: NC:IF+ -//38: NC:IF- -//39: NC:5Vout (only available when connected as USB device) -//40: VCC3.3 -/* -cellpair -02 21 02 -30 01 00 page request - -temp -79b 02 21 04 - +2 more pages -7bb -020314 -020713 -020c13 -020d13 - -+1300fffffff - -saw 30 01 04 ??? -*/ \ No newline at end of file
--- a/TFT_fonts.lib Wed Feb 27 03:47:06 2013 +0000 +++ b/TFT_fonts.lib Sun Mar 03 15:50:54 2013 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/TickTock/code/TFT_fonts/#dd46e436f435 +http://mbed.org/users/TickTock/code/TFT_fonts/#49b5ef080441
--- a/TOUCH_TFTx2.lib Wed Feb 27 03:47:06 2013 +0000 +++ b/TOUCH_TFTx2.lib Sun Mar 03 15:50:54 2013 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/TickTock/code/TOUCH_TFTx2/#fd0abf6a7f59 +http://mbed.org/users/TickTock/code/TOUCH_TFTx2/#fd7ae99850a9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/displayModes.h Sun Mar 03 15:50:54 2013 +0000 @@ -0,0 +1,295 @@ +// This contains all the display subroutines + +#include "TOUCH_TFTx2.h" +#include "SPI_TFTx2.h" +#include "Arial12x12.h" +#include "Arial12x12_prop.h" +#include "Arial28x28.h" +#include "Neu42x35.h" +#include "SCProSB31x55.h" + +TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, "TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs0, cs1, reset + +extern "C" { + void printLast (bool force){ + CANMessage msg; + tt.locate(0,6); + tt.foreground(Red); + tt.background(Yellow); + if(force) tt.cls(); // Just clear screen if forced - always update display + tt.set_font((unsigned char*) Arial12x12_prop); // select the font + for(int i=0; i<19; i++){ + msg = lastMsg[i+indexOffset]; + printf("%03x : %02x %02x %02x %02x %02x %02x %02x %02x \n",msg.id,msg.data[0],msg.data[1],msg.data[2],msg.data[3],msg.data[4],msg.data[5],msg.data[6],msg.data[7]); + } + } + + void printChanged (bool force){ + CANMessage msg; + unsigned char i,j; + tt.locate(0,6); + tt.foreground(Red); + tt.background(Yellow); + if(force) tt.cls(); // Just clear screen if forced - always update display + tt.set_font((unsigned char*) Arial12x12_prop); // select the font + i=0; + j=indexOffset; + do{ + j=j<99?j+1:j; + if(msgChanged[j]>0){ + msg = lastMsg[j]; + printf("%03x : %02x %02x %02x %02x %02x %02x %02x %02x \n",msg.id,msg.data[0],msg.data[1],msg.data[2],msg.data[3],msg.data[4],msg.data[5],msg.data[6],msg.data[7]); + i++; + }// if changed + }while(i<19&&j<99); + } + + void printLog (bool force){ + static unsigned char lastDisplayLoc = 0; + if(force||displayLoc!=lastDisplayLoc){ //only update if changed + tt.foreground(Amber); + tt.background(Black); + tt.cls(); + tt.locate(0,6); + tt.set_font((unsigned char*) Arial12x12); + for(int i=0; i<19; i++){ + printf("%s",displayLog[displayLoc]); + displayLoc=displayLoc>17?0:displayLoc+1; + } + } + lastDisplayLoc=displayLoc; + } + + void printDTE (bool force){ + unsigned short gids, SOC, packV; + static unsigned short lgids=0, lSOC=0, lpackV=0; + CANMessage msg; + + msg = lastMsg[indexLastMsg[0x5bc]]; //Get gids + gids = (msg.data[0]<<2)+(msg.data[1]>>6); + msg = lastMsg[indexLastMsg[0x55b]]; //Get SOC + SOC = (msg.data[0]<<2)+(msg.data[1]>>6); + msg = lastMsg[indexLastMsg[0x1db]]; //Get pack volts + packV = (msg.data[2]<<2)+(msg.data[3]>>6); + + tt.background(Navy); + if(force) tt.cls(); + if(force||gids!=lgids){ + tt.foreground(Amber); + tt.set_font((unsigned char*) Arial28x28); + tt.locate(10,10); + printf("%4d gids\n",gids); + tt.locate(10,200); + printf("%4.1f kWh\n",(float)gids*0.08); + tt.set_font((unsigned char*) SCProSB31x55); + //tt.set_font((unsigned char*) Neu42x35); + tt.foreground(Green); + tt.locate(60,96); + printf("%4.1f mi \n",(float)(gids-5)*0.33); // Approx for now + lgids=gids; + } + if(force||SOC!=lSOC){ + tt.foreground(Amber); + tt.set_font((unsigned char*) Arial28x28); + tt.locate(200,10); + printf("%4.1f%s\n",(float)SOC/10,"%"); + lSOC=SOC; + } + if(force||packV!=lpackV){ + tt.foreground(Amber); + tt.set_font((unsigned char*) Arial28x28); + tt.locate(200,200); + printf("%4.1fV\n",(float)packV/2); + lpackV=packV; + } + } + + void braking (bool force, bool prdata){ + unsigned short targetBraking, regenBraking, speed; + static unsigned short maxTarget = 0, maxRegen = 0, tarDivReg = 0; + short rpm; + unsigned long temp; + static unsigned char lastPressure[4] = {200,200,200,200}; + unsigned char i,r,t; + static unsigned char lr, lt; + CANMessage msg; + + msg = lastMsg[indexLastMsg[0x1cb]]; //Get Target and Regen + regenBraking = (msg.data[0]<<3)+(msg.data[1]>>5); + targetBraking = (msg.data[2]<<3)+(msg.data[3]>>5); + if (targetBraking>maxTarget) maxTarget=targetBraking; + if (regenBraking>maxRegen) maxRegen=regenBraking; + if (regenBraking>50) { + temp = 1000*targetBraking; + temp /= regenBraking; + if (temp>tarDivReg) tarDivReg=temp; + } + msg = lastMsg[indexLastMsg[0x176]]; //Get rpms - not sure what this is but scales to mph with .0725 + rpm = ((short)msg.data[0]<<8)+msg.data[1]; + speed =rpm>0?rpm>>3:-rpm>>3; //Take absolute to get speed; div8 + msg = lastMsg[indexLastMsg[0x1ca]]; //Get brake pressure + + tt.background(Navy); + if (force) { + tt.cls(); + tt.rect(0,111,170,239,White); + tt.line(0,207,170,207,White); + tt.line(0,175,170,175,White); + tt.line(0,143,170,143,White); + lastPressure[0] = 200; + lastPressure[1] = 200; + lastPressure[2] = 200; + lastPressure[3] = 200; + } + // plot bar graph for each wheel pressure + for (i=0; i<4; i++){ + if (msg.data[i]<239) { + if (msg.data[i]>lastPressure[i]){ + tt.fillrect(10+40*i,239-msg.data[i],40+40*i,239,Red); + } else if (msg.data[i]<lastPressure[i]) { + tt.fillrect(10+40*i,238-lastPressure[i],40+40*i,238-msg.data[i],Navy); + } + lastPressure[i]=msg.data[i]; + } + } + + if(targetBraking>50){ + targetBraking *= speed; + regenBraking *= speed; + temp = 200*targetBraking/maxTarget; + t = (char) temp; + temp = 200*regenBraking*tarDivReg/maxTarget; + r = (char) temp; + if(lr!=r&&prdata){ + tt.foreground(Amber); + tt.set_font((unsigned char*) Arial28x28); + tt.locate(100,50); + printf("%d %d \n",regenBraking,maxRegen); + tt.locate(100,90); + printf("%3.1f (%3.1f%s) \n",(float)tarDivReg/1000,(float)regenBraking*tarDivReg/targetBraking/1000,"%"); + } + if(lt!=t&&prdata){ + tt.foreground(Amber); + tt.set_font((unsigned char*) Arial28x28); + tt.locate(100,10); + printf("%d %d \n",targetBraking,maxTarget); + } + if((lr!=r||lt!=t)&&!prdata){ + if(r<lr) + tt.fillrect(200,239-lr,300,239-r,Red); + else + tt.fillrect(200,239-r,300,239,Green); + if(t<lt) + tt.fillrect(200,239-lt,300,239-t,Navy); + else + tt.fillrect(200,239-t,300,238-r,Red); + lt=t; + lr=r; + } + } + } + + void cpData(bool force){ + short unsigned max, min, jv, i, bd; + unsigned avg; + if(force){ + tt.foreground(White); + tt.background(Navy); + tt.set_font((unsigned char*) Arial12x12_prop); // select the font + max=0; + min=9999; + avg=0; + for(i=0; i<96; i++){ + bd=(battData[i*2+3]<<8)+battData[i*2+4]; + avg+=bd; + if(bd>max) max=bd; + if(bd<min) min=bd; + } + avg /= 96; + if(min<3713) { + jv=avg-(max-avg)*1.5; + } else { // Only compute judgement value if min cellpair meets <= 3712mV requirement + jv=0; + } + tt.cls(); + tt.locate(0,6); + printf(" MAX MIN AVG CVLI T1 T2 T3 T4\n %04d %04d %04d %04d %02dC %02dC %02dC %02dC\n\n",max,min,avg,jv,battData[224+5],battData[224+8],battData[224+11],battData[224+14]); + tt.locate(0,36); + for(i=0; i<16; i++){ + printf("%02d-%02d : %04d %04d %04d %04d %04d %04d\n",i*6+1,i*6+6,(battData[i*12+3]<<8)+battData[i*12+4],(battData[i*12+5]<<8)+battData[i*12+6],(battData[i*12+7]<<8)+battData[i*12+8],(battData[i*12+9]<<8)+battData[i*12+10],(battData[i*12+11]<<8)+battData[i*12+12],(battData[i*12+13]<<8)+battData[i*12+14]); + } + tt.rect(8+0*41,16,40+0*41,28,Green); + tt.rect(8+1*41,16,40+1*41,28,Yellow); + //tt.rect(8+2*41,16,40+2*41,28,White); + tt.rect(8+3*41,16,40+3*41,28,Red); + for(i=0; i<96; i++){ + bd=(battData[i*2+3]<<8)+battData[i*2+4]; + if(bd>0){ + if(bd==max) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Green); + //if(bd==avg) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,White); + if(bd==min) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Yellow); + if(bd<jv) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Red); + } + } + showCP=false; + } + } + + void updateDisplay(char display){ + bool changed; + changed = dMode[display]!=lastDMode[display]; + tt.set_display(display); + switch (dMode[display]) { + case logScreen: + printLog(changed); + break; + case dteScreen: + printDTE(changed); + break; + case brakeScreen: + braking(changed,true); + break; + case powerScreen: + braking(changed,false); + break; + case monitorScreen: + printLast(changed); + break; + case changedScreen: + printChanged(changed); + break; + case cpScreen: + cpData(changed||showCP); + break; + default: + tt.background(Black); + tt.cls(); + break; + } + lastDMode[display]=dMode[display]; + + switch (sMode) { + case 1: + tt.foreground(Yellow); + tt.background(DarkCyan); + tt.set_font((unsigned char*) Arial12x12); + tt.fillrect(btn31x1,btn11y1,btn31x2,btn11y2,DarkCyan); + tt.locate(btn31x1+5,btn11y1+5); + printf("<-Prev\n"); + tt.fillrect(btn32x1,btn11y1,btn32x2,btn11y2,DarkCyan); + tt.fillrect(btn33x1,btn11y1,btn33x2,btn11y2,DarkCyan); + tt.locate(btn33x2-50,btn11y1+5); + printf("Next->\n"); + tt.set_display(0); + tt.locate(btn32x1+15,btn11y1+5); + printf("Select %d\n",dMode[0]); + tt.set_display(1); + tt.locate(btn32x1+15,btn11y1+5); + printf("Select %d\n",dMode[1]); + tt.background(Black); + break; + default: + break; + } + } +} \ No newline at end of file
--- a/main.cpp Wed Feb 27 03:47:06 2013 +0000 +++ b/main.cpp Sun Mar 03 15:50:54 2013 +0000 @@ -1,504 +1,23 @@ -#include "CANary.h" +//#include "utility.h" +//#include "displayModes.h" //To Do: -// USB device detect -// config file on local fs -// user programmable message decode -// brake trainer -// write and read the Mode Data -LocalFileSystem local("local"); - -// to write to USB Flash Drives, or equivalent (SD card in Reader/Writer) -MSCFileSystem fs("fs"); // to write to a USB Flash Drive - -extern "C" void mbed_reset(); - -time_t seconds ; -Beep spkr(p21); - -Ticker ticker; -Timer timer; -DigitalOut led1(LED1); -DigitalOut led2(LED2); -DigitalOut led3(LED3); -DigitalOut led4(LED4); -PwmOut dled(p24); - -InterruptIn touchpad(p17); -CAN can1(p9, p10); // CAN2 uses pins 9 and 10 (rx, tx) and pin 27 (rs) -DigitalOut can1SleepMode(p8); // Use pin 8 to control the sleep mode of can2 -CAN can2(p30, p29); // CAN1 uses pins 30 and 29 (rx, tx) and pin 28 (rs) -DigitalOut can2SleepMode(p28); // Use pin 28 to control the sleep mode of can1 - -bool logEn = true,logOpen = false; -FILE *rfile; -FILE *file; -char fileName[35] = "" ; -char writeBuffer[maxBufLen][13]; // buffer for USB write -char indexLastMsg[0x800]={0}; // index table for last message -CANMessage lastMsg[100]; // table to store last message of eachtype -unsigned char battData[256]={0}; -unsigned char msgChanged[100]; // inidcates which bytes changed -char c; -volatile int writePointer = 0; -volatile int secsNoMsg = 0, secsNoTouch = 0; -volatile bool canIdle = false, userIdle = false; -bool getXY=0; //flag to read touchscreen -char counter = 0; -unsigned char dMode[2] = {7,2}; //display mode -unsigned char sMode = 0; // setup mode -unsigned char lastDMode[2] = {0,0}; //last screen mode -char displayLog[20][40]; -unsigned char displayLoc = 0; -unsigned char indexOffset = 1; -bool showCP = false; - -TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, "TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs0, cs1, reset - -extern "C" void RTC_IRQHandler() { - timer.reset(); // zero ms at the-seconds-tic - canIdle=(++secsNoMsg>canTimeout); - userIdle=(++secsNoTouch>userTimeout); - LPC_RTC->ILR |= (1<<0); // clear interrupt to prepare for next -} - -extern "C" void RTC_Init (void) { - LPC_RTC->ILR=0x00; // set up the RTC interrupts - LPC_RTC->CIIR=0x01; // interrupts each second - LPC_RTC->CCR = 0x01; // Clock enable - //NVIC_SetPriority( RTC_IRQn, 10 ); - NVIC_EnableIRQ( RTC_IRQn ); -} - -void logMsg (char *msg) { - strcpy(displayLog[displayLoc],msg); - displayLoc=displayLoc>17?0:displayLoc+1; -} - -void touched(){ - LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); - secsNoTouch = 0; - getXY=true; -} - -unsigned short getTimeStamp() { - unsigned short msec = timer.read_ms() ; // read ms from the timer - unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 - unsigned short isecs = secs%60 ; // modulo 60 for 0-59 seconds from RTC - return ((isecs<<10)+msec) ; // return the two byte time stamp -} - -void logCan (char mType, CANMessage canRXmsg) { - char sTemp[40]; - unsigned short ts = getTimeStamp(); - unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 - static unsigned char ii = 0, lasti = 0; // indexindex - unsigned char changed,i; - static unsigned char bdi; - if(logOpen){ - if(canRXmsg.id>0) { - writeBuffer[writePointer][0]=mType; - writeBuffer[writePointer][1]=((secs%60)<<2)+((ts&0x300)>>8); - writeBuffer[writePointer][2]=ts&0xff; - writeBuffer[writePointer][3]=canRXmsg.id&0xff; - writeBuffer[writePointer][4]=(canRXmsg.id>>8)+(canRXmsg.len<<4); - for(i=5;i<13;i++){ - writeBuffer[writePointer][i]=canRXmsg.data[i-5]; - } - if (++writePointer >= maxBufLen) { - writePointer = 0; - led3 = !led3; - } - } - }//if logOpen - if(indexLastMsg[canRXmsg.id]==0) { //Check if no entry - ii=ii<99?ii+1:0; - indexLastMsg[canRXmsg.id]=ii; //Create entry if first message - } - if(dMode[0]==changedMode||dMode[1]==changedMode){ - changed=msgChanged[indexLastMsg[canRXmsg.id]]; - for(i=0;i<8;i++){ - if(lastMsg[indexLastMsg[canRXmsg.id]].data[i]!=canRXmsg.data[i]){ - changed |= 1<<i; - } - } - msgChanged[indexLastMsg[canRXmsg.id]]=changed; - } - lastMsg[indexLastMsg[canRXmsg.id]]=canRXmsg; //Store in table - if(mType==1&&canRXmsg.id==0x7bb){ // is battery data? Need to store all responses - if(canRXmsg.data[0]<0x20){ - if(canRXmsg.data[3]==2){//cellpair data - bdi=0; - sprintf(sTemp,"Getting cell pair data\n"); - logMsg(sTemp); - }else if(canRXmsg.data[3]==4){//temperature data - bdi=0x20; - sprintf(sTemp,"Getting temperature data\n"); - logMsg(sTemp); - }else bdi=0; - lasti=0; - } - i=canRXmsg.data[0]&0x0f; //lower nibble of D0 is index - if(lasti>i){ //detect rolloever and offset index appropriately - bdi=0x10; - } - lasti=i; //remember the msb to detect rollover next time around - i+=bdi; - i*=7; - if(i<0xfa){ - battData[i+0]=canRXmsg.data[1]; - battData[i+1]=canRXmsg.data[2]; - battData[i+2]=canRXmsg.data[3]; - battData[i+3]=canRXmsg.data[4]; - battData[i+4]=canRXmsg.data[5]; - battData[i+5]=canRXmsg.data[6]; - battData[i+6]=canRXmsg.data[7]; - } - }//if 0x7bb -} - -void logTS () { - CANMessage tsMsg; - unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 - tsMsg.id=0xfff; - tsMsg.len=0xf; - tsMsg.data[0]=secs&0xff; - tsMsg.data[1]=(secs>>8)&0xff; - tsMsg.data[2]=(secs>>16)&0xff; - tsMsg.data[3]=secs>>24; - tsMsg.data[4]=0xff; - tsMsg.data[5]=0xff; - tsMsg.data[6]=0xff; - tsMsg.data[7]=0xff; - logCan(0,tsMsg); -} - -void sendCPreq() { - char i; - char data[8] = {0x02, 0x21, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff}; - can1.monitor(false); // set to active mode - can1SleepMode = 0; // enable TX - can1.write(CANMessage(0x79b, data, 8)); - data[0]=0x30; //change to request next line message - data[1]=0x01; - data[2]=0x00; - for(i=0;i<64;i++){ - wait_ms(16); //wait 16ms - can1.write(CANMessage(0x79b, data, 8)); - } - can1SleepMode = 1; // disable TX - can1.monitor(true); // set to snoop mode -} - -void sendTreq() { - char i; - char data[8] = {0x02, 0x21, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff}; - can1.monitor(false); // set to active mode - can1SleepMode = 0; // enable TX - can1.write(CANMessage(0x79b, data, 8)); - data[0]=0x30; //change to request next line message - data[1]=0x01; - data[2]=0x00; - for(i=0;i<8;i++){ - wait_ms(16); //wait 16ms - can1.write(CANMessage(0x79b, data, 8)); - } - can1SleepMode = 1; // disable TX - can1.monitor(true); // set to snoop mode -} - -void recieve1() { - CANMessage msg1; - secsNoMsg=0; // reset deadman switch - can1.read(msg1); - logCan(1, msg1); - led1 = !led1; -} - -void recieve2() { - CANMessage msg2; - secsNoMsg=0; // reset deadman switch - can2.read(msg2); - logCan(2, msg2); - led2 = !led2; -} - -void printLast (bool force){ - CANMessage msg; - tt.locate(0,6); - tt.foreground(Red); - tt.background(Yellow); - if(force) tt.cls(); // Just clear screen if forced - always update display - tt.set_font((unsigned char*) Arial12x12_prop); // select the font - for(int i=0; i<19; i++){ - msg = lastMsg[i+indexOffset]; - printf("%03x : %02x %02x %02x %02x %02x %02x %02x %02x \n",msg.id,msg.data[0],msg.data[1],msg.data[2],msg.data[3],msg.data[4],msg.data[5],msg.data[6],msg.data[7]); - } -} - -void printChanged (bool force){ - CANMessage msg; - unsigned char i,j; - tt.locate(0,6); - tt.foreground(Red); - tt.background(Yellow); - if(force) tt.cls(); // Just clear screen if forced - always update display - tt.set_font((unsigned char*) Arial12x12_prop); // select the font - i=0; - j=indexOffset; - do{ - j=j<99?j+1:j; - if(msgChanged[j]>0){ - msg = lastMsg[j]; - printf("%03x : %02x %02x %02x %02x %02x %02x %02x %02x \n",msg.id,msg.data[0],msg.data[1],msg.data[2],msg.data[3],msg.data[4],msg.data[5],msg.data[6],msg.data[7]); - i++; - }// if changed - }while(i<19&&j<99); -} - -void printLog (bool force){ - static unsigned char lastDisplayLoc = 0; - if(force||displayLoc!=lastDisplayLoc){ //only update if changed - tt.foreground(Amber); - tt.background(Black); - tt.cls(); - tt.locate(0,6); - tt.set_font((unsigned char*) Arial12x12); - for(int i=0; i<19; i++){ - printf("%s",displayLog[displayLoc]); - displayLoc=displayLoc>17?0:displayLoc+1; - } - } - lastDisplayLoc=displayLoc; -} - -void printDTE (bool force){ - unsigned short gids, SOC, packV; - static unsigned short lgids=0, lSOC=0, lpackV=0; - CANMessage msg; - - msg = lastMsg[indexLastMsg[0x5bc]]; //Get gids - gids = (msg.data[0]<<2)+(msg.data[1]>>6); - msg = lastMsg[indexLastMsg[0x55b]]; //Get SOC - SOC = (msg.data[0]<<2)+(msg.data[1]>>6); - msg = lastMsg[indexLastMsg[0x1db]]; //Get pack volts - packV = (msg.data[2]<<2)+(msg.data[3]>>6); - - tt.background(Navy); - if(force) tt.cls(); - if(force||gids!=lgids){ - tt.foreground(Amber); - tt.set_font((unsigned char*) Arial28x28); - tt.locate(10,10); - printf("%4d gids\n",gids); - tt.locate(10,200); - printf("%4.1f kWh\n",(float)gids*0.08); - tt.set_font((unsigned char*) SCProSB31x55); - //tt.set_font((unsigned char*) Neu42x35); - tt.foreground(Green); - tt.locate(60,96); - printf("%4.1f mi\n",(float)gids*0.33); // Approx for now - lgids=gids; - } - if(force||SOC!=lSOC){ - tt.foreground(Amber); - tt.set_font((unsigned char*) Arial28x28); - tt.locate(200,10); - printf("%4.1f%s\n",(float)SOC/10,"%"); - lSOC=SOC; - } - if(force||packV!=lpackV){ - tt.foreground(Amber); - tt.set_font((unsigned char*) Arial28x28); - tt.locate(200,200); - printf("%4.1fV\n",(float)packV/2); - lpackV=packV; - } -} - -void braking (bool force, bool prdata){ - unsigned short targetBraking, regenBraking, speed; - static unsigned short maxTarget = 0, maxRegen = 0, tarDivReg = 0; - short rpm; - unsigned long temp; - static unsigned char lastPressure[4] = {200,200,200,200}; - unsigned char i,r,t; - static unsigned char lr, lt; - CANMessage msg; - - msg = lastMsg[indexLastMsg[0x1cb]]; //Get Target and Regen - regenBraking = (msg.data[0]<<3)+(msg.data[1]>>5); - targetBraking = (msg.data[2]<<3)+(msg.data[3]>>5); - if (targetBraking>maxTarget) maxTarget=targetBraking; - if (regenBraking>maxRegen) maxRegen=regenBraking; - if (regenBraking>50) { - temp = 1000*targetBraking; - temp /= regenBraking; - if (temp>tarDivReg) tarDivReg=temp; - } - msg = lastMsg[indexLastMsg[0x176]]; //Get rpms - not sure what this is but scales to mph with .0725 - rpm = ((short)msg.data[0]<<8)+msg.data[1]; - speed =rpm>0?rpm>>3:-rpm>>3; //Take absolute to get speed; div8 - msg = lastMsg[indexLastMsg[0x1ca]]; //Get brake pressure - - tt.background(Navy); - if (force) { - tt.cls(); - tt.rect(0,111,170,239,White); - tt.line(0,207,170,207,White); - tt.line(0,175,170,175,White); - tt.line(0,143,170,143,White); - lastPressure[0] = 200; - lastPressure[1] = 200; - lastPressure[2] = 200; - lastPressure[3] = 200; - } - // plot bar graph for each wheel pressure - for (i=0; i<4; i++){ - if (msg.data[i]<239) { - if (msg.data[i]>lastPressure[i]){ - tt.fillrect(10+40*i,239-msg.data[i],40+40*i,239,Red); - } else if (msg.data[i]<lastPressure[i]) { - tt.fillrect(10+40*i,238-lastPressure[i],40+40*i,238-msg.data[i],Navy); - } - lastPressure[i]=msg.data[i]; - } - } - - if(targetBraking>50){ - targetBraking *= speed; - regenBraking *= speed; - temp = 200*targetBraking/maxTarget; - t = (char) temp; - temp = 200*regenBraking*tarDivReg/maxTarget; - r = (char) temp; - if(lr!=r&&prdata){ - tt.foreground(Amber); - tt.set_font((unsigned char*) Arial28x28); - tt.locate(100,50); - printf("%d %d \n",regenBraking,maxRegen); - tt.locate(100,90); - printf("%3.1f (%3.1f%s) \n",(float)tarDivReg/1000,(float)regenBraking*tarDivReg/targetBraking/1000,"%"); - } - if(lt!=t&&prdata){ - tt.foreground(Amber); - tt.set_font((unsigned char*) Arial28x28); - tt.locate(100,10); - printf("%d %d \n",targetBraking,maxTarget); - } - if((lr!=r||lt!=t)&&!prdata){ - if(r<lr) - tt.fillrect(200,239-lr,300,239-r,Red); - else - tt.fillrect(200,239-r,300,239,Green); - if(t<lt) - tt.fillrect(200,239-lt,300,239-t,Navy); - else - tt.fillrect(200,239-t,300,238-r,Red); - lt=t; - lr=r; - } - } -} - -void cpData(bool force){ - short unsigned max, min, jv, i, bd; - unsigned avg; - if(force){ - tt.foreground(White); - tt.background(Navy); - tt.set_font((unsigned char*) Arial12x12_prop); // select the font - max=0; - min=9999; - avg=0; - for(i=0; i<96; i++){ - bd=(battData[i*2+3]<<8)+battData[i*2+4]; - avg+=bd; - if(bd>max) max=bd; - if(bd<min) min=bd; - } - avg /= 96; - jv=avg-(max-avg)*2.5; - tt.cls(); - tt.locate(0,6); - printf(" MAX MIN AVG CVLI T1 T2 T3 T4\n %04d %04d %04d %04d %02dC %02dC %02dC %02dC\n\n",max,min,avg,jv,battData[224+5],battData[224+8],battData[224+11],battData[224+14]); - tt.locate(0,36); - for(i=0; i<16; i++){ - printf("%02d-%02d : %04d %04d %04d %04d %04d %04d\n",i*6+1,i*6+6,(battData[i*12+3]<<8)+battData[i*12+4],(battData[i*12+5]<<8)+battData[i*12+6],(battData[i*12+7]<<8)+battData[i*12+8],(battData[i*12+9]<<8)+battData[i*12+10],(battData[i*12+11]<<8)+battData[i*12+12],(battData[i*12+13]<<8)+battData[i*12+14]); - } - tt.rect(8+0*41,16,40+0*41,28,Green); - tt.rect(8+1*41,16,40+1*41,28,Yellow); - //tt.rect(8+2*41,16,40+2*41,28,White); - tt.rect(8+3*41,16,40+3*41,28,Red); - for(i=0; i<96; i++){ - bd=(battData[i*2+3]<<8)+battData[i*2+4]; - if(bd>0){ - if(bd==max) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Green); - //if(bd==avg) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,White); - if(bd==min) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Yellow); - if(bd<jv) tt.rect(58+(i%6)*41,34+(int)(i/6)*12,90+(i%6)*41,46+(int)(i/6)*12,Red); - } - } - showCP=false; - } -} - -void updateDisplay(char display){ - bool changed; - changed = dMode[display]!=lastDMode[display]; - tt.set_display(display); - switch (dMode[display]) { - case logMode: - printLog(changed); - break; - case dteMode: - printDTE(changed); - break; - case brakeMode: - braking(changed,true); - break; - case powerMode: - braking(changed,false); - break; - case monitorMode: - printLast(changed); - break; - case changedMode: - printChanged(changed); - break; - case cpMode: - cpData(changed||showCP); - break; - default: - tt.background(Black); - tt.cls(); - break; - } - lastDMode[display]=dMode[display]; - - switch (sMode) { - case 1: - tt.foreground(Yellow); - tt.background(DarkCyan); - tt.set_font((unsigned char*) Arial12x12); - tt.fillrect(btn31x1,btn11y1,btn31x2,btn11y2,DarkCyan); - tt.locate(btn31x1+5,btn11y1+5); - printf("<-Prev\n"); - tt.fillrect(btn32x1,btn11y1,btn32x2,btn11y2,DarkCyan); - tt.fillrect(btn33x1,btn11y1,btn33x2,btn11y2,DarkCyan); - tt.locate(btn33x2-50,btn11y1+5); - printf("Next->\n"); - tt.set_display(0); - tt.locate(btn32x1+15,btn11y1+5); - printf("Select %d\n",dMode[0]); - tt.set_display(1); - tt.locate(btn32x1+15,btn11y1+5); - printf("Select %d\n",dMode[1]); - tt.background(Black); - break; - default: - break; - } -} +// * USB device detect +// * config file on local fs with touchscreen calibration +// * user programmable message decode +// * brake trainer +// * write and read the Mode Data +// * Date entry config screen (keypad) +// * auto-poll option for cellpair data +// * cellpair histogram +// * +#include "mbed.h" +#include "CAN.h" +#include "beep.h" +#include "MSCFileSystem.h" +#include "PowerControl.h" +#include "EthernetPowerControl.h" +#include "utility.h" +#include "displayModes.h" int main() { int readPointer=0; @@ -522,9 +41,13 @@ tt.background(Black); tt.cls(); tt.set_display(0); // select left display - tt.calibrate(); // calibrate the touch + if(true){ // bypass calibration + tt.setcal(5570, 34030, 80, 108, 33700, 5780, 82, 108, 32500); + } else { // calibrate the touch + tt.calibrate(); + } tt.claim(stdout); // send stdout to the TFT display - touchpad.rise(&touched); + touchpad.rise(&touch_ISR); tt.wfi(); // enable interrupt on touch dled = 0.8; // turn on display LED 80% timer.start() ; @@ -563,6 +86,7 @@ // strftime(sTemp, 32, "%a %m/%d/%Y %X", localtime(&seconds)); // printf("%s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS } + //ticker.attach(&tickerISR, 60); //poll cellpair data every minute while (true) { if (!logOpen) { // Open new file if one is not already open if(logEn){ //logging enable @@ -623,7 +147,7 @@ secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 while (secsNoMsg>canTimeout && secsNoTouch>userTimeout) { //DeepPowerDown(); - tt.wfi(); //enable touchpad input + tt.wfi(); //enable touch interrupt __wfi(); // freeze CPU and wait for interrupt (from canbus or touch) //Sleep(); //DeepPowerDown(); @@ -642,10 +166,10 @@ } } // if idle - if(getXY){ + if(touched){ lastTouch = tt.get_touch(); lastTouch = tt.to_pixel(lastTouch); // convert to pixel pos - getXY = false; // clear interrupt flag + touched = false; // clear interrupt flag } if (!userIdle) { if (secsNoTouch<2) {// Recently touched @@ -659,15 +183,15 @@ if (lastTouch.y>btn11y1 && lastTouch.y<btn11y2) { if(sMode==1){ if (lastTouch.x>btn31x1 && lastTouch.x<btn31x2) { - dMode[i]=dMode[i]>0?dMode[i]-1:maxModes; + dMode[i]=dMode[i]>0?dMode[i]-1:maxScreens; } else if (lastTouch.x>btn32x1 && lastTouch.x<btn32x2) { secsNoTouch = userTimeout; // immediately exit config mode } else if (lastTouch.x>btn33x1 && lastTouch.x<btn33x2) { - dMode[i]=dMode[i]<maxModes?dMode[i]+1:0; + dMode[i]=dMode[i]<maxScreens?dMode[i]+1:0; } } else sMode=1; } else { - if (dMode[i]==monitorMode||dMode[i]==changedMode) { + if (dMode[i]==monitorScreen||dMode[i]==changedScreen) { if (lastTouch.x>btn31x1 && lastTouch.x<btn31x2) { indexOffset=indexOffset>4?indexOffset-4:1; } else if (lastTouch.x>btn32x1 && lastTouch.x<btn32x2) { @@ -676,13 +200,9 @@ } else if (lastTouch.x>btn33x1 && lastTouch.x<btn33x2) { indexOffset=indexOffset<77?indexOffset+4:80; } - } else if (dMode[i]==cpMode) { + } else if (dMode[i]==cpScreen) { if (lastTouch.x>btn32x1 && lastTouch.x<btn32x2){ - sendCPreq(); // send cellpair data request. - wait_ms(16); - sendTreq(); //send temperature request - wait_ms(16); - showCP=true; + pollCP=true; } } } //top of screen @@ -694,6 +214,14 @@ lastDMode[1]=99; } } + if(pollCP){ + sendCPreq(); // send cellpair data request. + wait_ms(16); + sendTreq(); //send temperature request + wait_ms(16); + pollCP=false; + showCP=true; + } display=display<1?display+1:0; // toggle display updateDisplay(display); //wait(0.1); // We get >2K messages per second
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility.h Sun Mar 03 15:50:54 2013 +0000 @@ -0,0 +1,319 @@ +// utility.cpp +#include "mbed.h" +#include "CAN.h" +#include "beep.h" +#include "MSCFileSystem.h" +#include "PowerControl.h" +#include "EthernetPowerControl.h" + +#define upLine "\033[1A" +#define maxBufLen 768 +#define canTimeout 500 +#define userTimeout 10 +#define btn31x1 12 +#define btn31x2 101 +#define btn32x1 115 +#define btn32x2 204 +#define btn33x1 218 +#define btn33x2 307 +#define btn11y1 180 +#define btn11y2 229 +#define maxScreens 7 +#define offScreen 0 +#define logScreen 1 +#define dteScreen 2 +#define brakeScreen 3 +#define powerScreen 4 +#define monitorScreen 5 +#define changedScreen 6 +#define cpScreen 7 +LocalFileSystem local("local"); + +// to write to USB Flash Drives, or equivalent (SD card in Reader/Writer) +MSCFileSystem fs("fs"); // to write to a USB Flash Drive + +time_t seconds ; +Beep spkr(p21); + +Ticker ticker; +Timer timer; +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); +PwmOut dled(p24); + +InterruptIn touchpad(p17); +CAN can1(p9, p10); // CAN1 (EV) uses pins 9 and 10 (rx, tx) and pin 8 (rs) +DigitalOut can1SleepMode(p8); // Use pin 8 to control the sleep mode of can2 +CAN can2(p30, p29); // CAN2 (CAR) uses pins 30 and 29 (rx, tx) and pin 28 (rs) +DigitalOut can2SleepMode(p28); // Use pin 28 to control the sleep mode of can1 + +bool logEn = true,logOpen = false; +FILE *rfile; +FILE *file; +char fileName[35] = "" ; +char writeBuffer[maxBufLen][13]; // buffer for USB write +char indexLastMsg[0x800]={0}; // index table for last message +CANMessage lastMsg[100]; // table to store last message of eachtype +unsigned char battData[256]={0}; +unsigned char msgChanged[100]; // inidcates which bytes changed +char c; +volatile int writePointer = 0; +volatile int secsNoMsg = 0, secsNoTouch = 0; +volatile bool canIdle = false, userIdle = false; +bool touched=0; //flag to read touchscreen +char counter = 0; +unsigned char dMode[2] = {7,2}; //display mode +unsigned char sMode = 0; // setup mode +unsigned char lastDMode[2] = {0,0}; //last screen mode +char displayLog[20][40]; +unsigned char displayLoc = 0; +unsigned char indexOffset = 1; +bool showCP = false; +bool pollCP = false; + +extern "C" { + void mbed_reset(); + void RTC_IRQHandler() { + timer.reset(); // zero ms at the-seconds-tic + canIdle=(++secsNoMsg>canTimeout); + userIdle=(++secsNoTouch>userTimeout); + LPC_RTC->ILR |= (1<<0); // clear interrupt to prepare for next + } + + extern "C" void RTC_Init (void) { + LPC_RTC->ILR=0x00; // set up the RTC interrupts + LPC_RTC->CIIR=0x01; // interrupts each second + LPC_RTC->CCR = 0x01; // Clock enable + //NVIC_SetPriority( RTC_IRQn, 10 ); + NVIC_EnableIRQ( RTC_IRQn ); + } + + void logMsg (char *msg) { + strcpy(displayLog[displayLoc],msg); + displayLoc=displayLoc>17?0:displayLoc+1; + } + + void touch_ISR(){ + LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); + secsNoTouch = 0; + touched=true; + } + + unsigned short getTimeStamp() { + unsigned short msec = timer.read_ms() ; // read ms from the timer + unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 + unsigned short isecs = secs%60 ; // modulo 60 for 0-59 seconds from RTC + return ((isecs<<10)+msec) ; // return the two byte time stamp + } + + void logCan (char mType, CANMessage canRXmsg) { + char sTemp[40]; + unsigned short ts = getTimeStamp(); + unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 + static unsigned char ii = 0, lasti = 0; // indexindex + unsigned char changed,i; + static unsigned char bdi; + if(logOpen){ + if(canRXmsg.id>0) { + writeBuffer[writePointer][0]=mType; + writeBuffer[writePointer][1]=((secs%60)<<2)+((ts&0x300)>>8); + writeBuffer[writePointer][2]=ts&0xff; + writeBuffer[writePointer][3]=canRXmsg.id&0xff; + writeBuffer[writePointer][4]=(canRXmsg.id>>8)+(canRXmsg.len<<4); + for(i=5;i<13;i++){ + writeBuffer[writePointer][i]=canRXmsg.data[i-5]; + } + if (++writePointer >= maxBufLen) { + writePointer = 0; + led3 = !led3; + } + } + }//if logOpen + if(indexLastMsg[canRXmsg.id]==0) { //Check if no entry + ii=ii<99?ii+1:0; + indexLastMsg[canRXmsg.id]=ii; //Create entry if first message + } + if(dMode[0]==changedScreen||dMode[1]==changedScreen){ + changed=msgChanged[indexLastMsg[canRXmsg.id]]; + for(i=0;i<8;i++){ + if(lastMsg[indexLastMsg[canRXmsg.id]].data[i]!=canRXmsg.data[i]){ + changed |= 1<<i; + } + } + msgChanged[indexLastMsg[canRXmsg.id]]=changed; + } + lastMsg[indexLastMsg[canRXmsg.id]]=canRXmsg; //Store in table + if(mType==1&&canRXmsg.id==0x7bb){ // is battery data? Need to store all responses + if(canRXmsg.data[0]<0x20){ + if(canRXmsg.data[3]==2){//cellpair data + bdi=0; + sprintf(sTemp,"Getting cell pair data\n"); + logMsg(sTemp); + }else if(canRXmsg.data[3]==4){//temperature data + bdi=0x20; + sprintf(sTemp,"Getting temperature data\n"); + logMsg(sTemp); + }else bdi=0; + lasti=0; + } + i=canRXmsg.data[0]&0x0f; //lower nibble of D0 is index + if(lasti>i){ //detect rolloever and offset index appropriately + bdi=0x10; + } + lasti=i; //remember the msb to detect rollover next time around + i+=bdi; + i*=7; + if(i<0xfa){ + battData[i+0]=canRXmsg.data[1]; + battData[i+1]=canRXmsg.data[2]; + battData[i+2]=canRXmsg.data[3]; + battData[i+3]=canRXmsg.data[4]; + battData[i+4]=canRXmsg.data[5]; + battData[i+5]=canRXmsg.data[6]; + battData[i+6]=canRXmsg.data[7]; + } + }//if 0x7bb + } + + void logTS () { + CANMessage tsMsg; + unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 + tsMsg.id=0xfff; + tsMsg.len=0xf; + tsMsg.data[0]=secs&0xff; + tsMsg.data[1]=(secs>>8)&0xff; + tsMsg.data[2]=(secs>>16)&0xff; + tsMsg.data[3]=secs>>24; + tsMsg.data[4]=0xff; + tsMsg.data[5]=0xff; + tsMsg.data[6]=0xff; + tsMsg.data[7]=0xff; + logCan(0,tsMsg); + } + + void sendCPreq() { + char i; + char data[8] = {0x02, 0x21, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff}; + can1.monitor(false); // set to active mode + can1SleepMode = 0; // enable TX + can1.write(CANMessage(0x79b, data, 8)); + data[0]=0x30; //change to request next line message + data[1]=0x01; + data[2]=0x00; + for(i=0;i<27;i++){ + wait_ms(16); //wait 16ms + can1.write(CANMessage(0x79b, data, 8)); + } + can1SleepMode = 1; // disable TX + can1.monitor(true); // set to snoop mode + } + + void sendTreq() { + char i; + char data[8] = {0x02, 0x21, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff}; + can1.monitor(false); // set to active mode + can1SleepMode = 0; // enable TX + can1.write(CANMessage(0x79b, data, 8)); + data[0]=0x30; //change to request next line message + data[1]=0x01; + data[2]=0x00; + for(i=0;i<2;i++){ + wait_ms(16); //wait 16ms + can1.write(CANMessage(0x79b, data, 8)); + } + can1SleepMode = 1; // disable TX + can1.monitor(true); // set to snoop mode + } + + void tickerISR() { //This is the ticker ISR for auto-polling + pollCP=true; //Set a flag to do in main loop instead of here + } //since ticker blocks other interrupts + + void recieve1() { + CANMessage msg1; + secsNoMsg=0; // reset deadman switch + can1.read(msg1); + logCan(1, msg1); + led1 = !led1; + } + + void recieve2() { + CANMessage msg2; + secsNoMsg=0; // reset deadman switch + can2.read(msg2); + logCan(2, msg2); + led2 = !led2; + } +} + +//LEAF OBD +//1: +//2: +//3: AVCAN-L White/Blue +//4: VSS-Shield +//5: VSS Brown,White/Brown +//6: CARCAN-H Green +//7: +//8: 12V-SW Orange,White/Orange +//9: +//10: +//11: AVCAN-H Blue +//12: EVCAN-L White/Grey +//13: EVCAN-H Grey +//14: CARCAN-L White/Green +//15: +//16: 12V-AON Red/Blue,Blue/Red + +//VP230 +//1:D +//2:GND +//3:VCC +//4:R +//5:Vref +//6:CANL +//7:CANH +//8:RS + +//LPC1768 +//1: VSS +//2: NC:VIN (4.5-9V supply) +//3: NC:VB +//4: NC:nR +//5: SPI:CS0 +//6: SPI:CS1 +//7: SPI:Reset +//8: CAN1:Sleep --> 8:CAN1:RS +//9: CAN1:RX --> 4:CAN1:R +//10: CAN1:TX --> 1:CAN1:D +//11: SPI:MOSI +//12: SPI:MISO +//13: SPI:SCLK +//14: NC:Ain +//15: MON12V --> 4K to 12V, 1K to VSS (To be implemented) +//16: TOUCH_X+ +//17: TOUCH_X- +//18: NC:Aout +//19: TOUCH_Y+ +//20: TOUCH_Y- +//21: Spkr+ +//22: Spkr- (optional complimentary output for more volume) +//23: NC:pwm +//24: LED +//25: NC:pwm +//26: NC:pwm +//27: NC +//28: CAN2:Sleep --> 8:CAN2:RS +//29: CAN2:TX --> 1:CAN2:D +//30: CAN2:RX --> 4:CAN2:R +//31: USB_D+ +//32: USB_D- +//33: NC:Eth_TD+ +//34: NC:Eth_TD- +//35: NC:Eth_RD+ +//36: NC:Eth_RD- +//37: NC:IF+ +//38: NC:IF- +//39: NC:5Vout (only available when connected as USB device) +//40: VCC3.3 \ No newline at end of file