2

NXP LPC4330 (Arm Cortex M0/M4 デュアル コア) 用のアプリケーションを構築しています。arm-none-eabi-gcc 4.9.3 を使用してコンパイルしています。コードのある時点で、(32 ビット) メモリ ロケーションへの書き込みを実行しています。その直後に、そのメモリ位置から読み返すと、約 10 分の 1 の頻度で書き込みが行われなかったことが示されます。その後の読み取りは同じことを示しているため、一時的な状態ではありません。割り込みはグローバル レベルで無効にされており、コンパイラによって生成されたアセンブラは明らかに書き込みを試みています。

具体的には、SGPIO ペリフェラルのメモリ マップド レジスタである SLICE_MUX_CFG0 に書き込みます。書き込みが機能すると、ペリフェラルは正しく機能します。リードバックが書き込みが機能していないことを示している場合、ペリフェラルは正しく機能していません。そのため、リードバックで示されているように、問題のレジスタが正しく設定されていないようです。

.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;
}
4

1 に答える 1

2

(私は自分の質問に答えています。この答えは、上記のコメントで提供された手がかりに基づいて到達しました)。

簡潔な答え

ペリフェラルは、それを駆動しているペリフェラル クロック (CGU_BASE_PERIPH_CLK) の速度が書き込み操作時に変更されたばかりであるため、レジスタ更新を確実に実行していません。クロックの速度を更新するときに AUTOBLOCK ビットを設定すると、問題が解消されます。

討論

おそらく、周辺機器へのクロックは、条件によっては、周波数の変更中に一時的に無効になります。おそらく、エッジのタイミングがたまたま正しければ、変更中に非常に短いクロック パルスが通過します。または、同様に不快なものがクロックラインを下って周辺機器に到達します。いずれにせよ、これらの予測不可能な状況では、書き込みが行われず、報告された障害が発生する可能性があります。

当然のことながら、クロック速度の変更とその後の割り当ての間の期間を待機することでも、問題が解消されます。質問で報告されているように、書き込みの前にレジスタの読み取りを実行すると、問題も解消されます。これが時間がかかるためなのか、周辺クロックが安定するまで (理由が不明なため) 読み取り操作がブロックされるためなのかは不明です。

AUTOBLOCK は、「周波数の変更中にクロックを自動的にブロックする」という機能のステートメントまでしか文書化されていません。ユーザー マニュアルには、クロック速度の変更中にビットを設定またはクリアしたままにしておく条件が示されていません。ただし、ここで報告された証拠を考えると、明確な理由がない限り、これらのデバイスのいずれかでクロックの速度を更新するときは常に AUTOBLOCK を設定するポリシーが賢明なようです。

参照: LPC43xx 用の NXP ユーザー マニュアル、UM10503 Rev 1.9、第 13 章。

于 2015-06-12T10:35:50.173 に答える