/* 12CE67x EEPROM access routines, ported to CCS C These routines use the original assembler routines from Microchip, wrapped into C functions. The assembler source was taken from the FL67XINC.ASM file from Microchip, Inc. You access the EEPROM by setting eedata and eeaddr if necessary, then call the appropriate routine: access_eeprom(access_type) This will return 1 if the function was performed, 0 if not (due to busy EEPROM and the like) The valid access_types are (just like the Microchip routine names) WRITE_BYTE READ_RANDOM READ_CURRENT These routines are faster than the CCS examples since they use acknowledge test to indicate when the EEPROM is ready for more access, while the CCS routines just wait 11ms after writes. WARNING! If this is used on a device with 2K or more of ROM, you must ensure the Goto_Jump_Table does not fall across an 11 bit boundary. Otherwise the goto may not function since PCLATH is NOT preloaded. See AN556 from Microchip for more info. This routine is for 4MHz only! */ // Label defs for routines #define OK 0x01 #define NO 0x00 #define YES 0x01 #define MAYBE 0x02 #define I2C_PORT 0x05 #define SCL 0x07 #define SDA 0x06 #define EE_OK 0x07 #define STATUS 0x03 #define C 0x00 #define PCLATH 0x0A #define PCL 0x02 // access_eeprom function constants #define READ_CURRENT 0x84 #define READ_RANDOM 0x83 #define WRITE_BYTE 0x80 // Global variables used by routines int eeaddr, eedata; // // access_eeprom // // This contains the bulk of the Microchip assembler for accessing the internal // EEPROM. You must set PC_OFFSET prior to calling this for proper operation // If you use the predefined routines at the end, they do it for you boolean access_eeprom(int pc_offset) { int ee_counter, eebyte; TRY_AGAIN: restart_wdt(); if (pc_offset == READ_CURRENT) { // No need to setup SCL/SDA goto INIT_READ_CONTROL; } else { // We setup the control byte here and keep going #ASM MOVLW 0b10100000 // Control byte with write bit, bit 0 = '0' #ENDASM } #ASM START_BIT: BCF I2C_PORT,SDA // Start bit, SDA and SCL preset to '1' //******* Set up output data (control, address, or data) and EE_COUNTER ******** //*************************************************************************** PREP_TRANSFER_BYTE: MOVWF EEBYTE // Byte to transfer to EEPROM already in W MOVLW 8 // EE_COUNTER to transfer 8 bits MOVWF EE_COUNTER //************ Clock out data (control, address, or data) byte ************ //*************************************************************************** OUTPUT_BYTE: NOP BCF I2C_PORT,SCL // Set clock low during data set-up RLF EEBYTE, F // Rotate left, high order bit into carry bit BCF I2C_PORT,SDA // Set data low, if rotated carry bit is BTFSC STATUS,C // a '1', then: BSF I2C_PORT,SDA // reset data pin to a one, otherwise leave low NOP BSF I2C_PORT,SCL // clock data into EEPROM DECFSZ EE_COUNTER, F // Repeat until entire byte is sent GOTO OUTPUT_BYTE NOP // Needed to meet Timing (Thigh=4000nS) //************************** Acknowledge Check ***************************** //*************************************************************************** BCF I2C_PORT,SCL // Set SCL low, 0.5us < ack valid < 3us NOP // Needed to meet Timing (Tlow= 4700nS) BSF I2C_PORT,SDA // set data line high to check for acknowledge // GOTO $+1 GOTO SET_SCL_HIGH SET_SCL_HIGH: BSF I2C_PORT,SCL // Raise SCL, EEPROM acknowledge still valid NOP // Tsu:dat (allow time for ack setup) BTFSC I2C_PORT,SDA // Check SDA for acknowledge (low) BCF PC_OFFSET,EE_OK // If SDA not low (no ack), set error flag BCF I2C_PORT,SCL // Lower SCL, EEPROM release bus BTFSS PC_OFFSET,EE_OK // If no error continue, else stop bit GOTO STOP_BIT //***** Set up program EE_COUNTER offset, based on EEPROM operating mode ***** //*************************************************************************** // // NOTE! If we fall across value here we are screwed! Not sure how to handle this // // movlw HIGH Goto_Jump_Table // get high order bits of current address // movwf PCLATH MOVF PC_OFFSET,W ANDLW 0b00000111 Goto_Jump_Table: ADDWF PCL, F GOTO INIT_ADDRESS //PC offset=0, write control done, send address GOTO INIT_WRITE_DATA //PC offset=1, write address done, send data GOTO STOP_BIT //PC offset=2, write done, send stop bit GOTO INIT_ADDRESS //PC offset=3, write control done, send address GOTO INIT_READ_CONTROL //PC offset=4, send read control GOTO READ_BIT_EE_COUNTER //PC offset=5, set EE_COUNTER and read byte GOTO STOP_BIT //PC offset=6, random read done, send stop //********** Initalize EEPROM data (address, data, or control) bytes ****** //*************************************************************************** INIT_ADDRESS: INCF PC_OFFSET, F // Increment PC offset to 2 (write) or to 4 (read) MOVF EEADDR,W // Put EEPROM address in W, ready to send to EEPROM GOTO PREP_TRANSFER_BYTE INIT_WRITE_DATA: INCF PC_OFFSET, F // Increment PC offset to go to STOP_BIT next MOVF EEDATA,W // Put EEPROM data in W, ready to send to EEPROM GOTO PREP_TRANSFER_BYTE INIT_READ_CONTROL: BSF I2C_PORT,SCL // Raise SCL BSF I2C_PORT,SDA // raise SDA INCF PC_OFFSET, F // Increment PC offset to go to READ_BIT_EE_COUNTER next MOVLW 0b10100001 // Set up read control byte, ready to send to EEPROM GOTO START_BIT // bit 0 = '1' for read operation //************************** Read EEPROM data ***************************** //*************************************************************************** READ_BIT_EE_COUNTER: BSF I2C_PORT,SDA // set data bit to 1 so we're not pulling bus down. NOP BSF I2C_PORT,SCL MOVLW 0x08 // Set EE_COUNTER so 8 bits will be read into EEDATA MOVWF EE_COUNTER READ_BYTE: BSF I2C_PORT,SCL // Raise SCL, SDA valid. SDA still input from ack BSF STATUS,C // Assume bit to be read = 1 BTFSS I2C_PORT,SDA // Check if SDA = 1 BCF STATUS,C // if SDA not = 1 then clear carry bit RLF EEDATA, F // rotate carry bit (=SDA) into EEDATA// BCF I2C_PORT,SCL // Lower SCL BSF I2C_PORT,SDA // reset SDA DECFSZ EE_COUNTER, F // Decrement EE_COUNTER GOTO READ_BYTE // Read next bit if not finished reading byte BSF I2C_PORT,SCL NOP BCF I2C_PORT,SCL //****************** Generate a STOP bit and RETURN *********************** //*************************************************************************** STOP_BIT: BCF I2C_PORT,SDA // SDA=0, on TRIS, to prepare for transition to '1' BSF I2C_PORT,SCL // SCL = 1 to prepare for STOP bit CALL DELAY4 // wait 4 cycles Tsu:sto (4.7 us) BSF I2C_PORT,SDA // Stop bit, SDA transition to '1' while SCL high BTFSS PC_OFFSET,EE_OK // Check for error // RETLW NO // if error, send back NO GOTO TRY_AGAIN // Loop back and try again RETLW OK // if no error, send back OK DELAY4: RETLW 0 //**************************************************************************** //************************ End EEPROM Subroutines ************************** #ENDASM }