0

Interesting Webcast about microcontroller in Human Interface

Posted by Yann on Oct 5, 2009 in Capacitive Touch, Displays, General

Technical Editor Robert Cravotta explores processor and software-processing architectures and the impact they have on system and software development. Relevant architectures include microprocessors, microcontrollers, digital signal processors (DSPs), multiprocessor architectures, processor fabrics, coprocessors, and accelerators, plus embedded cores in FPGAs, SOCs, and ASICs.

EDN Webcast

 
0

Braille Interfaces

Posted by Keith on Jul 13, 2009 in Displays

When I was in college, many years ago, I worked for a company that made CNC systems (computerized numeric controls) for milling machines and lathes.  And, at one point in time they were actively considering a capacitive touch interface to get around contamination problems.  To evaluate the technology, the company even purchased a Qwerty keyboard made with capacitive touch buttons.

At the time, I was so impressed by the technology that I failed to see the inherent flaw in the design.  Basically, by using capacitive touch for the buttons, they created a keyboard that no touch typist could ever use because touch typists rest their fingers on the home row keys.  With a capacitive touch keyboard, that means that the keyboard will always report a press on the home keys.  Now, you could get around the problem by having the typist lift and press for home row keys, but that requires the user to modify their normal behavior just to get around your design problem, so really, it is not a very clean solution.  What you really need is something that has the same dust and moisture resistance of capacitive, while requiring an actual press by the user to actuate the key.

OK, so much for the lesson in ergonomics, cap touch and Qwerty are a bad combination.  What does this have to do with the rest of the user interface world?  Well, I’ll tell you; there is one other group that relies on touch to identify buttons locations, blind people.  That’s right; the ADA (Americans with Disabilities Act) requires that critical systems, such as elevators and access controls, must have user interfaces that support Braille labeling on their controls.  And because Braille uses a series of raised bumps, which are ‘read’ by the user passing their filters over the bumps, capacitive touch is basically useless because the buttons will trigger when the user is trying to find/identity the buttons.

So, how do we solve the problem?  We want to seal the interface to prevent contamination by moisture and dust, but we need a system that only responds to an actual press by the users.  The answer is simple, use the new inductive touch technology.  The inductive touch system uses a solid Fascia of plastic or metal, so it can be sealed, and it detects a user’s touch by detecting the minute deflection of the Fascia caused by the user’s press.  This gives us the best of both worlds, a solid front panel (Fascia) with no cracks or gaps for contamination, and the light brush of the Braille labeling will not cause a false press when someone is just reading the Braille legend because it requires a stronger actuation force by the user to cause a press.  Simple and elegant, we have a simple sealed keyboard, and it won’t trigger when someone passes their fingers over the legends

One final note; it has been 30 years since I saw the capacitive touch Qwerty keyboard, and though I thought it was a cool keyboard, I have no idea who built the thing so please don’t email asking for the manufacturer.  Just accept the fact that the manufacture probably discontinued the design once they figured out that their product had such a market limiting feature.

Tags: ,

 
0

Selecting a Color TFT LCD display for your embedded application – Part 2

Posted by Rawin on May 15, 2009 in Displays, General, Output

In the previous post, we talked about the terminologies of color depth, display size, resolution, and backlight. I’d like to dedicate this post to discuss about the frame buffer and why understanding if your display has a built-in frame buffer or not is important. As always, Wikipedia has a good generic summary on the frame buffer, http://en.wikipedia.org/wiki/Framebuffer. I will elaborate more from the perspective of an embedded system. First, let’s imagine a typical embedded system with a display; this will help illustrate key points in this article. At its simplest, there are 4 components, a microcontroller, a frame buffer, a display controller, and a display glass as shown in Figure 1.

Figure 1:

fig1

The potential confusing part is you may see other names in the real world for some of the four components that I’ve mentioned. So to avoid any confusion, I will explicitly explain what each of the above components does in my imagined system.

Starting from the right of Figure 1, we have the display glass; it displays screen images from the data-stream fed by the display controller. If the display controller stops feeding data to the display glass, it will stop showing meaningful images, and stay blank/dark. Next is the display controller, its only job is to continuously read from the frame buffer and stream pixel data to the display glass. The frame buffer stores color information for each pixel on the display glass. If the display glass supports 1-bit color depth, then 1-bit of frame buffer memory is required to represent 1 pixel. If the display glass supports 16-bit color depth (RGB 565), then 2 bytes of frame buffer memory are required per pixel.

Assuming that we have a display glass with a resolution of 320×240 and 16-bit color depth, how much frame buffer memory would be required to display one full screen? Well, the calculation is easy:

Frame Buffer Required in Byte:

= Number of Pixels x ( Color Depth in Bits / 8 )

= 320×240 x (16/8)

= 153,600 bytes

Let’s try another example. You may see a device advertised as having a frame buffer size of 256Kbytes. Is this big enough for a 480×272 display with 16-bit color depth? Let’s calculate:

Frame Buffer Required in Byte:

= Number of Pixels x ( Color Depth in Bits / 8 )

= 480×272 x (16/8)

= 261,120 bytes

A 256KBytes is equal to 262,144 bytes. Since 262,144 is larger than 261,120, a 256Kbytes frame buffer is therefore large enough to support a 480×247 display with 16-bit color depth. I hope you are now more comfortable with the concept of the frame buffer and how its size relates to the display resolution and color depth.

The last piece of the puzzle is putting useful data into the frame buffer. This is typically done by a microcontroller transferring data into the frame buffer. The microcontroller does not need to update everything in the frame buffer to change the screen. It only has to update what needs to be shown differently from the previous screen. This could be something as simple as changing a red square area on a yellow background to blue. See Figure 2 as an example, assuming a display resolution of 8×8, 16-bit color depth.

Figure 2:

fig2

Assuming the application is already displaying a red square on a yellow background. When the screen information is to be updated, the microcontroller doesn’t need to write color yellow to the frame buffer again, that information is already there. It only needs to write to memory areas that store the color red and change them to blue. In this case, only 4 pixels have to be updated, represented by 8 bytes of memory. Processing just 8 bytes of data once instead of having to always update the whole screen continuously (which would be 8 x 8 x (16/8) = 128 bytes in this case) is the key architectural factor which allows a non 32-bit microcontroller to be used in an embedded graphical application. Do also note that when there’s nothing to change on the display screen, the microcontroller doesn’t have to spend any CPU time to deal with the graphical sub-systems at all.

So far I’ve described 4 basic components that make up an embedded display system, but how are they packaged and sold in the market? Figure 3 shows four common architectures of an embedded display system available in the market place.

Figure 3:

fig31

In Figure 3-A, when a display has a built-in frame-buffer, I call it a display module. This is not a standard terminology, but it helps differentiate what I’m referring to in this article. The size of the built-in frame buffer varies, depending on what the display glass needs. A microcontroller can typically connect to a display module via a parallel or serial interface. Not every display has a built-in frame buffer. Smaller displays with lower resolution tend to have a built-in frame buffer, while bigger displays do not.

When a display doesn’t have a built-in frame buffer, it is often referred to as a ‘dumb glass’. In this article, I refer to the dumb glass purely as just a display glass, while a display with a built-in frame buffer is referred to as a display module. A display glass typically has what’s called the RGB interface. An RGB interface is identifiable when you see the following signals: HSYNC, VSYNC, Pixel Clock (Dot Clock), and Red/Green/Blue data lines. A RGB interface is not the same as the parallel interface mentioned in Figure 3-A. When I talk about a parallel interface, I’m talking about the Intel 8080 or Motorola 6800 like buses. I hope this is clear.

So when you shop for a display, you can identify if it’s just a display glass or a display module by checking if it has a RGB interface and/or a built-in frame buffer. Most display datasheets do not use the term ‘module’ or ‘dumb glass’; so the only way you could tell what it does is to look at the specifications and be knowledgeable about you what you are looking at. As a recap, if you see a built-in frame buffer and a parallel interface, the display is a module; and if you see a RGB interface, it is just a display glass. Some devices support both modes, such as any displays with the SSD1289 from Solomon-Systech (http://www.solomon-systech.com).

If your display has just a RGB interface, you will need to use either architecture B, C, or D shown in Figure 3. Not all microcontrollers have a built-in display controller, so I won’t spend too much time on architecture C or D. Let’s focus on Figure 3-B for the moment. A microcontroller may not have enough processing power to continuously feed data over the RGB interface, let alone having enough RAM to be used as a frame buffer. In this case, a 3rd device is required to interface between the display glass and the microcontroller; I call this device a graphic controller chip. A graphic controller chip has exactly the two things that were missing, a frame buffer and a display controller. It connects to a microcontroller via a parallel or serial interface, and to a display glass using a RGB interface. There are many choices available for a graphic controller chip, an example is the SSD1926. Chip suppliers tend to have different names for this kind of device, such as image processor, graphic controller, LCD driver, LCD controller, etc. They all tend to have at the basic level, a frame buffer and a display controller, but some do have additional features such as 2D hardware accelerator, JPEG decoder, etc. The discussion related to these additional features is beyond the scope of this article.

To wrap things up, architectures C and D show a microcontroller with a built-in display controller, this means it can drive a display glass with just a RGB interface directly. Do beware though that some of these microcontrollers have internal frame buffer, and some don’t. When they don’t, an external memory will be required. Knowing these differences and requirements is crucial in being able to calculate the total cost in implementing an embedded display system. Now that you are armed with the understanding of frame buffer, you would have no problems when someone tells you “The display I’m using in my project is a 3.5″ display with 320×240 resolution, supporting at least 16-bit color depth, with LED backlight, and 256KB frame buffer, connected to the main microcontroller using Intel 8080 16-bit parallel bus.” Way to go. There’re still a lot of materials left to be covered in future posts, but this one will have to do for now. Happy shopping for a display!

Tags: , , , , , , , ,

 
1

Scanning LED displays

Posted by Carol on Mar 9, 2009 in Displays

 

Another staple of embedded user interfaces is scanning LED displays using firmware.  The simple process of lighting each display, one at a time, and using the principle of persistence of vision to blur the individual digits into one seemingly continuously lit display.  Originally, the practice was used to reduce cost by cutting down on the number of BCD to 7 segment converter chips, it now accomplishes the same saving by limiting the number of microcontroller GPIO used to drive the display.

 So, what’s involved?  Well, there are a couple of things that have to happen;

  1. The amount of time each display is lit must be equal to the lit time for all the other displays, if the intensity is to be consistent.
  2. The amount of current driven through the display must be correspondingly larger to maintain the correct intensity.  Specifically, if the display is multiplexed 4:1, (4 displays) then the current must be 4x the continuous drive current.
  3. To prevent flicker, each display must be driven at least 2-3x the power line frequency.  If it is not, then the beat frequency between the flashes in a fluorescent lamp, and the display, will be visible.
  4. To provide the higher drive current, the digit select must be capable of delivering 8x the individual segment current, for a total of 16-24x the DC segment drive current.  This typically requires a discrete transistor for each digit drive.
  5. If a current limiting driver is not used, then a current limiting resistor will be needed, one for each common segment.  Don’t try to use a single resistor on the digit common, it will vary the intensity of the display based on the number of segments lit.

 

Alright, so we have a group of digits configured for scanning, with individual GPIO for each of the segments, and additional GPIO (with transistor drivers) for each of the display commons.  What’s involved in generating the software?

 The following listing is a basic display scanning routine.

 #define CH0 0b00111111            // THIS SECTION BUILDS A SET OF DEFINES FOR THE

#define CH1 0b00000110            // BCD TO 7 SEGMENT DECODER

#define CH2 0b01011011            // IT GENERATES DECODING FOR 0-9 PLUS HELP AND A BLANK

#define CH3 0b01001111

#define CH4 0b01100110            // NOTE: THE DECODER IS DONE THIS WAY TO COMPENSATE FOR

#define CH5 0b01101101            // THE NORMAL PIN SCRAMBLING THAT OCCURS DURING THE BOARD

#define CH6 0b01111101            // LAYOUT

#define CH7 0b00000111

#define CH8 0b01111111

#define CH9 0b01101111

#define CHH 0b01110110

#define CHE 0b01111001

#define CHL 0b00111000

#define CHP 0b01110011

#define CHb 0b00000000

 

#define DIG0 0b00001000    // THIS SECTION BUILDS ANOTHER SET OF DEFINES FOR THE

#define DIG1 0b00000100    // INDIVIDUAL DIGIT DRIVERS

#define DIG2 0b00000010

#define DIG3 0b00000001

 

// THIS SECTION TAKES THE DEFINES AND CREATES CONSTANT ARRAYS FOR ACCESSING THE DATA

 

const unsigned char SEGMENT[] = {CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8, CH9, CHH, CHE, CHL, CHP, CHb};

const unsigned char DRIVE[] = {DIG0, DIG1, DIG2, DIG3};

 

// THIS SECTION DEFINES THE DIGIT COUNTER TO KEEP TRACK OF WHICH DISPLAY IS CURRENT

// AND ANOTHER DATA ARRAY FOR THE ACTUAL DISPLAY, IN THIS CASE 4 DIGITS

 

static signed char DIGIT;                // Digit counter

static unsigned char VALUES[4] = {0,0,0,0};     // VALUES TO BE DISPLAYED

 

void init(void)

{

       DIGIT = 3;          // THE DIGIT COUNTER STARTS AT 3 AND COUNTS DOWN

       PORTD = 0xFF;              // PORT D IS THE SEGMENT DRIVE FOR THE DISPLAY

       TRISD = 0×00;

       PORTA = 0×00;              // PORT A IS THE DIGIT DRIVE FOR THE DISPLAY

       TRISA = 0xF0;

       OPTION = 0b10000011; // TIMER0 PROVIDES A CONSISTEN TIMEBASE FOR SCANNING

       TMR0   = 0;          // THE DISPLAY

       T0IE   = 1;

       T0IF   = 0;

       GIE    = 1;

}

 

static void interrupt isr(void)          // THIS IS THE TIMER INTERRUPT FUNCTIONS

{

       T0IF = 0;                         // FIRST OF ALL CLEAR THE INTERRUPT

       PORTA = 0b00000000;               // BLANK THE DISPLAY TO PREVENT GHOSTING

       PORTD = SEGMENT[VALUES[DIGIT]];   // PUT OUT THE SEGMENT INFO FOR NEXT DIGIT

       PORTA = DRIVE[DIGIT];                    // TURN ON THE NEXT DISPLAY

       DIGIT–;                          // DECREMENT TO THE NEXT DISPLAY RIGHT

       if (DIGIT < 0) DIGIT = 3;         // IF ROLL OVER, RESET THE DIGIT VALUE

}

 

Let’s take a look at the various sections;

First of all are the #defines that give us a label for the specific bit combination for each display and each number.  This is done to make the function more portable, if the individual bit combinations are hard-coded into the routine, then it would require editing the routines for each new system.  Using the #defines, all we have to do is update them for the new bit order and the compiler takes care of the rest.

The same is true of the digit drivers.  The #defines allow us to redefine which bits in the port are tied to the display, and it allows us to change the polarity of the drive with only a simple change of the #define.

Note: The port used for both the segments and digits assumes that all unused bits are inputs.  If this is not the case, then you will have to AND off the old bits and OR on the new ones instead of just assigning a new value.

OK, so we have a basic scanning interrupt setup, what else do we need?  Well, one additional feature that is nice to have is leading zero blanking.  You know, instead of 0021, we would much rather have just 21.  This is accomplished by using a simple flag, flags.blank.  At roll over, the flag is set to indicate all zero values are blanked, and each time the interrupt is called, if the flags is set and if the digit to be displayed is zero, then the segments are left off.  Now you know why we started at digit 3 and counted down, this allows us to blank the display of leading zeros until we hit a non-zero value.

If the value of the digit to be displayed is not zero, then the flag flags.blank is reset and all subsequent digits are displayed even they are zero.  This allows us to display 100 and 1 0 0 without the blanking routine turning it into just 1 and two blank spaces.  Finally, digit zero is always displayed even if the total number is zero.  The modified code is shown below;

Struct                            // THIS STRUCTURE HOLDS THE LEADING ZERO FLAG

       {

              char   blank:1;

              char   balance:7;

       } flags;

 

static void interrupt isr(void)

{

       T0IF = 0;

       PORTA = 0b00000000;

       PORTD = SEGMENT[VALUES[DIGIT]];

 

       if (VALUES[DIGIT] > 0)     flags.blank = 0;   // IF A NON-ZERO VALUE, CLEAR BLANKING

       if (DIGIT == 0)      flags.blank = 0;   // IF DIGIT 0, CLEAR BLANKING

       if (flags.blank == 1)      PORTD = 0;        // IF BLANKING IS STILL SET, BLANK DIGIT

 

       PORTA = DRIVE[DIGIT];

       DIGIT–;

       if (DIGIT < 0)

       {

               DIGIT = 3;

               flags.blank = 1;          // AT ROLL OVER SET THE BLANKING FLAG AGAIN

       }     

}

Alright, now we have an Timer0 interrupt triggering an LED display scanning routine, and it has leading zero suppression; what if I have to display a decimal point?  That affects leading zero suppression and my segment drive, how do we fold that into the routine.  And, we have to contend with a decimal point drive that shares the GPIO of the segment drive.

Well, first of all, we need a couple of bits to determine where the decimal point lies in the display, remember to account for left or right hand locations.  They are both driven off the same digit common, but one leads the display and one lags.  The routines below assume a lagging, or right handed decimal point display.

Struct                     // THIS STRUCTURE HOLDS THE LEADING 0 FLAG & decimal point

       {

              char ` blank:1;

              char   decpnt:2;

              char   balance:5;

       } flags;            

 

 

static void interrupt isr(void)

{

       T0IF = 0;

       PORTA = 0b00000000;

       PORTD = SEGMENT[VALUES[DIGIT]];

 

       if (flags.decpnt == DIGIT)        // HERE WE CHECK THE LOCATION OF DECIMAL PT

       {

              PORTD |=0×80;              // IF IT IS HERE, THEN ADD TO THE SEGMENT

              flags.blank = 0;           // ALSO TURN OFF BLANKING FOR 0.XX

       }     

       if (VALUES[DIGIT] > 0)     flags.blank = 0;

       if (DIGIT == 0)      flags.blank = 0;

       if (flags.blank == 1)      PORTD = 0;

       PORTA = DRIVE[DIGIT];

       DIGIT–;

       if (DIGIT < 0)

       {

               DIGIT = 3;

               flags.blank = 1;

       }     

}

The result is essentially the same interrupt service routine, we just have to turn on the decimal point at the right time.  Note, we also have to turn off the blanking for any zero leading the decimal point. 

For routines with left hand decimal points, we have to check for both the condition of when the decimal point value equal DIGIT-1, and when the decimal point equals DIGIT.  At DIGIT we have to turn off the blanking, and at DIGIT+1 we have to turn on the decimal point for the digit to the left.

OK, there you have it, a simple display driver routine that handles scanning the displays, leading zero suppression, and the decimal point, all in less than 60 lines of C code.  It is reasonably portable, and once it is initialized, it is basically invisible to the main program.

Tags: , ,

Copyright © 2010 Notes from the Lab All rights reserved. Theme by Laptop Geek.