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
Null
7,81618 gold badges38 silver badges49 bronze badges
asked Mar 21, 2019 at 22:32
\$\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
```
answered Feb 12, 2020 at 0:06
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.