在对嵌入式系统(TI CC2530 上的 IAR C)进行重大重构后,我最终陷入了以下情况:
在外围设备的基本初始化和全局中断使能之后,执行错误地在与外部硬件通信的中断处理程序中结束。由于此硬件未准备好(请记住,我们最终错误地进入了 ISR),程序冻结并触发看门狗复位。
如果我在 main() 中插入 1、2、3、5、6、7 等 NOP,一切正常。但是如果我插入 0、4、8 等 NOP,我就会得到错误的行为。
CC2530 在 4 字节边界上从闪存中提取 4 字节指令。
这告诉我在代码内存方面有些东西未对齐,但我根本不知道从哪里开始。AFAIK 的目标设置没有任何变化。
这里的任何人以前见过这种情况,或者可以指出我正确的方向?
#include <common.h>
#include <timer.h>
#include <radio.h>
#include <encryption.h>
#include "signals.h"
#include "lock.h"
#include "nfc.h"
#include "uart1_trace.h"
#include "trace.h"
//------------------------------------------------------------------------------
// Public functions
//------------------------------------------------------------------------------
void main(void)
{
setTp;
// Initialize microcontroller and peripherals
ClockSourceInit();
WatchdogEnable();
PortsInit();
TraceInit();
Timer4Init();
SleepInit();
RadioInit();
Uart1Init();
LoadAesKey("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
clrTp;
NfcInit();
__enable_interrupt();
asm("nop");
// Initialize threads
LockInit();
while (true)
{
WDR();
LockRun();
}
}
Run Code Online (Sandbox Code Playgroud)
void NfcInit(void)
{
// Enable wake up interrupt on external RF field present
// The process for enabling interrupts is described in section 2.5.1 in the CC2530 datasheet.
// Configure interrupt source: interrupt on falling edge, Port 0, pin 7:0
PICTL |= BIT(0);
// 1. Clear port 0 individual interrupt flag. Read-modify-write is not allowed.
// Writing 1 to a bit in this register has no effect, so 1 should be written to flags that are not to be cleared.
P0IFG = ~BIT(3);
// Clear port 0 interrupt flag. This register is bit-accessible.
P0IF = 0;
// 2. Set pin 3 interrupt-enable
P0IEN |= BIT(3);
// 3. Set port 0 interrupt-enable
IEN1 |= BIT(5);
// 4. Global interrupt enable is set in main()
}
Run Code Online (Sandbox Code Playgroud)
// Interrupt handler: falling edge on signal Wake.
// This interrupt will only occur when device is powered off and NFC field present.
// When device is powered on, VCORE is always asserted.
#pragma vector = 0x6B
__interrupt static void NFC_WAKE_ISR(void)
{
static uint16 cnt = 0;
TracePutUint16(cnt); TracePuts("\r\n");
if (++cnt > 10)
IEN1 &= ~BIT(5);
P0IFG = ~BIT(3); // Clear port 1 individual interrupt flag. Read-modify-write is not allowed.
P0IF = 0; // Clear port 1 CPU interrupt flag. This register is bit-accessible.
return;
Run Code Online (Sandbox Code Playgroud)
软件初始化截图。
CH1 = 外部中断信号,低电平有效(信号唤醒)。
CH2 = main.c 中的 TP (setTp / clrTp)。
CC-debugger 上的复位按钮似乎没有去抖动,所以 TP 信号在稳定之前打开和关闭几次(应该不是问题)。VCC 在复位前很长时间是稳定的。当 TP 最后一次变低时,所有外设都被初始化。
当存在 NFC 场时,外部 NFC IC 用于将 MCU 从睡眠模式唤醒。NFC IC 由 CC2530 I/O 引脚之一供电。通常情况下,IC 会关闭以保持电源。在这种状态下,来自 NFC 场的能量足以产生唤醒信号(低电平有效)。当 MCU 检测到该信号时,它会唤醒,为 NFC IC 供电,然后 NFC 通信开始。
NFC IC 在通电或存在 NFC 场时生成信号。
复位后,所有 I/O 引脚都配置为带上拉的输入。该上拉输入足以为 NFC IC 供电,这就是生成唤醒信号的原因。复位后立即配置 I/O(在函数 PortsInit() 中),并关闭 NFC IC 的电源。这使得唤醒信号变低。缓慢的上升和下降时间可能是由于电容器造成的,我现在将其移除。
这就是事情变得奇怪的地方。尽管唤醒信号为低电平,但外部中断配置为下降沿,并且挂起的 int 标志在启用全局输入之前被清除,几毫秒后我最终进入 ISR(在屏幕截图中未看到)。但只有使用正确数量的 NOP,如上所述。
如果我在全局 int 启用之前添加 > 15 毫秒的延迟,一切都很好。这与从 TP 低点到唤醒高点测量的时间一致。
有人可能认为 int 被错误地配置为低电平有效,但在这种情况下,我应该得到多个整数,而我没有。此外,这并不能解释神奇的 NOP...
编译器生成 ISR 汇编代码:
// 77 // Interrupt handler: falling edge on signal Wake.
// 78 // This interrupt will only occur when device is powered off and NFC field present.
// 79 // When device is powered on, VCORE is always asserted.
// 80 #pragma vector = 0x6B
RSEG NEAR_CODE:CODE:NOROOT(0)
// 81 __interrupt static void NFC_WAKE_ISR(void)
NFC_WAKE_ISR:
// 82 {
PUSH A
MOV A,#-0xe
LCALL ?INTERRUPT_ENTER_XSP
; Saved register size: 15
; Auto size: 0
// 83 static uint16 cnt = 0;
// 84
// 85 TracePutUint16(cnt); TracePuts("\r\n");
; Setup parameters for call to function PutUint16
MOV R4,#(TPutc & 0xff)
MOV R5,#((TPutc >> 8) & 0xff)
MOV DPTR,#??cnt
MOVX A,@DPTR
MOV R2,A
INC DPTR
MOVX A,@DPTR
MOV R3,A
LCALL PutUint16
; Setup parameters for call to function TPuts
MOV R2,#(`?<Constant "\\r\\n">` & 0xff)
MOV R3,#((`?<Constant "\\r\\n">` >> 8) & 0xff)
LCALL TPuts
// 86
// 87 if (++cnt > 10)
MOV DPTR,#??cnt
MOVX A,@DPTR
ADD A,#0x1
MOV R0,A
INC DPTR
MOVX A,@DPTR
ADDC A,#0x0
MOV R1,A
MOV DPTR,#??cnt
MOV A,R0
MOVX @DPTR,A
INC DPTR
MOV A,R1
MOVX @DPTR,A
CLR C
MOV A,R0
SUBB A,#0xb
MOV A,R1
SUBB A,#0x0
JC ??NFC_WAKE_ISR_0
// 88 IEN1 &= ~BIT(5);
CLR 0xb8.5
// 89
// 90
// 91 P0IFG = ~BIT(3); // Clear port 1 individual interrupt flag. Read-modify-write is not allowed.
??NFC_WAKE_ISR_0:
MOV 0x89,#-0x9
// 92 P0IF = 0; // Clear port 1 CPU interrupt flag. This register is bit-accessible.
CLR 0xc0.5
// 93
// 94 return;
MOV R7,#0x1
LJMP ?INTERRUPT_LEAVE_XSP
REQUIRE _A_P0
REQUIRE P0IFG
REQUIRE _A_P1
REQUIRE _A_IEN1
REQUIRE _A_IRCON
Run Code Online (Sandbox Code Playgroud)
////////////////////////////////////////////////////////////////////////////////
// lnk51ew_CC2530F64.xcl: linker command file for IAR Embedded Workbench IDE
// Generated: Mon May 24 00:00:01 +0200 2010
//
////////////////////////////////////////////////////////////////////////////////
//
// Segment limits
// ==============
//
// IDATA
// -----
-D_IDATA0_START=0x00
-D_IDATA0_END=0xFF
//
// PDATA
// -----
// We select 256 bytes of (I)XDATA memory that can be used as PDATA (see also "PDATA page setup" below)
-D_PDATA0_START=0x1E00
-D_PDATA0_END=0x1EFF
//
//
// IXDATA
// ------
-D_IXDATA0_START=0x0001 // Skip address 0x0000 (to avoid ambiguities with NULL pointer)
-D_IXDATA0_END=0x1EFF // CC2530F64 has 8 kB RAM (NOTE: 256 bytes are used for IDATA)
//
//
// XDATA
// -----
-D_XDATA0_START=_IXDATA0_START
-D_XDATA0_END=_IXDATA0_END
//
// NEAR CODE
// ---------
-D_CODE0_START=0x0000
-D_CODE0_END=0xFFFF // CC2530F64 has 64 kB code (flash)
//
// Special SFRs
// ============
//
// Register bank setup
// -------------------
-D?REGISTER_BANK=0x0 // Sets default register bank (0,1,2,3)
-D_REGISTER_BANK_START=0x0 // Start address for default register bank (0x0, 0x8, 0x10, 0x18)
//
// PDATA page setup
// ----------------
-D?PBANK_NUMBER=0x1E // High byte of 16-bit address to the PDATA area
//
// Virtual register setup
// ----------------------
-D_BREG_START=0x00
-D?VB=0x20
-D?ESP=0x9B //Extended stack pointer register location
////////////////////////////////////////////////////////////////////////////////
//
// IDATA memory
// ============
-Z(BIT)BREG=_BREG_START
-Z(BIT)BIT_N=0-7F
-Z(DATA)REGISTERS+8=_REGISTER_BANK_START
-Z(DATA)BDATA_Z,BDATA_N,BDATA_I=20-2F
-Z(DATA)VREG+_NR_OF_VIRTUAL_REGISTERS=08-7F
-Z(DATA)PSP,XSP=08-7F
-Z(DATA)DOVERLAY=08-7F
-Z(DATA)DATA_I,DATA_Z,DATA_N=08-7F
-U(IDATA)0-7F=(DATA)0-7F
-Z(IDATA)IDATA_I,IDATA_Z,IDATA_N=08-_IDATA0_END
-Z(IDATA)ISTACK+_IDATA_STACK_SIZE#08-_IDATA0_END
-Z(IDATA)IOVERLAY=08-FF
//
// ROM memory
// ==========
//
// Top of memory
// -------------
-Z(CODE)INTVEC=0
-Z(CODE)CSTART=_CODE0_START-_CODE0_END
//
// Initializers
// ------------
-Z(CODE)BIT_ID,BDATA_ID,DATA_ID,IDATA_ID,IXDATA_ID,PDATA_ID,XDATA_ID=_CODE0_START-_CODE0_END
//
// Program memory
// --------------
-Z(CODE)RCODE,DIFUNCT,CODE_C,CODE_N,NEAR_CODE=_CODE0_START-_CODE0_END
//
// Checksum
// --------
-Z(CODE)CHECKSUM#_CODE0_END
//
// XDATA memory
// ============
//
// Stacks located in XDATA
// -----------------------
-Z(XDATA)EXT_STACK+_EXTENDED_STACK_SIZE=_EXTENDED_STACK_START
-Z(XDATA)PSTACK+_PDATA_STACK_SIZE=_PDATA0_START-_PDATA0_END
-Z(XDATA)XSTACK+_XDATA_STACK_SIZE=_XDATA0_START-_XDATA0_END
//
// PDATA - data memory
// -------------------
-Z(XDATA)PDATA_Z,PDATA_I=_PDATA0_START-_PDATA0_END
-P(XDATA)PDATA_N=_PDATA0_START-_PDATA0_END
//
// XDATA - data memory
// -------------------
-Z(XDATA)IXDATA_Z,IXDATA_I=_IXDATA0_START-_IXDATA0_END
-P(XDATA)IXDATA_N=_IXDATA0_START-_IXDATA0_END
-Z(XDATA)XDATA_Z,XDATA_I=_XDATA0_START-_XDATA0_END
-P(XDATA)XDATA_N=_XDATA0_START-_XDATA0_END
-Z(XDATA)XDATA_HEAP+_XDATA_HEAP_SIZE=_XDATA0_START-_XDATA0_END
-Z(CONST)XDATA_ROM_C=_XDATA0_START-_XDATA0_END
//
// Core
// ====
-cx51
////////////////////////////////////////////////////////////////////////////////
//
// Texas Instruments device specific
// =================================
//
// Flash lock bits
// ---------------
//
// The CC2530 has its flash lock bits, one bit for each 2048 B flash page, located in
// the last available flash page, starting 16 bytes from the page end. The number of
// bytes with flash lock bits depends on the flash size configuration of the CC2530
// (maximum 16 bytes, i.e. 128 page lock bits, for the CC2530 with 256 kB flash).
// Note that the bit that controls the debug interface lock is always in the last byte,
// regardless of flash size.
//
-D_FLASH_LOCK_BITS_START=(_CODE0_END-0xF)
-D_FLASH_LOCK_BITS_END=_CODE0_END
//
// Define as segment in case one wants to put something there intentionally (then comment out the trick below)
-Z(CODE)FLASH_LOCK_BITS=_FLASH_LOCK_BITS_START-_FLASH_LOCK_BITS_END
//
// Trick to reserve the FLASH_LOCK_BITS segment from being used as normal CODE, avoiding
// code to be placed on top of the flash lock bits. If code is placed on address 0x0000,
// (INTVEC is by default located at 0x0000) then the flash lock bits will be reserved too.
//
-U(CODE)0x0000=(CODE)_FLASH_LOCK_BITS_START-_FLASH_LOCK_BITS_END
//
////////////////////////////////////////////////////////////////////////////////
Run Code Online (Sandbox Code Playgroud)
据 TI 称,该部分具有 8051 内核。除了恐龙垃圾,8051 是一个 8 苦,所以对齐不适用。
当对代码的随机修改导致完全不相关的错误或失控的代码时,通常是由以下原因之一引起的:
还要确保所有 ISR 都在中断向量表中注册。
问题更改 6/4 后编辑:
你通常不 应该return从中断!我不知道您的具体设置如何工作,但是对于通用嵌入式系统编译器,非标准中断关键字意味着两件事:
在 8051 上,这意味着反汇编的 ISR 绝对必须以RETI指令而不是RET指令结束!机会是很高,return导致RET这将破坏你的筹码。拆开看看是否确实如此。