Autor Tema: Mis experiencias con Teensy 3.6  (Leído 12828 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #15 en: 15 de Mayo de 2017, 13:59:41 »
He conseguido compilar desde línea de comandos.

Sólo hay que seguir los siguientes pasos:
1. Copiar en otra dirección todo el contenido del directorio "Arduino/hardware/teensy/avr/cores/teensy3"
    Es necesario copiar el directorio en otra dirección para no corromper los archivos que utiliza Arduino.
2. Entrar en el directorio y modificar el Makefile para actualizar las rutas (paths) correctos
    Compilador: Arduino/hardware/tools/arm/bin
    Librerias: Arduino/hardware/teensy/avr/libraries
3. Modificar el archivo main.cpp para incluir el programa de usuario
4. Compilar con make
5. Cargar el programa en Teensy con teensy_loader_cli:
    https://www.pjrc.com/teensy/loader_cli.html
    https://github.com/PaulStoffregen/teensy_loader_cli

Saludos.
« Última modificación: 15 de Mayo de 2017, 14:02:17 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #16 en: 15 de Mayo de 2017, 14:04:31 »
No he sido capaz de generar el código ensamblador.
He probado con la opción -S y da error.
La opción -fverbose-asm tampoco genera ensamblador.

¿Alguna idea?

Saludos.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Mis experiencias con Teensy 3.6
« Respuesta #17 en: 15 de Mayo de 2017, 14:10:40 »
si utiliza los arm-none-eabi-* creo que podrias usar el arm-none-eabi-objdump, para hacer el dissasembly del .o generado.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #18 en: 15 de Mayo de 2017, 17:30:05 »
Este es el bucle que enciende y apaga el led:
Código: ASM
  1. ldr     r3, .L4
  2.         ldr     r3, [r3, #104]
  3.         movs    r2, #1
  4. .L2:
  5.         strb    r2, [r3, #128]
  6.         strb    r2, [r3, #256]
  7.         b       .L2

Parece que todo está bien. Estoy pensando que quizás tarda tanto porque hay retardo en la escritura a memoria.

Un saludo.

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
Re:Mis experiencias con Teensy 3.6
« Respuesta #19 en: 15 de Mayo de 2017, 19:12:56 »
Gracias por compartir los avances que vas teniendo :).

Con respecto a la frecuencia que alcanzan los pines, en algunos micros la frecuencia a la cual pueden "togglear" esta limitado por el mismo periferico, no conozco los Kinetis pero en un micro que tengo lo maximo a lo que pueden cambiar de estado es ~ 20MHz, tal vez llegaste en ese limite ( al limite del micro que tienes en la Teensy ) y por eso no pueden in más rápido.

Ese dato debe de estar en el datasheet, pero entre los tantos que tienen para cada familia de micros no sabria en cual mirar.

Saludos

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Mis experiencias con Teensy 3.6
« Respuesta #20 en: 15 de Mayo de 2017, 19:45:23 »
Código: C
  1. .L2:
  2.         strb    r2, [r3, #128]
  3.         strb    r2, [r3, #256]
  4.         b       .L2

El loop es ese. Y es lo minimo que puede haber... Ya con los valores precargados y luego ejecutar las instrucciones, Los store creo que ocupan 2 ciclos cada uno, pero luego el branch ocupa de 2 a 4 ciclos segun si debe limpiar todo el pipeline. Y ahi deberia tener tus 8, pero seria mas corto el pulso en alto.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Mis experiencias con Teensy 3.6
« Respuesta #21 en: 15 de Mayo de 2017, 22:54:20 »
Y el assemby usando las instrucciones de Arduino?
-
Leonardo Garberoglio

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #22 en: 16 de Mayo de 2017, 03:22:56 »
En el datasheet no he encontrado el dato de máxima velocidad de los pines de salida:
http://www.nxp.com/assets/documents/data/en/data-sheets/K66P144M180SF5V2.pdf
Pero en el DSPI dicen que la velocidad máxima es de 30MHz.

El loop (branch) no tarda nada. Lo he probado con el osciloscopio. Si repito dentro del bucle varias veces las instrucciones de subir y bajar nivel, siempre tarda 4 ciclos cada una. El branch no añade ningún ciclo extra. Al ser tan pequeño el código debe almacenarlo todo en el prefetch con predicción de salto.

Para elgarbe: las instrucciones de Arduino son C.

Saludos.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Mis experiencias con Teensy 3.6
« Respuesta #23 en: 16 de Mayo de 2017, 07:33:42 »
Pero que assemby te genera?, porque si tarda mucho más debe haber algo más.
-
Leonardo Garberoglio

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #24 en: 16 de Mayo de 2017, 08:36:19 »
Lo que he puesto es el assembly generado desde línea de comandos. En principio debe ser el mismo que el generado por el IDE de Arduino (he utilizado el mismo makefile) pero lo voy a comprobar enviando al Teensy el archivo compilado desde línea de comandos.
También voy a probar a meter assembler en Arduino, pero el paso de parámetros me resulta complicado en GCC.

Saludos.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Mis experiencias con Teensy 3.6
« Respuesta #25 en: 16 de Mayo de 2017, 09:10:45 »
Me parece que es evidente que el assembly generado por el primer programa que pusiste no es igual al generado por el segundo ya que los tiempos sin distintos. En el primero usas librería de c++ y en el segundo macros.
Mi teoría es que el código generado usando las librerías de wiring? Arduino? C++? O como se llame lo del primer ejemplo agrega un montón de código innecesario y es lo que creo se llama overhead de c++.

Sds.
-
Leonardo Garberoglio

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #26 en: 16 de Mayo de 2017, 11:18:07 »
En el primer caso hacía uso de una función c de Arduino que hace de enlace con el hardware de cada placa:

digitalWrite(pin, level)

No utiliza C++ ni tiene overhead. Tarda más en ejecutarse porque tiene un código c que realiza ciertas simplificaciones y comprobaciones antes de escribir el pin.
La función está definida en el archivo Arduino/hardware/teensy/avr/cores/teensy3/pins_teensy.c:
Código: C
  1. void digitalWrite(uint8_t pin, uint8_t val)
  2. {
  3.         if (pin >= CORE_NUM_DIGITAL) return;
  4.  
  5.         if (*portModeRegister(pin)) {
  6.                 if (val) {
  7.                         *portSetRegister(pin) = 1;
  8.                 } else {
  9.                         *portClearRegister(pin) = 1;
  10.                 }
  11.         } else {
  12.                 volatile uint32_t *config = portConfigRegister(pin);
  13.                 if (val) {
  14.                         *config |= (PORT_PCR_PE | PORT_PCR_PS);
  15.                 } else {
  16.                         *config &= ~(PORT_PCR_PE);
  17.                 }
  18.         }
  19. }


La función digitalWrite() a su vez utiliza para escribir en los pines, una macro basada en una tabla de punteros.
La macro portSetRegister(pin) está definida en el archivo Arduino/hardware/teensy/avr/cores/teensy3/pins_arduino.h:
Código: C
  1. #define portSetRegister(pin)    ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32))
  2. #define portClearRegister(pin)  ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64))
  3. #define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96))

La macro está basada en una tabla constante de punteros digital_pin_to_info_PGM[] que está definida en el archivo Arduino/hardware/teensy/avr/cores/teensy3/pins_teensy.c

Código: C
  1. #if defined(KINETISK)
  2. #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000)
  3. #define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit)))
  4. const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[] = {
  5.         {GPIO_BITBAND_PTR(CORE_PIN0_PORTREG, CORE_PIN0_BIT), &CORE_PIN0_CONFIG},
  6.         {GPIO_BITBAND_PTR(CORE_PIN1_PORTREG, CORE_PIN1_BIT), &CORE_PIN1_CONFIG},
  7.         {GPIO_BITBAND_PTR(CORE_PIN2_PORTREG, CORE_PIN2_BIT), &CORE_PIN2_CONFIG},
  8.         {GPIO_BITBAND_PTR(CORE_PIN3_PORTREG, CORE_PIN3_BIT), &CORE_PIN3_CONFIG},
  9.         {GPIO_BITBAND_PTR(CORE_PIN4_PORTREG, CORE_PIN4_BIT), &CORE_PIN4_CONFIG},
  10.         {GPIO_BITBAND_PTR(CORE_PIN5_PORTREG, CORE_PIN5_BIT), &CORE_PIN5_CONFIG},
  11.         {GPIO_BITBAND_PTR(CORE_PIN6_PORTREG, CORE_PIN6_BIT), &CORE_PIN6_CONFIG},
  12.         {GPIO_BITBAND_PTR(CORE_PIN7_PORTREG, CORE_PIN7_BIT), &CORE_PIN7_CONFIG},
  13.         {GPIO_BITBAND_PTR(CORE_PIN8_PORTREG, CORE_PIN8_BIT), &CORE_PIN8_CONFIG},
  14.         {GPIO_BITBAND_PTR(CORE_PIN9_PORTREG, CORE_PIN9_BIT), &CORE_PIN9_CONFIG},
  15.         {GPIO_BITBAND_PTR(CORE_PIN10_PORTREG, CORE_PIN10_BIT), &CORE_PIN10_CONFIG},
  16.         {GPIO_BITBAND_PTR(CORE_PIN11_PORTREG, CORE_PIN11_BIT), &CORE_PIN11_CONFIG},
  17.         {GPIO_BITBAND_PTR(CORE_PIN12_PORTREG, CORE_PIN12_BIT), &CORE_PIN12_CONFIG},
  18.         {GPIO_BITBAND_PTR(CORE_PIN13_PORTREG, CORE_PIN13_BIT), &CORE_PIN13_CONFIG},
  19.         {GPIO_BITBAND_PTR(CORE_PIN14_PORTREG, CORE_PIN14_BIT), &CORE_PIN14_CONFIG},
  20.         {GPIO_BITBAND_PTR(CORE_PIN15_PORTREG, CORE_PIN15_BIT), &CORE_PIN15_CONFIG},
  21.         {GPIO_BITBAND_PTR(CORE_PIN16_PORTREG, CORE_PIN16_BIT), &CORE_PIN16_CONFIG},
  22.         {GPIO_BITBAND_PTR(CORE_PIN17_PORTREG, CORE_PIN17_BIT), &CORE_PIN17_CONFIG},
  23.         {GPIO_BITBAND_PTR(CORE_PIN18_PORTREG, CORE_PIN18_BIT), &CORE_PIN18_CONFIG},
  24.         {GPIO_BITBAND_PTR(CORE_PIN19_PORTREG, CORE_PIN19_BIT), &CORE_PIN19_CONFIG},
  25.         {GPIO_BITBAND_PTR(CORE_PIN20_PORTREG, CORE_PIN20_BIT), &CORE_PIN20_CONFIG},
  26.         {GPIO_BITBAND_PTR(CORE_PIN21_PORTREG, CORE_PIN21_BIT), &CORE_PIN21_CONFIG},
  27.         {GPIO_BITBAND_PTR(CORE_PIN22_PORTREG, CORE_PIN22_BIT), &CORE_PIN22_CONFIG},
  28.         {GPIO_BITBAND_PTR(CORE_PIN23_PORTREG, CORE_PIN23_BIT), &CORE_PIN23_CONFIG},
  29.         {GPIO_BITBAND_PTR(CORE_PIN24_PORTREG, CORE_PIN24_BIT), &CORE_PIN24_CONFIG},
  30.         {GPIO_BITBAND_PTR(CORE_PIN25_PORTREG, CORE_PIN25_BIT), &CORE_PIN25_CONFIG},
  31.         {GPIO_BITBAND_PTR(CORE_PIN26_PORTREG, CORE_PIN26_BIT), &CORE_PIN26_CONFIG},
  32.         {GPIO_BITBAND_PTR(CORE_PIN27_PORTREG, CORE_PIN27_BIT), &CORE_PIN27_CONFIG},
  33.         {GPIO_BITBAND_PTR(CORE_PIN28_PORTREG, CORE_PIN28_BIT), &CORE_PIN28_CONFIG},
  34.         {GPIO_BITBAND_PTR(CORE_PIN29_PORTREG, CORE_PIN29_BIT), &CORE_PIN29_CONFIG},
  35.         {GPIO_BITBAND_PTR(CORE_PIN30_PORTREG, CORE_PIN30_BIT), &CORE_PIN30_CONFIG},
  36.         {GPIO_BITBAND_PTR(CORE_PIN31_PORTREG, CORE_PIN31_BIT), &CORE_PIN31_CONFIG},
  37.         {GPIO_BITBAND_PTR(CORE_PIN32_PORTREG, CORE_PIN32_BIT), &CORE_PIN32_CONFIG},
  38.         {GPIO_BITBAND_PTR(CORE_PIN33_PORTREG, CORE_PIN33_BIT), &CORE_PIN33_CONFIG},
  39. };

Este código extra de llamada a función y de comprobación del rango del pin es lo que hace que la función sea más lenta que la escritura directa a memoria. La ventaja obvia es que simplifica bastante la tarea de activar un pin.


En el segundo programa hice uso directamente de la macro portSetRegister(pin) para escribir en el pin de salida.

Un saludo.
« Última modificación: 17 de Mayo de 2017, 13:01:43 por Picuino »

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Mis experiencias con Teensy 3.6
« Respuesta #27 en: 16 de Mayo de 2017, 11:22:53 »
Excelente!
-
Leonardo Garberoglio

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #28 en: 16 de Mayo de 2017, 11:35:41 »
El osciloscopio me marca 169ns para la llamada a la función digitalWrite(), que a 180MHz significan:
  169ns / 5.555ns = 30 ciclos de reloj

Lo que no termino de entender es porqué no tarda solo 2 ciclos de reloj la instrucción  "*portSetRegister(13) = 1"
que en ensamblador se traduce en una simple instrucción "strb    r2, [r3, #128]"

A ver si escribiendo directamente en ensamblador funciona bien.

Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:Mis experiencias con Teensy 3.6
« Respuesta #29 en: 16 de Mayo de 2017, 12:35:06 »
Bien, el problema definitivamente no está en el programa.
El retardo se produce en la escritura a la memoria de activación o borrado de pin.

Este es el programa que he probado:

Código: C
  1. void setup() {
  2.   pinMode(13, OUTPUT);
  3.  
  4.   __asm__ volatile (
  5.     " ldr     r3, =digital_pin_to_info_PGM"  "\n"
  6.     " ldr     r3, [r3, #104]"  "\n"
  7.     " movs    r2, #1"          "\n"
  8.     ".repeat_label:"           "\n"
  9.     " strb    r2, [r3, #128]"  "\n"
  10.     " strb    r2, [r3, #256]"  "\n"
  11.     " b       .repeat_label"   "\n"
  12.     :  // Outputs
  13.     :  // Inputs
  14.     : "r2", "r3" // Clobbers
  15.   );
  16.  
  17. }
  18.  
  19. void loop() {}

El bucle principal está compuesto por dos instrucciones assembler "strb" y por un salto incondicional o branch. Cada una de las instrucciones "strb" tarda 4 ciclos de reloj en vez de los 2 ciclos declarados en el datasheet y el branch no tarda nada en ejecutarse.

Las constantes están sacadas directamente del código desensamblado anteriormente.
En concreto:
#104 es la posición 13 (pin13) de la tabla de punteros digital_pin_to_info_PGM donde cada una de las posiciones ocupa 8 bytes (13*8 = 104)
#128 es el offset en bytes correspondiente a la dirección de SetPin
#128 es el offset en bytes correspondiente a la dirección de ClearPin

Saludos.


 

anything