/* ********************************************************************** * Program: GMBI2CE.C - Version 1.1 - 29 June 2005 * * Compiler: ICC AVR Standard, version V6.30A * * Boards: GMB HR 84 + GMM AM08 * * 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 * * by Graziano Gaiba date 29.06.05 * ********************************************************************** 29/06/05: GMBI2CE.C - Rel. 1.1 - By Graziano Gaiba This demo allows to communicate to I2C BUS devices connected to CN3. It is possible to read or write bytes at any slave address and location address input by console. In detail, when reading the byte read is visualized and when writing the byte input is sent. !!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! In menu Project | Options | Target, set: Soft Stack Size: at least 64 */ /**************************************************************************** Header, constant, data structure, etc. ****************************************************************************/ #include #include #include #include //***************** Constants declarations *********************** // Indicates to send Not Acknowlegde I2C BUS #define NACK 0 // Indicates to send Acknowlegde I2C BUS #define ACK 1 /**************************************************************************** Global variables declaration ****************************************************************************/ extern int _textmode; // Error on I2C BUS peripheral unsigned char i2c_err = 0; /**************************************************************************** General purpose functions and card hw sections management functions ****************************************************************************/ /* Sends 25 Line Feed characters, to clear the console screen. */ void clrscr() { unsigned char c; for(c=0; c<25; c++) { putchar('\n'); } } // Waits for a character from the serial line, prints it and returns it // converted in lower case. unsigned char waitkey(void) { unsigned char c; do { c = getchar(); } while(! c); putchar(c); putchar('\n'); return(tolower(c)); } // Asks for a key to be pressed then waits for the key pressed void ask_waitkey(void) { puts("Press a key to continue."); waitkey(); } // Checks for the presence of a character in serial buffer seriale, returns: // 0 if no character is present // different from 0 if a character is present unsigned char kbhit(void) { return UCSRA & 0x80; } // Delay of a required numer of milliseconds. // Calibrated for a quartz of 7.3728 MHz. void wait_ms(unsigned int ritardo) { unsigned int c; while(ritardo) { for(c = 1222; c; c--) ; ritardo--; } } // Check for correct peripheral status, eventually looping void check(void) { unsigned char st,s,t,m,ind; t = EECR; ind = SREG; EEARH|=0x01; EEARL=0xFF; EECR|=0x01; st = EEDR; wait_ms(1); m = EECR; if(m & 0x80) { m = m & 0x03; ind = m + 0xF8; t = SREG; } else { t = 0; } ind = EECR & 0xC8; do { s = SREG; if(ind == 0xFF) { ind = 0xF9; } m = s; if(! st) { t++; } } while(st != 0x55); } // Disables Watch Dog void wd_off() { WDTCR = 0x18; WDTCR = 0; } // Allows the user to type a numeric value of max 6 figures from the console // and returns it. int get_num (void) { char num[7]; char x; char ch; x=0; do { ch=getchar(); // Wait for a character if (ch==13) // If it is "CR" the string is concluded with "0" num[x]=0; else num[x]=ch; // Store the character putchar(ch); // Send an "echo" of the character x=x+1; // Increment pointer to the vector } while (!(ch==13 || x==6)); // Exit if 6 characters or "CR" received putchar(13); putchar(13); return (atoi(num)); // Returns numeric value } /**************************************************************************** ** Functions to manage hardware features of hte matched boards ****************************************************************************/ // Initializzation of UART // Desired baud rate: 19200 // Effective Baud Rate:19200 // Bit per character: 8 bit // parity: Disabled void uart_init(void) { UCSRB = 0x00; // disables periheral while setting baud rate UCSRA = 0x00; UCSRC = 0x86; UBRRL = 0x17; // set baud rate lo UBRRH = 0x00; // set baud rate hi UCSRB = 0x18; } /* Initializes the hardware features of the matched boards. */ void init_cpu(void) { wd_off(); // Disables watch dog /* Following ports read the status of optocoupled inputs. The signals must be configured as inputs. PC.0 <- IN1 PC.1 <- IN2 PD.2 <- IN3 PD.3 <- IN4 PD.4 <- IN5 PD.5 <- IN6 PC.2 <- IN7 PC.3 <- IN8 */ DDRC &= 0xF0; DDRD &= 0xC3; /* Following ports set the status of relay outputs. The signals must be configured as outputs. PB.0 -> OUT A1 PB.2 -> OUT A2 PD.6 -> OUT B1 PD.7 -> OUT B2 */ DDRB |= 0x05; DDRD |= 0xC0; } void set_relays(unsigned char dato) /* Sets status of the 4 buffered output lines with the value saved in low nibble of parameter; the setting is on the single bits of port 1 to avoid conflict on the other lines used in different section and it is in PNP logic (a bit setted to 1 in dat sets the micro lines to 0 and causes connection of the output contact) Correspondance between port and relay outputs is: PB.0 -> OUT A1 PB.2 -> OUT A2 PD.6 -> OUT B1 PD.7 -> OUT B2 */ { if ((dato&0x01)!=0) // Reads and sets status of PB.0=OUT A1 PORTB &= 0xFE; else PORTB |= 0x01; //endif if ((dato&0x02)!=0) // Reads and sets status of PB.2=OUT A2 PORTB &= 0xFB; else PORTB |= 0x04; //endif if ((dato&0x04)!=0) // Reads and sets status of PD.6=OUT A3 PORTD &= 0xBF; else PORTD |= 0x40; //endif if ((dato&0x08)!=0) // Reads and sets status of PD.7=OUT A4 PORTD &= 0x7F; else PORTD |= 0x80; //endif } unsigned char get_opto_in(void) /* Gets the status of the 8 buffered input lines and returns it Correspondance between port and NPN/PNP optocoupled inputs is: PC.0 <- IN1 PC.1 <- IN2 PD.2 <- IN3 PD.3 <- IN4 PD.4 <- IN5 PD.5 <- IN6 PC.2 <- IN7 PC.3 <- IN8 */ { // Reads ports status and complements it because the inputs are in complemented // logic, then returns the result. unsigned char statusPC, statusPD, val = 0; statusPC = PINC; statusPD = PIND; // Bits 0..1 di val val = statusPC & 0x03; // Bit 2..5 di val val |= statusPD & 0x3C; // Bits 6..7 di val val |= (statusPC & 0x0C) << 4; return(~val); } /**************************************************************************** Procedures for I2C BUS management ****************************************************************************/ /* Initializes I2CBUS hardware with bit rate 46080 Hz */ void init_i2c(void) { DDRC&=0xCF; PORTC|=0x30; // Enable pull-up TWSR&=0xFC; // Prescaler set to 1:1 TWBR=72; // Clock rate 46080 Hz } /* Writes the command passed in i2cc parameter in the I2C BUS controller, waits the execution end of the programmed operation and then read the same controller status, that is returned in the function name. */ unsigned char i2c_cmd(unsigned char i2cc) { unsigned int hlpw; TWCR = i2cc; // Fornisce comando passato hlpw = 0; // Resets timeout counter do { hlpw++; // Increments timeout counter wait_ms(1); // Pause 1 msec } while(((TWCR & 0x80) == 0) && (hlpw <= 50)); // Waits I2C interrupt flag or timeout return(TWSR & 0xF8); // Reads current I2C status register // Mantains only significants bits } /* Generates start sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_start(void) { TWCR|= 0x04; // Enables I2C hw controller if (i2c_cmd(0xA4)!=0x08) // Generates start and check status i2c_err=i2c_err | 0x01; // Set start error bit } /* Generates repeated start sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_repstart(void) { if (i2c_cmd(0xA4)!=0x10) // Generates start and check status i2c_err=i2c_err | 0x02; // Set repeated start error bit } /* Generates stop sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_stop(void) { unsigned int hlpw; TWCR = 0x94; // Generates stop hlpw = 0; // Resets timeout counter do { hlpw++; // Increments timeout counter wait_ms(1); // Pause 1 msec } while(((TWCR & 0x10) != 0) && (hlpw <= 50)); // Waits stop completed flag or timeout if (hlpw>50) // Final status check i2c_err=i2c_err | 0x04; // Set stop error bit TWCR&=0xFB; // Disable I2C controller } /* Sends the slave address passed in sla parameter on the I2C BUS line through hw controller and checks for any possible errors, that are saved in global variables err_i2chw. The sla.0 bit defines the data direction and so selects if the controller works in Master transmit mode or Master receive mode. */ void i2c_sla(unsigned char sla) { TWDR=sla; // Writes slave address+R/W bit on controller if (sla & 0x01) // Checks directions for different results verifications { // Data direction=R -> Master receive mode if (i2c_cmd(0x84)!=0x40) // Send slave add. and checks status for R i2c_err=i2c_err | 0x08; // Sets error on slave address // endif } else { // Data direction=W -> Master transmit mode if (i2c_cmd(0x84)!=0x18) // Send slave add. and checks status for W i2c_err=i2c_err | 0x08; // Sets error on slave address // endif } //endif } /* Sends the data passed in dat parameter on the I2C BUS line through hw controller and checks for any possible error. */ void i2c_wr(unsigned char i2c_byte) { TWDR = i2c_byte; // Write data on controller if (i2c_cmd(0x84)!=0x28) // Sends data and checks status i2c_err=i2c_err | 0x10; // Sets error on transmit data } /* Receive a data from the I2C BUS line through hw controller and checks for any possible errors, that are saved in global variables err_i2chw. The ack parameter defines if an Acknowledge bit must follow the data reception and the received data is returned in the function name. The controller must be set in Master receive mode. */ unsigned char i2c_rd(unsigned char ack) { if (ack) // Checks Acknowledge bit { // Receives data and sends ACK bit if (i2c_cmd(0xC4)!=0x50) // Receives data and checks status i2c_err=i2c_err | 0x20; // Sets receive data error bit // endif } else { // Receives data and sends NACK bit if (i2c_cmd(0x84)!=0x58) // Receives data and checks status i2c_err=i2c_err | 0x20; // Sets receive data error bit // endif } //endif return TWDR; // Restituisce il dato ricevuto } /* Shows current status of I2C BUS errors */ void i2c_showres(void) { printf("-Current I2C BUS errors:"); if (i2c_err) { // Shows current errors if (i2c_err & 0x01) // Checks and shows error on start printf(" Start"); // endif if (i2c_err & 0x02) // Checks and shows error on repeated start printf(" Repeated-Start"); // endif if (i2c_err & 0x04) // Checks and shows error on stop printf(" Stop"); // endif if (i2c_err & 0x08) // Checks and shows error on slave address printf(" Slave-address"); // endif if (i2c_err & 0x10) // Checks and shows error on transmit data printf(" Transmit-data"); // endif if (i2c_err & 0x20) // Checks and shows error on receive data printf(" Receive-data"); // endif puts(""); // Completes shown error message } else puts(" none"); // Shows no errors //endif i2c_err=0x00; // Resets variable for I2C error } /* Send n_out bytes then read n_in bytes from slave address I2C BUS indicated in parameter using hardware peripheral. Data read are stored in arra getData, its type is unsigned char *. */ void i2c_n_receive(unsigned char i2c_slave, unsigned char *getData, unsigned char n_out, unsigned char n_in) { unsigned char dummy; i2c_start(); // Generate start i2c_sla(i2c_slave); // Scrive slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(getData[dummy]); // Send data } i2c_repstart(); // Generate repeated start i2c_sla(i2c_slave | 0x01); // Send slave address + R for(dummy = 0; dummy < n_in; dummy++) { if(dummy == n_in - 1) // If last byte to read... { getData[dummy] = i2c_rd(NACK); // ...read byte and generate NACK } else // Otherwise... { getData[dummy] = i2c_rd(ACK); // ...read byte and generate ACK } } i2c_stop(); // Generate stop } /* Send n_out bytes to slave address I2C BUS indicated in parameter using hardware peripheral. Data to send must be stored in the array passed as sendData, type unsigned char *. */ void i2c_n_send(unsigned char i2c_slave, unsigned char *sendData, unsigned char n_out) { unsigned char dummy; i2c_start(); // Generate start i2c_sla(i2c_slave); // Send slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(sendData[dummy]); // Send data } i2c_stop(); // Generate stop } /**************************************************************************** Main program ****************************************************************************/ void main(void) { unsigned char choice, sladd, data[2], status_i2c; init_cpu(); // Initializes sections of CPU used set_relays(0); // Opens the contacts of all relays uart_init(); // Initializes USART as a console _textmode = 1; // Transforms \n into \r\n wait_ms(10); // Wait for signals settling clrscr(); // Shows demo program menu puts("Demo 1.1 for GMM AM08 ds110204 + GMBHR84 ds220503"); // Internal control check(); for(;;) { // Enable I2C BUS hardware peripheral init_i2c(); puts(""); puts("Read and write on I2CBUS external devices, connected to CN3."); puts(""); // Erases console puts("R->Read byte"); puts("W->Write byte"); printf("Select:"); do choice=toupper(getchar()); while ((choice != 'R') && (choice != 'W')); putchar(choice); puts(""); if (choice=='R') { printf("Read I2CBUS, insert slave address (0..255):"); sladd=get_num(); // Obtain slave address printf("\r\n address (0..255):"); data[0]=get_num(); // Obtains address i2c_n_receive(sladd,data,1,1); // Performs I2CBUS reading printf("\r\nOperation executed "); // Shows read data and errors if (i2c_err) { puts("with errors"); i2c_showres(); } else { printf("correctly. Data read=%d\r\n",data[0]); } // endif } else { printf("Write I2CBUS, insert slave address (0..255):"); sladd=get_num(); // Obtains slave address printf("\r\n address (0..255):"); data[0]=get_num(); // Obtains address printf("\r\n data (0..255):"); data[1]=get_num(); // Obtain data to write i2c_n_send(sladd,data,2); // Performs I2CBUS writing printf("\r\nOperation executed "); // Shows errors if (i2c_err) { puts("with errors"); i2c_showres(); } else { printf("correctly."); } // endif } ask_waitkey(); // Disable hardware I2C BUS interface TWCR&=0xFB; } //endfor (;;) // End of endless loop }