为什么写入内存映射的外设寄存器不起作用(LPC43xx)?

时间:2015-06-11 22:31:39

标签: gcc arm embedded nxp-microcontroller

我正在为恩智浦LPC4330(Arm Cortex M0 / M4双核)构建应用程序。我正在使用arm-none-eabi-gcc编译4.9.3。在我的代码中,我正在执行对(32位)内存位置的写入。紧接着,如果我从该存储器位置读回来,大约十分之一的结果表明写入没有发生。稍后的后续读取表明相同的事情,因此它不是瞬态条件。在全局级别禁用中断,编译器生成的汇编器显然正在尝试写入,那么如何才能执行写操作?

具体来说,我正在写入SLICE_MUX_CFG0,它是SGPIO外设中的存储器映射寄存器。写入工作时,外围设备正常运行。当回读表明写操作无效时,外围设备无法正常工作。因此,似乎没有正确设置有问题的寄存器,如回读所示。

查看.asm(下面列出),写得很清楚。当我读回之后的值时,它读为零,如果给出下面的列表,那么在我看来是不可能的。如果我在写入之前立即执行读操作(参见下面的.c列表),问题就会消失,这可能是一个线索。

所以上面说明了什么?这会破坏使用内存总线的一些规则吗?我查看了GCC错误列表,看不到任何与此相关的内容。

该函数遵循源和ASM,带有一些注释。可能会发生什么,这里?为什么写“商店价值”显然没有任何影响?

20000f7c <camera_SGPIO_init_sub>:
; disable interrupts globally
20000f7c:   b672        cpsid   i
20000f7e:   2346        movs    r3, #70 ; 0x46
20000f80:   4a16        ldr r2, [pc, #88]   ; (20000fdc <camera_SGPIO_init_sub+0x60>)
20000f82:   6013        str r3, [r2, #0]
20000f84:   4a16        ldr r2, [pc, #88]   ; (20000fe0 <camera_SGPIO_init_sub+0x64>)
20000f86:   6013        str r3, [r2, #0]
20000f88:   4a16        ldr r2, [pc, #88]   ; (20000fe4 <camera_SGPIO_init_sub+0x68>)
20000f8a:   6013        str r3, [r2, #0]
20000f8c:   4a16        ldr r2, [pc, #88]   ; (20000fe8 <camera_SGPIO_init_sub+0x6c>)
20000f8e:   6013        str r3, [r2, #0]
20000f90:   4a16        ldr r2, [pc, #88]   ; (20000fec <camera_SGPIO_init_sub+0x70>)
20000f92:   3301        adds    r3, #1
20000f94:   6013        str r3, [r2, #0]
20000f96:   4a16        ldr r2, [pc, #88]   ; (20000ff0 <camera_SGPIO_init_sub+0x74>)
20000f98:   6013        str r3, [r2, #0]
20000f9a:   4a16        ldr r2, [pc, #88]   ; (20000ff4 <camera_SGPIO_init_sub+0x78>)
20000f9c:   6013        str r3, [r2, #0]
20000f9e:   4a16        ldr r2, [pc, #88]   ; (20000ff8 <camera_SGPIO_init_sub+0x7c>)
20000fa0:   6013        str r3, [r2, #0]
20000fa2:   4a16        ldr r2, [pc, #88]   ; (20000ffc <camera_SGPIO_init_sub+0x80>)
20000fa4:   6013        str r3, [r2, #0]
20000fa6:   2240        movs    r2, #64 ; 0x40
20000fa8:   4b15        ldr r3, [pc, #84]   ; (20001000 <camera_SGPIO_init_sub+0x84>)
20000faa:   601a        str r2, [r3, #0]
20000fac:   2290        movs    r2, #144    ; 0x90
20000fae:   4b15        ldr r3, [pc, #84]   ; (20001004 <camera_SGPIO_init_sub+0x88>)
20000fb0:   0512        lsls    r2, r2, #20
20000fb2:   601a        str r2, [r3, #0]
; load value
20000fb4:   23c6        movs    r3, #198    ; 0xc6
; load destination address
20000fb6:   4a14        ldr r2, [pc, #80]   ; (20001008 <camera_SGPIO_init_sub+0x8c>)
; store value
20000fb8:   6013        str r3, [r2, #0]
; read value back
20000fba:   6810        ldr r0, [r2, #0]
20000fbc:   4a13        ldr r2, [pc, #76]   ; (2000100c <camera_SGPIO_init_sub+0x90>)
20000fbe:   6013        str r3, [r2, #0]
20000fc0:   4a13        ldr r2, [pc, #76]   ; (20001010 <camera_SGPIO_init_sub+0x94>)
20000fc2:   6013        str r3, [r2, #0]
20000fc4:   4a13        ldr r2, [pc, #76]   ; (20001014 <camera_SGPIO_init_sub+0x98>)
20000fc6:   6013        str r3, [r2, #0]
20000fc8:   4a13        ldr r2, [pc, #76]   ; (20001018 <camera_SGPIO_init_sub+0x9c>)
20000fca:   6013        str r3, [r2, #0]
20000fcc:   4a13        ldr r2, [pc, #76]   ; (2000101c <camera_SGPIO_init_sub+0xa0>)
20000fce:   6013        str r3, [r2, #0]
20000fd0:   4a13        ldr r2, [pc, #76]   ; (20001020 <camera_SGPIO_init_sub+0xa4>)
20000fd2:   6013        str r3, [r2, #0]
20000fd4:   4a13        ldr r2, [pc, #76]   ; (20001024 <camera_SGPIO_init_sub+0xa8>)
20000fd6:   6013        str r3, [r2, #0]
; enable interrupts globally
20000fd8:   b662        cpsie   i
20000fda:   4770        bx  lr
20000fdc:   40086480    .word   0x40086480
20000fe0:   40086484    .word   0x40086484
20000fe4:   40086488    .word   0x40086488
20000fe8:   40086494    .word   0x40086494
20000fec:   40086380    .word   0x40086380
20000ff0:   40086384    .word   0x40086384
20000ff4:   40086388    .word   0x40086388
20000ff8:   4008639c    .word   0x4008639c
20000ffc:   40086208    .word   0x40086208
20001000:   40086204    .word   0x40086204
20001004:   40050064    .word   0x40050064
20001008:   40101080    .word   0x40101080
2000100c:   401010a0    .word   0x401010a0
20001010:   40101090    .word   0x40101090
20001014:   401010a4    .word   0x401010a4
20001018:   40101088    .word   0x40101088
2000101c:   401010a8    .word   0x401010a8
20001020:   40101094    .word   0x40101094
20001024:   401010ac    .word   0x401010ac

以上编译的C代码如下。

volatile uint32_t vol_dummy_for_read;
#define __SFS(addr, value) *((volatile uint32_t*)addr) = value;
#define SGPIO_SLICE_MUX_CFG0 (*((volatile uint32_t*)  ... some address ... ))

uint32_t camera_SGPIO_init_sub()
{
    __asm volatile ("cpsid i" : : : "memory");

    //  configure pins to SGPIO
    __SFS(P9_0, SCU_SFS_INPUT | 6); // D0, SGPIO0
    __SFS(P9_1, SCU_SFS_INPUT | 6);
    __SFS(P9_2, SCU_SFS_INPUT | 6);
    __SFS(P9_5, SCU_SFS_INPUT | 6);
    __SFS(P7_0, SCU_SFS_INPUT | 7);
    __SFS(P7_1, SCU_SFS_INPUT | 7);
    __SFS(P7_2, SCU_SFS_INPUT | 7);
    __SFS(P7_7, SCU_SFS_INPUT | 7); // D7, SGPIO7

    //  SGPIO8
    __SFS(P4_2, SCU_SFS_INPUT | 7); // PCLK, SGPIO8

    //  configure pins to GPIO
    __SFS(P4_1, SCU_SFS_INPUT | 0); // HSYNC, GPIO2[1]

    //  bring SGPIO clock up to full speed (same as PLL1, M4)
    CGU_BASE_PERIPH_CLK = (0 << 1) | (0 << 11) | (9 << 24);

    //  SLICE_MUX_CFG
    uint32_t SLICE_MUX_CFG_VALUE =
          (1 << 1) /* clock on falling edge */
        | (1 << 2) /* clock from external pin */
        | (3 << 6) /* shift 8 bytes per clock */
        ;

////    see note above (this fixes it)
//vol_dummy_for_read = SGPIO_SLICE_MUX_CFG0 ;

    SGPIO_SLICE_MUX_CFG0  = SLICE_MUX_CFG_VALUE; // A
    uint32_t ret = SGPIO_SLICE_MUX_CFG0;
    SGPIO_SLICE_MUX_CFG8  = SLICE_MUX_CFG_VALUE; // I
    SGPIO_SLICE_MUX_CFG4  = SLICE_MUX_CFG_VALUE; // E
    SGPIO_SLICE_MUX_CFG9  = SLICE_MUX_CFG_VALUE; // J
    SGPIO_SLICE_MUX_CFG2  = SLICE_MUX_CFG_VALUE; // C
    SGPIO_SLICE_MUX_CFG10 = SLICE_MUX_CFG_VALUE; // K
    SGPIO_SLICE_MUX_CFG5  = SLICE_MUX_CFG_VALUE; // F
    SGPIO_SLICE_MUX_CFG11 = SLICE_MUX_CFG_VALUE; // L

    __asm volatile ("cpsie i" : : : "memory");

    return ret;
}

1 个答案:

答案 0 :(得分:2)

(我正在回答我自己的问题;这个答案是基于上述评论中提供的线索而达成的。)

简答

外围设备没有可靠地执行寄存器更新,因为驱动它的外设时钟(CGU_BASE_PERIPH_CLK)在写操作时只是改变了它的速度。在更新时钟速度时设置AUTOBLOCK位消除了这个问题。

<强>讨论

据推测,在频率变化期间,外设的时钟暂时无效,具体取决于条件。也许,如果边缘的时间恰好是正常的,那么非常短的时钟脉冲会在变化期间找到。或类似不愉快的东西沿着时钟线向外围发现。在任何情况下,在这些不可预测的情况下,写入可能不会发生,导致报告失败。

在时钟速度变化和后续分配之间等待一段时间也可以解决问题,这是可以理解的。正如问题中所报告的那样,在写入之前执行寄存器读取也消除了问题;这是因为它需要时间,还是读取操作阻塞(原因不清楚),直到外设时钟结束,目前还不清楚。

仅在功能声明中记录AUTOBLOCK:&#34;在频率变化期间自动阻止时钟&#34;。用户手册未指示在时钟速度变化期间应该设置或清除该位的条件。但是,鉴于此处报告的证据,在更新其中一个设备的时钟速度时始终设置AUTOBLOCK的策略,除非有明确的理由说清楚,这似乎是明智的。

参考:恩智浦LPC43xx用户手册,UM10503 Rev 1.9,第13章。