Jump to content
43oh

TV-B-Gone using Launchpad


Recommended Posts

This is a reimplementation of adafruit's TV-B-Gone kit. It has been written from scratch to be more efficient and more precise than the AVR version. Assembly code is used for the critical timing, everything else is in C. Clock is 1 MHz (vs. 8 MHz for AVR).

 

This code is small enough to fit in a G2231 (2K flash, 128 RAM) that comes with the launchpad. There are only 39 codes due to limited flash capacity. Obviously larger parts like the G2553 could be used to fit all codes and add additional features.

 

main code (excerpt)

void send_code(TIRCODE * const ic)
{
   const uint8_t *code_byte;
   unsigned code_bitmask;
   static uint8_t idx[100];    // static so it is not on the stack
   unsigned n, j;
   uint8_t *p;

   // Make sure there is room for all indicies 
   if(ic->pair_count > sizeof(idx)) return;

   // Convert variable bit count to uint8_t
   n = ic->pair_count;
   code_byte = ic->bitstream;
   code_bitmask = 0x80;
   p = idx;
   // Iterate indicies
   while(n--) {
       *p = 0;
       j = ic->bits_per_index;
       // Iterate bits
       while(j--) {
           *p <<= 1;
           if(*code_byte & code_bitmask) *p |= 4;
           code_bitmask >>= 1;
           if(!code_bitmask) ++code_byte, code_bitmask = 0x80;
       }
       ++p;
   }

   if(ic->carrier_period) {
       TACCR0 = ic->carrier_period;
       TACCR1 = ic->carrier_period >> 1;
       tx_ir_carrier(ic->pair_count, idx, ic->durations);
   } else {
       tx_ir_pulse(ic->pair_count, idx, ic->durations);
   }
}


void main(void)
{
   unsigned n;

   WDTCTL = WDTPW + WDTHOLD;                       // Disable watchdog
                                                   //
   DCOCTL = 0;                                     // Use 1 MHz calibration
   BCSCTL1 = CALBC1_1MHZ;                          //
   DCOCTL = CALDCO_1MHZ;                           //
                                                   //
                                                   // See chart for I/O assignment
   P1OUT = 0x0E;                                   // Txd, Rxd, S2 high
   P1REN = 0x0C;                                   // Rxd / S2 pullup enabled
   P1DIR = 0xF3;                                   // Rxd / S2 in, all others out
   P1SEL = 0x50;                                   // Timer A T0.1 / SMCLK
   TACTL = TASSEL_2 | MC_1;                        // Clock = SMCLK, Mode = UP
                                                   //
   do {                                            //
       /// todo: Sleep while waiting for S2 press  //                                                  
       while(P1IN & 8);                            // Wait for S2 press                                            
                                                   //
       for(n = 0; n < code_count; ++n) {           //
           P1OUT |= 0x01;                          // LED on 
           delay10us(450 * 100u);                  // Wait 450 ms
           P1OUT &= ~0x01;                         // LED off
           send_code(CodeList[n]);                 // Send code
       }                                           //
   } while(1);                                     //
}

 

ir transmission code (excerpt)

tx_ir_carrier                           ; void tx_ir_carrier(unsigned n, uint8_t *i, TDUR *d)
                                       ; R12 Duration pair count
                                       ; R13 Pointer to duration indicies
                                       ; R14 Pointer to durations
                                       ;
           mov     #OUTMOD_7, R10      ; IR Carrier On (reset/set output mode)
           mov     #OUTMOD_5, R11      ; IR Carrier Off (reset output mode)
                                       ;
ir_tx_loop  mov.b   @R13, R15           ; Get duration index
           add     R14, R15            ; Add duration pointer
           mov     @R15, R15           ; Get duration
                                       ;
           mov     R10, &TACCTL1       ; Turn on IR
           call    #delay              ; Wait for on duration
                                       ;
           nop2                        ; Precise timing
                                       ;
           mov.b   @R13+, R15          ; Get duration index and increment pointer
           incd    R15                 ; Adjust for off duration
           add     R14, R15            ; Add duration pointer
           mov     @R15, R15           ; Get duration
                                       ;
           mov     R11, &TACCTL1       ; Turn off IR 
           call    #delay              ; Wait for off duration
                                       ;
           dec     R12                 ; Decrement pair count
           jne     ir_tx_loop          ; Do next duration pair...
                                       ;
           ret                         ; Return
                                       ;
                                       ;
                                       ;
                                       ; - Delay in units of 10 cycles (10 us at 1 MHz)
delay       cmp     #4, R15             ; Compare to minimum
           jlo     dlyret              ; Below minimum, return...      
           sub     #2, R15             ; Adjust loop count for overhead
           jmp     eloop               ; Make the first iteration shorter
                                       ;
delay10us   mov     R12, R15            ; C callable
                                       ;                                       
dloop       nop2                        ; 7 cycles of nop
           nop2                        ;
           nop2                        ;
eloop       nop                         ;
           dec     R15                 ; Decrement loop count - 1 cycle
           jne     dloop               ; Loop if not zero - 2 cycles
                                       ;
dlyret      ret                         ;

 

Complete code attached

tvbg_lp.zip

Link to post
Share on other sites

Consumer IR is 940/950 nm, so whatever LED you choose, make sure it is the proper wavelength. The IR333 type is a very common generic IR LED. It is made by many manufactures and there are a few variants of it. The exact specs and quality will vary from one mfg to another. I have been using Vishay IR LEDs - mostly TSAL6200. They have superior specs, but I don't know if that makes any real difference in the real world. Here is a list of some of the Vishay parts and two IR333 for comparison...

 

IR333A 20 degrees 
TSAL6100 20 degrees 
TSAL5100 20 degrees 

TSAL6200 35 degrees 
TSAL7200 35 degrees 

IR333C/H0/L10 40 degrees 

TSAL5300 45 degrees 
TSAL7300 45 degrees 

TSAL6400 50 degrees 
TSAL7400 50 degrees 

TSAL7600 60 degrees

 

I think the TASL6x00 and TSAL7x00 are the same die in a different package (tinted vs clear).

 

A PN2222A or PZT2222A works well for driving the IR LED. The beta drops as IC (collector current) increases, so it is effectively current limited. It is a proven design (that is often questioned by those who don't understand it). An IR LED will typically handle 50 to 100 mA continuous, and 500 to 1000 mA for a short time. Most IR protocols use bursts of 30 to 60 kHz, so the IR LED can be driven near it's maximum rating. The Vf is about 1 volt (current dependent), much lower than visible LEDs. If you are developing firmware then it is a good idea to limit the current to 50 mA or less until the code is proven to work properly.

 

I have not done any hardware for the MSP430 yet, but I have done some AVR designs that show the IR LED driver circuit.

 

The CHiP (Compact High Power): This design fits in one compartment of a AA battery holder. It can operate at moderate power when 2 AA cells are used, or high(er) power when 3 AA cells are used. An emitter follower is used for the high power mode only.

 

The EHP (Extereme High Power): Several adafruit forum members built this and it performs very well. It pulls about 6 amp pulses from the 4 AA cells and often makes them squeal.

 

Keychain: Uses two CR2032 cell - one for the micro, and one for the MCU. This prevents MCU brownout while allowing max LED current.

Link to post
Share on other sites

My camera intervalometer project uses the Vishay TSAL7400 driven by a 2N2222. I've used these LEDs on several projects and they're practically indestructible!

 

I second what oPossum says above. The IR LEDs can be driven at what seem like excessive currents simply because of the switching frequencies.

Link to post
Share on other sites
It pulls about 6 amp pulses from the 4 AA cells and often makes them squeal.

That's interesting, never heard of noise-making batteries before...

Instead of power-off, I will program to send volume up :)

How much memory would it take to add another function and button? Seems to me all that would be needed is a few IF statements in certain places. ;)

Link to post
Share on other sites
  • 4 weeks later...
  • 2 months later...
  • 2 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...