miércoles, 10 de octubre de 2012

Control de Rotor de LU7HZ (firmware)

Aprovechando el fin de semana largo provocado por el "puente" del feriado del 12 de Octubre, que en el peculiar calendario argentino de feriados se celebra el Lunes 8 de Octubre, pude progresar en completar la construcción del prototipo de hardware asi como la finalización y la depuración del firmware.
El hardware está documentado en una entrada anterior y no ha tenido variantes significativas con la excepción de remover el capacitor de desacople en pin 4 (GP3) del PIC 12F675 que probó generar mas problemas que los que solucionaba. Por ahora la versión prototipo sigue teniendo un potenciometro para simular la señal de realimentación de posición del rotor.
El firmware, tal como lo había anticipado, fue construido en mikro Pascal PRO for PIC usando el excelente ambiente provisto por Mikroelectrónica. Este software en su versión FREE permite desarrollar código de hasta 1K de extensión, lo que es ideal para el PIC 12F675 que no tiene mas que eso.
Tal como de alguna manera ya anticipaba la combinación de un hardware muy básico con una aplicación relativamente compleja para los recursos disponibles resultó un desafío interesante y entretenido. En primer lugar hice un pequeño software de diagnóstico que me permitiera poner a punto la configuración del PIC, las rutinas de entrada/salida serie y los puertos digitales/analógicos configurados. Esto parece a priori como un trabajo redundante porque ese pequeño programa (que llamé hztest.mpas) se deja de lado para el programa final. Sin embargo ahorra tiempo en forma invaluable al permitir concentrarse en configurar correctamente las opciones y registros del PIC 12F675, luego testear los cableados eléctricos y finalmente poner a punto tanto la recepción como la transmisión serie. Una opción interesante pare este propósito es poder emitir letras "U" (así mayúsculas) puesto que en ASCII mas con un bit de arranque y uno de parada dan un tren de pulsos regulares que permite medir con bastante precisión el ancho usando un osciloscopio y por lo tanto ir calibrando los retardos para dar con la velocidad justa. La conversión de niveles de tensión RS232 a TTL se resuelve muy económica y simplemente con el MAX232 el cual confirma que es la mejor opción para este tipo de diseños.
El segundo paso fue avanzar sobre el corazón de la lógica del programa principal, pero utilizando directivas de compilación condicional ({$DEFINE},{$IFDEF/$ENDIF}) para agregar o separar pedazos de código.
Es importante utilizar estos recursos en lugar del mucho mas crudo recurso de "comentar" partes del programa que uno quiere incluir o excluir, la experiencia me dice que esa es una mala práctica con la que inevitablemente comentamos algo de mas o de menos, o peor aun, borramos algo que no debemos con lo que se generan "bugs" de muy dificil seguimiento.
Con este recurso anulé todas las partes relativas a I/O tanto digital como serie o analógico para que las rutinas respectivas no estuvieran esperando un input que no ocurriría (todavía) y los retardos no fueran tediosos de seguir (apretar 100 veces una tecla para recorrer un loop de retardo, por ejemplo). Con esta salvedad ejecuté el programa en el ambiente de simulación provisto por el compilador con lo que pude depurar la lógica de mas alto nivel de procesamiento de comandos, lectura de sensores y control de rotación.
El tercer paso fue probar el programa ya compilado completo con un terminal ASCII (una versión provista por el compilador mismo) hasta despulgar tanto la recepción como emisión por el puerto serie y luego la lógica básica del control.
Para ayudarme en este paso inclui en el programa un modo especial de "diagnóstico" que se activa si cuando el micro se prende descubre que está apretado el pulsador en GP4 (que posteriormente se utilizará para establecer el acimut semi-automático). En este modo de diagnóstico el programa emite alguna información adicional que ayuda para saber si el funcionamiento es correcto.
Aqui me enfrenté con el primer problema realmente serio, tal como está implementada la rutina serie es "half-duplex", es decir no puede recibir y transmitir a la vez. Esto ocurre porque los "bits" durante la recepción o la transmisión son controlados mediante retardos de software muy precisos, pero que mientras el procesador los controla no puede hacer otra cosa; es decir, si está controlando la duración de un bit parte de la transmisión de un caracter no está leyendo el pin de entrada para ver si está comenzando la recepción de otro (y viceversa). Y la recepción de comandos por momentos era buena y por momentos dejaba de serlo. Finalmente fui depurando los retardos para que el funcionamiento fuera consistentemente correcto; para mi sorpresa la lógica básica de funcionamiento "semi-automático" funcionó bien rápido y el controlador actuaba correctamente prendiendo el pin correspondiente al actuador correcto para ir en la dirección de giro que se suponía que tenía que ir y deteniendose cuando la posición del rotor (simulado) marcaba lo pedido.
Por último conecté el controlador con el programa N1MMRotor.exe de la suite del N1MM, por gentileza deTom Wagner (N1MM) especialmente para esta prueba contaba con el código fuente de este programa y por lo tanto sabía exactamente que enviaría y que esperaría recibir en cada momento, lo que facilitó enórmemente el proceso de depuración. Proceso que resultó mas lento y engorroso que lo que hubiera esperado por pruebas previas puesto que el programa utiliza el puerto serie con solo un bit de stop (había escrito el firmware para poder realizar el procesamiento durante los dos bits de stop); lamentablemente el programa no tiene como opción configurar esto; y esto restringía enormemente los recursos disponibles en el procesador. Este programa N1MMRotor ordena al controlador que tiene que hacer y obtiene información de estado por medio del protocolo Hy-Gain DCU-1 (en realidad una variante mas moderna implementada en el rotor EZ-Rotor).
Al principio nada andaba. Siguiendo con el osciloscopio las señales (curiosa la combinación de mundos en este tipo de diseño...) pude verificar que los comandos efectivamente llegaban a la pata 4 del PIC (GP3) con la polaridad y tiempos correctos pero nada salia de la pata 2 (GP5) en respuesta. Es decir el firmware no estaba entendiendo que lo que recibía fueran comandos válidos, y por lo tanto no generaba respuestas. En particular al comando "AI1;" al cual el controlador debería contestar con "nnn;" donde "nnn" es el acimut en grados. Multiples pruebas despues llegué a la conclusión que el problema era de timing por lo que con ajustes progresivos a las rutinas respectivas primero consegui que funcionaran los comandos básicos (tales como AI1; o AM1;) con lo que pude verificar que cuando el comando era comprendido y se producía una respuesta esta era correctamente tomada e interpretada por el programa N1MMRotor. El problema remanente fue con "AP1nnn;" que es el comando para establecer una dirección de destino; distintos problemas en la lógica de interpretar ese comando, por ser mas largo y por tener que convertir desde la representación en ASCII del número a un número que pudiera manipularse matemáticamente requirieron iteraciones adicionales.
El problema básico es lo muy al límite que se encuentran los recursos del procesador (pero sin que esto sea una queja, despues de todo es la fuente de diversión). El N1MMRotor envia en forma continua "AP1xxx;AM1;", esto es establece la dirección de destino y dispara el movimiento. Lo hace además son solo un bit de parada entre ambos comandos (200 microsegundos a 4800 bps), es un tiempo relativamente corto para hacer todo el procesamiento, en especial cuando la lógica original del puerto serie esperaba medio bit para asegurar que estaba el stop bit como corresponde, dejando solo algo menos de 100 microsegundos de margen. Esto es poco toda vez que eso equivale a un poco mas de 50 instrucciones de máquina, y esto es mas o menos lo que toma la lógica de procesar los comandos, controlar los sensores y vigilar la rotación. 
Finalmente, ajustando los retardos y optimizando el código pude acomodar que tuviera margen para procesar. Afortunadamente ninguno de los dos comandos requiere respuesta. Por otra parte si el N1MMRotor enviara un pedido de acimut en forma inmediatamente anterior a estos comandos probablemente ahi si van a existir conflictos porque estaría enviando la respuesta cuando le llega el nuevo comando; confío que en la práctica eso será un escenario poco frecuente y que no complicara el uso real del controlador.
En el estado actual el firmware está implementado en el programa HZRotor  (con su versión en hex Intel HZRotor). El programa ha superado las primeras pruebas y anda razonablemente bien, resta aún someterlo a pruebas mas rigurosas y al "bautismo de fuego" de efectivamente utilizarlo en el aire, y si mostrara signos de solidez incluso durante el CQ WW que se aproxima. Tiene aún una tendencia a ignorar los comandos de cambio de dirección, los que en oportunidades tienen que emitirse mas de una vez, sospecho del mismo problema de atiempamiento que al comienzo impedía recibir todos los comandos, solo que mas mitigado.
Seguramente haré las pruebas en un clásico estilo "araña" sobre el controlador de rotor actual (manual) aunque el destino final es construir un controlador totalmente nuevo con esta plataforma.

No hay comentarios:

Publicar un comentario

Buscar este blog

Vistas de página en total