/* ********************************************************************** * File GMBCANE.C - Rel. 1.1 with uC/51 V. 1.10.09 * * GRIFO(R) via Dell'Artigiano 8/6 40016 S. Giorgio di Piano (BO) * * Tel. +39 051 892052 Fax. +39 051 893661 * * http://www.grifo.com http://www.grifo.it * * sales@grifo.it tech@grifo.it grifo@grifo.it * * by Angelini Gianluca date 11.07.03 * ********************************************************************** 11/07/03: GMBCANE.C - Rel. 1.1 - By Angelini Gianluca If Mini Module is provided with CAN line on CN4, this demo allows to program by console the typical parameters of CAN communication, then send and receive messages. Thanks to this flexibility it is possible to communicate to any other device provided with CAN line. Note To avoid problems do not use complex operations on a single source line, especially inside procedures by using their parameters or their local variables. */ /**************************************************************************** Header, constant, data structure, etc. ****************************************************************************/ #include "canarye.h" #include #include #define FALSE 0x00 // Boolean value #define TRUE 0xFF #define LF 0x0A // ASCII codes #define CRET 0x0D #define TOUTCAN 10000 // Time out constant for CAN controller #define FCAN 7372800 // CAN controller frequency // Global variables for I2C BUS management near unsigned char resi2c; // I2C BUS error variable bit unsigned char SDACAN @ 0xA1; // SDA pin on CAN GMx=P2.1 bit unsigned char SCLCAN @ 0xA0; // SCL pin on CAN GMx=P2.0 bit unsigned char SDA5115 @ 0xA0; // SDA pin on GMM 5115=P2.0 bit unsigned char SCL5115 @ 0xA1; // SCL pin on GMM 5115=P2.1 // Global variables for CAN management typedef unsigned char canbuf[9]; // CAN controller exchange data array near unsigned char msgobj; // CAN controller message object near unsigned int id; // CAN identifier near unsigned char rtr; // CAN message frame type near unsigned char errcan; // CAN controller errors variable inear canbuf txbufcan,rxbufcan; // CAN tx/rx buffer // Global variables for interrupts management near unsigned int nint0,nint1; // General purpose global variables used by main and procedures near unsigned char minmod,choice,dr,dw,hlp; near unsigned int val; inear unsigned char input[9]; // Console input buffer /**************************************************************************** General purpose functions and card hw sections management functions ****************************************************************************/ unsigned char divappr(unsigned long divid,unsigned long divis) /* Procedure that calculates the 8 bit integer quotient, correctly approximated, between the dividend and the divisor passed as parameters, by using the successive subtractions tecnique. This function is used to reserve the 2K of code required by the same librari functions. */ { unsigned char d; d=0; // Set quotient to zero while (divid>=divis) { divid=divid-divis; d++; } //endwhile divis=divis>>1; // Halves divisor to check the remainder if (divid>=divis) d++; //endif return d; } void init_cpu(void) /* Perform some specific initialization of CPU SFRs */ { EA=0; // Ensures interrupt disabled CKCON=0x00; // Set X1 clock mode = standard mode AUXR=0x0C; // Selects ERAM on external data area EECON=0x00; // Disables internal EEPROM } void iniser(unsigned long baud) /* Initializes the serial line with: Bit x chr = 8 Stop bit = 1 Parity = None Baud rate = baud using timer 1 as baud rate generator. */ { SCON=0x052; // Mode 1, enables receiver TMOD&=0x00F; // Timer 1 in auto-reload mode TMOD|=0x020; TR1=0; // Stops TIMER 1 TH1=(unsigned char)(256-divappr((2*14745600),(384*baud))); // 14.7456 MHz PCON=PCON|0x080; // Sets SMOD=1 for high baud rates TR1=1; // Starts TIMER 1 TI=1; // Sets end of transmission bit for optimized console (SIOTYPE=k) } void clrscr(void) /* Performs the clear screen function for a generic console */ { unsigned char r; putc(CRET); for (r = 0 ; r < 25 ; r++) { putc(LF); // Transmit 25 Line Feeds } //endfor } void notavail(void) /* Shows message of resource not available on selected Mini Module and stop execution */ { printf("Resource not available on Mini Module. "); for(;;); } void delay(unsigned int del) /* Executes a software delay of del milliseconds, calibrated on a 14.7456 MHz CPU Clock */ { unsigned int r,dt1ms; dt1ms=100; // Experimental value for 1 msec. delay do { for (r=0 ; r0); } void setP1234inp(void) /* Sets all the lines of all the ports (P1,P2,P3,P4) del modulo CAN GM1 in input. */ { ADCF=0x00; // Sets P1.x as I/O port P1=0xFF; // Sets Port 1 as INPUT dr=P1; P2=0xFF; // Sets Port 2 as INPUT dr=P2; P3=0xFF; // Sets Port 3 as INPUT dr=P3; P4=0xFF; // Sets Port 4 as INPUT dr=P4; } void riti2c(void) /* Performs a delay for syncronous I2CBUS communication. The delay is sufficient for a 22 MHz clock, X1 modality */ { #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm } void starti2c(void) /* Generates start sequence for I2C BUS */ { if (minmod=='3') { SCL5115=0; // Start sequence with GMM 5115 SDA5115=1; riti2c(); SCL5115=1; SDA5115=0; riti2c(); SCL5115=0; } else { SCLCAN=0; // Start sequence with CAN GMx SDACAN=1; riti2c(); SCLCAN=1; SDACAN=0; riti2c(); SCLCAN=0; } //endif } void stopi2c(void) /* Generates stop sequences for I2C BUS */ { if (minmod=='3') { SCL5115=0; // Stop sequence with GMM 5115 SDA5115=0; riti2c(); SCL5115=1; SDA5115=1; riti2c(); SCL5115=0; } else { SCLCAN=0; // Stop sequence with CAN GMx SDACAN=0; riti2c(); SCLCAN=1; SDACAN=1; riti2c(); SCLCAN=0; } //endif } void wri2c_bit(unsigned char i2cbit) /* Serializes the D0 bit of i2cbit, on I2CBUS */ { if (minmod=='3') { SCL5115=0; // Sets SDA and generates positive pulse on SCL with GMM 5115 SDA5115=i2cbit; riti2c(); SCL5115=1; riti2c(); SCL5115=0; } else { SCLCAN=0; // Sets SDA and generates positive pulse on SCL with CAN GMx SDACAN=i2cbit; riti2c(); SCLCAN=1; riti2c(); SCLCAN=0; } //endif } unsigned char rdi2c_bit(void) /* Deserializes one bit from I2CBUS and saves it on lsb of the returned value */ { unsigned char biti2c; if (minmod=='3') { SDA5115=1; // Avoids conflicts in SDA acquisition SCL5115=0; // Ensures SCL status riti2c(); SCL5115=1; // Generates positive pulse on SCL and reads SDA biti2c=SDA5115; riti2c(); SCL5115=0; } else { SDACAN=1; // Avoids conflicts in SDA acquisition SCLCAN=0; // Ensures SCL status riti2c(); SCLCAN=1; // Generates positive pulse on SCL and reads SDA biti2c=SDACAN; riti2c(); SCLCAN=0; } //endif return biti2c; } void wri2c_byte(unsigned char i2cbyte) /* Serializes the i2cbyte byte on I2CBUS */ { unsigned char b; for (b = 1; b <= 8; b++) { if ((i2cbyte & 0x80) == 0) // Determines and sets b bit wri2c_bit(0); else wri2c_bit(1); i2cbyte = i2cbyte << 1; } } unsigned char peekb(unsigned int addr) /* Reads the byte from addr address of external data area and returns it */ { return *(xdata unsigned char *)addr; // Gets byte from location } void rd_ee(unsigned int eeaddr,unsigned char *eedat) /* Reads the eedat byte from eeaddr address of internal EEPROM */ { AUXR=0x2E; // Deselects ERAM and increase MOVX duration EECON=0x02; // Selects microprocessor EEPROM on external data area *eedat=peekb(eeaddr); // Performs EEPROM reading AUXR=0x0C; // Selects ERAM on external data area EECON=0x00; // Disables microprocessor EEPROM } void inican(unsigned long brc,unsigned char sjw,unsigned char smp,unsigned char prs,unsigned char phs1,unsigned char phs2) /* Initializes the CAN controller with passed parameters: brc = CAN line bit rate (9000..1000000); sjw = bit duration tollerance (0..3); smp = bit sampling number (0..1); prs = bit compensation time (0..7); phs1 = bit presampling time (0..7); phs2 = bit postsampling time (0..7); and updates the global error variable */ { unsigned char mo,nd; P4_0=1; // Sets TxDC high to allow CAN communication nd=P4_0; P4_1=1; // Sets RxDC high to allow CAN coomunication nd=P4_1; CANGCON=0x01; // Resets CAN controller ECAN=0; // Disables CAN interrupt controller ETIM=0; CANGSTA=0x00; // Resets general error flags CANIE2=0x00; // Disables interrupt from message object do { // Cycle that waits card ready dr=P2_1; starti2c(); wri2c_byte(0xA0); dw=rdi2c_bit(); } while ((dr==0) || (dw==1)); for (mo=0; mo<4; mo++) // Initializes the mailbox { CANPAGE=mo << 4; // Selects message object CANCONCH=0x00; // Disables message object CANSTCH=0x00; CANIDT1=0x00; CANIDT2=0x00; CANIDT3=0x00; CANIDT4=0x00; CANIDM1=0x00; CANIDM2=0x00; CANIDM3=0x00; CANIDM4=0x00; for (nd=0; nd<8; nd++) // Resets data into mailbox CANMSG=0x00; } nd=4+prs+phs1+phs2; // Calculates Tscl number for bit nd=divappr(FCAN,(nd*brc)); // Calculates brp prescaler for bit rate nd=nd-1; nd=nd << 1; CANBT1=nd; // Configures bit timing registers nd=sjw << 5; mo=prs << 1; nd=nd | mo; CANBT2=nd; nd=phs2 << 4; mo=phs1 << 1; mo=mo | smp; nd=nd | mo; CANBT3=nd; CANGCON=0x02; // Enables CAN controller; no test; no listening mode } void trbasid(unsigned int id,unsigned char *idh,unsigned char *idl) /* Converts id identificator into the two components bytes in BASIC CAN mode, saved in idl and idh */ { *idh=(unsigned char)(id >> 3); // Determines bits 10..3 of identificator *idl=(unsigned char)(id & 0x07); // Determines bits 2..0 of identificator *idl=*idl << 5; } void txmsgcan(unsigned char *msgcan) /* Transmits, through the CAN controller in BascicCAN=2.0A modality, the message saved in msgcan: msgcan[0] = bytes number of the messagge msgcan[1..n] = messagge datas moreover uses and updates: msgobj = global message object variable id = global identificator variable rtr = global frame type variable errcan = global error variable */ { unsigned char hl,hh; CANPAGE=msgobj << 4; // Selects message object CANIE2=0x00; // Disables interrupt from message object CANSTCH=0x00; // Resets status register trbasid(id,&hh,&hl); // Determines and sets Basic CAN identificator CANIDT1=hh; CANIDT2=hl; CANIDT3=0x00; // Not used in Basic CAN if (rtr) // Verifies and sets Remote Trasmission Request hl=0x04; // RTR=1 else hl=0x00; // RTR=0 CANIDT4=hl; for (hl=1; hl<=msgcan[0]; hl++) CANMSG=msgcan[hl]; // Loads bytes to transmit hl=msgcan[0]; // Gets data n. of the message hl=hl | 0x40; // Adds transmission enable CANCONCH=hl; // Sets data n. and enables Basic CAN transmission CANCONCH=0x88; // Reenables Basic CAN reception } void setrxcan(unsigned int idrx,unsigned int mskrx) /* Configures the CAN controller to receive the msgobj message object in BasicCAN=2.0A modality, with the passed parameters: idrx = reception acceptance identificator (0..2047); mskrx = acceptance mask (0..2047); */ { unsigned char hl,hh; do { // Cycle that waits card ready dr=P2_1; starti2c(); wri2c_byte(0xA0); dw=rdi2c_bit(); } while ((dr==0) || (dw==1)); CANPAGE=msgobj << 4; // Selects message object trbasid(idrx,&hh,&hl); // Determines and sets Basic CAN identificator CANIDT1=hh; CANIDT2=hl; CANIDT3=0x00; // Not used in Basic CAN CANIDT4=0x00; // Sets for data frame trbasid(mskrx,&hh,&hl); // Determines and sets Basic CAN mask CANIDM1=hh; CANIDM2=hl; CANIDM3=0x00; CANIDM4=0x01; // Accepts only Basic CAN messages CANCONCH=0x88; // Enables BASIC CAN reception } unsigned char rxmsgcan(unsigned char *msgcan) /* Controls if CAN controller has received a messagge, in BasicCAN=2.0A modality, and returns a proper boolean flag. Returns also the possible message into msgcan: msgcan[0] = bytes number of the message msgcan[1..n] = message datas moreover uses and updates: msgobj = global message object variable id = global identificator variable rtr = global frame type variable errcan = global error variable */ { unsigned char hl,rxok; CANPAGE=msgobj << 4; // Selects message object hl=CANSTCH; // Gets status register rxok=hl & 0x20; // Checks if message object has received a message CANSTCH=hl & 0xDF; // Resets RXOK flag if (rxok) { hl=CANIDT1; // Gets,determines and saves Basic CAN identificator id=hl << 3; hl=CANIDT2; hl=hl & 0xE0; hl=hl >> 5; id=id | hl; hl=CANIDT4; // Gets,determines and saves Remote Trasmission Request if (hl & 0x04) rtr=0xFF; // RTR=1 else { rtr=0x00; // RTR=0 hl=CANCONCH; // Gets and determines received datas n. hl=hl & 0x0F; msgcan[0]=hl; // Saves received datas n. for (hl=1; hl<=msgcan[0]; hl++) msgcan[hl]=CANMSG; // Gets and saves received data } CANCONCH=0x88; // Reenables Basic CAN reception } return(rxok); } void wtmsgcan(unsigned char *msgcan) /* Waits reception of a message from CAN controller, in BasicCAN=2.0A modality, and returns it into msgcan: msgcan[0] = bytes number of the message msgcan[1..n] = message datas moreover uses and updates: msgobj = global message object variable id = global identificator variable rtr = global frame type variable errcan = global error variable */ { unsigned int tmp; tmp=0; // Resets time out counter do { tmp++; } while ((!rxmsgcan(msgcan)) && (tmp=TOUTCAN) errcan=errcan | 0x40; // Sets timeout error } void checkcan (void) /* Controls error and overrun flags of CAN controller and possibly resets them. Returns the global error variable updated with following bits: errcan.5 -> overflow error errcan.4 -> eco on transmitted bit error errcan.3 -> stuff bit detection error on received message errcan.2 -> errore di crc su messaggio ricevuto errcan.1 -> frame error errcan.0 -> acknowledge detection error */ { unsigned char hl; CANPAGE=msgobj << 4; // Selects message object hl=CANSTCH; // Gets message object status register CANSTCH=hl & 0xE0; // Resets message object error flags hl=hl & 0x1F; // Mask message object error flags errcan=errcan | hl; // Adds message object error flags hl=CANGSTA; // Gets general status register CANGSTA=hl & 0xBF; // Resets general error flags hl=hl & 0x40; // Masks general error flags hl=hl >> 1; // Places general error flags errcan=errcan | hl; // Adds general error flags } /**************************************************************************** Main program ****************************************************************************/ void main(void) { unsigned long bitr; // Variables for CAN demo unsigned int rxmsk,rxid; unsigned char sjw,smp,prs,phs1,phs2; init_cpu(); // Initializes the used CPU iniser(19200); // Initializes serial line for console with timer 1 setP1234inp(); // Sets Port 1,2,3,4 as INPUT clrscr(); // Selects used Mini Module puts("1->CAN GM1 , 2->CAN GM2 , 3->GMM 5115"); printf("Select Mini Module mounted on ZC1 socket (1,2,3):"); do minmod=toupper(getc()); while ((minmod<'1') || (minmod>'3')); switch (minmod) { case '1': puts("CAN GM1"); break; case '2': puts("CAN GM2"); break; case '3': puts("GMM 5115"); break; } //endswitch if (minmod=='3') // Cycle that waits card ready { // on GMM 5115 do rd_ee(0x07F8,&dr); while (dr!=0); } else { // on CAN GM1, CAN GM2 do { dr=P2_1; starti2c(); wri2c_byte(0xA0); dw=rdi2c_bit(); } while ((dr==0) || (dw==1)); } //endif if (minmod!='3') { for(;;) // Endless loop { errcan=0; // Resets global CAN error variable msgobj=0; // Selects message object 0 printf("CAN line demo, on CN4."); printf("\r\nBit rate (9000..1000000) [16600]="); inputse(input, 8); // Gets unsigned long bitr=(unsigned long)atol(input); printf("\r\nBit tolerance (0..3) [3]="); inputse(input, 8); // Gets unsigned char sjw=(unsigned char)atoi(input); printf("\r\nSampling number (0..1) [1]="); inputse(input, 8); // Gets unsigned char smp=(unsigned char)atoi(input); printf("\r\nCompensation time (0..7) [2]="); inputse(input, 8); // Gets unsigned char prs=(unsigned char)atoi(input); printf("\r\nPresampling time (0..7) [3]="); inputse(input, 8); // Gets unsigned char phs1=(unsigned char)atoi(input); printf("\r\nPostsampling time (0..7) [3]="); inputse(input, 8); // Gets unsigned char phs2=(unsigned char)atoi(input); printf("\r\nAcceptance rx Id. (0..2047) [255]="); inputse(input, 8); // Gets unsigned int rxid=(unsigned int)atoi(input); printf("\r\nAcceptance rx mask (0..2047) [0]="); inputse(input, 8); // Gets unsigned int rxmsk=(unsigned int)atoi(input); inican(bitr,sjw,smp,prs,phs1,phs2);// Initializes CAN controller timing setrxcan(rxid,rxmsk); // Initializes CAN messages acceptance puts("\r\nCAN initialized..."); puts("Received messages and errors are displayed. Press T to transmit a message,"); puts("E to exit."); do { if (rxmsgcan(rxbufcan)) // If CAN message received { setrxcan(rxid,rxmsk); // Sets again CAN messages acceptance puts("Received msg:"); // Shows datas of rx message printf("Identificator= %d\r\n",id); printf("Msg type= "); if (rtr) puts("Remote Frame"); else { puts("Data Frame"); printf("Data number = %d\r\n",rxbufcan[0]); for (dr=1; dr <= rxbufcan[0]; dr++) printf("Rx data n. %d = %d\r\n",dr,rxbufcan[dr]); // endfor } // endif putc(LF); } // endif if (kbhit()) // If key pressed { choice=getc(); // Gets the key code and obtain upper case choice=toupper(choice); if (choice == 'T') { puts("Msg to transmit:"); // Requires datas of tx message printf("Identificator (0..2047)="); inputse(input, 8); // Gets unsigned int id=(unsigned int)atoi(input); printf("\r\nMsg type: Data or Remote frame (D/R)="); do { dr=getc(); dr=toupper(dr); } while ((dr != 'D') && (dr != 'R')); if (dr == 'R') { // If remote frame sets flag and there are no data puts("Remote Frame"); rtr=0xFF; } else { // If data frame resets flag and ask data puts("Data Frame"); rtr=0x00; printf("Data number (0..8)="); inputse(input, 8); // Gets unsigned char txbufcan[0]=(unsigned char)atoi(input); for (dr=1; dr <= txbufcan[0]; dr++) { printf("\r\nTx data n. %d (0..255)=",dr); inputse(input, 8); // Gets unsigned char txbufcan[dr]=(unsigned char)atoi(input); } // endfor puts(""); } // endif puts(""); txmsgcan(txbufcan); // Transmit inserted message setrxcan(rxid,rxmsk); // Sets again CAN messages acceptance } // endif } // endif checkcan(); // Controls and manages CAN errors dr=1; // Shows CAN errors do { dw=errcan & dr; // Mask single error flags if (dw) { switch (dw) { case 0x80: break; case 0x40: printf("Elapsed timeout"); break; case 0x20: printf("Overflow"); break; case 0x10: printf("Eco detection"); break; case 0x08: printf("Stuff bit detection"); break; case 0x04: printf("Crc"); break; case 0x02: printf("Frame"); break; case 0x01: printf("Acknowledge"); break; } // endswitch puts(" error"); } // endif dr=dr << 1; } while (dr != 0); errcan=0; // Resets global CAN error variable delay(50); // Delay for cosole } while (choice!='E'); // Waits E key pressed } // endfor (;;) // End of endless loop } else notavail(); // Resource not available on selected Mini Module //endif }