Проблема AVR TWI (I2C): операнд 1 вне диапазона - PullRequest
0 голосов
/ 17 июня 2019

Я использую ЭСППЗУ Atmega2560 и 24c16A для тестирования кода I2C. На каждый переход состояния контроллер отвечает изменением регистра состояния TWSR. После того, как условие запуска передано, EEPROM отвечает, а затем также для адреса устройства и инструкции записи (SLA + R / W), регистр состояния обновляется нормально. Но когда я передаю следующие 8 битов вместо ACK (Байт данных отправил ACK), состояние меняется на повторный запуск. Код приведен ниже. Я никогда не мог найти возможное решение, чтобы заставить его работать.

.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

Выход

D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(41,0): error: Operand 1 out of range: 0xb9
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(43,0): error: Operand 1 out of range: 0xb8
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(45,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(51,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(53,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(60,0): error: Operand 1 out of range: 0xbb
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(62,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(64,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(72,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(78,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(80,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(83,0): error: Operand 2 out of range: 0xbc
    Assembly failed, 12 errors, 0 warnings

Строки кода, связанные с этими ошибками:

     OUT    TWSR, R21
     OUT    TWBR, R21
     OUT    TWCR, R21
     OUT    TWCR, R21
     IN     R21, TWCR   
     OUT    TWDR, R27
     OUT    TWCR, R21
     IN     R21, TWCR
     OUT    TWCR, R21
     OUT    TWCR, R21
     IN     R21, TWCR
     IN     R27, TWCR

1 Ответ

1 голос
/ 17 июня 2019

Обычно в AVR все регистры ввода / вывода отображаются в область памяти, начиная с адреса 0x0020

in и out инструкции могут использоваться ТОЛЬКО с первыми 64 из них (с0x20 ... 0x5F адресов памяти) sbi, cbi, sbis и sbic имеют дополнительные ограничения и могут использоваться только с первыми 32 регистрами ввода / вывода (с адресом памяти 0x20 ... 0x3F).Пожалуйста, обратитесь к Руководству по набору инструкций AVR

В таблице к ATmega2560 , раздел 33 «Сводка регистра», стр. 401, вы можете видеть, что регистры TWI имеют адресаОт 0xB8 до 0xBD, т.е. к ним нельзя получить доступ с помощью инструкций in и out.Вы должны использовать STS и LDS.Т.е. LDS R21, TWCR вместо IN R21, TWCR и т. Д.

Кроме того, всегда будьте осторожны при доступе к первым 64 регистрам.Убедитесь, что соответствующие имена определяют их ввод / вывод, а не адреса ОЗУ.Т.е. PORTA должен быть равен 0x02 (адрес ввода-вывода для команды in / out), а не 0x22 (адрес RAM или PORTA, который при обращении с использованием in или out равен регистру EEARH).

...