Mostrando entradas con la etiqueta XC16. Mostrar todas las entradas
Mostrando entradas con la etiqueta XC16. Mostrar todas las entradas

jueves, 11 de febrero de 2021

Interrupción por TMR1 con reloj secundario (SOSC) en PIC24

Llegué a este problema al tratar de utilizar el módulo RTCC, el cual requiere un cristal secundario de 32.768 kHz, porque me di cuenta de que no estaba seguro si el reloj secundario estaba funcionando en primer lugar. El programa que voy a comentar en esta entrada me permitió resolver los errores que estaba comentiendo. Empezando por los capacitores. Para el cristal de 32.768 kHz deben de ser de entre 5 y 12 pF (los de 10 pF me funcuinaron bien):
Estoy utilizando el compilador XC16 y el PIC24FJ32GB002. En la página 115 de su datasheet se menciona que esta familia es más suceptible al ruido por lo que podría dar problemas al usar un protoboard y hay que tener cuidado al diseñar una aplicación en PCB (acercar lo más posible el cristal a los pines y tener capacitores de desacople entre Vcc y GND). El programa es muy secillo y ya está probado en circuito fisico en una placa diseñada para una aplicación de sensado remoto en cavernas sumergidas. Lo que hace togglear un led cada segundo. Si les funciona es casi seguro que es un error de conexión o problemas de capacitancias parásitas.

sábado, 27 de junio de 2020

Consola serial en PIC en XC16

Chan ya es famoso por ser el autor de la librería para manejo de archivos FAT32 en memorias SD pero tiene muchas otras creaciones geniales. Aquí describiré un ejemplo para usar la librería xprint que permite dotar de forma sencilla a casi cualquier microcontrolador de una pequeña consola de operación o depuración. Usaré un PIC24FJ32GA002 pero entendiendo la idea general se puede portar facilmente a cualquier otro dispositivo.  Primero, deben descargar los archivos xprinf.h y xprintf.c. Esta librería está escrita en ANSI C por lo que es independiente de la plataforma y el compilador. Las tres funciones más importantes que contiene son:
  • void xputs (const char* str)          : análoga a la función puts()
  • void xprintf (const char* fmt, ...) : análoga a la función printf()
  • int xgets (char* buff, int len)        : similar a la función gets()

 xputs() permite escribir una cadena simple. como un "Bienvenidos al programa". xprintf() nos permite dar formato a la cadena, como ("Temperatura %d",temp), como lo haríamos en un C en una PC. xgets() es muy útil y la que la dará mucha presentación a un programa para microcontrolador. Es en esencia muy distinta a su contraparte gets(). Lo que hace xgets es ir capturando en tiempo real lo que se vaya recibiendo el microcontrolador del puerto serial hasta que se presiona ENTER. La misma función va enviado simultáneamente cada carácter a Tx como espejo (aunque esta opción puede desactivarse en los macros del header). ¡Permite incluso borrar caracteres!    

La librería no puede funcionar por si sola. Es necesario asociarla a funciones de escritura y lectura bajo nivel. Lo que sigue ahora es crear un programa que contenga las rutinas para enviar y recibir un byte por puerto serial con la siguiente forma:

//-- Poner byte en el registro Rx
unsigned char uart_getc(void);

//-- Poner byte en el registro Tx

void uart_putc(unsigned char d);


Esta parte del programa siempre será dependiente del dispositivo y compilador. Estas dos rutinas pueden tener cualquier nombre siempre y cuando se asocien en el código principal de la siguiente manera:

//-- Unir UART con funciones de consola
xdev_in(uart_getc);        
xdev_out(uart_putc);

La implementación de las funciones de comunicación serial también están basadas en la implementación de Chan pero las he reescrito de una forma más clara y comentadas lo mejor que pude. Esta implementación utiliza dos colas (registros FIFO), una de envío y otra de recepción. Esto es muy útil porque permite aprovechar las interrupciones de la UART para no perder bytes. Las referencias a páginas son para la data del GB004 pero es la misma información.   

Aislamiento

Si están utilizando baterías para alimentar al PIC o van a estar realizando depuración es una buena práctica utilizar opto-acopladores. Esto también permite utilizar módulos de conversión USB-Serial que no tengan salida de 3.3v:


 

Programa completo:

domingo, 5 de abril de 2020

Comunicación SPI para PIC24FJXXGA004 en XC16

En este ejemplo haré referencia a la hoja de datos para la familia PIC24FJXXGA004, así que deben tenerla a la mano. 'XX' hace referencia al tamaño de la memoria de programa. En este caso particular usaré un PIC24FJ32GA004 (32Kb). Lo primero que hay que saber es que esta familia de PIC's tiene pines remapeables (Peripheral Pin Select). Para usar los pines asociados al SPI, UART, PWM, interrupciones externas, etc, se deben mapear a los pines del puerto virtual RP. Para trabajar con SPI requerimos 3 pines: SCK1,  SDO1 y SDI1. Para poder realizar el mapeo, existen dos grupos de registros que hay que configurar. Uno es el grupo de 24 registros de mapeo entrada: del RPINR0 al RPINR23 (pags. 111-117). El otro es el grupo de 13 registros mapeo de salida: del RPOR0 al RPOR12  (pags 118-124). La forma de mapear entradas es muy distinta a la de mapear salidas. Para mapear un pin de entrada debe elegirse el registro asignado al periférico que nos interesa mapear. Para esto podemos consultar la Tabla 10-2 de la página 108. Ahí podremos ver que la entrada SDI1 se configura con el registro RPINR20. Lo que debemos hacer ahora es escribir en RPINR20.SDI1R el numero de RPx a dónde queremos poner a SDI1. En este ejemplo lo pondremos en RP2 (RB0) de la siguiente manera:

RPINR20bits.SDI1R = 2; // SDI -> RP2/RB2

Para mapear las salidas debe elegirse primero el RPx, RP0 y RP1 para SCK1 y SDO1 respectivamente en este ejemplo. El registro necesario será por lo tanto RPOR0 (pag. 118). Este registro tiene los campos RP0R y RP1R asociados a RP0 y RP1. Para elegir las funciones de estos pines debe consultarse la Tabla 10-3 de la pagina 109. Se podrá ver que el código para SKC1OUT es 8 y para SDO1 es 7.  Configuramos los dos pines de la siguiente manera:

 RPOR0bits.RP0R = 8;  // SCK -> RP0/RB0 
RPOR0bits.RP1R = 7;  // SDO -> RP1/RB1

El circuito simulado en Proteus es el siguiente:
(Click para agrandar)
El código completo:

miércoles, 11 de marzo de 2020

Blinking-led en PIC24FJXXGB002 en XC16

El led parpadeante es el Hola Mundo de los microcontroladores. Pero a diferencia de su contraparte de consola es muy útil en la práctica para verificar empíricamente que la configuración del reloj se haya hecho correctamente.

Primero, veamos la conexión física. Esta serie de microcontroladores trabajan a 3.3v lo que los hace más susceptibles al ruido si no se hace un buen conexionado. Es estrictamente necesario colocar capacitores de 0.1 uF entre cada par de pines Vdd-Vss como se muestra en la Figura 2-1 de la datasheet (yo estaré usando en este ejemplo un PIC24FJ32GB002):

Si no se colocan estos capacitores el PIC tendrá un comportamiento errático debido al ruido. Usaré en este ejemplo un cristal de 8MHz con capacitores de 22pF. Una vez conectado el circuito podemos avanzar a la configuración del oscilador. Configuraremos el oscilador externo con PLL activado con la frecuencia de reloj FOSC máxima de 32 MHz (recordemos que FCY = FOSC/2). He marcado el camino que nos interesa sobre el diagrama de la Figura 8-1 de la página 107:
 Si estamos usando un cristal de 8 MHz ¿Qué modo es el adecuado? Eso lo ponemos encontrar en la tabla 8-3 de la pag. 114, el cual dice que es XTPLL. En la misma tabla se indica que el divisor del PLL requerido es 2. Ahora solo necesitamos saber que bits de configuración necesitamos modificar. En la tabla 8-1 de la página 108 podemos ver que son POSCMD y FNOSC. Para encontrar los macros necesarios podemos ir a Compiler Help en el dashboard de MPLAB X:

Abrirá un archivo HTML donde debemos buscar Configuration Settings Reference. De ahí podrán copiar los pragmas requeridos. Ahora solo falta un ajuste más pero se hará escribiendo en un registro. Lo que falta es asegurarnos que FOSC tenga un frecuencia de 32 MHz. Para esto debemos revisar el registro CLKDIV (pág. 111) dónde podremos ver que el valor de división del último postcaler es de 0. Ahora tenemos toda la información necesaria para escribir nuestro programa: