I am using ATmega2560 for testing an I2C code. I wrote subrutines in assembler for init, start, write, read and stop the I2C setup. The goal is that master writes 11110000 to a slave with address 1101000 (SLA+R/W): 11010000. The code is given below:
.nolist
.include "./m2560def.inc"
.list
.cseg
.org 0x00
jmp inicio ; PC = 0x0000 RESET
inicio:
LDI R21, HIGH(RAMEND) ;Set Up Stack
OUT SPH, R21
LDI R21, LOW(RAMEND)
OUT SPL, R21
CALL I2C_INIT ;Initialize TWI(I2C)
CALL I2C_START ;Transmit START condition
LDI R27, 0b11010000 ;SLA(0b1001100) + W(0)
CALL I2C_WRITE ;Write R27 ato the I2C bus
LDI R27, 0b11110000 ;Data to be transmitted
CALL I2C_WRITE ;Write R27 ato the I2C bus
CALL I2C_STOP ;Transmit STOP condition
HERE: RJMP HERE
;----------------------------I2C_INIT-----------------------------
I2C_INIT:
LDI R21, 0
OUT TWSR, R21 ;Set prescaler bits to 0
LDI R21, 0x47 ;R21 = 0x47
OUT TWBR, R21 ;Fclk = 50 KHz (8 MHz Xtal)
LDI R21, (1<<TWEN) ;R21 = 0x04
OUT TWCR, R21 ;HEnable TWI (I2C)
RET
;----------------------------I2C_START-----------------------------
I2C_START:
LDI R21, (1<<TWINT)|1<<(TWSTA)|(1<<TWEN)
OUT TWCR, R21 ;Transmit START condition
WAIT1:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT1 ;Jump a WAIT1 if TWINT is 1
RET
;----------------------------I2C_WRITE -----------------------------
I2C_WRITE:
OUT TWDR, R27 ;Move the byte into TWRD
LDI R21, (1<<TWINT)|(1<<TWEN)
OUT TWCR, R21 ;Configure TWCR to send TWDR
WAIT3:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT3 ;Jump a WAIT3 if TWINT is 1
RET
;----------------------------I2C_STOP------------------------------
I2C_STOP:
LDI R21, (1<<TWINT)|1<<(TWSTO)|(1<<TWEN)
OUT TWCR, R21 ;Transmit STOP condition
RET
;----------------------------I2C_READ------------------------------
I2C_READ:
LDI R21, (1<<TWINT)|(1<<TWEN)
OUT TWCR, R21
WAIT2:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT2 ;Jump a WAIT2 if TWINT is 1
IN R27, TWCR ;Read received data into R21
RET
The code produces the flowwing compilation errors:
enter image description here I never could find the possible solution to make it work.
-
2\$\begingroup\$ Could you possibly re-post that code so it includes line numbers on the left? \$\endgroup\$hekete– hekete2019年06月16日 09:09:39 +00:00Commented Jun 16, 2019 at 9:09
2 Answers 2
Due to the limited number of address bits in IN and OUT opcodes, these instructions can only access I/O addresses from 0x00 to 0x3f. The I2C Registers TWBR to TWAMR are at 'memory mapped' addresses 0xb8~0xbd, so to access them you have to use LD and ST instructions.
LD and ST work only with the 16 bit index registers X, Y and Z, which are concatenations of 8 bit registers R26-27, R28-29 and R30-31. To use them you must first load the address into the index register.
So in line 27 you could replace:-
OUT TWSR, R21 ;Set prescaler bits to 0
with
LDI XH,0
LDI XL,TWSR
ST X, R21 ;Set prescaler bits to 0
For subsequent access to a different I/O address you only need to load XL (assuming you don't change XH/R27 in the mean time).
just change all the out instructions to sts instruction
change all the in instructions to lds instruction
the datasheets use generic asm and don't change the two instructions mentioned above even when it will never work!
make the changes I mentioned and it will work
i have the code but i can't deal with the code formatting on this website
-
1\$\begingroup\$ Hello Chris, welcome to EE.SE. Formatting is not that difficult. In many cases it is sufficient to use a indentation to format code. Have a look at the buttons on top of the editor frame! And don't forget to take the tour: electronics.stackexchange.com/tour \$\endgroup\$Ariser– Ariser2019年09月16日 05:17:43 +00:00Commented Sep 16, 2019 at 5:17