Here are some bit-banged I^2C routines that should be easy to understand. They are fairly optimized, with near-minimum instruction count allowable for 4MHz operation.
Tested/bulletproof at 4MHz. Bank switching is provided. Routines exit with Bank 0 selected.;------------------------------------------------------------------------ ; ; I^2C master send/receive routines for 24Cxx EEPROM memory chips ; by Andrew D. Vassallo ; ; email: firstname.lastname@example.org ; ; Timing set for 4MHz clock, 4.7K pullup resistors to SDA and SCL lines. ; Checks provided for failed ACK during EEPROM write access. ; Optimized for speed and clarity of function. ; Full comments provided. ; Bank switching correct. ; ;------------------------------------------------------------------------ ;------ NOTE: Locate all variables in Bank 1!! CBLOCK GenCount ; generic counter/temp register (use with caution) Mem_Loc ; EEPROM memory address to be accessed Data_Buf ; byte read from EEPROM is stored in this register OutputByte ; used for holding byte to be output to EEPROM flags ; flag bit register ENDC ;------ Define port pins: RB2=SDA=data, RB1=SCL=clock ;------ Pins are connected via 4.7K pullup resistors for passive control ;------ Any port pins can be used. #define SDA TRISB, 2 #define SCL TRISB, 1 ;------ The memory address is predefined as Mem_Loc coming in to this routine to read from EPROM. ;------ Note that using the 24Cxx requires an address for bits <1:3> for control bytes. For a one- ;------ memory circuit used here, just use address 000. This routine uses "random addressing." ;------ This code has been optimized for speed at 4MHz, assuming Temperature is between -40 and +85 deg. C. ; ; Call with: EEPROM address in Mem_Loc ; Returns with: byte in Data_Buf ReadEPROM bcf STATUS, RP0 movf PORTB, 0 ; for EEPROM operation, andlw 0xF9 ; load zero into RB1 and RB2 movwf PORTB ; for passive control of bus bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) bsf SDA ; let SDA line get pulled high bsf SCL ; let SCL line get pulled high bcf SDA ; START - data line low movlw 0xA0 ; send "dummy" write (10100000) to set address call Byte_Out btfsc flags, 0 goto Error_Routine ; NOTE: MUST USE "RETURN" FROM THERE movf Mem_Loc, 0 call Byte_Out btfsc flags, 0 goto Error_Routine bcf SCL ; pull clock line low in preparation for 2nd START bit nop bsf SDA ; pull data line high - data transition during clock low bsf SCL ; pull clock line high to begin generating START bcf SDA ; 2nd START - data line low movlw 0xA1 ; request data read from EPROM (read=10100001) call Byte_Out btfsc flags, 0 goto Error_Routine ;------ Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master. call Byte_In movf Data_Buf, 0 ; put result into W register for returning to CALL bcf SCL ; extra cycle for SDA line to be freed from EPROM nop bcf SDA ; ensure SDA line low before generating STOP bsf SCL ; pull clock high for STOP bsf SDA ; STOP - data line high bcf STATUS, RP0 ; leave with Bank 0 active as default return ;------ Save each byte as it's written (not page write mode). ;------ We can speed this up to ~1.5ms for fast page write capable EEPROMs, but in case we want to ;------ use another slower memory chip, the default is 10ms delay per write. ; ; Call with: EEPROM address in Mem_Loc, byte to be sent in Data_Buf ; Returns with: nothing returned WriteEPROM bcf STATUS, RP0 movf PORTB, 0 ; for EEPROM operation, andlw 0xF9 ; load zero into RB1 and RB2 movwf PORTB ; for passive control of bus bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) bsf SDA ; ensure SDA line is high bsf SCL ; pull clock high bcf SDA ; START - data line low movlw 0xA0 ; send write (10100000) to set address call Byte_Out btfsc flags, 0 goto Error_Routine ; NOTE: MUST USE "RETURN" FROM THERE movf Mem_Loc, 0 call Byte_Out btfsc flags, 0 goto Error_Routine movf Data_Buf, 0 ; move data to be sent to W call Byte_Out btfsc flags, 0 goto Error_Routine bcf SCL ; extra cycle for SDA line to be freed from EPROM nop bcf SDA ; ensure SDA line low before generating STOP bsf SCL ; pull clock high for STOP bsf SDA ; STOP - data line high call Delay10ms ; 10ms delay max. required for EPROM write cycle bcf STATUS, RP0 ; leave with Bank 0 active by default return ;------ This routine reads one byte of data from the EPROM into Data_Buf Byte_In clrf Data_Buf movlw 0x08 ; 8 bits to receive movwf GenCount ControlIn rlf Data_Buf, 1 ; shift bits into buffer bcf SCL ; pull clock line low nop bsf SCL ; pull clock high to read bit bcf STATUS, RP0 ; select Bank 0 to read PORTB bits directly! btfss SDA ; test bit from EPROM (if bit=clear, skip because Data_Buf is clear) goto $+3 bsf STATUS, RP0 ; select Bank 1 to access variables bsf Data_Buf, 0 ; read bit into 0 first, then eventually shift to 7 bsf STATUS, RP0 ; select Bank 1 to access variables decfsz GenCount, 1 goto ControlIn return ;------ This routine sends out the byte in the W register and then waits for ACK from EPROM (256us timeout period) Byte_Out movwf OutputByte movlw 0x08 ; 8 bits to send movwf GenCount rrf OutputByte, 1 ; shift right in preparation for next loop ControlOut rlf OutputByte, 1 ; shift bits out of buffer bcf SCL ; pull clock line low nop btfsc OutputByte, 7 ; send current "bit 7" goto BitHigh bcf SDA goto ClockOut BitHigh bsf SDA ClockOut bsf SCL ; pull clock high after sending bit decfsz GenCount, 1 goto ControlOut bcf SCL ; pull clock low for ACK change bsf SDA ; free up SDA line for slave to generate ACK nop nop nop ; wait for slave to pull down ACK bsf SCL ; pull clock high for ACK read clrf GenCount ; reuse this register as a timeout counter (to 256us) to test for ACK WaitForACK bsf STATUS, RP0 ; select Bank1 for GenCount access incf GenCount, 1 ; increase timeout counter each time ACK is not received btfsc STATUS, Z goto No_ACK_Rec bcf STATUS, RP0 ; select Bank0 to test SDA PORTB input directly! btfsc SDA ; test pin. If clear, EEPROM is pulling SDA low for ACK goto WaitForACK ; ...otherwise, continue to wait bsf STATUS, RP0 ; select Bank1 as default during these routines bcf flags, 0 ; clear flag bit (ACK received) return ;------ No ACK received from slave (must use "return" from here) ;; Typically, set a flag bit to indicate failed write and check for it upon return. No_ACK_Rec bsf flags, 0 ; set flag bit return ; returns to Byte_Out routine (Bank 1 selected) ;------ No ACK received from slave. This is the error handler. Error_Routine ; Output error message, etc. here bcf STATUS, RP0 ; select Bank0 as default before returning home return ; returns to INITIAL calling routine Delay10ms movlw 0x0A movwf GenCount Delay_Start nop movlw 0x07 ; 249 cycles * 4us per cycle + 5us = 1.000ms Delay addlw 0x01 btfss STATUS, Z goto Delay decfsz GenCount, 1 goto Delay_Start return
PICList post "IIC Routines - giving, not needing"
I am currently exploring the capabilities of i2c. We are using the picdem.net demo board from Microchip and what I want to do is write to and read to the eeprom (24LC256) on the demo board using a pic18c452 microchip. I'm using assembler sample code I got from the Microchip site, but I can't seem to get the i2c up and running. The demo board has a OscFreq of 19.66 MHz, so maybe I got the i2c clock rate wrong?Or maybe I don't set the configuration bits correctly. I don't think there is anything wrong with the code. I would much appreciate any help you can give me. With this email I will include the sample assembler code I'm using. Thank you in advance Andre Steenkamp
Hello, All I can find on the Internet are assembler sources that allow the PIC to be an I2C MASTER. That's exactly what I need. But when you want your PIC master to communicate with a PC, you need I2C slave software for the PC. And that's where the problem is. There is no such thing as as PC I2C SLAVE. Well... Not that I can find one. What I need is a simple piece of software for the PIC and PC so the PIC can send a few bytes of data to the PC every 100ms. This doesn't HAVE to be I2C... Thanks to anyone who can point me in the right direction. Kees
|file: /Techref/microchip/i2c-dv.htm, 11KB, , updated: 2013/11/25 15:51, local time: 2022/6/25 19:39,
|©2022 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?|
<A HREF="http://piclist.com/techref/microchip/i2c-dv.htm"> PIC Microcontoller Input / Output Methods for I2C</A>
|Did you find what you needed?|
We sell a few items to support this site
Welcome to piclist.com!