5

STM32F4 を使用していて、C 内から呼び出された ASM 関数を書き込もうとしています。この関数は、C 関数内で呼び出され、割り込みでも呼び出されます。r4-r7 をプッシュ アンド ポップしています。他に何かする必要がありますか?私の仮定は、r0-r3 はプッシュする必要がないということです。また、ASM 関数でグローバル変数を変更しています。私の推測では、これらは volatile と宣言する必要があります。どんなヒントでも大歓迎です。また、ARM によって概説されている Cortex M4 命令セットが、GCC コンパイラで使用できると思われる命令と同じではないことに気付きました。たとえば、書き戻しはありません。つまり、ポスト インクリメントの r0,[r1],#4 は不正です。どの ASM 命令が許可されているかのリストはありますか? 私はSTM32F4がthumb2を使用すると仮定しています

これまでのところ、機能していないようで、アセンブリのエラーとは別に、考えられる問題が何であるか疑問に思っています

4

2 に答える 2

2

8 時間待つまで自分の質問に答えられませんでしたか? とにかくここに私が得たものがあり、それは動作します!! この関数ではかなりのことが行われています。これは基本的に、正弦値に LUT を使用する正弦波発振器です。また、制御用のポットに接続された ADC を使用して割り当てられる指数値のテーブルも使用します。ルックアップ用にスケーリングされるランプを作成する 32 ビット位相アキュムレータがあります。サイン テーブル (あまり含まれていません) は、14 ビットのテーブル サイズに切り捨てられた 16 ビットの値です。このコードには多くの最適化を行う必要があると確信していますが、少なくともそれで始めることができます。この関数の各パスで 16 個の正弦波サンプル @48k を生成し、(この関数の外で) DMA に転送され、Discovery オンボード コーデックを介して出力されるバッファを埋めています。それは私が言わなければならない非常に滑らかな音です。これまでのところ、合計命令サイクルは約 1200 のようです。必要に応じて最大56000サイクルあるので、これはかなり良いです. 私が苦労していることの1つは、サイン出力のスケーリングです。正弦テーブルは int16_t 値であり、分数を掛けて音量を制御できるようにしたいと考えています。これまでのところ、smul、mulなどを使用して機能するものは何も試していません.

    @ void get_sine(void)
        .align 2                    @ Align to word boundary
        .global get_sine       @ This makes it a real symbol
        .thumb_func
        .type get_sine STT_FUNC    @ Declare get_sine to be a function.

    get_sine:                  @ Start of function definition
        push    {r4-r7}
        ldr     r0,=pitch       @   get pitch address
        ldr     r1,=expoLUT     @   expo_tab address
        ldr     r7,[r0,#0]      @   pitch val into r7
        lsl     r7,r7,#2
        ldr     r7,[r1,r7]      @   move lookup expo tab value with r7 into r7

        ldr     r2,=sineLUT     @   sine_tab base addy
        ldr     r4,=WaveBuffer  @   storage array addy
        ldr     r5,=writePos    @   get writepos addr
        mov     r6,#0           @   clear increment r6

    outloop:
        ldr     r3,=phase       @   phase address to r3
        ldr     r1,[r3,#0]      @   get current phase
        add     r1,r1,r7        @   add current phase and ph_inc
        str     r1,[r3,#0]      @   store phase
        lsr     r0,r1,#18       @   shift it right by 18 into r0 for sine_tab lookup
        lsl     r0,r0,#2        @   align it
        ldr     r0,[r2,r0]      @   lookup sine val with r0 into r1
        lsl     r1,r0,#16       @   shift to left channel
        add     r0,r0,r1        @   add right channel
        ldr     r1,[r5,#0]      @   get writePos
        push    {r1}            @   push it before align
        lsl     r1,r1,#2        @   align address 4
        str     r0,[r4,r1]      @   store sine to WaveBuffer
        pop     {r1}            @   pop writepos back
        add     r1,r1,#1        @   increment array pointer writepos
        ldr     r3,=1024        @   load BUFFERSIZE compare
        cmp     r1,r3           @   skip if less than BUFFERSIZE
        bne     skip
        mov     r1,#0           @   clr writepos if >=BUFFERSIZE

    skip:
        str     r1,[r5,#0]      @   store writepos value
        add     r6,r6,#1        @   increment loop counter
        ldr     r0,=dataSize    @   get datasize counter addr
        ldr     r1,[r0,#0]      @   get val
        add     r1,r1,#1        @   increment datasize counter
        str     r1,[r0,#0]      @   store counter
        cmp     r6,#16          @   compare with 16 (i=0;i<16;i++)
        bne     outloop
        pop     {r4-r7}
        bx      lr



    .section .rodata
        sineLUT:
        @ Array goes in here. Type can be .byte, .hword or .word
        @ NOTE! No comma at the end of a line! This is important

    .word   0x0000,0x000c,0x0018,0x0024,0x0030,0x003c,0x0048,0x0054
    .word   0x0064,0x0070,0x007c,0x0088,0x0094,0x00a0,0x00ac,0x00bc
    .word   0x00c8,0x00d4,0x00e0,0x00ec,0x00f8,0x0104,0x0114,0x0120
    .word   0x012c,0x0138,0x0144,0x0150,0x015c,0x016c,0x0178,0x0184
    .word   0x0190,0x019c,0x01a8,0x01b4,0x01c4,0x01d0,0x01dc,0x01e8
    .word   0x01f4,0x0200,0x020c,0x021c,0x0228,0x0234,0x0240,0x024c
    .word
于 2012-06-10T17:12:26.373 に答える
1

あなたの質問に対するいくつかの回答は、「ARM アーキテクチャのプロシージャ コール標準」という本にあります。ここにリンクがあります。

この本によると、最初の 4 つのレジスタ r0 ~ r3 (および FPU の場合は s0 ~ 15) は、引数値をサブルーチンに渡し、関数から結果値を返すために使用されます。また、ルーチン内で中間値を保持するために使用することもできます (ただし、一般的には、サブルーチン呼び出し間のみ)。レジスタ r4 ~ r8、r10、および r11 (および FPU の場合は s16 ~ s31) は、ルーチンのローカル変数の値を保持するために使用されます。サブルーチンは、このレジスタの内容を保存する必要があります。

今約volatile。はい、プログラムロジックを「壊す」可能性のあるコンパイラの最適化を防ぐためにそれを使用する必要があります。

そしてあなたのサインについて。英語は私の自然言語ではないので、あなたが何を必要としているのかよくわかりませんが、問題の一部として高速で正確な正弦近似が必要な場合は、次の記事に興味があるかもしれません: http://devmaster.net/forums /topic/4648-fast-and-accurate-sinecosine/ http://www.coranac.com/2009/07/sines/.

そして最後。Cortex-M4 のサイン近似関数をほぼ完成させました。FPU を使用し、約 30 サイクルかかり、単一の浮動小数点範囲でゼロ エラーの結果をもたらします。

于 2012-06-11T10:49:22.250 に答える