assembly Attiny167和Attiny87由于JMP与RJMP不向后兼容,如何化解

eagi6jfj  于 2023-08-06  发布在  其他
关注(0)|答案(4)|浏览(108)

我面临的问题是,attiny 167和attiny 87,尽管在数据表上说,他们是下降的替代品,实际上不是。程序是用AVR汇编语言编写的。
Attiny 87的向量表使用RJMP,而Attiny 167使用JMP。这意味着我需要在我的程序中有两个独立的向量表示例,我认为这是不可能的。有没有一种方法可以编写代码,使程序可以检查签名字节,以检查哪个硬件设备处于打开状态,然后使用适当的“jmp”指令?- 谢谢你-谢谢
到目前为止,我已经尝试使用任何需要的jmp指令编写程序的两个单独示例,但是我需要一种方法让程序自动完成这一点,而不是必须手动检查。

1u4esq0p

1u4esq0p1#

简单的解决方案是让reset将签名字节读入一个变量,以便稍后可以在该变量上进行分支。初始代码可能如下所示:

rjmp reset
rjmp vec_1
rjmp vec_2
rjmp vec_3
...

vec_1:
; odd vectors are always attiny87
; this is INT0
; attiny167 never gets here so no branching
...

vec_2:
; if we are attiny87 this is INT1
; if we are attiny167 this is INT0
; so do a conditional branch to the proper place
...

vec_3:
; again odd vector so this is PCINT0 on an attiny87
...

字符串
如果你不喜欢重复的分支,你可以把一个聪明的分派器放在一起,用RCALL和返回地址来工作。这可能是矫枉过正,但很有趣,所以在这里:

#include <avr/io.h>

; set up a variable to store the signature byte
; arbitrary address
.equ signature_byte_1, 0x100

    rjmp reset
.rept 39
    rcall dispatch
.endr

dispatch:
; save Y
    push r28
    push r29
; get SP into Y
    in r28, _SFR_IO_ADDR(SPL)
    in r29, _SFR_IO_ADDR(SPH)
; put ZH on stack
    std Y + 3, r31
; get return address into ZH
    ldd r31, Y + 4
; put ZL on stack
    std Y + 4, r30
; save SREG
    in r30, _SFR_IO_ADDR(SREG)
    push r30
; assume this has been set up during reset
; 0x93 for attiny87
; 0x94 for attiny167
    lds r30, signature_byte_1
; return address is
; attiny87:   2, 3, 4, ...
; attiny167:  3, 5, 7, ...
; we want for indexing: 0, 2, 4 ...
    dec r31
; multiply attiny87 by 2
    sbrc r30, 0
    lsl r31
; now both are 2, 4, 6, ...
; fix pointer, assume it's in first 256 bytes
    mov r30, r31
    ldi r31, 0
    ldi r28, lo8(vectors-2)
    add r30, r28
; both LPM and ICALL use Z :(
    lpm r28, Z+
    lpm r29, Z
    mov r30, r28
    mov r31, r29
    icall

; restore SREG
    pop r30
    out _SFR_IO_ADDR(SREG), r30
; restore Y
    pop r29
    pop r28
; restore Z
    pop r31
    pop r30
; done
    reti

; here is the real vector table
vectors:
    .word pm(int0_handler)
    .word pm(int1_handler)
    .word pm(pcint0_handler)
    .word pm(pcint1_handler)
; ...

reset:
    ldi r16, lo8(RAMEND)
    ldi r17, hi8(RAMEND)
    out _SFR_IO_ADDR(SPL), r16
    out _SFR_IO_ADDR(SPH), r17
; read signature byte into variable
; left as exercise for reader :)

; TEST CODE
; verify these are not changed
    ldi r28, 28
    ldi r29, 29
    ldi r30, 30
    ldi r31, 31
; simulate attiny87
    ldi r16, 0x93
    sts signature_byte_1, r16
; invoke PCINT0
    rcall 3*2
; invoke INT1
    rcall 2*2
; simulate attiny167
    ldi r16, 0x94
    sts signature_byte_1, r16
; invoke PCINT0
    rcall 6*2
; invoke INT1
    rcall 4*2
end:
    rjmp end

int0_handler:
    ret

int1_handler:
    ret

pcint0_handler:
    ret

pcint1_handler:
    ret

bjg7j2ky

bjg7j2ky2#

我很惊讶没有人建议使用汇编宏,假设你的中断向量例程位于地址0x1200,而你的中断向量地址位于地址0x0006

.ORG 0x0006
    .IF DEFINED(__ATtiny87__)
        RJMP 0x1200
    .ELIF DEFINED(__ATtiny167__)
        JMP 0x1200
    .ENDIF

字符串
你也可以使用预处理器做一些更脏但更酷的事情:

#define MJUMP defined(__ATtiny87__) ? RJMP : JMP    ; PASTE THIS ANYWHERE IN YOUR CODE


对于第二种方法,现在基本上可以在代码中的任何地方将JMPRJMP的每个示例替换为MJMP,并且它将更全局地解决问题(不仅仅是中断)。

nwo49xxi

nwo49xxi3#

ATtiny 167和ATtiny 87尽管在数据表上说它们是替代品,但实际上不是。

  • “直接更换”* 是指可以用另一个控制器 * 物理地 * 更换一个控制器,包括:
  • 相同的占地面积/ Package
  • 在可比条件下相同的电流消耗
  • I/O引脚的源/宿功能相同
  • ...

并不意味着芯片是二进制兼容的,即它们可以使用相同的二进制代码/可执行文件来编程。

iqxoj9l9

iqxoj9l94#

根据目录表,这两种类型都兼容硬件和软件。两者都使用两个字表示向量表。仅当FLASH大小小于4KiBy时,才可以使用一个字(rjmp)。
Atmel® ATtiny 87和ATtiny 167是硬件和软件兼容的。它们仅在内存大小上有所不同,如表1-1所示x1c 0d1x
阅读DS的1.1
因此,您可以将JMP用于两个MCU
在使用几个不兼容类型的情况下,这通过条件转换来解决,例如根据签名或族类型。

**编辑:**我对表1.1中的信息感到困惑。在为ATTiny 87编写时,它使用2个字作为中断向量表。事实上,它只使用一个单词,因为rjmp可以跳转到8 KiBy(+-2KWord)。在这种情况下,可以使用条件翻译。例如,在AVRASM2中,如下所示

.if SIGNATURE_000==0x1e && SIGNATURE_001==0x93 && SIGNATURE_002==0x87   ;ATTiny87
  rjmp RESET ; Reset Handler
  rjmp INT0addr ; IRQ0 Handler
  rjmp INT1addr ; IRQ1 Handler
  rjmp PCINT0addr ; PCINT0 Handler
  rjmp PCINT1addr ; PCINT1 Handler
  rjmp WDTaddr ; Watchdog Timer Handler
  rjmp ICP1addr ; Timer1 Capture Handler
  rjmp OC1Aaddr ; Timer1 Compare A Handler
  rjmp OC1Baddr ; Timer1 Compare B Handler
  rjmp OVF1addr ; Timer1 Overflow Handler
  rjmp OC0Aaddr ; Timer0 Compare A Handler
  rjmp OVF0addr ; Timer0 Overflow Handler
  rjmp LINTCaddr ; LIN Transfer Complete Handler
  rjmp LINERRaddr ; LIN Error Handler
  rjmp SPIaddr ; SPI Transfer Complete Handler
  rjmp ADCCaddr ; ADC Conversion Complete Handler
  rjmp ERDYaddr ; EEPROM Ready Handler
  rjmp ACIaddr ; Analog Comparator Handler
  rjmp USISTARTaddr ; USI Start Condition Handler
  rjmp USIOVFaddr ; USI Overflow Handler
.endif

.if SIGNATURE_000==0x1e && SIGNATURE_001==0x94 && SIGNATURE_002==0x87   ;ATTiny167
   jmp RESET ; Reset Handler
   jmp INT0addr ; IRQ0 Handler
   jmp INT1addr ; IRQ1 Handler
   jmp PCINT0addr ; PCINT0 Handler
   jmp PCINT1addr ; PCINT1 Handler
   jmp WDTaddr ; Watchdog Timer Handler
   jmp ICP1addr ; Timer1 Capture Handler
   jmp OC1Aaddr ; Timer1 Compare A Handler
   jmp OC1Baddr ; Timer1 Compare B Handler
   jmp OVF1addr ; Timer1 Overflow Handler
   jmp OC0Aaddr ; Timer0 Compare A Handler
   jmp OVF0addr ; Timer0 Overflow Handler
   jmp LINTCaddr ; LIN Transfer Complete Handler
   jmp LINERRaddr ; LIN Error Handler
   jmp SPIaddr ; SPI Transfer Complete Handler
   jmp ADCCaddr ; ADC Conversion Complete Handler
   jmp ERDYaddr ; EEPROM Ready Handler
   jmp ACIaddr ; Analog Comparator Handler
   jmp USISTARTaddr ; USI Start Condition Handler
   jmp USIOVFaddr ; USI Overflow Handler

.endif

字符串

相关问题