Accessing the Chumby Analog-To-Digital Converter

[Note: This article refers frequently to the Freescale i.MX233 reference manual, which you can download here.]

The Freescale i.MX233 applications processor used in the Chumby One has six pins that are inputs to a 12-bit low-resolution analog to digital converter (LRADC). However, all of the pins are used for monitoring Chumby hardware, such as the LCD and battery, and none is easy to get to. This article shows you how to hack the Chumby hardware to access one of the LRADC inputs and use it to monitor an analog signal from your robot.

All of the LRADC inputs are used by the Chumby. To use one of the LRADCs for your own purposes, you must give up some functionality. Four of the LRADCs are used to read the touchscreen. I needed to use the touchscreen on my robot, so repurposing those inputs was not an option for me. The remaining two LRADC inputs connect to the battery temperature input (LRADC0) and the microphone input (LRADC1).

My robot doesn’t use a battery in the Chumby, so I first tried to connect LRADC0 to my robot. However, I discovered quickly that voltage changes on the LRADC0 pin cause the Chumby to crash. I’m guessing that there is code somewhere that monitors the battery temperature. When the temperature is out of range, the Chumby shuts down. I couldn’t find the code, so I moved on to LRADC1.

To change LRADC1 to a general purpose analog input, you need to

  1. Alter the hardware to remove all of the resistors and capacitors that enabled LRADC1 to function as a microphone input.
  2. Write code to initialize an analog-to-digital conversion and read the result from the i.MX233 registers.

These modifications are described in the following two sections.

Hardware Modifications

Schematics for the Chumby are available at chumby.com. The relevant portion of the schematic containing the LRDAC input is shown in the following figure:

First, remove C700, C701, and C702. Second, remove R700 and replace it with a solder jumper. Third, connect the analog output from your robot to solder pad J701. This pad is large; it holds enough solder to make a good connection to 22-30 gauge wire. You now have a direct connection from J701 to the LRADC1 input on the i.MX233 processor. The red ellipse in following figure shows the location of the components that you need to remove.

Software

You can start an analog-to-digital conversion and read the result by using just three commands:

# regutil -w HW_LRADC_CTRL2_SET=0x02000000
Setting 0x80050024: 0x02008000 -> 0x02008000 ok
# regutil -w HW_LRADC_CTRL0_SET=0x00000002
Setting 0x80050004: 0x00100000 -> 0x00100002 ok
# regutil -r HW_LRADC_CH1
Value at 0x80050060: 0x3c0008b1

The first command sets the channel 1 divide-by-two bit. This enables the channel to read voltages up to 3.7 V. If you do not set this bit, the maximum input voltage is 1.85 V. The second command initiates a conversion on channel 1, which is connected to LRADC1. The third command reads channel 1: the 12 LSBs are the result of the conversion, which is 0x8b1 in this example.

You can download the C source code for regutil from the Chumby web site. You must then compile it yourself to produce an executable.

If you want to read an analog voltage from your robot program, use the C code in the following example. The code uses multisampling and the interrupt bit, which are explained after the code.

// file: adc.c v1.1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "imx233.h"

#define LRADC_IRQ_PENDING 0x00000002
#define CH1_SCHEDULE 0x00000002

// NUM_SAMPLES is a 5-bit value
#define NUM_SAMPLES 0x10

extern int imx233_rd(long offset);
extern int imx233_wr(long offset, long value);
extern void usleep(int value);

int main(int argc, char **argv) {

   unsigned value;
   struct timeval tv;

   // If the name of the offset ends in CLR, the bits that are hi will be set to 0.
   // If the name of the offset ends in SET, the bits that are hi will be set to 1.
   // If the name of the offset ends in TOG, the bits that are hi will be toggled.

   imx233_wr(HW_LRADC_CTRL2_SET, 0x02000000);  // Set ch 1 divide-by-two bit
   imx233_wr(HW_LRADC_CTRL1_CLR, 0x00000002);  // Clear interrupt bit

   imx233_wr(HW_LRADC_CH1_SET, 0x20000000);  // Set accumulate bit
   imx233_wr(HW_LRADC_CH1_CLR, 0x0003ffff);  // Clear accumulator
   imx233_wr(HW_LRADC_CH1_CLR, 0x1f000000);  // Clear num samples
   if ( NUM_SAMPLES > 0 ) {
      value = (NUM_SAMPLES-1) << 24;
      //printf( "samples=0x%08x \n", value );
      imx233_wr(HW_LRADC_CH1_SET, value);  // Set num samples
   }

   gettimeofday(&tv,NULL);
   printf( "Start of conversion: %d %d\n", tv.tv_sec, tv.tv_usec );

   // Check for interrupt bit going hi, which indicates that all conversions
   // are complete.
   while ( !(imx233_rd(HW_LRADC_CTRL1) & LRADC_IRQ_PENDING) ) {
      // Schedule a conversion on ch 1
      imx233_wr(HW_LRADC_CTRL0_SET, CH1_SCHEDULE);
      printf( "conversion scheduled...\n" );

      // Wait for schedule bit to be cleared, indicating conversion complete
      while ( (imx233_rd(HW_LRADC_CTRL0) & CH1_SCHEDULE) ) { }
      printf( "conversion complete.\n" );

      // The next line is a hack. I've found that the data is somtimes not
      // ready even though the processor cleared the schedule bit. This slight
      // delay is enough time to allow the data to become ready.
      usleep(100);	  

   }

   gettimeofday(&tv,NULL);
   printf( "End of conversion: %d %d\n", tv.tv_sec, tv.tv_usec );

   value = imx233_rd(HW_LRADC_CH1) & 0x3ffff; // Value is in the 12 LSBs
   printf( "total=0x%08x \n", value );
   if ( NUM_SAMPLES > 0 ) {
      printf( "average=0x%08x \n", value / NUM_SAMPLES );
   }

   return 0;

}

This code uses two features of the LRADC that are not used in the command line examples:

  1. The interrupt bit – Bits 7:0 of HW_LRADC_CTRL1 are the interrupt bits for each of the channels. Bit 1 is the interrupt bit for channel 1. This bit goes high when the conversion on channel 1 is complete. The C code waits for this bit before proceeding.
  2. Multisampling using the accumulator – Bits 28:24 of HW_LRADC_CH1, the NUM_SAMPLES bits, indicate how many samples to take before setting the interrupt bit. If you also set bit 29 of HW_LRADC_CH1, the ACCUMULATE bit, the samples will be summed. You can then find the average of the samples by dividing bits 17:0 of HW_LRADC_CH1, the VALUE bits, by the number of samples.

In the Downloads section at the end of this article, you can find adc.c, which contains the code shown above, and imx233.c, which contains the imx233_wr and imx233_rd procedures.

Results

On my Chumby, a zero volt analog input produces a value of 20 decimal. The maximum value of 4095 is reached when the analog input voltage is approximately 3.8V. Each unit of value equals 0.9 mV. An analog to digital conversion took 200 uS.

Further Reading

  • The reference manual for the i.MX233 application processor is located here (http://www.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf?fpsp=1)
  • This article (http://demandperipherals.com/docs/chumbot_chumby_intro.pdf) is a good introduction to using the Chumby as a robot controller.

Downloads:

2 comments to Accessing the Chumby Analog-To-Digital Converter