2012-06-10 8 views
5

Używam STM32F4 i próbuję napisać funkcję ASM z wywołanego z C. Funkcja ma być wywoływana wewnątrz funkcji C, która również jest przerwana. Pcham i popping r4-r7. Czy muszę zrobić cokolwiek innego? Moim założeniem jest, że r0-r3 nie wymaga pchania. Modyfikuję również zmienne globalne za pomocą funkcji ASM. Zgaduję, że powinny one zostać uznane za niestabilne. Wszelkie wskazówki byłyby mile widziane. Zauważyłem także, że instrukcja instrukcji Cortex M4 opisana przez ARM to nie to samo co instrukcje, które wydają się być dostępne dla kompilatora GCC. Na przykład nie ma odpisać, tj. R0, [r1], # 4 dla przyrostu post jest nielegalne. Czy istnieje lista instrukcji ASM, które są dopuszczalne? jestem zakładając STM32F4 wykorzystuje thumb2Funkcja ASM z C ARM osadzona

Jak dotąd nie wydaje się działać i zastanawiam się co ewentualne problemy mogą być Oprócz błędów w montażu

+0

Spróbowałeś? Co nie działało? Mówisz, że próbujesz wywołać funkcję zespołu, ale reszta twojego pytania brzmi tak, jakbyś próbowała je napisać. Spróbuj wyjaśnić lepiej. –

+0

Powinieneś zadeklarować globalny var jako zmienny, ale nie robiłem ARM-a od dłuższego czasu, więc nie mogę pomóc z resztą przepraszam. – lxop

+1

Nie ma powodu, aby zadeklarować zmienną globalną 'volatile', chyba że może ona zmienić się poza kontrolą sterowania programem. Wywołanie funkcji złożenia samo w sobie nie jest wystarczającym powodem, aby wymagać 'volatile'. * Dowolne * wywołanie funkcji może zmienić wartość globalną. –

Odpowiedz

2

nie mógł odpowiedzieć na moje własne pytanie, dopóki nie czekał 8 godzin? tak czy inaczej tutaj jest to, co mam i działa! W tej funkcji dzieje się całkiem sporo. Jest to zasadniczo oscylator fali sinusoidalnej, który używa wartości LUT dla wartości sinusoidalnych. Używa również tabeli wartości wykładniczych, które są przypisane za pomocą ADC podłączonego do puli do kontroli. Jest akumulator z 32-bitową fazą, który tworzy rampę, która jest następnie skalowana do wyszukiwania. Tabela sinusów (której nie zawierałem zbyt wiele) to wartości 16-bitowe obcięte do rozmiaru stołu 14-bitowego. Jestem pewien, że w tym kodzie jest wiele optymalizacji, ale przynajmniej to mnie uruchomi. Generuję 16 próbek fali sinusoidalnej @ 48k przy każdym przejściu tej funkcji i wypełnianiu bufora, który (poza tą funkcją) jest przesyłany do DMA i przesyłany przez pokładowy kodek Discovery. Bardzo gładko brzmi, muszę powiedzieć. Łączne cykle instrukcji wydają się wynosić około 1200 . Mam do 56 000 cykli, jeśli ich potrzebuję, więc jest całkiem niezła. Jedną z rzeczy, z którą mam problemy jest skalowanie wyjścia sinusoidalnego. Tabela sinusowa ma wartości int16_t i chcę ją pomnożyć przez ułamek, aby uzyskać kontrolę głośności. Do tej pory nic Próbowałem prace przy użyciu smul, mul itp

@ 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 
1

Niektóre odpowiedzi na pytania są w „Procedure Call standard dla ARM architektura” książki. Oto link.

Książka mówi, że pierwsze cztery rejestry r0-r3 (i s0-15 dla FPU) są używane do przekazywania wartości argumentów do podprogramu i do zwracania wartości wyniku z funkcji. Mogą być również używane do utrzymywania wartości pośrednich w ramach rutyny (ale, ogólnie, tylko pomiędzy wywołaniami podprogramów). Rejestry r4-r8, r10 i r11 (oraz s16-s31 dla FPU) służą do przechowywania wartości lokalnych zmiennych rutyny. Podprogram musi zachować zawartość tych rejestrów.

Teraz około volatile. Myślę, że tak, należy go użyć, aby zapobiec optymalizacji kompilatora, który może "hamować" programowanie logiki.

I o twoim sinusie. Angielski nie jest moim naturalnym językiem, więc nie bardzo rozumiem, czego potrzebujesz, ale jeśli potrzebujesz jakiegoś szybkiego i precyzyjnego aproksymacji sinusoidalnej jako części twojego problemu, możesz być zainteresowany tymi artykułami: http://devmaster.net/forums/topic/4648-fast-and-accurate-sinecosine/ http: //www.coranac. com/2009/07/sines /.

I ostatnia. Prawie skończyłem moją funkcję aproksymacji sinusa dla Cortex-M4. Wykorzystuje FPU, wykonuje około 30 cykli i daje zerowy wynik błędu w jednym zakresie zmiennoprzecinkowym.

+0

Dzięki za komentarze. Jeśli chodzi o Sine, używam stołu, ponieważ jest to teraz najszybsza droga dla mnie. Muszę wygenerować 384 sinusy –

+0

Dzięki za komentarze. Jeśli chodzi o Sine, używam stołu, ponieważ jest to teraz najszybsza droga dla mnie. Pracuję nad syntezą dodatków i muszę być w stanie wygenerować 24 fale sinusoidalne i koperty ADSR dla każdego z częstotliwości próbkowania 48k, więc szybkość jest bardzo ważna. –