Tutoriales

Review - MiE32U de Microingenia

Los amigos de Microingenia han puesto a la venta una tarjeta que incluye un PIC32MX440F512H de la compañía Microchip con conexiones para hacer pruebas en protoboard o con otros módulos de expansión (rapid prototyping). Incluye todo lo necesario para que alimentes al PIC, cargues y corras tus programas. Si quieres iniciarte con la programación en 32 bits de los micros más potentes de Microchip entonces sigue leyendo.

 

 

La tarjeta, sus archivos y sus manuales se encuentran disponibles en la página de Microingenia:
http://www.microingenia.com/electronics/product.php?id_product=30


Ítems necesarios

- Una tarjeta entrenadora MiE32U v1.0
- Descargar todo archivo relacionado desde la página de Microingenia
- Una computadora con Windows XP en adelante
- Compilador C32 de Microchip v1.10
- Pickit2 o Pickit3


Características de la tarjeta

La tarjeta mide 86.36 x 86.36mm (3.4’’ x 3.4’’) y contiene el PIC32MX, varios reguladores de voltaje, headers para cables macho o hembra, conectores USB (modo Host, Device u On The Go), puerto ICSP, jack de alimentación, cristales para el reloj del micro, dos leds y un push button.

 

 

Los headers son bastante prácticos para conectar módulos de expansión (como el Mod10LedArray) o conectarse a un protoboard. Tener cuidado con los headers hembra ya que puede haber confusión... por ejemplo, en la foto se observa como a un lado de cada tira de headers hay una etiqueta mostrando la conexión de cada uno (RB5, RB6, 3V3, etc.) pero esa etiqueta sólo funciona con el header macho y el header hembra a su lado. Los dos headers exteriores son 3V3 y GND.

La tarjeta está diseñada para hacer uso de las muchas funciones del PIC32, en especial de sus modos USB. Para ello contiene diversos reguladores de voltaje que permiten la alimentación de la tarjeta para operar bajo cualquier modo USB. La mejor forma de alimentarla es usando el Jack J1 que según especificaciones puede recibir de 7V a 12V y de ahí se generarán 5V para los esclavos USB y 3.3V para todo lo demás. Pero también puede alimentarse desde el puerto USB mini AB si el dispositivo está como esclavo USB. El voltaje de 3.3V se genera mediante U3 y así se alimenta el micro.

También puede usarse simplemente el voltaje del programador ICSP. Si conectas tu Pickit2 o Pickit3 en el puerto ICSP, éste entregará 3.3V, y los 5V para los esclavos USB se generan mediante el CI Charge Pump U4.

Mediante pruebas de alimentación en ICSP me di cuenta que al alimentar con 3.3V se generan voltajes parásito en los puertos USB y demás terminales de voltaje. Si no piensas usar el modo USB y alimentar únicamente vía ICSP, entonces no hay problema; pero si piensas usar el modo USB, es mejor que emplees una fuente de 7V a 12V en el Jack. Los voltajes parásitos son como de 2.5V y podrían afectar a tus dispositivos esclavos USB ya que ellos esperan un voltaje siempre regulado de 5V. Además existen esclavos USB que requerirán 500mA de corriente de la tarjeta y el regulador U2 será capaz de suministrarlos.

La tarjeta viene acompañada con 2 cristales, uno de 8MHz y otro de 32.768kHz. El de 8MHz está conectado al oscilador primario del PIC y mediante PLL puedes lograr que el PIC opere hasta 80MIPS. El de 32.768kHz está conectado al oscilador secundario del PIC y puedes emplearlo para el periférico de tiempo real (Real Time Clock) y para demás cosas.

Y por último trae dos leds (uno bicolor) y un push button de reset. A mi me pareció poco el que sólo incluyera estos dos leds ya que al tener tantos pines se podría haber agregado una barra de leds SMD y no habría ocupado mucho espacio, pero seguramente el amigo J1M tuvo una mejor razón para no agregarla. ;-)

Internamente el PIC32MX440F512H trae grabado un Bootloader HID USB para que no hagas uso de programadores, simplemente conectas tu tarjeta a Windows, cargas el software Bootloader suministrado y listo. Si eres fan del Pickit2 o del Pickit3, ambos ofrecen compatibilidad de programación con este PIC32. El Pickit3 además ofrece modo de depuración.

 

 


Compilando un primer programa - ¡Prendamos un LED!

Este ejemplo y los siguientes no hacen uso del bootloader, sólo grábalo si cuentas con un Pickit2 o Pickit3 para restaurar el Bootloader (en caso de que te sea útil).

Se asume que ya estás un poco familiarizado con los compiladores C de Microchip. En caso contrario puedes revisar este tutorial. De lectura obligatoria si no sabes cómo incluir los archivos de cabecera del PIC32MX.
http://www.migsantiago.com/index.php?option=com_content&view=article&id=17:breve-tutorial-pic32mx&catid=1:tutorial&Itemid=23

/*
Programa de prueba MiE32u v1.0
MigSantiago, Agosto 2010
*/
#include <p32mx440f512h.h>
#include <plib.h>

//Entrada de cristal a 8MHz
//Para CPU será elevada a 80Mhz

//CPU
//XT es de 8MHz y hay que elevarlo a 80MHz
#pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_1
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_8
#pragma config FSOSCEN = OFF //sin oscilador secundario

// Let compile time pre-processor calculate the PR1 (period)
#define SYS_FREQ             (80000000L)
#define PB_DIV                 8
#define PRESCALE               256
#define TOGGLES_PER_SEC        1
#define T1_TICK               (SYS_FREQ/PB_DIV/PRESCALE/TOGGLES_PER_SEC)

//Leds a usar
#define TRIS_LEDR TRISGbits.TRISG8
#define TRIS_LEDV TRISGbits.TRISG9
#define LEDR LATGbits.LATG8
#define LEDV LATGbits.LATG9

//////////////////////////////////////////////////////////////////////////////////////////
int main()
{
   //Habilita la caché de lectura ROM
   SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

   //Deshabilita los pines de programación JTAG
   //Hace que las terminales RB10, RB11, RB12 y RB13 sean I/O
   DDPCONbits.JTAGEN = 0;

   //Configura pines RGx como salidas
   TRIS_LEDR = 0; //Salida
   TRIS_LEDV = 0; //Salida

   //Configura el Timer1 para operar con reloj interno, 1:256 prescale
   OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_256, T1_TICK);

/*
El timer1 es de 16 bits y a 10MHz, 1:256 (FPBDIV es entre 8) se desbordaría cada
1.677s
*/
   //Habilita la interrupción con prioridad 2
   ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);

   //Habilita las interrupciones
   INTEnableSystemMultiVectoredInt();

   //Prende Verde y Apaga Rojo
   LEDV = 1;
   LEDR = 0;

   //A partir de aquí el PIC sólo trabajará en la subrrutina de interrupción
   while(1);
}
//////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////
//Interrupción timer 1
void __ISR(_TIMER_1_VECTOR, ipl2) Timer1Handler(void)
{
   //Limpia la bandera de interrupción
   mT1ClearIntFlag();

   LEDV^=1; //toggle
   LEDR^=1; //toggle

   //Nota: las dos instrucciones anteriores pueden mejorarse haciendo
   //uso de registros atómicos INVERT ;)
}
//////////////////////////////////////////////////////////////////////////////////////////

El ejemplo es muy trivial. Se configura el TIMER1 para que genere una interrupción cada 1s. Al atenderse la interrupción se invierte el estado de los LEDs y listo. El tiempo de desborde se calcula con el precompilador, en la sección de defines.

Para grabar el programa sólo utiliza tu Pickit y carga el HEX. Conecta el pin RG8 al led ROJO y RG9 al led VERDE. Luego enciende la alimentación ICSP del Pickit y listo, verás ambos LEDs prender y apagar cada 1s.


Segundo ejemplo - Un gran salto... operando el PWM

En este ejemplo vamos a configurar el PWM para ver un efecto de desvanecimiento del LED.

/*
Programa de prueba MiE32u v1.0
Genera un PWM
MigSantiago, Agosto 2010
*/
#include <p32mx440f512h.h>
#include <plib.h>

//CPU
//XT es de 8MHz y hay que elevarlo a 80MHz
#pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_1
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_1 //periféricos @ 80MHz
#pragma config FSOSCEN = OFF //sin oscilador secundario

//Delays
#define GetInstructionClock()  (80000000L)
#include "TimeDelay.c"

//Pines a usar
#define TRIS_AUDIO TRISDbits.TRISD0
#define AUDIO LATDbits.LATD0
#define TRIS_LED TRISGbits.TRISG8
#define LED LATGbits.LATG8

#define SYS_FREQ             (80000000L)
#define PB_DIV                 1
#define PRESCALE               1

//////////////////////////////////////////////////////////////////////////////////////////
int main()
{
   //Habilita la caché de lectura ROM
   SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

   //Deshabilita los pines de programación JTAG
   //Hace que las terminales RB10, RB11, RB12 y RB13 sean I/O
   DDPCONbits.JTAGEN = 0;

   //Configura pines
   AUDIO=0;
   TRIS_AUDIO = 0; //Salida PWM
   TRIS_LED = 0;

   LED=1;

   DelayMs(1000);

   //Configura OC1 junto con TIMER2 para generar PWM en RD0
   //Duty cycle (es el que cambiara constantemente)
   OC1R = 0; //sólo se debe escribir al inicio
   OC1RS = 0;
   //Modo de operación PWM sin Fault Pin
   OC1CONbits.OCM = 0b110;
   //Elige TIMER2 como origen de comparaciones
   OC1CONbits.OCTSEL = 0;
   //Arranca PWM
   OC1CONbits.ON = 1;
   //TIMER2 corriendo 1:1, 80MHz generará evento cada 25us
   //Periodo PWM = 25us = 40kHz
   //(1999+1)(1/80MHz)=25us
   OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 1999);

   BOOL sentido=1;
   while(1)
      {
      Delay10us(25);
      if(sentido)
         {
         ++OC1RS;
         if(OC1RS==1999)
            sentido=0;
         }
      else
         {
         --OC1RS;
         if(OC1RS==0)
            sentido=1;
         }
      }
}
//////////////////////////////////////////////////////////////////////////////////////////


El periférico PWM operará en base a la misma velocidad del micro... 80MHz. Estos PIC incluyen un pin PWM Fault que puede detener la señal PWM instantáneamente ante cualquier fallo, en nuestro caso lo dejaremos deshabilitado. Se usará el Timer2 para un periodo de 25us del PWM.

Para el efecto de desvanecimiento, cada 250us se ampliará el tiempo de trabajo del PWM en 1, hasta llegar a 1999 que equivale al 100% del tiempo de trabajo. Luego se decrementará el periodo hasta 0 y así sucesivamente.

Deberás conectar el pin RD0 (OC1 es salida PWM) al led que quieras, cargar el HEX y alimentar vía ICSP. El efecto del PWM se observa en este video.


Tercer ejemplo - Reproduciendo audio sin tener un DAC

Este ejemplo es más complejo ya que hago uso del PWM a 40kHz para reproducir una señal de audio con ancho de banda de 4kHz. El código principal es el siguiente y el archivo binario de audio lo puedes descargar de aquí (contraseña migsantiago.com).

/*
Programa de prueba MiE32u v1.0
Genera un PWM
MigSantiago, Agosto 2010

v0.2
Se vuelca archivo de onda senoidal de audio en ROM
Exitosamente reproduce señal de audio con TIP41 y filtro 10k y 2.2uF
*/
#include <p32mx440f512h.h>
#include <plib.h>

//Entrada de cristal a 8MHz
//Para CPU será elevada a 80Mhz

//CPU
//XT es de 8MHz y hay que elevarlo a 80MHz
#pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_1
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_1 //periféricos @ 80MHz
#pragma config FSOSCEN = OFF //sin oscilador secundario

//Delays
#define GetInstructionClock()  (80000000L)
#include "TimeDelay.c"

//Pines a usar
#define TRIS_AUDIO TRISDbits.TRISD0
#define AUDIO LATDbits.LATD0
#define TRIS_LED TRISGbits.TRISG8
#define LED LATGbits.LATG8

#define SYS_FREQ             (80000000L)

//Inserta el sonido wav de 8 bits @ 8kHz directamente en la ROM
//#include "wav_plano.h" //señal senoidal con barrido
//#include "zelda.h"
#include "bionic.h"

//////////////////////////////////////////////////////////////////////////////////////////
int main()
{
   //Habilita la caché de lectura ROM
   SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

   //Deshabilita los pines de programación JTAG
   //Hace que las terminales RB10, RB11, RB12 y RB13 sean I/O
   DDPCONbits.JTAGEN = 0;

   //Configura pines
   AUDIO=0;
   TRIS_AUDIO = 0; //Salida PWM
   TRIS_LED = 0;

   LED=1;

   DelayMs(1000);

   //Configura OC1 junto con TIMER2 para generar PWM en RD0
   //Duty cycle (es el que cambiara constantemente)
   OC1R = 0; //sólo se debe escribir al inicio
   OC1RS = 0;
   //Modo de operación PWM sin Fault Pin
   OC1CONbits.OCM = 0b110;
   //Elige TIMER2 como origen de comparaciones
   OC1CONbits.OCTSEL = 0;
   //Arranca PWM
   OC1CONbits.ON = 1;
   //TIMER2 corriendo 1:1, 80MHz generará evento cada 25us
   //Periodo PWM = 25us = 40kHz
   //(1999+1)(1/80MHz)=25us
   OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 1999);

   UINT32 apunta=0;
   while(1)
      {
      Delay10us(10); //debería ser 125us pero los delays no son exactos
      ++apunta;
      if(apunta==tam_wav_plano)
         apunta=0;
      OC1RS=wav_plano[apunta] << 3; //con ganacia
      }
}
//////////////////////////////////////////////////////////////////////////////////////////


Primero se debe obtener una señal de audio muestreada a 8kSps por lo que incluirá señales de hasta 4kHz. Normalmente estas señales de audio se pueden obtener de archivos MP3 o WAV. Si ya cuentas con un archivo WAV entonces generar el archivo binario de este proyecto será fácil, sólo asegúrate de que el archivo:

- Sea muestreado a 8kSps
- Sea monaural
- Sea muestreado a 8 bits

Cada muestra de audio se deberá depositar en OC1RS (el registro del duty cycle del PWM) en un periodo de 8kSps que equivale a 125us. El generador de delays en C32 no funciona tan biencomo en C18 o C30, por lo que mi delay terminó siendo de 100us en software.

Para extraer el contenido del archivo de audio puedes implementar una memoria EEPROM externa, una memoria SD o leer una memoria USB... pero cómo estamos empezando y no quiero complicarte la vida, lo haremos más fácil, usaremos los 512kB de memoria de programa para embeber el archivo de audio.

Los pasos son los siguientes:

- Asegúrate de que tu archivo de audio no rebasa los 500kB de tamaño y cumple con las características de arriba.
- Descarga el lector hexadecimal XVI32.
- Abre tu archivo WAV usando el lector.
- Da click en la posición 40 (celda 64) y en el menú Edit selecciona Delete to Cursor. Esto borrará las cabeceras estorbosas del formato WAV.
- Guarda el archivo como archivo.bin.
- Descarga el convertidor de archivo binario a arreglo de C SL File2Array.
- Convierte el archivo, llámalo archivo.h y modifícalo para que el arreglo quede así:

const UINT32 tam_wav_plano = 511999;
const BYTE wav_plano[] = {
0x80, 0x7F, 0x7F, 0x7F, 0x7E, ...

- tam_wav_plano es el número de bytes que wav_plano incluye

Al hacer esto los datos RAW del archivo de audio se inyectarán en la memoria de programa del PIC32, permitiéndote grabar hasta 62.5 segundos de audio. Una vez que el archivo ya está en la ROM sólo basta leerlo continuamente e irlo depositando en el PWM.

El PWM será como una portadora de la señal de audio, por lo que para escuchar la señal de audio sólo falta que apliques un filtro pasa bajos externo y listo. El circuito se ve a continuación. Este circuito es sólo para pruebas, hace falta que se le aplique un mejor filtro y un amplificador decente. Está basado en la propiedad de Emisor Seguidor de los transistores. Te tocará mejorarlo si deseas mejor audio ;-)

 

 

La calidad de audio es buena para un archivo muestreado a 8kSps. Definitivamente puedes lograr mejores resultados si se muestrea a más kSps y más resolución, pero tendrás que usar un mayor almacenamiento para albergar esos archivos. Este experimento fácilmente puede reemplazar circuitos grabadores de audio. ;-)


Conclusiones

La tarjeta MiE32U de Microingenia definitivamente es una buena inversión para arrancar con los micros PIC32MX de Microchip. Te ahorra la molestia de soldar componentes SMD y la implementación de puertos USB. Te da la oportunidad de utilizarla junto con más módulos de expansión y con tu protoboard olvidándote de problemas como la alimentación o el orden de los pines del PIC.