00001 /* 00002 * CAN Bus access for Sensor Control 00003 * initializes CAN Bus and provides recieving interrupt + sender routines 00004 * 00005 * (c) 2007 by Matthias Arndt <matthias.arndt@tu-clausthal.de> 00006 */ 00008 #include "t89c51cc02.h" 00009 #include "datatypes.h" 00010 #include "can.h" 00011 #include "command.h" 00012 00019 volatile BYTE idata can_data[8]; 00020 00029 void CAN_init() 00030 { 00031 BYTE num_channel,num_data; 00032 00033 CANGCON |= MSK_CANGCON_GRES;/* reset CAN */ 00034 /* reset all mailboxes */ 00035 for (num_channel = 0; num_channel < 4; num_channel++) 00036 { 00037 CAN_setchannel(num_channel); 00038 00039 CANCONCH = CH_DISABLE; 00040 CANSTCH = 0; 00041 CANIDT1 = 0; 00042 CANIDT2 = 0; 00043 CANIDT3 = 0; 00044 CANIDT4 = 0; 00045 CANIDM1 = 0; 00046 CANIDM2 = 0; 00047 CANIDM3 = 0; 00048 CANIDM4 = 0; 00049 for (num_data = 0; num_data < 8; num_data++) CANMSG = 0; 00050 } 00051 /* setup bit timing for 250kbps as used on the robot with the Powercubes connected */ 00052 CANBT1 = BRP_250k << 1; 00053 CANBT2 &= ~0x60; 00054 CANBT2 |= SJW_250k << 5; 00055 CANBT2 &= ~0x0E; 00056 CANBT2 |= PRS_250k << 1; 00057 CANBT3 &= ~0x70; 00058 CANBT3 |= PHS2_250k << 4; 00059 CANBT3 &= ~0x0E; 00060 CANBT3 |= PHS1_250k << 1; 00061 CANGCON |= MSK_CANGCON_ENA; 00062 00063 /* Channel 0 init */ 00064 CAN_setchannel(0); /* CHNB=0x00; select channel 0 */ 00065 CANSTCH = 0x00; /* reset channel staus */ 00066 CANCONCH = CH_DISABLE; /* reset control and dlc register */ 00067 00068 /* Channel 0: identifier = 11bits. CANIDT=0x400 */ 00069 00070 CANIDT1 = (BYTE) (((CAN_RECVID<<5) & 0xff00)>>8); 00071 CANIDT2 = (BYTE) (((CAN_RECVID<<5) & 0x00ff)); 00072 00073 /* 00074 CANIDT1 = 0x24; 00075 CANIDT2 &= ~0x80; 00076 CANIDT2 |= 0x60; 00077 */ 00078 00079 /* Channel 0: mask = 11bits. 0xFFF */ 00080 CANIDM1 = 0xFF; 00081 CANIDM2 = 0xE0; 00082 00083 CANIDM4 = 0; 00084 00085 /* Channel 0 configuration */ 00086 CANIDT4 &=~0x04; /* clear bit rtr in CANIDT4. */ 00087 CANCONCH |= DLC_MAX; /* Reception 8 bytes.*/ 00088 CANCONCH |= CH_RxENA; /* Reception enabled without buffer.*/ 00089 00090 /* Channel 1 init */ 00091 CAN_setchannel(1); 00092 CANSTCH = 0x00; /* reset channel status */ 00093 CANCONCH = CH_DISABLE; /* reset control and dlc register */ 00094 00095 /* Channel 1: identifier = 11bits. CANIDT=0x401 */ 00096 CANIDT1 = (BYTE) (((CAN_SENDID<<5) & 0xff00)>>8); 00097 CANIDT2 = (BYTE) (((CAN_SENDID<<5) & 0x00ff)); 00098 00099 CANIDM1 = 0xFF; 00100 CANIDM2 = 0xE0; 00101 00102 CANIDM4 = 0; 00103 00104 CANSTCH &= !(MSK_CANSTCH_TxOk); 00105 00106 /* interrupt configuration */ 00107 CANIE=0x01; /* IECH0=1 */ 00108 CANGIE |= MSK_CANGIE_ENTX; /* Can_Tx IT enable */ 00109 CANGIE |= MSK_CANGIE_ENRX; /* Can_Rx IT enable */ 00110 ECAN = 1; /* CAN IT enable */ 00111 00112 } 00113 00119 void CAN_interrupt(void) interrupt 7 using 1 00120 { 00121 bit tmpbit; 00122 BYTE save_canpage; 00123 BYTE i,nr_bytes; /* can_data index, nr of bytes recieved */ 00124 00125 /* CAUTION can interrupt function modify CANPAGE. Save CANPAGE at beginning 00126 and restore it at ending */ 00127 save_canpage = CANPAGE; /* save current context */ 00128 00129 /* echo received data on channel 0 reception */ 00130 CAN_setchannel(0); /* CHNB=0x00; select channel 0 */ 00131 if(CANSTCH&MSK_CANSTCH_RxOk) 00132 { 00133 /* if we did recieve something on Channel 0 - we process it here */ 00134 nr_bytes = (CANCONCH & 0x0f); 00135 00136 for (i=0; i<nr_bytes; i++) can_data[i] = CANMSG; /* save receive data */ 00137 00138 /* check for possible commands*/ 00139 switch(can_data[0]) 00140 { 00141 case COMMAND_READ: 00142 /* request reading of a given sensor 00143 * Frame length: 2 bytes 00144 * Frame struct: COMMAND_READ <sensor> 00145 */ 00146 if(nr_bytes!=2) 00147 { 00148 CAN_SendNAK(COMMAND_READ); 00149 } else { 00150 Command_SetRead(can_data[1]); 00151 CAN_SendACK(COMMAND_READ); 00152 } 00153 break; 00154 00155 case COMMAND_MONITOR: 00156 /* request monitoring of a given sensor 00157 * Frame length: 5 bytes 00158 * Frame struct: COMMAND_MONITOR <sensor> <boundary> <direction> 00159 * <boundary> is encoded into 2 bytes, high byte first (Big Endian) 00160 */ 00161 if(nr_bytes!=5) 00162 { 00163 CAN_SendNAK(COMMAND_MONITOR); 00164 } else { 00165 tmpbit=0; 00166 if(can_data[4]!=0) 00167 tmpbit=1; 00168 Command_EnableMonitor(can_data[1],can_data[2]*256+can_data[3],tmpbit); 00169 CAN_SendACK(COMMAND_MONITOR); 00170 } 00171 break; 00172 00173 case COMMAND_STOPMONITOR: 00174 /* stop monitoring of a given sensor 00175 * Frame length: 2 bytes 00176 * Frame struct: COMMAND_STOPMONITOR <sensor> 00177 */ 00178 if(nr_bytes!=2) 00179 { 00180 CAN_SendNAK(COMMAND_STOPMONITOR); 00181 } else { 00182 Command_DisableMonitor(can_data[1]); 00183 CAN_SendACK(COMMAND_STOPMONITOR); 00184 } 00185 break; 00186 00187 case COMMAND_MONITORSTATUS: 00188 /* report status of active monitors */ 00189 can_data[0]='m'; 00190 can_data[1]= (BYTE) ((monitor & 0xFF000000) >> 24); 00191 can_data[2]= (BYTE) ((monitor & 0x00FF0000) >> 16); 00192 can_data[3]= (BYTE) ((monitor & 0x0000FF00) >> 8); 00193 can_data[4]= (BYTE) (monitor & 0x000000FF); 00194 CAN_SendMsg(5); /* send status package */ 00195 break; 00196 00197 case COMMAND_RECALLMONITOR: 00198 /* schedule a reload of the monitor settings from the EEPROM contents */ 00199 read_eeprom_config=1; 00200 CAN_SendACK(COMMAND_RECALLMONITOR); 00201 break; 00202 00203 case COMMAND_STOPALLMONITORS: 00204 /* stop all monitoring processes */ 00205 monitor=0; 00206 CAN_SendACK(COMMAND_STOPALLMONITORS); 00207 break; 00208 00209 case COMMAND_REPORT: 00210 /* start of reporting: 00211 * Frame length: 2 bytes 00212 * Frame struct: COMMAND_REPORT <boundary> 00213 */ 00214 if(nr_bytes!=2) 00215 { 00216 CAN_SendNAK(COMMAND_REPORT); 00217 } else { 00218 Command_EnableReport(can_data[1]); 00219 CAN_SendACK(COMMAND_REPORT); 00220 } 00221 break; 00222 00223 case COMMAND_STOPREPORT: 00224 /* stop of reporting */ 00225 Command_DisableReport(); 00226 CAN_SendACK(COMMAND_STOPREPORT); 00227 break; 00228 00229 case COMMAND_TIMECHECK_ENABLE: 00230 /* enable checking of timing constraints */ 00231 Command_TimecheckEnable(); 00232 CAN_SendACK(COMMAND_TIMECHECK_ENABLE); 00233 break; 00234 00235 case COMMAND_TIMECHECK_DISABLE: 00236 /* disable checking of timing constraints */ 00237 Command_TimecheckDisable(); 00238 CAN_SendACK(COMMAND_TIMECHECK_DISABLE); 00239 break; 00240 00241 case COMMAND_TIMECHECKSTATUS: 00242 /* report status of timing constraints */ 00243 can_data[0]='t'; 00244 if(Command_CheckTime()) 00245 { 00246 can_data[1]=0x01; 00247 } else { 00248 can_data[1]=0x00; 00249 } 00250 CAN_SendMsg(2); /* send status package */ 00251 break; 00252 00253 case COMMAND_EEPROM_SAVEMONITOR: 00254 /* save current monitoring parameters to EEPROM */ 00255 write_eeprom_config=1; 00256 CAN_SendACK(COMMAND_EEPROM_SAVEMONITOR); 00257 break; 00258 00259 case COMMAND_EEPROM_CLEAR: 00260 /* TODO: clear EEPROM configuration */ 00261 CAN_SendNAK(COMMAND_EEPROM_CLEAR); 00262 break; 00263 00264 case COMMAND_RESET: 00265 /* disables all report and monitor functions */ 00266 Command_DisableReport(); 00267 Command_ClearRead(); 00268 Command_ClearMonitor(); 00269 CAN_SendACK(COMMAND_RESET); 00270 break; 00271 default: 00272 /* unrecognized commands are ignored */ 00273 /* CAN_SendNAK(can_data[0]); */ 00274 break; 00275 } 00276 } 00277 00278 CAN_setchannel(0); /* CHNB=0x00; select channel 0 */ 00279 CANCONCH = CH_DISABLE; /* reset channel 0 configuration */ 00280 CANCONCH |= DLC_MAX; /* receive 8 bytes */ 00281 CANCONCH |= CH_RxENA; /* reception enable */ 00282 CAN_enablechannel(0); /* channel 0 enable */ 00283 CANSTCH=0x00; /* reset channel 0 status */ 00284 00285 CANPAGE= save_canpage; /* restore saved context */ 00286 00287 CANGIT = 0x00; /* reset all flags */ 00288 } 00289 00296 void CAN_SendACK(BYTE cmd) 00297 { 00298 CAN_setchannel(1); /* CHNB=0x00; select channel 1 */ 00299 while(!(CANSTCH&MSK_CANSTCH_TxOk)); /* wait for last transmission to finish */ 00300 /* Channel 1 configuration */ 00301 CANCONCH = CH_DISABLE; /* reset channel 1 configuration */ 00302 CANMSG = cmd; 00303 CANMSG = CAN_ACK; /* answer is ASCII ACK 0x06*/ 00304 00305 CANCONCH |= 2; 00306 00307 CANCONCH |= CH_TxENA; /* emission enabled */ 00308 CAN_enablechannel(1); /* channel 1 enable */ 00309 CANSTCH=0x00; 00310 } 00311 00319 void CAN_SendNAK(BYTE cmd) 00320 { 00321 CAN_setchannel(1); /* CHNB=0x00; select channel 1 */ 00322 while(!(CANSTCH&MSK_CANSTCH_TxOk)); /* wait for last transmission to finish */ 00323 /* Channel 1 configuration */ 00324 CANCONCH = CH_DISABLE; /* reset channel 1 configuration */ 00325 CANMSG = cmd; 00326 CANMSG = CAN_NAK; /* answer is ASCII ACK 0x06*/ 00327 00328 CANCONCH |= 2; 00329 00330 CANCONCH |= CH_TxENA; /* emission enabled */ 00331 CAN_enablechannel(1); /* channel 1 enable */ 00332 CANSTCH=0x00; 00333 } 00334 00335 00344 void CAN_SendMsg(BYTE length) 00345 { 00346 BYTE i; 00347 CAN_setchannel(1); /* CHNB=0x00; select channel 1 */ 00348 while(!(CANSTCH&MSK_CANSTCH_TxOk)); /* wait for last transmission to finish */ 00349 /* Channel 1 configuration */ 00350 CANCONCH = CH_DISABLE; /* reset channel 1 configuration */ 00351 00352 ECAN=0; /* to make sure the internal data buffer is not overwritten, we disable the CAN IRQ */ 00353 for(i=0;i<length;i++) 00354 CANMSG = can_data[i]; 00355 00356 CANCONCH |= length; 00357 ECAN=1; 00358 00359 CANCONCH |= CH_TxENA; /* emission enabled */ 00360 CAN_enablechannel(1); /* channel 1 enable */ 00361 CANSTCH=0x00; 00362 }