Archivo de la etiqueta: Electrónica

Conexión de un receptor RC al computador, emulando Joystick USB

Pues un hack rápido.

Quería conectar mi transmisor de RC al computador, para poder usar los simuladores de radio control, especialmente el VRC Pro, usando los componentes que tenía a la mano.

Tenía una placa Digispark, que usa un micro ATTINY85 emulando un dispositivo Joystick HID. Conectándolo al receptor RC podemos usar la pistola del transmisor, como un joystick en el computador (inalámbrico!) y usarlo dentro del simulador.

El código fuente, y el esquema de conexión , se encuentran en mi repositorio de github https://github.com/patolin/rc-receiver-joystick

 

Stellaris Launchpad y Energia: Programando un Cortex-M3 fácilmente

Luego de tenerlo algún tiempo empolvándose, decidí darle una prueba al Stellaris Launchpad que compré  (en $5.00) cuando lo lanzaron hace más de 6 meses, y la verdad que el precio de $12.00 actual, sigue siendo una ganga, para toda la potencia de este microcontrolador.

StellarisLaunchPad_estore

Entre los periféricos importantes de este micro, podemos comentar:

  • Reloj principal de 80Mhz y 32khz para modo de bajo consumo
  • 256kb de memoria flash
  • 32kb de memoria ram
  • 2kb de memoria EEPROM
  • Controlador uDMA de 32 bits
  • 2 ADC de 12 bits – 1MSPS
  • Comparadores Analógicos
  • 8 puertos UART
  • 4 puertos SPI
  • Puerto USB Host/Device/OTG
  • 12 Timers
  • 16 Salidas PWM
  • Puertos GPIO
  • Debugger integrado en la tarjeta
  • 2 pulsantes, y 1 led RGB para pruebas

stellaris_perifericos

 

Como vemos, este micro, tiene mucha potencia en ese pequeño paquete, pero tanta potencia tiene un precio. Desarrollar para este micro puede convertirse en un dolor de cabeza, ya que es necesario utilizar Code Composer Studio de TI. Este IDE basado en Eclipse, nos permite programar y depurar al stellaris, pero su gran tamaño (la descarga es de 1GB aproximadamente) y lo lento de Eclipse, puede hacernos despechar de cualquier proyecto pequeño que tengamos.

Afortunadamente, existe el Proyecto Energia, que nos permite programar al Stellaris Launchpad con una interfaz de programación similar a la de nuestro conocido Arduino, y nos brinda facilidad de programación, usando toda la potencia del Stellaris.

Al descargar y abrir Energia, vamos a tener una interfaz idéntica a la del IDE de Arduino, salvo por el color rojo de la misma (Rojo Stellaris XD), y podemos compilar algunos de los ejemplos, como el típico Blink.ino incluido dentro del IDE

stellarisblink

Ahora, vamos a hacer algo más útil. Aprovechando los ADC de alta velocidad, vamos a intentar capturar datos con el ADC a la máxima velocidad posible (tomando en cuenta que lso ADC son de 1MSPS).

Por ventaja para nosotros, Energía trae precompiladas todas las librerías Stellarisware,  que nos brindan rutinas de configuración y acceso a todos los periféricos de nuestro micro. Con estas librerías, programamos un sketch que va a hacer 3 cosas:

  • Habilitar el puerto serial para envío y recepción de datos
  • Capturar datos con el ADC, usando interrupciones, iniciando las interrupciones del ADC al recibir un dato desde el puerto serial. Se capturará 2048 datos en ráfaga, sin usar DMA.
  • Generar un timer de 1hz para referencia

Nuestro sketch para realizar esto es el siguiente:

#include "Energia.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/timer.h"

int i=0;
int j=1;
int dato0=0;
int adc[1024];
unsigned char dataReady=0;
unsigned long ulADC0Value[1];
unsigned long time1;
unsigned long time2;
unsigned long ttotal;

void setup() {
  Serial.begin(115200);
  pinMode(RED_LED, OUTPUT);
  pinMode(BLUE_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);

  initADC();  
  initTimer(2);

  Serial.println("Inicio OK. ");
  Serial.print(SysCtlClockGet());
  Serial.println(" hz");

}

void loop() {
  unsigned char serialIn;
  int i;
   digitalWrite(GREEN_LED,1); 

   if (Serial.available() > 0) {
     serialIn=Serial.read();
     ADCIntEnable(ADC0_BASE, 3);
   } 

   if (dataReady!=0) {
     Serial.println("Datos ADC");
     for (i=0;i<=1023;i++) {
         Serial.println(adc[i]);
     }

     dataReady=0;
   }
}

 void Timer0IntHandler()
{

  // Clear the timer interrupt
  TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  //leeADC();
  digitalWrite(RED_LED, j&0x01);  
  j++;

}

void ADC0IntHandler() {
   ADCIntClear(ADC0_BASE,3);
   ADCSequenceDataGet(ADC0_BASE, 3, ulADC0Value);
   adc[i]=(int)ulADC0Value[0];  
   i++;
   if (i&0b10000000000) { i=0; ADCIntDisable(ADC0_BASE, 3); dataReady=1;}
   //ADCProcessorTrigger(ADC0_BASE, 3);
   //digitalWrite(RED_LED, i&0x01);
}

void initTimer(unsigned Hz)
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
  //TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
  TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
  unsigned long ulPeriod = (SysCtlClockGet() / Hz) / 2;
  TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod -1);
  IntEnable(INT_TIMER0A);
  TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0IntHandler);
  TimerEnable(TIMER0_BASE, TIMER_A);

}

void initADC(void) {
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
	SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
        //SysCtlADCSpeedSet(SYSCTL_ADCSPEED_500KSPS);
	ADCSequenceDisable(ADC0_BASE, 3);
	//ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
        ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0);
	ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); //Sequencer 3 Step 0: Samples Channel PE3
	//ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END); //Sequencer 3 Step 0: Samples TS
        ADCIntRegister(ADC0_BASE, 3, ADC0IntHandler);
	ADCSequenceEnable(ADC0_BASE, 3);
        ADCIntEnable(ADC0_BASE, 3);
        //ADCProcessorTrigger(ADC0_BASE, 3);
}

Como vemos en el código, tenemos 2 rutinas de inicialización de periféricos, 2 rutinas de interrupción, y las cásicas setup() y loop() del programa principal. Facil no?

Ahora, debemos tener una consideración adicional. El compilador para este procesador Cortex, necesita un archivo llamado startup.gcc (que se encuentra dentro del IDE Energia) que define las subrutinas de interrupción de cada uno de los periféricos. Es por esto, que debemos modificar el nuestro, para que quede algo así:

/*
 * create some overridable default signal handlers
 */
__attribute__((weak)) void UARTIntHandler(void) {}
__attribute__((weak)) void ToneIntHandler(void) {}
__attribute__((weak)) void I2CIntHandler(void) {}
__attribute__((weak)) extern void Timer0IntHandler(void) {}
__attribute__((weak)) extern void ADC0IntHandler(void) {}

y un poco mas abajo

__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
   (void *)&_estack,                        // The initial stack pointer, 0x20008000 32K
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    GPIOAIntHandler,                        // GPIO Port A
    GPIOBIntHandler,                        // GPIO Port B
    GPIOCIntHandler,                        // GPIO Port C
    GPIODIntHandler,                        // GPIO Port D
    GPIOEIntHandler,                        // GPIO Port E
    UARTIntHandler,                         // UART0 Rx and Tx
    UARTIntHandler,                         // UART1 Rx and Tx
    IntDefaultHandler,                      // SSI0 Rx and Tx
    I2CIntHandler,                          // I2C0 Master and Slave
    IntDefaultHandler,                      // PWM Fault
    IntDefaultHandler,                      // PWM Generator 0
    IntDefaultHandler,                      // PWM Generator 1
    IntDefaultHandler,                      // PWM Generator 2
    IntDefaultHandler,                      // Quadrature Encoder 0
    IntDefaultHandler,                      // ADC Sequence 0
    IntDefaultHandler,                      // ADC Sequence 1
    IntDefaultHandler,                      // ADC Sequence 2
    ADC0IntHandler,                      // ADC Sequence 3
    IntDefaultHandler,                      // Watchdog timer
    Timer0IntHandler,                      // Timer 0 subtimer A

podemos ver que el ADC sequece 3, y el Timer 0 tienen aquí definidas sus subrutinas en este archivo. Si quieren descargar el archivo completo, pueden usar este link.

Y que tal funciona? pues midiendo una señal de referencia de 8khz, vemos que muestrea eficientemente a 950Ksps, que es mucho más alto de los 10Khz que se obtiene con el Arduino… hay mejora cierto?

Hackeando al Raspberry Pi

El famoso Raspberry Pi, que no ha tenido mayor uso desde que está en mis manos (más por falta de tiempo, que por falta de ganas), necesitaa un upgrade básico: un conexión WIFI.

El tener un puerto ethernet en la microcomputadora, de hecho que es una ayuda gigantezca, pero resulta poco práctico si el único chance de obtener una conexión por cable a la red, es dejarlo conectado debajo de mi escritorio, al router de internet. Es por esto que se volvió justo y necesario, darle una conexión wireless, para poder seguir con las pruebas y los experimentitos.

Por si no lo sabían, el Pi tiene 2 puertos USB, pero con un pequeño limitante. Estos tienen un fusible que limita a 140mA la corriente máxima de cada uno, y ciertos dispositivos USB no funcionan correctamente con ese límite (de hecho un teclado flexible que pensaba usarlo ahi no se enlaza 🙁 ), así que frente a esto quedan 2 opciones:

  • La primera, que es la más común entre los dueños de este bicho, es utilizar un hub usb energizado, que aunque no lo crean, resultó bastante escazo por acá (el único que encontre buscando un poco, pedían $40, así que negado). Por seguridad creo que voy a buscar un hub chinito en ebay, y esperar que llegue; pero…..
  • La segunda opción es meterle mano al Pi, con la pérdida de garantía que eso conlleva, y eliminar los límites de corriente.

Para no perder la costumbre, me fuí por la segunda opción, pero a medias, ya le realicé un puente únicamente en el puerto usb superior, quedando el inferior con protección (ahí tengo conectado un mini hub usb para el teclado y el mouse), así que el wireless irá en el puerto de arriba.

2012-08-29 20.34.07

Como se puede ver en la foto (mirenla en flickr, para verla en detalle), pueden ver el cablecito de puente sobre el fusible que se encuentra a un costado del conector…… cero garantía contra daños y 100% conexión!

Ahora, una vez que logramos alimentar correctamente el usb, tenemos que instalar el módulo en el sistema operativo del RPi.

El módulo usado es un TP-Link 723n que para mi buena suerte, costó $18 y es compatible 100% con Debian Wheezy pero para facilitar aún más las cosas, encontré un script que se encarga de toda la instalación de drivers, y configuración de la red wireless. Este script lo pueden encontrar en esta url http://dl.dropbox.com/u/80256631/install-rtl8188cus-latest.sh y lo deben ejecutar con el siguiente comando, desde el terminal de su RPi:

sudo ./install-rtl8188cus-latest.sh

Es cuestión de seguir los pasos (ojo, no se debe conectar el módulo USB hasta que el script lo solicite), colocar el nombre de la SSID y la contraseña, y voilá! tenemos wifi en el Pi.

Les dejo algunas imágenes del hack, y hasta ahora está funcionando sin problema. Además, me olvidaba. El Pi está overclockeado a 900Mhz (viene a 700Mhz de fabrica) y hasta ahora está super estable.

Les dejo algunas fotitos adicionales.

 

2012-08-29 20.43.43

2012-08-29 20.42.24

2012-08-29 20.34.07