Después de leer el excelente artículo sobre bare metal de David Welch ( https://github.com/dwelch67/raspberrypi/tree/master/baremetal ), un amigo y yo estamos tratando de implementar un conmutador GPIO simple. Está construido sobre el blinker01 de David Welch ( https://github.com/dwelch67/raspberrypi/tree/master/blinker01 ). Simplemente actualicé los registros periféricos para que correspondan a GPIO 3 en la frambuesa pi. Encontré estas direcciones mirando la hoja de datos BCM2835 ( https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf ). El Capítulo 6 enumera todas las ubicaciones de la configuración de pines GPIO.
Cargamos el código en una tarjeta SD y luego lo encendemos. El programa funciona: obtenemos una onda cuadrada de 2,5 MHz en el osciloscopio.
** ¿Por qué es tan lento? **
El procesador tiene una velocidad de reloj de 1 Ghz. La operación que implementamos recorre 10 líneas de ensamblaje (es decir, hace 10 líneas de ensamblaje y luego se bifurca de nuevo a la primera línea de esas 10). Soy nuevo en los procesadores/bare metal y entiendo que una determinada línea de ensamblaje puede tomar varios ciclos de reloj. Suponiendo que cada línea toma 10 ciclos de reloj, aún esperaría un período de 100 ns para la salida, que sería de 10 MHz. Siento que es un límite inferior conservador en la frecuencia de salida, ya que algunas líneas de ensamblaje solo toman un ciclo.
Además, encontré este artículo: http://codeandlife.com/2012/07/03/benchmarking-raspberry-pi-gpio-speed/
Esta persona logró obtener una salida de 22 MHz en una raspberry pi 1 usando un enfoque similar pero usando mmap de linux. El código que usaron como base se encuentra como primer ejemplo en esta página: http://elinux.org/RPi_GPIO_Code_Samples
** Editar: originalmente pensé que los 22MHz se lograron en una raspberry pi 2, pero eso es incorrecto. Afirman que lograron esta tasa de salida en un pi 1 que tiene el chip BCM 2835 **
Nota: aunque esto discutiblemente pertenece a StackOverflow, sentí que es un problema "más difícil" porque tiene que ver con los circuitos del procesador y los periféricos.
Editar: el código de ensamblaje está aquí: Desensamblaje de la sección .text:
00008000 `<_start`>:
8000: e3a0d902 mov sp, #32768 ; 0x8000
8004: eb000005 bl 8020 <notmain>
00008008 `<hang`>:
8008: eafffffe b 8008 <hang>
0000800c `<PUT32`>:
800c: e5801000 str r1, [r0]
8010: e12fff1e bx lr
00008014 `<GET32`>:
8014: e5900000 ldr r0, [r0]
8018: e12fff1e bx lr
0000801c `<dummy`>:
801c: e12fff1e bx lr
00008020 `<notmain`>:
8020: e92d4010 push {r4, lr}
8024: e59f002c ldr r0, [pc, #44] ; 8058 <notmain+0x38>
8028: ebfffff9 bl 8014 <GET32>
802c: e3c01c0e bic r1, r0, #3584 ; 0xe00
8030: e3811c02 orr r1, r1, #512 ; 0x200
8034: e59f001c ldr r0, [pc, #28] ; 8058 <notmain+0x38>
8038: ebfffff3 bl 800c <PUT32>
803c: e3a01008 mov r1, #8
8040: e59f0014 ldr r0, [pc, #20] ; 805c <notmain+0x3c>
8044: ebfffff0 bl 800c <PUT32>
8048: e3a01008 mov r1, #8
804c: e59f000c ldr r0, [pc, #12] ; 8060 <notmain+0x40>
8050: ebffffed bl 800c <PUT32>
8054: eafffff8 b 803c <notmain+0x1c>
8058: 20200000 eorcs r0, r0, r0
805c: 2020001c eorcs r0, r0, ip, lsl r0
8060: 20200028 eorcs r0, r0, r8, lsr #32
`
El culpable principal es una combinación de limitaciones de hardware/periféricos y configuración del reloj. Si bien no he tenido que trabajar específicamente con BCM Baremetal, estos son problemas comunes de los proyectos baremetal en cualquier arquitectura compleja.
Como sugerencia sobre las limitaciones de los controladores de salida GPIO, puede ver que cuando está conectado como salida de reloj de hardware, la frecuencia de salida máxima es de 125 MHz.
De la página 106 de la hoja de datos del periférico BCM que proporcionó
Frecuencia de funcionamiento : la frecuencia de funcionamiento máxima de los relojes de uso general es de ~125 MHz a 1,2 V, pero se reducirá si los pines GPIO están muy cargados o tienen una carga capacitiva.
Esto es en el contexto de configurar el periférico GPIO para generar el reloj periférico directamente sin alternar el software.
Diría que es razonable esperar que incluso si los relojes están configurados correctamente y la CPU funciona a la velocidad máxima, no puede esperar que un GPIO cambie más rápido que esto debido a limitaciones de hardware.
También conocido como el hecho de que el periférico pueda bloquear su comando de software a tiempo, no significa que los transistores del controlador de salida física, que son grandes y robustos, con mucha carga inherente, puedan cambiar tan rápido como su código puede ejecutarse. Si está realizando pruebas, es imperativo que utilice un osciloscopio con suficiente ancho de banda analógico y sondas de alta calidad, porque también está cambiando su resultado con el sistema de medición. Un analizador lógico puede no ser suficiente, una velocidad de respuesta lenta no es identificable con entradas con umbral.
Parece que si su objetivo es conducir GPIO tan rápido como lo necesita, para fines de reloj, debe usar estos pines de salida de reloj incorporados del periférico. Estos se configuran a través de registros.
CM_GP0CTL
CM_GP0DIV
(repita para las salidas de reloj gp 1 y 2)
Luego, según los resultados de esto, identificará la frecuencia de conmutación máxima para su sistema de hardware teniendo en cuenta la carga máxima de GPIO y el VDD de su circuito PIO.
Si la salida del reloj es más lenta de lo esperado para la configuración de su divisor nominal, esto indicaría que no ha configurado el reloj del sistema, el enrutamiento del reloj y los PLL de manera adecuada.
Una vez que haya identificado ese desacuerdo, puede modificar su código de arranque básico para configurar los PLL y ver si se puede hacer que un cambio controlado por software se ejecute tan rápido como la salida del reloj controlada por hardware y continuar desde allí.
Los factores contribuyentes adicionales pueden estar en las memorias caché de instrucciones y datos, que requieren configuración de software, si no puede alinear el software alternando con el límite de hardware solo a través de PLL, ese sería el próximo lugar en el que buscaría.
Acabo de encontrar esta pregunta en una publicación cruzada.
El problema principal que no se discute en todos los comentarios anteriores es la velocidad del autobús.. El procesador puede funcionar a 3 GHz, pero los buses del chip no. El bus del lado ARM es mucho más lento que 3GHz. El bus hacia el GPIO es aún más lento, funcionando a la velocidad de la GPU. Agregue a eso el tiempo perdido por el cruce del dominio del reloj y el hecho de que los buses son un recurso compartido entre los núcleos ARM y la GPU. Además, el chip utiliza el sistema AXI que tiene un reconocimiento de escritura, por lo que el procesador puede esperar a que llegue el reconocimiento de escritura, que es el doble de la velocidad de respuesta del bus. En la infraestructura del bus, se necesitan varios ciclos de reloj para llevar la señal de un lado del bus al otro (pero permite que haya múltiples transacciones en el bus al mismo tiempo).
Ale..chenski
Ignacio Vázquez-Abrams
Cazador Akins
Lundin
usuario39382
dibosco
usuario39382
Cazador Akins