2012-06-10 34 views
5

Estoy usando STM32F4 y tratando de escribir una función ASM desde llamada desde C. La función debe ser llamada dentro de una función C y que también está en una interrupción. Estoy presionando y haciendo estallar r4-r7. ¿Debo hacer algo más? Mi suposición es r0-r3 no es necesario presionar. También estoy modificando las variables globales con la función ASM. Mi conjetura es que estos deberían declararse volátiles. Cualquier consejo sería bienvenido. También he notado que el conjunto de instrucciones Cortex M4 descrito por ARM no es lo mismo que las instrucciones que parecen estar disponibles para el compilador GCC. Por ejemplo, no hay escritura atrás, es decir, r0, [r1], # 4 para el incremento posterior es ilegal. ¿Hay una lista de las instrucciones de ASM permitidas? Asumo STM32F4 utiliza thumb2Función ASM de C ARM incrustado

Hasta el momento no parece estar funcionando y me pregunto cuáles son los temas posibles podrían ser Aparte de los errores en el montaje

+0

¿Lo intentó? ¿Qué no funcionó? Dice que está tratando de llamar a una función de ensamblaje, pero el resto de su pregunta parece que está intentando escribir una. Por favor trata de explicar mejor. –

+0

Definitivamente debería declarar la var global como volátil, pero no he hecho ARM asm por un tiempo, así que no puedo evitar el resto lo siento. – lxop

+1

No hay ninguna razón para declarar una variable global 'volátil' a menos que pueda cambiar fuera del flujo de control del programa. Llamar a una función de ensamblaje no es una razón suficiente para requerir 'volátil'. * Cualquier llamada de función * puede cambiar el valor de global. –

Respuesta

2

no podía responder a mi propia pregunta hasta que yo esperó 8 horas? de todos modos aquí es lo que tengo y funciona !! Hay bastante en esta función. Básicamente es un oscilador de onda sinusoidal que utiliza una LUT para valores sinusoidales. También usa una tabla de valores exponenciales que se asignan usando ADC conectado a un pot para control. Hay un acumulador de fase de 32 bits que crea una rampa que luego se escala para la búsqueda. La tabla sinusoidal (que no incluí mucho) es un valor de 16 bits truncado a un tamaño de tabla de 14 bits. Estoy seguro de que hay muchas optimizaciones para hacer en este código, pero al menos me ayuda a comenzar. Estoy generando 16 muestras de onda sinusoidal a 48k con cada pasada de esta función y llenando un buffer que (fuera de esta función) se transfiere a DMA y se envía a través del códec de Discovery incorporado. Es un sonido muy suave, debo decir. El total de ciclos de instrucción parece estar alrededor de 1200 hasta el momento. Tengo hasta 56000 ciclos si los necesito así que esto es bastante bueno. Una cosa con la que estoy teniendo problemas es escalar la salida sinusoidal. La tabla senoidal es int16_t valores y quiero poder multiplicarla por una fracción para obtener control de volumen. Hasta el momento nada de lo que he intentado obras utilizando smul, etc. 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 
1

Algunas respuestas a sus preguntas se encuentran en el "Call estándar Procedimiento para la arquitectura ARM" libro. Aquí está el link.

El libro dice que los primeros cuatro registros r0-r3 (y s0-15 para FPU) se utilizan para pasar valores de argumento a una subrutina y devolver un valor de resultado de una función. También se pueden usar para mantener valores intermedios dentro de una rutina (pero, en general, solo entre llamadas de subrutina). Los registros r4-r8, r10 y r11 (y s16-s31 para FPU) se utilizan para contener los valores de las variables locales de una rutina. Una subrutina debe preservar el contenido de estos registros.

Ahora sobre volatile. Creo que sí, debes usarlo para evitar optimizaciones del compilador que puedan "frenar" tu lógica de programación.

Y sobre su seno. El inglés no es mi lenguaje natural, por lo que no entiendo muy bien lo que necesita, pero si necesita una aproximación sine rápida y precisa como parte de su problema, puede interesarle este artículo: http://devmaster.net/forums/topic/4648-fast-and-accurate-sinecosine/ http: //www.coranac. com/2009/07/senos /.

Y el último. Casi he terminado mi función de aproximación sinusoidal para Cortex-M4. Utiliza FPU, toma alrededor de 30 ciclos y trae el resultado del error zerro en un rango de coma flotante simple.

+0

Gracias por los comentarios. Respecto al seno Estoy usando una tabla, ya que es la forma más rápida para mí en este momento. Necesito generar 384 seno –

+0

Gracias por los comentarios. Respecto al seno Estoy usando una tabla, ya que es la forma más rápida para mí en este momento. Estoy trabajando en la síntesis de aditivos y necesito poder generar 24 ondas sinusoidales y sobres ADSR para cada una de las frecuencias de muestreo de 48k, por lo que la velocidad es muy importante. –