Mercurial > public > mk2
diff code_part1/OSTC_code_asm_part1/i2c_eeprom.asm @ 0:96a35aeda5f2
Initial setup
author | heinrichsweikamp |
---|---|
date | Tue, 12 Jan 2010 15:05:59 +0100 |
parents | |
children | 73014f788032 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/code_part1/OSTC_code_asm_part1/i2c_eeprom.asm Tue Jan 12 15:05:59 2010 +0100 @@ -0,0 +1,365 @@ + +; OSTC - diving computer code +; Copyright (C) 2008 HeinrichsWeikamp GbR +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; You should have received a copy of the GNU General Public License +; along with this program. If not, see <http://www.gnu.org/licenses/>. +; provides routines for external EEPROM via I2C +; written by: Matthias Heinrichs, info@heinrichsweikamp.com +; written: 10/30/05 +; last updated: 08/21/06 +; known bugs: +; ToDo: use 2nd 32KB from external EEPROM for something + +incf_eeprom_address macro ext_ee_temp1 ; Will increase eeprom_address:2 with the 8Bit value "ext_ee_temp1" and takes + movlw ext_ee_temp1 ; care of bank switching at 0x8000 + call incf_eeprom_address0 + endm + +incf_eeprom_address0: + movwf ext_ee_temp1 +incf_eeprom_address1: + movlw d'1' ; increase address + addwf eeprom_address+0,F + movlw d'0' + addwfc eeprom_address+1,F + btfss eeprom_address+1,7 ; at address 8000? + bra incf_eeprom_address2 ; No, continue + + ; Yes, clear eeprom_address:2 + clrf eeprom_address+0 ; Clear eeprom address + clrf eeprom_address+1 + +incf_eeprom_address2: + decfsz ext_ee_temp1,F ; All done? + bra incf_eeprom_address1 ; No, continue + return ; Done. + +decf_eeprom_address macro ext_ee_temp1 ; Will decrease eeprom_address:2 with the 8Bit value "ext_ee_temp1" and takes + movlw ext_ee_temp1 ; care of bank switching at 0x8000 + call decf_eeprom_address0 + endm + +decf_eeprom_address0: + movwf ext_ee_temp1 +decf_eeprom_address1: + movlw d'1' ; decrease address + subwf eeprom_address+0,F + movlw d'0' + subwfb eeprom_address+1,F + + btfss eeprom_address+1,7 ; at address 8000? + bra decf_eeprom_address2 ; No, continue + + movlw b'01111111' ; yes, reset highbyte + movwf eeprom_address+1 + +decf_eeprom_address2: + decfsz ext_ee_temp1,F ; All done? + bra decf_eeprom_address1 ; No, continue + return ; Done. + + +write_external_eeprom: ; data in WREG + ; increase address eeprom_address+0:eeprom_address+1 after write + ; with banking after 7FFF + rcall I2CWRITE ; writes WREG into EEPROM@eeprom_address + movlw d'1' ; increase address + addwf eeprom_address+0,F + movlw d'0' + addwfc eeprom_address+1,F + bcf eeprom_overflow + btfss eeprom_address+1,7 ; at address 8000? + return ; no, return + + clrf eeprom_address+0 ; Clear eeprom address + clrf eeprom_address+1 + bsf eeprom_overflow ; and set overflow bit + return +write_external_eeprom_block: ; Writes a block of 64Byte (one page in external EEPROM without stop condition + btfsc eeprom_blockwrite ; Blockwrite continue? + rcall I2CWRITE_BLOCK2 + btfss eeprom_blockwrite ; Blockwrite start? + rcall I2CWRITE_BLOCK + bsf eeprom_blockwrite ; After the start, do blockwriting for the next 63Bytes! + + movlw d'0' ; increase address + incf eeprom_address+0,F + addwfc eeprom_address+1,F + bcf eeprom_overflow + + btfss eeprom_address+1,7 ; at address 8000 + return ; no, return + + clrf eeprom_address+0 ; Clear eeprom address + clrf eeprom_address+1 + bsf eeprom_overflow ; and set overflow bit + return +I2CWRITE_BLOCK: + movwf ext_ee_temp1 ; Data byte in WREG + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10100110' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff eeprom_address+1,SSPBUF ; High Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff eeprom_address+0,SSPBUF ; Low Address byte + rcall WaitMSSP + rcall I2C_WaitforACK +I2CWRITE_BLOCK2: + movff ext_ee_temp1, SSPBUF ; Data Byte + rcall WaitMSSP + rcall I2C_WaitforACK + return + + +get_free_EEPROM_location: ; Searches 0xFD, 0xFD, 0xFE and sets Pointer to 0xFE + clrf ext_ee_temp1 ; low address counter + clrf ext_ee_temp2 ; high address counter + bcf second_FD ; clear flags + bcf first_FD +get_free_EEPROM_location3: + bsf SSPCON2, PEN ; Stop condition + rcall WaitMSSP + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10100110' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + btfsc SSPCON2,ACKSTAT + bra get_free_EEPROM_location3 ; EEPROM NOT acknowledged, retry! + + movff ext_ee_temp2,SSPBUF ; High Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff ext_ee_temp1,SSPBUF ; Low Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + + bsf SSPCON2,RSEN ; Start condition + rcall WaitMSSP + movlw b'10100111' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + +get_free_EEPROM_location2: + bsf SSPCON2, RCEN ; Enable recieve mode + rcall WaitMSSP + btfsc first_FD + bra test_2nd_FD + bsf first_FD ; found first 0xFD? + movlw 0xFD + cpfseq SSPBUF + bcf first_FD ; No + bra get_free_EEPROM_location2c + +test_2nd_FD: + btfsc second_FD + bra test_FE + bsf second_FD ; found second 0xFD? + movlw 0xFD + cpfseq SSPBUF + bra get_free_EEPROM_location2b ;No, clear both flags + bra get_free_EEPROM_location2c +test_FE: + movlw 0xFE ; found the final 0xFE? + cpfseq SSPBUF + bra get_free_EEPROM_location2b ;No, clear both flags + movff ext_ee_temp1,eeprom_address+0 ;Yes, copy ext_ee_temp1->eeprom_address+0 and + movff ext_ee_temp2,eeprom_address+1 ;ext_ee_temp2->eeprom_address+1 + bra get_free_EEPROM_location4 ; Done. + +get_free_EEPROM_location2b: + bcf second_FD ; clear both flags! + bcf first_FD +get_free_EEPROM_location2c: + movlw d'1' ; and increase search address + addwf ext_ee_temp1,F + movlw d'0' + addwfc ext_ee_temp2,F + + btfsc ext_ee_temp2,7 ; 8000 reached? + bra get_free_EEPROM_location3b ; yes + + bsf SSPCON2, ACKEN ; no, send Ack + rcall WaitMSSP + bra get_free_EEPROM_location2 ; and continue search +get_free_EEPROM_location3b: + clrf eeprom_address+0 ; Not found in entire EEPROM, set to address 0 + clrf eeprom_address+1 +get_free_EEPROM_location4: + bsf SSPCON2, PEN ; Stop + rcall WaitMSSP + + bcf second_FD ; clear flags + bcf first_FD + return ; return + + +I2CREAD: + bsf SSPCON2, PEN ; Stop + rcall WaitMSSP + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10100110' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + btfsc SSPCON2,ACKSTAT + bra I2CREAD ; EEPROM NOT acknowledged, retry! + movff eeprom_address+1,SSPBUF ; High Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff eeprom_address+0,SSPBUF ; Low Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + + bsf SSPCON2,RSEN ; Start condition + rcall WaitMSSP + movlw b'10100111' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + + bsf SSPCON2, RCEN ; Enable recieve mode + rcall WaitMSSP + movf SSPBUF,W ; copy read byte into WREG + bsf SSPCON2, PEN ; Stop + rcall WaitMSSP + return + +I2CREAD2: ; same as I2CREAD but with automatic address increase + rcall I2CREAD + movlw d'1' + addwf eeprom_address+0,F + movlw d'0' + addwfc eeprom_address+1,F + bcf eeprom_overflow + btfss eeprom_address+1,7 ; at 0x8000? + return ; no, return + + clrf eeprom_address+0 ; Yes, clear address + clrf eeprom_address+1 + bsf eeprom_overflow ; and set overflow bit + return + +I2CWRITE: + movwf ext_ee_temp1 ; Data byte + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10100110' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff eeprom_address+1,SSPBUF ; High Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff eeprom_address+0,SSPBUF ; Low Address byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff ext_ee_temp1, SSPBUF ; Data Byte + rcall WaitMSSP + rcall I2C_WaitforACK + bsf SSPCON2,PEN ; Stop condition + rcall WaitMSSP + WAITMS d'6' ; Write delay + return + +I2C_WaitforACK: + btfsc SSPCON2,ACKSTAT ; checks for ACK bit from slave + rcall I2CFail + return + +I2CFail: + ostc_debug 'M' ; Sends debug-information to screen if debugmode active + call set_LEDy + rcall I2CReset ; I2C Reset + bcf PIR1,SSPIF + clrf i2c_temp + return + +WaitMSSP: + decfsz i2c_temp,F ; check for timeout during I2C action + bra WaitMSSP2 + bra I2CFail ; timeout occured +WaitMSSP2: + btfss PIR1,SSPIF + bra WaitMSSP + clrf i2c_temp + bcf PIR1,SSPIF + return + +I2CReset: ; Something went wrong (Slave holds SDA low?) + clrf SSPCON1 ; wake-up slave and reset entire module + ostc_debug 'N' ; Sends debug-information to screen if debugmode active + clrf SSPCON2 + clrf SSPSTAT + bcf TRISC,3 ; SCL OUTPUT + bsf TRISC,4 ; SDA Input + bcf PORTC,3 + movlw d'9' + movwf i2c_temp ; clock-out 9 clock cycles manually +I2CReset_1: + bsf PORTC,3 ; SCL=1 + nop + btfsc PORTC,4 ; SDA=1? + bra I2CReset_2 ; =1, SDA has been released from slave + bcf PORTC,3 ; SCL=0 + bcf PORTC,3 + decfsz i2c_temp,F + bra I2CReset_1 ; check for nine clock cycles +I2CReset_2: + bsf TRISC,3 ; SCL Input + clrf SSPCON1 ; set I²C Mode + WAITMS d'10' ; Reset-Timeout for I2C devices + movlw b'00000000' + movwf SSPSTAT + movlw b'00101000' + movwf SSPCON1 + movlw b'00000000' + movwf SSPCON2 + movlw d'8' ; 400kHz I2C clock @ 16MHz Fcy + movwf SSPADD + call clear_LEDy + ostc_debug 'O' ; Sends debug-information to screen if debugmode active + return +I2C_TX: + movwf i2c_temp2 ; Data byte + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10010000' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + movff i2c_temp2, SSPBUF ; Data Byte + rcall WaitMSSP + rcall I2C_WaitforACK + bsf SSPCON2,PEN ; Stop condition + rcall WaitMSSP + return +I2C_RX: + bcf PIR1,SSPIF + bsf SSPCON2,SEN ; Start condition + rcall WaitMSSP + movlw b'10010001' ; Bit0=0: WRITE, Bit0=1: READ + movwf SSPBUF ; control byte + rcall WaitMSSP + rcall I2C_WaitforACK + bsf SSPCON2, RCEN ; Enable recieve mode + rcall WaitMSSP + movff SSPBUF,i2c_temp2 ; Data Byte + bsf SSPCON2,ACKEN ; Master acknowlegde + rcall WaitMSSP + bsf SSPCON2,PEN ; Stop condition + rcall WaitMSSP + return \ No newline at end of file