0
\$\begingroup\$

I have this project communicating MPR121 capacitive touch sensing keyboard with 8051 microcontroller, with some references I've implemented some I2C code for serial communication between master and slave, and I wanted to know whether the slave is responding to transmitted data, so whenever master sends the slave address and some other register or data I wanted to know whether there is a ACK or a NACK and show 1 in the 7seg display when is NACK as in 1-SDA high OR show 0 in 2nd 7seg display as in 0-SDA low, so I made

    MOV P1,#00000001B 
    MOV P0, #00000111B ; when NACK 

    MOV P1,#00000010B    
    MOV P0, #01111111B ; when ACK

But the problem is that even with the right and the wrong slave address 0 is showing in the display, where I'm wrong, and btw I tried this code and technique with some other sensor and it worked, is my sensor gone or my code wrong help please ..

Here is all the code:

; MPR121 Address 
slaveaddr EQU 10110100B

; I2C connections
SCLPin     BIT     P3.6           ;I2C serial clock line.
SDAPin     BIT     P3.7           ;I2C serial data line.
IRQ        BIT     P3.2

; I2C Data storage locations
BitCnt     DATA    8H             ;Bit counter for I2C routines.
ByteCnt    DATA    9H             ;Byte counter for I2C routines.
SlvAdr     DATA    0DH            ;Slave address for I2C routines.

SndDat     DATA    21H            ;I2C transmit buffer, 4 bytes max.
RcvDat     DATA    25H            ;I2C receive buffer, X bytes max.

Flags      DATA    20H            ;Location for bit flags
MPR_REG    DATA    0CH        ;Location for QMC bit flags
MPR_STATUS DATA    2BH        ;QMC Status Register (06H in QMC)
MPR_RNG    DATA    2CH        ;QMC Range (2G or 8G)
NoAck      BIT     Flags.0        ;I2C no acknowledge flag.
BusFault   BIT     Flags.1        ;I2C bus fault flag.
I2CBusy    BIT     Flags.2        ;I2C busy flag.



org 0
 ljmp reset

    org 30H




;##############################
; I2C ROUTINES                #
;##############################

BitDly:    NOP                    ;NOPs to delay  
           NOP                        
           RET


; SCLHigh - sends SCL pin high and waits for any clock stretching peripherals.

SCLHigh:   SETB    SCLPin         ;Set SCL from our end.
           JNB     SCLPin,$       ;Wait for pin to actually go high.
           RET


; SendStop - sends an I2C stop, releasing the bus.

SendStop:  CLR     SDAPin         ;Get SDA ready for stop.
           ACALL   SCLHigh        ;Set clock for stop.
           ACALL   BitDly
           SETB    SDAPin         ;Send I2C stop.
           ACALL   BitDly
           CLR     I2CBusy        ;Clear I2C busy status.
           RET                    ;Bus should now be released.


; SendByte - sends one byte of data to an I2C slave device.
; Enter with:
;   ACC = data byte to be sent.

SendByte:  MOV     BitCnt,#8      ;Set bit count.
SBLoop:    CLR     C           
           RLC     A              ;Send one data bit.
           MOV     SDAPin,C       ;Put data bit on pin.
           ACALL   SCLHigh        ;Send clock.
           ACALL   BitDly
           CLR     SCLPin
           ACALL   BitDly
           DJNZ    BitCnt,SBloop  ;Repeat until all bits sent.

           SETB    SDAPin         ;Release data line for acknowledge.
           ACALL   SCLHigh        ;Send clock for acknowledge.
           ACALL   BitDly
           JNB     SDAPin,SBEX    ;Check for valid acknowledge bit.
           SETB    NoAck          ;Set status for no acknowledge.
           MOV P1,#00000001B
                   ;.gfedcba
           MOV P0, #00000111B 
SBEX:      
           MOV P1,#00000010B
                   ;.gfedcba
           MOV P0, #01111111B 
           CLR     SCLPin         ;Finish acknowledge bit.
           ACALL   BitDly
           RET


; GoMaster - sends an I2C start and slave address.
; Enter with:
;   SlvAdr = slave address.

GoMaster:  SETB    I2CBusy        ;Indicate that I2C frame is in progress.
           CLR     NoAck          ;Clear error status flags.
           CLR     BusFault
           JNB     SCLPin,Fault   ;Check for bus clear.
           JNB     SDAPin,Fault
           CLR     SDAPin         ;Begin I2C start.
           ACALL   BitDly
           CLR     SCLPin
           ACALL   BitDly         ;Complete I2C start.
           MOV     A,SlvAdr       ;Get slave address.
           ACALL   SendByte       ;Send slave address.
           RET

Fault:     SETB    BusFault       ;Set fault status
           RET                    ;  and exit.


; SendData - sends one or more bytes of data to an I2C slave device.
; Enter with:
;   ByteCnt = count of bytes to be sent.
;   SlvAdr  = slave address.
;   @R1     = data to be sent (the first data byte will be the 
;             subaddress, if the I2C device expects one).

SendData:  ACALL   GoMaster       ;Acquire bus and send slave address.
           JB      NoAck,SDEX     ;Check for slave not responding.

SDLoop:    MOV     A,@R1          ;Get data byte from buffer.
           ACALL   SendByte       ;Send next data byte.
           INC     R1             ;Advance buffer pointer.
           JB      NoAck,SDEX     ;Check for slave not responding.
           DJNZ    ByteCnt,SDLoop ;All bytes sent?

SDEX:      ACALL   SendStop       ;Done, send an I2C stop.
           RET


;RcvByte - receives one byte of data from an I2C slave device.
; Returns:
;   ACC = data byte received.

RcvByte:   MOV     BitCnt,#8      ;Set bit count.
           CLR     A
RBLoop:    ACALL   SCLHigh        ;Read one data bit.
           ACALL   BitDly
           MOV     C,SDAPin       ;Get data bit from pin.
           RLC     A              ;Rotate bit into result byte.
           CLR     SCLPin
           ACALL   BitDly
           DJNZ    BitCnt,RBLoop  ;Repeat until all bits received.

           PUSH    ACC            ;Save accumulator
           MOV     A,ByteCnt
           CJNE    A,#1,RBAck     ;Check for last byte of frame.
           SETB    SDAPin         ;Send no acknowledge on last byte.
           SJMP    RBAClk

RBAck:     CLR     SDAPin         ;Send acknowledge bit.
RBAClk:    ACALL   SCLHigh        ;Send acknowledge clock.
           POP     ACC            ;Restore accumulator
           ACALL   BitDly
           CLR     SCLPin
           SETB    SDAPin         ;Clear acknowledge bit.
           ACALL   BitDly
           RET


;RcvData - receives sends one or more bytes of data from an I2C slave device.
; Enter with:
;   ByteCnt = count of bytes to be sent.
;   SlvAdr  = slave address.
; Returns:
;   @R1     = data received.

; Note: to receive with a subaddress, use SendData to set the subaddress
;   first (no provision for repeated start).

RcvData:   
       ACALL GoMaster
       MOV A, QMC_REG     ; Start reading from Register 00 of QMC
       ACALL SendByte
       ACALL SCLHigh    
       INC     SlvAdr         ;Set for READ of slave.
           ACALL   GoMaster       ;Acquire bus and send slave address.
           JB      NoAck,RDEX     ;Check for slave not responding.

RDLoop:    ACALL   RcvByte        ;Recieve next data byte.
           MOV     @R1,A          ;Save data byte in buffer.
           INC     R1             ;Advance buffer pointer.
           DJNZ    ByteCnt,RDLoop ;Repeat untill all bytes received.

RDEX:      ACALL   SendStop       ;Done, send an I2C stop.
           RET


reset:  MOV SP,#2fH
    MOV Flags, #0      ; Reset I2C Flags
    MOV SndDat+0,#2BH  ; MHDR register  
    MOV SndDat+1,#01H  ; value to be written into 2Bh

Main:
    MOV SlvAdr, #slaveaddr 
    MOV R1, #SndDat       ;Start of data.
    MOV ByteCnt, #2       ;Send register and value to be written
    ACALL SendData

        SJMP $

END
\$\endgroup\$
3
  • 1
    \$\begingroup\$ It looks like you've written your own bit-bang I2C implementation, likely you are going to have to debug it yourself as well. Use a scope to make sure the bus actually has or does not have an ACK condition as it should. Then look at your logic, presumably you are looking in the wrong place or not successfully testing the line. Or maybe the scope will show that the line is jammed low or a pull-up resistor problem means it is not rising quickly enough. \$\endgroup\$ Commented Mar 22, 2019 at 0:29
  • \$\begingroup\$ Did you resolve this? You just posted another question about what seems to be a related issue in the same project \$\endgroup\$ Commented Mar 23, 2019 at 16:04
  • \$\begingroup\$ You need to post your own answer here and accept it so that this shows as resolved \$\endgroup\$ Commented Mar 23, 2019 at 19:01

1 Answer 1

1
\$\begingroup\$

You appear to be missing a jmp command after the setb noack decision. It falls into

      MOV P1,#00000001B
      MOV P0, #00000111B

but then immediately falls into

SBEX:

       MOV P1,#00000010B
       MOV P0, #01111111B 

and so you see the same thing regardless of whether it was ACK or NoACK.

You need to put a JMP LABEL1 after

      MOV P0, #00000111B

and then place the

label1:

just before the line:

       CLR     SCLPin         ;Finish acknowledge bit.

Maybe like this

           SETB    NoAck          ;Set status for no acknowledge.
           MOV P1,#00000001B
                   ;.gfedcba
           MOV P0, #00000111B 
           JMP  LABEL1
SBEX:      
           MOV P1,#00000010B
                   ;.gfedcba
           MOV P0, #01111111B 
LABEL1:
           CLR     SCLPin         ;Finish acknowledge bit.
           ACALL   BitDly
           RET

```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.