PLL 寄存器配置生成中断 (ARM)
PLL register configuration generates an interrupt (ARM)
我正在使用 Infineon 生产的 ARM 设备。 配置 PLL 时似乎有一个问题我似乎找不到解决方案。当为正常的 PLL 模式配置保存 N、P 和 K 值的寄存器时,代码会产生一个中断,之后不会暂停。这是反汇编程序 (Eclipse) 中显示的代码:
1333 SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk |
08000cc8: ldr r1, [pc, #252] ; (0x8000dc8 <XMC_SCU_CLOCK_StartSystemPll+400>)
08000cca: ldr r3, [pc, #252] ; (0x8000dc8 <XMC_SCU_CLOCK_StartSystemPll+400>)
08000ccc: ldr r2, [r3, #8]
08000cce: ldr r3, [pc, #252] ; (0x8000dcc <XMC_SCU_CLOCK_StartSystemPll+404>)
08000cd0: ands r3, r2
1334 SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
08000cd2: ldr r2, [r7, #4]
08000cd4: subs r2, #1
08000cd6: lsls r2, r2, #8
08000cd8: orrs r2, r3
1335 ((kdiv_temp - 1UL) << SCU_PLL_PLLCON1_K2DIV_Pos) |
08000cda: ldr r3, [r7, #16]
08000cdc: subs r3, #1
08000cde: lsls r3, r3, #16
1334 SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
08000ce0: orrs r2, r3
1336 ((pdiv - 1UL)<< SCU_PLL_PLLCON1_PDIV_Pos));
似乎是以下指令中的代码 "breaks":
08000cce: ldr r3, [pc, #252] ; (0x8000dcc <XMC_SCU_CLOCK_StartSystemPll+404>)
换句话说,如果我使用 'step into' 函数,它会在移动到上面显示的 'ldr' 指令之前跳转到下面的中断。以下是我用过的N、P、K值配置
.syspll_config.n_div = 80U,
.syspll_config.p_div = 2U,
.syspll_config.k_div = 4U,
有人告诉我,处理程序的名称意义不大,但这是反汇编程序在程序无法执行 08000cce 行后确定的名称。
08000298: b.n 0x8000298 <VADC0_G3_3_IRQHandler>
此外,这是控制台中显示的内容。
Starting target CPU...
Debugger requested to halt target...
...Target halted (PC = 0x08000298)
/.../
WARNING: Failed to read memory @ address 0xFFFFFFE8
WARNING: Failed to read memory @ address 0xFFFFFFE8
编辑:也许为了完整起见,我会包含来自 system.c 文件的代码片段,它使用默认值初始化 PLL 模块, 工作正常。它与这个问题的第一个代码窗格中显示的代码非常相似,可能除了在写入新的 P、N 和 K 值之前重置受影响的寄存器值之外。我将初始化代码分为两部分——重置和设置值;似乎在重置阶段的代码 "breaks"。
SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
(PLL_K2DIV_24MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
(PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
问题最终是由从外部振荡器 OSC 断开 VCO(voltage-controlled 振荡器)时生成的陷阱请求(提升到 NMI)引起的。断开两个硬件组件的连接对于配置 PLL 寄存器很重要,但是,如果 loss-of-lock 上的陷阱请求未被 清除和禁用 , 以下命令将产生一个中断:
/* disconnect Oscillator from PLL */
SCU_PLL->PLLCON0 |= (uint32_t)SCU_PLL_PLLCON0_FINDIS_Msk;
该命令位于以下行之前,我认为这是最初导致问题的原因,因此将其发布在问题中:
SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk | SCU_PLL_PLLCON1_PDIV_Msk))
请注意,陷阱请求可以帮助解决 PLL 模块的问题,因此需要再次启用它们。但是,无论 uC 是否对其进行操作(由 enable/disable 位决定),陷阱请求仍然会生成。因此,为了再次恢复陷阱功能,需要再次清除然后启用模块,如下所示:
SCU_TRAP->TRAPCLR |= SCU_TRAP_TRAPCLR_SVCOLCKT_Msk;
SCU_TRAP->TRAPDIS &= ~SCU_TRAP_TRAPDIS_SVCOLCKT_Msk;
一路上我发现了这篇有趣的文章,它可以帮助任何使用 ARM uC 并面临意外中断的人:Debugging and Diagnosing Hard Fault & Other Exceptions.
我正在使用 Infineon 生产的 ARM 设备。 配置 PLL 时似乎有一个问题我似乎找不到解决方案。当为正常的 PLL 模式配置保存 N、P 和 K 值的寄存器时,代码会产生一个中断,之后不会暂停。这是反汇编程序 (Eclipse) 中显示的代码:
1333 SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk |
08000cc8: ldr r1, [pc, #252] ; (0x8000dc8 <XMC_SCU_CLOCK_StartSystemPll+400>)
08000cca: ldr r3, [pc, #252] ; (0x8000dc8 <XMC_SCU_CLOCK_StartSystemPll+400>)
08000ccc: ldr r2, [r3, #8]
08000cce: ldr r3, [pc, #252] ; (0x8000dcc <XMC_SCU_CLOCK_StartSystemPll+404>)
08000cd0: ands r3, r2
1334 SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
08000cd2: ldr r2, [r7, #4]
08000cd4: subs r2, #1
08000cd6: lsls r2, r2, #8
08000cd8: orrs r2, r3
1335 ((kdiv_temp - 1UL) << SCU_PLL_PLLCON1_K2DIV_Pos) |
08000cda: ldr r3, [r7, #16]
08000cdc: subs r3, #1
08000cde: lsls r3, r3, #16
1334 SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
08000ce0: orrs r2, r3
1336 ((pdiv - 1UL)<< SCU_PLL_PLLCON1_PDIV_Pos));
似乎是以下指令中的代码 "breaks":
08000cce: ldr r3, [pc, #252] ; (0x8000dcc <XMC_SCU_CLOCK_StartSystemPll+404>)
换句话说,如果我使用 'step into' 函数,它会在移动到上面显示的 'ldr' 指令之前跳转到下面的中断。以下是我用过的N、P、K值配置
.syspll_config.n_div = 80U,
.syspll_config.p_div = 2U,
.syspll_config.k_div = 4U,
有人告诉我,处理程序的名称意义不大,但这是反汇编程序在程序无法执行 08000cce 行后确定的名称。
08000298: b.n 0x8000298 <VADC0_G3_3_IRQHandler>
此外,这是控制台中显示的内容。
Starting target CPU...
Debugger requested to halt target...
...Target halted (PC = 0x08000298)
/.../
WARNING: Failed to read memory @ address 0xFFFFFFE8
WARNING: Failed to read memory @ address 0xFFFFFFE8
编辑:也许为了完整起见,我会包含来自 system.c 文件的代码片段,它使用默认值初始化 PLL 模块, 工作正常。它与这个问题的第一个代码窗格中显示的代码非常相似,可能除了在写入新的 P、N 和 K 值之前重置受影响的寄存器值之外。我将初始化代码分为两部分——重置和设置值;似乎在重置阶段的代码 "breaks"。
SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
(PLL_K2DIV_24MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
(PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
问题最终是由从外部振荡器 OSC 断开 VCO(voltage-controlled 振荡器)时生成的陷阱请求(提升到 NMI)引起的。断开两个硬件组件的连接对于配置 PLL 寄存器很重要,但是,如果 loss-of-lock 上的陷阱请求未被 清除和禁用 , 以下命令将产生一个中断:
/* disconnect Oscillator from PLL */
SCU_PLL->PLLCON0 |= (uint32_t)SCU_PLL_PLLCON0_FINDIS_Msk;
该命令位于以下行之前,我认为这是最初导致问题的原因,因此将其发布在问题中:
SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk | SCU_PLL_PLLCON1_PDIV_Msk))
请注意,陷阱请求可以帮助解决 PLL 模块的问题,因此需要再次启用它们。但是,无论 uC 是否对其进行操作(由 enable/disable 位决定),陷阱请求仍然会生成。因此,为了再次恢复陷阱功能,需要再次清除然后启用模块,如下所示:
SCU_TRAP->TRAPCLR |= SCU_TRAP_TRAPCLR_SVCOLCKT_Msk;
SCU_TRAP->TRAPDIS &= ~SCU_TRAP_TRAPDIS_SVCOLCKT_Msk;
一路上我发现了这篇有趣的文章,它可以帮助任何使用 ARM uC 并面临意外中断的人:Debugging and Diagnosing Hard Fault & Other Exceptions.