2つのPWMのタイミングを揃えて、一方が他方から特定のオフセットを持つようにするコードがあります。プロジェクトの最適化が無効になっています。ちゃんとしたタイミングに必要なオフセットが変わってしまったことに気づくまでは、うまくいっていると思っていました。2つのタイマーを再起動するというタイムクリティカルな機能のかなり前に、関数呼び出し(テスト関数をコメントアウト)を追加することで問題を再現することができました。この例のタイミングの差は ~72ns ですが、他のコード変更によって差が大きくなったり小さくなったりすることがわかりました。デバイスのコマンドラインインターフェイスを使用して、デフォルト値でAlignPWMs関数を再度呼び出すと、同じタイミングが生成されます。他の値で AlignPWMs 関数を呼び出すと、既定値と一致するオフセット変更が生成されます。要約すると、コードを再度変更するまで、AlignPWMs 関数に渡される値は、リセットや電源喪失を通じてデフォルト値と一致するオフセットを生成します。
問題の原因を特定するために何度も試みたため、「__attribute__(((整列(32)))」、「__DSB()", "__ISB()」、および「__DMB))」を使用しました。これを使用して、コードの位置合わせ、命令とデータの同期、明示的なメモリ操作の順序の制御を試みました。また、逆アセンブルをレビューしたところ、関数呼び出しの変更以外に、同じアセンブリ コードが生成されていることがわかりました。
ARMがコードの変更で何かを変更する原因となっている2つのCTIMER_StartTimer関数呼び出しの処理方法には何か異なるものがあるはずだと思いますが、何が原因なのか、問題を修正するために何をすべきなのか途方に暮れています。どんな提案でもいただければ幸いです。また、2つのPWMを位置合わせする他の方法にもオープンです。
void Test( void )
{
}
__attribute__((aligned(32)))
void AlignPWMs( uint16_t nOffset )
{
// Test();
/* Disable the global interrupt to guarantee timing */
uint32_t primaskValue = DisableGlobalIRQ();
CTIMER_StopTimer( CTIMER0 );
CTIMER_Reset( CTIMER0 );
CTIMER_StopTimer( CTIMER3 );
CTIMER_Reset( CTIMER3 );
CTIMER0->TC = nOffset;
__DSB(); // Data Synchronization Barrier - completes all explicit memory accesses
__ISB(); // Instruction Synchronization Barrier - flushes the pipeline in the processor
__DMB(); // Data Memory Barrier - Ensures the apparent order of the explicit memory operations
CTIMER_StartTimer( CTIMER0 );
__DMB(); // Data Memory Barrier - Ensures the apparent order of the explicit memory operations
CTIMER_StartTimer( CTIMER3 );
__DMB(); // Data Memory Barrier - Ensures the apparent order of the explicit memory operations
EnableGlobalIRQ( primaskValue );
}私は、時間に敏感なコードをできるだけシンプルにすることで、この問題を回避しました。ペリフェラル レジスタ アドレスを事前に逆参照し、ビット単位または等号演算子を使用する代わりに割り当てを行いました。また、2 つのステートメントを使用する代わりに、2 つの式の割り当てをチェーンしました。これにより、アセンブリはわずか5行になり、関数の内部と外部の両方でコードを変更した後も一貫したタイミングが保たれているように見えます。
// Get the address of the TCR location to be change so that
// dereferencing does not need to occur in the time critical code
volatile uint32_t * px = & ( CTIMER3->TCR );
volatile uint32_t * py = & ( CTIMER0->TCR );
__DSB(); // Data Synchronization Barrier - completes all explicit memory accesses
__ISB(); // Instruction Synchronization Barrier - flushes the pipeline in the processor
__DMB(); // Data Memory Barrier - Ensures the apparent order of the explicit memory operations
* px = * py = CTIMER_TCR_CEN_MASK;
__DMB(); // Data Memory Barrier - Ensures the apparent order of the explicit memory operations2 つの PWM に使用している CTIMER ピンは、将来必要になった場合に提案を実装できる構成で SCTIMER 機能もサポートしていることがわかります。
問題は、タイマーを再起動する 2 行の外側にコードをプロジェクトに追加すると、PWM のオフセットが変更されることです。私が挙げた例では、テスト関数を追加すると72nsの変化が発生しました。この問題が見つかったのは、この関数以外のプロジェクト内のコードに対する他の変更により、PWM タイミング オフセットも変更されるように見えるためです。2つのタイマーを有効にするクリティカルタイミングセクションにないコードを変更すると、2つのPWMタイマー間のオフセットが変更されるため、混乱しています。私の予想では、2 つのタイマーを有効にする重要なタイミング セクションが変更されない場合、オフセットのタイミングは常に まったく同じ になるはずです。
現在の動作方法では、プロジェクトでコードを変更すると、PWM 間の実際のタイミング オフセットが変更されるため、オフセットとして 150 を渡すと、プロジェクトでコードが変更される前と同じオフセットが 2 つのタイマーの再起動と関係がなくても、オシロスコープで確認される PWM タイミングと同じオフセットが生成されません。