An I2C bus driver in pseudo codeIt is written in PseudoCode which is an imaginary programming language that any programmer should be capable of porting to his/her favorite language. First we will define a set of basic interface routines. All text between / / is considered as remark. Following variables are used :
/ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ / / **** I2C Driver V1.1 Written by V.Himpe. Released as Public Domain **** / / $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ / DECLARE N,SIZE,BUFFER,X Byte DECLARE DATA() Array of SIZE elements SUBroutine I2C_INIT / call this immediately after power-on / SDA=1 SCK=0 FOR n = 0 to 3 CALL STOP NEXT n ENDsub SUBroutine START SCK=1 / BUGFIX !/ SDA=1 / Improvement / SDA=0 SCK=0 SDA=1 ENDsub SUBroutine STOP SDA=0 SCK=1 SDA=1 ENDsub SUBroutine PUTBYTE(BUFFER) FOR n = 7 TO 0 SDA= BIT(n) of BUFFER SCK=1 SCK=0 NEXT n SDA=1 ENDsub SUBroutine GETBYTE FOR n = 7 to 0 SCK=1 BIT(n) OF BUFFER = SDA SCK=0 NEXT n SDA=1 ENDsub SUBroutine GIVEACK SDA=0 SCK=1 SCK=0 SDA=1 ENDsub SUBroutine GETACK SDA=1 SCK=1 WAITFOR SDA=0 SCK=0 ENDSUB / this concludes the low-level set of instructions for the I2C driver The next functions will handle the telegram formatting on a higher level / SUBroutine READ(Device_address,Number_of_bytes) Device_adress=Device_adress OR (0000.0001)b /This sets the READ FLAG/ CALL START CALL PUTBYTE(Device_adress) CALL GETACK FOR x = 0 to Number_of_bytes CALL GETBYTE DATA(x)=BUFFER /Copy received BYTE to DATA array / IF X< Number_of_bytes THEN /Not ack the last byte/ CALL GIVEACK END IF NEXT x CALL STOP ENDsub SUBroutine WRITE(Device_address,Number_of_bytes) Device_adress=Device_adress AND (1111.1110)b / This clears READ flag / CALL START CALL PUTBYTE(Device_adress) CALL GETACK FOR x = 0 to Number_of_bytes CALL PUTBYTE (DATA(x)) CALL GETACK NEXT x CALL STOP ENDsub SUBroutine RANDOMREAD(Device_adress,Start_adress,Number_of_bytes) Device_adress=Device_adress AND (1111.1110)b / This clears READ flag / CALL START CALL PUTBYTE(Device_adress) CALL GETACK CALL PUTBYTE(Start_adress) CALL GETACK CALL START /create a repeated start condition/ Device_adress=Device_adress OR (0000.0001)b /This sets the READ FLAG/ CALL PUTBYTE(Device_adress) CALL GETACK FOR x = 0 to Number_of_bytes CALL GETBYTE DATA(x)=BUFFER CALL GIVEACK NEXT x CALL STOP ENDsub SUBroutine RANDOMWRITE(Device_adress,Start_adress,Number_of_bytes) Device_adress=Device_adress AND (1111.1110)b / This clears READ flag / CALL START CALL PUTBYTE(Device_adress) CALL GETACK CALL PUTBYTE(Start_adress) CALL GETACK FOR x = 0 to Number_of_bytes CALL PUTBYTE (DATA(x)) CALL GETACK NEXT x CALL STOP ENDsub / $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ / / **** I2C Driver . (c)95-97 V.Himpe . Public Domain release *** / / $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ / Some notes about the high level routines. The READ and WRITE routine read / write one or more byte(s) from / to a slave device. Generally this will be used only with Number_of_bytes set to 1. An example: PCD8574=(0100.0000)b CALL READ(PCD8574,1) result = DATA(0) / will read the status of the 8 bit input port of a PCD8574. / DATA(0)=(0110.01010)b CALL WRITE(PCD8574,1) / will write 0110.0101 to the 8 bit port of the PCD8574 / When do you need a multi-read ? Consider a PCF8582 EEPROM. You want to read its contents in one time. PCF8582=(1010.0000)b CALL READ(PCF8582,255) You can do the same with WRITE for the EEPROM with the restriction that Number_of_bytes is not larger than 4 AND that you write on page boundaries (multiple of 4 for offset). You will have to check the components datasheets. The most useful instructions are RANDOMREAD and RANDOMWRITE. Write 4 bytes of data to location 20h of the EEPROM: DATA(0)=(1010.0011)b DATA(1)=(1110.0000)b DATA(2)=(0000.1100)b DATA(3)=(1111.0000)b CALL RANDOMWRITE (PCF8582,(20)h,3) The same goes for reading 16 bytes from the EEPROM starting at address 42h: CALL RANDOMREAD(PCF8582,(42)h,15) The results are stored in DATA. All you have to do is read them out of the array for processing. When you give the devices address to these routines you don't have to care about the R/W flag. It will be automatically set to the right state inside the routines. |
ESAcademy, 2000 All materials |