Software hanging at B.N instruction in disassembler -- No idea what it means

arm, assembly, cortex-m

Solution

In Cortex-M3, the lowest addresses are not code, but the vector table. For example, entry at 0 is the reset value of `SP`, at 4 is the reset `PC`, and the following entries are various exceptions. If we reinterptet the dump as data, we get the following:

00 DCD 0x10089FF0
04 DCD 0x10402BAD
08 DCD 0x10400041
0C DCD 0x10400043
10 DCD 0x10400045
14 DCD 0x10400047
18 DCD 0x10400049
1C DCD 0
20 DCD 0
24 DCD 0
28 DCD 0
2C DCD 0x1040004B
30 DCD 0x1040004D
34 DCD 0
38 DCD 0x1040004F
3C DCD 0x10401645

It becomes obvious that the code has been linked to run from 10400000. If we take that into account, and convert integers to offsets, we get:

00  DCD 0x10089FF0          ; Initial SP
04  DCD 0x10402BAD          ; reset PC
08  DCD loc_10400040+1      ; NMI handler
0C  DCD loc_10400042+1      ; Hard Fault handler
10  DCD loc_10400044+1      ; MPU Fault Handler
14  DCD loc_10400046+1      ; Bus Fault Handler
18  DCD loc_10400048+1      ; Usage Fault Handler
1C  DCD 0
20  DCD 0
24  DCD 0
28  DCD 0
2C  DCD loc_1040004A+1      ; SVCall Handler
30  DCD loc_1040004C+1      ; Debug Monitor Handler
34  DCD 0
38  DCD loc_1040004E+1      ; PendSV Handler
3C  DCD 0x10401645          ; SysTick Handler

40 loc_10400040
40   B loc_10400040

(The offsets have +1 because the code pointers on Cortex-M3 must have bit 0 set, to indicate that the target is Thumb code.)

The `loc_10400040` corresponds to the `B.N 0x40` in your disassembly. So, apparently, you ended up in the NMI handler.

Checking the LPC18xx User Manual, it seems NMI can only be triggered by the pins `P4_0` or `PE_4`. I'd suggest double-checking your board schematics and/or GPIO configuration code.

Problem

I'm trying to debug some software I've written for the NXP LPC1850 evaluation board. At the moment, when I halt my code I cannot see where it at in my C code, but I can in the disassembler window. The line it is hanging on is at address 0x40. The instruction is B.N . I've looked it up on the ARM Information Center but I don't know anything about assembler and I'm afraid that even after reading around it means nothing to me. ``` 0x0: 0x9ff0 LDR R7, [SP, #0x3c0] 0x2: 0x1008 ASRS R0, R1, #32 0x4: 0x2bad CMP R3, #173 ; 0xad 0x6: 0x1040 ASRS R0, R0, #1 0x8: 0x0041 LSLS R1, R0, #1 0xa: 0x1040 ASRS R0, R0, #1 0xc: 0x0043 LSLS R3, R0, #1 0xe: 0x1040 ASRS R0, R0, #1 0x10: 0x0045 LSLS R5, R0, #1 0x12: 0x1040 ASRS R0, R0, #1 0x14: 0x0047 LSLS R7, R0, #1 0x16: 0x1040 ASRS R0, R0, #1 0x18: 0x0049 LSLS R1, R1, #1 0x1a: 0x1040 ASRS R0, R0, #1 0x1c: 0x0000 MOVS R0, R0 0x1e: 0x0000 MOVS R0, R0 0x20: 0x0000 MOVS R0, R0 0x22: 0x0000 MOVS R0, R0 0x24: 0x0000 MOVS R0, R0 0x26: 0x0000 MOVS R0, R0 0x28: 0x0000 MOVS R0, R0 0x2a: 0x0000 MOVS R0, R0 0x2c: 0x004b LSLS R3, R1, #1 0x2e: 0x1040 ASRS R0, R0, #1 0x30: 0x004d LSLS R5, R1, #1 0x32: 0x1040 ASRS R0, R0, #1 0x34: 0x0000 MOVS R0, R0 0x36: 0x0000 MOVS R0, R0 0x38: 0x004f LSLS R7, R1, #1 0x3a: 0x1040 ASRS R0, R0, #1 0x3c: 0x1645 ASRS R5, R0, #25 0x3e: 0x1040 ASRS R0, R0, #1 0x40: 0xe7fe B.N 0x40 0x42: 0xe7fe B.N 0x42 0x44: 0xe7fe B.N 0x44 0x46: 0xe7fe B.N 0x46 0x48: 0xe7fe B.N 0x48 0x4a: 0xe7fe B.N 0x4a 0x4c: 0xe7fe B.N 0x4c 0x4e: 0xe7fe B.N 0x4e 0x50: 0x0000 MOVS R0, R0 0x52: 0x0000 MOVS R0, R0 0x54: 0x0000 MOVS R0, R0 0x56: 0x0000 MOVS R0, R0 0x58: 0x0000 MOVS R0, R0 0x5a: 0x0000 MOVS R0, R0 0x5c: 0x0000 MOVS R0, R0 0x5e: 0x0000 MOVS R0, R0 ``` I would be immensely grateful if somebody could explain what is going on and perhaps why program is hanging at that point. edit: added C code in below ``` #include "NXP\iolpc4350.h" #include "stdint.h" #include "modules\i2c_drv.h" #include "modules\drv_nvic.h" #define IRC_FREQ 12000000 #define XTAL_FREQ 12000000 //nt32_t ClockFrequency; uint32_t I2C0_PCLK; unsigned char Data[2]; #define MULTF 15 #define PCA9502_ADDR 0x4D volatile uint8_t flag0=0; #define flTick ( flag0 ) #define flTickSet() ( flag0 = 0xFF ) #define flTickClear() ( flag0 = 0x00 ) /************************************************************************* * Function Name: InitClock * Parameters: none * * Return: none * * Description: Initialize PLL and clock dividers. FCCO = 320MHz, * PLL1_OUT = 160MHz * *************************************************************************/ void InitClock(void) { /* 1. Init XTAL OSC */ CGU_XTAL_OSC_CTRL_bit.HF = 0; /* Xtal.freq is between 1MHz and 15MHZ */ CGU_XTAL_OSC_CTRL_bit.BYPASS = 0; /* Xtal.osc is connected */ CGU_XTAL_OSC_CTRL_bit.ENABLE = 0; /* Xtal.osc is enabled */ /* 2. Wait for OSC ready > 2ms */ for(volatile uint32_t j = 20000; j; j--); /* 3. Switch to OSC clk */ /* BASE_M4_CLK */ CGU_BASE_M4_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (6ul << 24) /* Source is XTAL osc. */ ; /* BASE_APB1_CLK */ CGU_BASE_APB1_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (6ul << 24) /* Source is XTAL osc. */ ; /* BASE_APB3_CLK */ CGU_BASE_APB3_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (6ul << 24) /* Source is XTAL osc. */ ; /* BASE_SPIFI_CLK */ CGU_BASE_SPIFI_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (6ul << 24) /* Source is XTAL osc. */ ; /* 4. Init PLL1 - In clk - OSC (12MHz) N = 3, M = 80, P = 1 VCO - 320MHz, PLL1 OUT - 160MHz */ CGU_PLL1_CTRL_bit.PD = 1; /* Power down PLL1 */ CGU_PLL1_CTRL_bit.BYPASS = 0; /* CCO clock sent to post-dividers */ CGU_PLL1_CTRL_bit.DIRECT = 0; /* Direct CCO output disabled */ CGU_PLL1_CTRL_bit.FBSEL = 0; /* CCO output as feedback divider */ CGU_PLL1_CTRL_bit.PSEL = 1-1; /* Post divider P = 1 */ CGU_PLL1_CTRL_bit.NSEL = 3-1; /* N = 3 */ CGU_PLL1_CTRL_bit.MSEL = 80-1; /* M = 80 */ CGU_PLL1_CTRL_bit.CLK_SEL = 6; /* Source is XTAL osc. */ CGU_PLL1_CTRL_bit.AUTOBLOCK = 1; /* Autoblock during freq.change enabled */ /* 5. Enable PLL1 */ CGU_PLL1_CTRL_bit.PD = 0; /* Power up (enable) PLL1 */ /* 5. Wait for the PLL1 to achieve lock */ while(!CGU_PLL1_STAT_bit.LOCK); /* 6. Dividers */ /* IDIVA - /4 input 160MHz, output 40MHz */ CGU_IDIVA_CTRL_bit.AUTOBLOCK = 1; /* Autoblock during freq.change enabled */ CGU_IDIVA_CTRL_bit.IDIV = 4-1; /* IDIV = 4 */ CGU_IDIVA_CTRL_bit.CLK_SEL = 9; /* Source is PLL1 */ CGU_IDIVA_CTRL_bit.PD = 0; /* Enable IDIVA */ /* 7. Init Clock output stages */ /* BASE_M4_CLK, APB0, APB2 - 160MHz */ CGU_BASE_M4_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (9ul << 24) /* Source is PLL1 */ ; /* BASE_APB1_CLK - 160MHz*/ CGU_BASE_APB1_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (9ul << 24) /* Source is PLL1 */ ; /* BASE_SPIFI_CLK - 40MHz */ CGU_BASE_SPIFI_CLK = (1ul << 11) /* Autoblock during freq.change enabled */ | (12ul << 24) /* Source is IDIVA */ ; /* Enable M4 Bus clock */ CCU1_CLK_M4_BUS_CFG_bit.RUN = 1; /* Enable APB 1 Bus clock */ CCU1_CLK_APB1_BUS_CFG_bit.RUN = 1; /* Enable SCU clock */ CCU1_CLK_M4_SCU_CFG_bit.RUN = 1; /* Set I2C0 module frequency = APB1 freq */ I2C0_PCLK = 160000000; } /************************************************************************* * Function Name: RIT_IRQHandler * Parameters: none * * Return: none * * Description: Repetitive interrupt timer handler * *************************************************************************/ void RITIMER_IRQHandler(void) { flTickSet(); /* Clear interrupt */ RIT_CTRL_bit.RITINT = 1; NVIC_ClearPendingIRQ(NVIC_RITIMER); } /************************************************************************* * Function Name: RIT_Init * Parameters: none * * Return: none * * Description: Initialization of repetitive interrupt timer * *************************************************************************/ void RITIMER_Init(void) { /* Value for 0.25s timer interrupt @ 180MHz timer clock */ RIT_COUNTER = 0; RIT_COMPVAL = 0x2AEA540; RIT_CTRL_bit.RITEN = 1; RIT_CTRL_bit.RITENCLR = 1; /* Enable interrupt */ NVIC_EnableIRQ(NVIC_RITIMER); NVIC_SetPriority(NVIC_RITIMER, 16); } /************************************************************************* * Function Name: main * Parameters: none * * Return: none * * Description: main * *************************************************************************/ int main() { // Configures Clock Generation Unit InitClock(); // Force a RESET to Cortex-M0 RGU_RESET_CTRL1 = ~RGU_RESET_ACTIVE_STATUS1 | RGU_RESET_CTRL1_M0APP_RST; // Configures Repetitve Interrupt Timer RITIMER_Init(); // Configure the onboard LED - GPIO4.1 GPIO_CLR4 = 1 << 1; GPIO_DIR4 |= 1 << 1; // Init I2C I2C_InitMaster(400000); // Everything below this line I have added in myself - Mitchell /* Configure PC_11 and PC_12 to serve as GPIO6[10] and GPIO6[11] to act as data select for SPP0_SSEL multiplexer 1. Set as outputs 2. Choose INTLCD_SSEL (option 0) as output by clearing both outputs 3. Configure both pins as GPIO */ // 1 GPIO_DIR6 |= 0x0C; // 2 GPIO_PIN6 &= ~0x0C;; // 3 SCU_SFSPC_11_bit.MODE = 4; SCU_SFSPC_12_bit.MODE = 4; // Set LCD_RST to reset the LCD RGU_RESET_CTRL0 |= RGU_RESET_CTRL0_LCD_RST; // LCD_RST autoclears when complete // wait until this done before moving on while(RGU_RESET_STATUS1_bit.LCD_RST == 1); /* SPI slave select is an active low signal. This means that to communicate with the onboard LCD, SSP0_SSEL must be cleared */ while(1) { } } ```

Original source