Autor Tema: Interrupción mediante USB  (Leído 3296 veces)

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

Desconectado matyvico

  • PIC10
  • *
  • Mensajes: 20
Interrupción mediante USB
« en: 13 de Enero de 2014, 19:22:11 »
Buenas a todos!

Estoy desarrollando un proyecto para la facultad (para dos materias), es un generador de señales (para medidas electrónicas) y este se conecta por USB a la PC (para técnicas digitales) y estoy usando:

- Windows 7 (64-bit's)
- CCS versión 4.130
- PICKit 3
- PIC 18F4550

El problema es el siguiente: el generador, para lograr la frecuencia requerida de las señales, no pregunta (generalmente) por ningún estado de ninguna variable (por lo menos yo no puse if, for, etc... jaja). Sin embargo, al mismo tiempo lo que se desea es que si el programa que corre en la PC vuelve a enviar información (sobre una nueva señal a generar o detener la generación) se salga de ese ciclo infinito de generación de la señal y se retome el 'main' del programa que permanece a la espera de información del buffer del usb...

Esto mismo que describo funciona desde una interrupción del tipo de RB0 (si se entra en un ciclo infinito para generar la señal, se logra salir por una interrupción de alto nivel como la que genera RB0), pero el problema es que no se como generar el manejo de una "interrupción" de USB para la recepción de nueva información. Según la ayuda del CCS la interrupción que maneja el USB es:

Citar
Relevant Interrupts:

#int_usb A USB event has happened, and requires application intervention. The USB library that CCS provides handles this interrupt automatically

El problema es que en realidad (según lo que leí en varias partes) ese manejo de interrupción es genérico para todo el funcionamiento del módulo USB y que "todo el tiempo" todas las interrupciones que se generan son tratadas por esa rutina de interrupción y no solo la de recepción de datos (por ejemplo).

En resumen: ¿Existe alguna manera de estando en un ciclo infinito (generando la señal) salir de este cuando se produzca una nueva recepción de datos por el USB desde la PC?

¡Muchas gracias a todos! (por este post y por todos los que ya he usado para tratar de lograr hacer andar este proyecto)

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Interrupción mediante USB
« Respuesta #1 en: 13 de Enero de 2014, 19:32:05 »
En efecto, como mencionas esa interrupcion no es accesible para lo que deseas, lo que puedes hacer es que dentro de tu ciclo infito del main estar verificando si tienes informacion en tu buffer de usb, y en cuanto recibas el dato desado envias a otra parte del código
"Nada es imposible, no si puedes imaginarlo"

Desconectado matyvico

  • PIC10
  • *
  • Mensajes: 20
Re: Interrupción mediante USB
« Respuesta #2 en: 13 de Enero de 2014, 19:38:56 »
En efecto, como mencionas esa interrupcion no es accesible para lo que deseas, lo que puedes hacer es que dentro de tu ciclo infito del main estar verificando si tienes informacion en tu buffer de usb, y en cuanto recibas el dato desado envias a otra parte del código

Gracias por la rápida respuesta rivale, creo que lo que me estas proponiendo es usar la función usb_kbhit(), ¿verdad? El tema es que eso debería estar presente (y constantemente) preguntando por nueva información en el buffer del endpoint ¿no?. No quise hacer eso desde un principio por el hecho de que se me van todos los tiempos calculados para las señales, específicamente para la senoidal (que tuve que retocar NOP por NOP en ASM  :roll: :z) :angry: ).
Lo que me llama la atención es que no exista algo similar a lo que comente al principio como una interrupción por RB0 o algo por el estilo... :roll:

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Interrupción mediante USB
« Respuesta #3 en: 13 de Enero de 2014, 19:42:26 »
para tu senoidal podrias usar tiempos establecidos por interrupciones, asi aunque estes preguntando por datos en tu buffer esto no afecta tu tiempo de muestreo y tambien te evitas el retocar con nops  ;-)
"Nada es imposible, no si puedes imaginarlo"

Desconectado matyvico

  • PIC10
  • *
  • Mensajes: 20
Re: Interrupción mediante USB
« Respuesta #4 en: 13 de Enero de 2014, 19:46:57 »
para tu senoidal podrias usar tiempos establecidos por interrupciones, asi aunque estes preguntando por datos en tu buffer esto no afecta tu tiempo de muestreo y tambien te evitas el retocar con nops  ;-)

Disculpame pero no entiendo a que te referís con "usar tiempos establecidos por interrupciones". Por las dudas aclaro esto: El PIC lee de una tabla valores que forman una señal senoidal, estos salen por el puerto D (se utiliza todo el puerto) a un DAC (con entrada paralelo desde todo el puerto D) que genera una señal analógica que luego va a una serie de OP AMP's que adecuan la ganancia y el Offset de la señal... Perdón si no me hice entender anteriormente y ¡muchas gracias de nuevo!

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Interrupción mediante USB
« Respuesta #5 en: 13 de Enero de 2014, 19:53:21 »
por lo que entiendo tu pic lee los valores de la tabla cada cierto tiempo, que es lo que tuviste que adecuar usando nops, para que la senoidal se genere de forma correcta.

ese tiempo es el que se veria afectado al estar leyendo los datos del usb?
"Nada es imposible, no si puedes imaginarlo"

Desconectado matyvico

  • PIC10
  • *
  • Mensajes: 20
Re: Interrupción mediante USB
« Respuesta #6 en: 13 de Enero de 2014, 20:09:11 »
Claro, me imaginaba que pensabas eso, pero no... Lamentablemente para generar con una buena resolución la señal senoidal y lograr así mismo una frecuencia de 10kHz (consigna de uno de los profesores) el PIC no tiene "tiempo extra" para variar, es decir no se usaron delay's (como delay_ms(), por ejemplo) en ningún momento, el código que muestra la señal (ni siquiera se calcula la señal sino que se muestra una tabla fija pre-calculada) es siempre el mismo, construido de manera modular y lo que cambia la frecuencia de la señal (que de hecho no es variable de a 1 o 10 Hz sino valores fijos de 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000 y 10000 Hz) es la cantidad de valores seguidos de la tabla que se muestran y entre estos una cantidad variable de NOP's (que son los que tuve que ir toqueteando de a poco). Te muestro un trozo para que entiendas mejor porque no soy muy bueno con las ideas y peor con algo tan rebuscado jaja


Para generar 100 Hz obviamente sobra muchisimo tiempo:

Código: [Seleccionar]
case 100: //100 Hz
    #ASM ASIS
        MOVLW 2
        MOVWF FSR0H
        MOVLW 0
        MOVWF FSR0L
       
        RETORNO_100:
        MOVF INDF0, W
        MOVWF PORTD
        INCFSZ FSR0L, 1
        GOTO SALTO_1_100
        INCF FSR0H, 1
        MOVLW 6
        SUBWF FSR0H, 0
        BTFSS STATUS, 2
        GOTO SALTO_1_100
        MOVLW 2
        MOVWF FSR0H
        MOVLW 0
        MOVWF FSR0L
        SALTO_1_100:
       
        MOVF INDF0, W
        MOVWF PORTD
        INCFSZ FSR0L, 1
        GOTO SALTO_2_100
        INCF FSR0H, 1
        MOVLW 6
        SUBWF FSR0H, 0
        BTFSS STATUS, 2
        GOTO SALTO_2_100
        MOVLW 2
        MOVWF FSR0H
        MOVLW 0
        MOVWF FSR0L
        SALTO_2_100:
       
        MOVF INDF0, W
        MOVWF PORTD
        INCFSZ FSR0L, 1
        GOTO SALTO_3_100
        INCF FSR0H, 1
        MOVLW 6
        SUBWF FSR0H, 0
        BTFSS STATUS, 2
        GOTO SALTO_3_100
        MOVLW 2
        MOVWF FSR0H
        MOVLW 0
        MOVWF FSR0L
        SALTO_3_100:
       
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        NOP NOP NOP
        GOTO RETORNO_100
    #ENDASM
    break;

No así para la generación de 10000 Hz:

Código: [Seleccionar]
case 10000: //10000 Hz
    #ASM ASIS
        MOVLW 1
        MOVWF FSR0H
        MOVLW 0
        MOVWF FSR0L
       
        RETORNO_10000:
        MOVF INDF0, W
        MOVWF PORTD
        INCF FSR0L
       
        MOVF INDF0, W
        MOVWF PORTD
        INCF FSR0L
       
        MOVF INDF0, W
        MOVWF PORTD
        INCF FSR0L
                           
        NOP NOP NOP
        GOTO RETORNO_10000
    #ENDASM
    break;

Lo que hace el código es simple, en vez de mostrar un valor de la tabla y luego un NOP (o más) para ajustar la frecuencia (cosa que no funciona bajo ningún punto de vista, incluso con el PIC a 48 MHz) lo que se hace es mostrar un número variable de valores de la tabla (puestos por prueba y error) y luego un número también variable de NOP's (también puestos a prueba y error), de esta forma la distorsión de la señal es mínima (de cualquier manera luego pasa por un muy buen filtro) y pueden así alcanzarse los valores pedidos con un mínimo error en frecuencia.

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Interrupción mediante USB
« Respuesta #7 en: 13 de Enero de 2014, 20:43:37 »
Hola matyvico,

por lo que veo estás en un cuello de botella. Algo vas a tener que cambiar. El CPU del uC es sólo uno. O sea que por más que logres interrumpir al USB sólo cuando recibís un paquete de datos (cosa que si mal no recuerdo no se puede), al ingresar a la interrupción del USB el uC va a dejar de generar la senoidal hasta retornar de la interrupción. Es decir, vos mísmo estás diciendo que ya tenés el CPU al 100% de uso para generar la señal de 10kHz. Por ende, no te sobra tiempo de CPU para absolutamente nada. Me parece que vas a tener que replantear el hardware/software lamentablemente. Tal vez derivar la generación de la senoidal a un uC esclavo, por ejemplo y dejar el 18F4550 para la parte de USB y selección de la frecuencia a generar.

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado xesc0

  • PIC10
  • *
  • Mensajes: 22
Re: Interrupción mediante USB
« Respuesta #8 en: 13 de Enero de 2014, 21:12:40 »

Estoy con Bruno, yo usaría el 18F4550 para comunicación y control y otro pic como esclavo para generar la señal.

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Interrupción mediante USB
« Respuesta #9 en: 13 de Enero de 2014, 22:14:15 »
++;

en efecto, como menciona bruno, creo que para realizar lo que quieres necesitas cambiar la estructura de tu programa
"Nada es imposible, no si puedes imaginarlo"

Desconectado matyvico

  • PIC10
  • *
  • Mensajes: 20
Re:Interrupción mediante USB
« Respuesta #10 en: 13 de Agosto de 2016, 12:00:41 »
Disculpen por el super tiempo muerto, pero estaba revisando los e-mails viejos, vi el tema y quería darle un cierre a como lo terminé realizando.

Siguiendo su consejo terminé usando dos uC uno se encargó de todo lo referido a la comunicación USB con la PC (18F14K50) me parece (junto a un programa que hice con Python 3 + PyQt 4) y otro para la generación de la señal (18F4550). Entre ellos se comunicaban usando la UART y cada vez que enviaba un cambio de la señal desde el programa el 18F14K50 reseteaba al 18F4550, le pasaba los nuevos parámetros y se mostraba la nueva señal. Después del 18F4550 venía obviamente toda una parte de manipulación de la señal del DAC (ganancia, offset, etc.)

Lamentablemente no llegaba con el tiempo y no tenía a mano las herramientas, pero la idea era que el offset y la ganancia también pudieran ser controlados desde la PC, así que eso quedo presente en la aplicación pero sin implementación real.

Les adjunto una captura de pantalla de como quedó la interfaz gráfica y como se ve la señal de salida de DAC desde un analizador lógico.

Si interesa (quizás en otro thread del foro) no tengo ningún problema en subir todo lo referido al proyecto.

Saludos!