changeset 138:a832a6908d9e main

Update firmware for new board; new cpu, change pins, now supports lcd.
author Bob Cook <bob@bobcookdev.com>
date Fri, 06 Apr 2012 12:18:49 -0700
parents 468faf23535b
children 1a3366477e09
files main/projects/robocam/controls.cpp main/projects/robocam/controls.h main/projects/robocam/diag.cpp main/projects/robocam/errorcondition.cpp main/projects/robocam/jamfile main/projects/robocam/main.cpp main/projects/robocam/project_defs.h main/projects/robocam/steppers.cpp main/projects/robocam/trigger.cpp
diffstat 9 files changed, 515 insertions(+), 221 deletions(-) [+]
line wrap: on
line diff
--- a/main/projects/robocam/controls.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/controls.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2010 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -51,18 +51,45 @@
 volatile led_mode_t g_red_led_mode;
 volatile led_mode_t g_green_led_mode;
 
-volatile bool g_button_down;
+volatile bool g_button_1_down;
+volatile bool g_button_2_down;
+
+static const uint16_t PROGMEM g_joystick_x_conversion[] = {
+    899, 894, 889, 884, 879, 874, 869, 865, 860, 855,
+    850, 845, 840, 835, 830, 825, 820, 815, 810, 806,
+    801, 796, 791, 786, 781, 776, 771, 766, 761, 756,
+    751, 746, 742, 737, 732, 727, 722, 717, 712, 707,
+    // zero rotation
+    680, 671, 663, 654, 646, 637, 629, 620, 612, 603,
+    595, 586, 578, 569, 561, 552, 544, 535, 527, 518,
+    510, 501, 493, 484, 476, 467, 459, 450, 442, 433,
+    425, 416, 408, 399, 391, 382, 374, 365, 357, 348,
+      0 // last entry should be zero
+};
 
-static const uint16_t PROGMEM g_joystick_conversion[] = {
-    937, 932, 927, 922, 917, 912, 907, 902, 897, 892,
-    887, 882, 877, 871, 865, 859, 853, 846, 839, 832,
-    824, 816, 808, 799, 789, 779, 768, 756, 744, 731,
-    717, 702, 686, 669, 651, 631, 610, 588, 564, 539,
+static const uint16_t PROGMEM g_joystick_y_conversion[] = {
+    912, 907, 902, 897, 892, 887, 882, 877, 872, 867,
+    862, 857, 852, 847, 842, 837, 832, 827, 822, 817,
+    812, 807, 802, 797, 792, 787, 782, 777, 772, 767,
+    762, 757, 752, 747, 742, 737, 732, 727, 722, 717,
     // zero rotation
-    481, 452, 424, 398, 374, 352, 331, 311, 293, 276,
-    260, 245, 231, 218, 206, 195, 185, 175, 166, 157,
-    149, 141, 134, 127, 120, 114, 108, 102,  96,  91,
-     86,  81,  76,  71,  66,  61,  56,  51,  46,  41,
+    693, 686, 680, 673, 666, 660, 653, 646, 639, 633,
+    626, 619, 613, 606, 599, 592, 586, 579, 572, 565,
+    559, 552, 545, 539, 532, 525, 518, 512, 505, 498,
+    492, 485, 478, 471, 465, 458, 451, 444, 438, 431,
+      0 // last entry should be zero
+};
+
+static const uint16_t PROGMEM g_joystick_z_conversion[] = {
+    907, 898, 889, 880, 871, 862, 853, 844, 835, 826,
+    817, 808, 799, 790, 782, 773, 764, 755, 746, 737,
+    728, 719, 710, 701, 692, 683, 674, 665, 656, 647,
+    638, 629, 620, 611, 602, 593, 584, 575, 566, 557,
+    // zero rotation
+    520, 510, 501, 492, 482, 473, 463, 454, 445, 435,
+    426, 417, 407, 398, 388, 379, 370, 360, 351, 342,
+    332, 323, 313, 304, 295, 285, 276, 267, 257, 248,
+    238, 229, 220, 210, 201, 192, 182, 173, 163, 154,
       0 // last entry should be zero
 };
 
@@ -77,83 +104,102 @@
         counter = 0;
     }
 
-    // red led
+    // red led PORTC.0
 
     if ( g_red_led_mode == led_mode_on )
     {
-        PORTB &= ~( 1 << PB0 );
+        PORTC &= ~( 1 << PC0 );
     }
     else if ( g_red_led_mode == led_mode_blink )
     {
         if ( counter % 10 == 0 )
         {
-            PORTB ^= ( 1 << PB0 );
+            PORTC ^= ( 1 << PC0 );
         }
     }
     else if ( g_red_led_mode == led_mode_pulse )
     {
         if ( counter == 60 || counter == 80 )
         {
-            PORTB &= ~( 1 << PB0 );
+            PORTC &= ~( 1 << PC0 );
         }
         else if ( counter == 70 || counter == 90 )
         {
-            PORTB |= ( 1 << PB0 );
+            PORTC |= ( 1 << PC0 );
         }
     }
     else
     {
-        PORTB |= ( 1 << PB0 );
+        PORTC |= ( 1 << PC0 );
     }
 
-    // green led
+    // green led PORTC.1
 
     if ( g_green_led_mode == led_mode_on )
     {
-        PORTB &= ~( 1 << PB1 );
+        PORTC &= ~( 1 << PC1 );
     }
     else if ( g_green_led_mode == led_mode_blink )
     {
         if ( counter % 10 == 0 )
         {
-            PORTB ^= ( 1 << PB1 );
+            PORTC ^= ( 1 << PC1 );
         }
     }
     else if ( g_green_led_mode == led_mode_pulse )
     {
         if ( counter == 60 || counter == 80 )
         {
-            PORTB &= ~( 1 << PB1 );
+            PORTC &= ~( 1 << PC1 );
         }
         else if ( counter == 70 || counter == 90 )
         {
-            PORTB |= ( 1 << PB1 );
+            PORTC |= ( 1 << PC1 );
         }
     }
     else
     {
-        PORTB |= ( 1 << PB1 );
+        PORTC |= ( 1 << PC1 );
     }
 
-    // check the state of the button
+    // check the state of the buttons PORTC.3, PORTC.4
 
-    static uint8_t button_down_counts = 0;
+    static uint8_t button_1_down_counts = 0;
 
-    if ( ( PINC & ( 1 << PC5 ) ) == 0 )
+    if ( ( PINC & ( 1 << PC3 ) ) == 0 )
     {
-        if ( button_down_counts > 20 )
+        if ( button_1_down_counts > 20 )
         {
-            g_button_down = true;
+            g_button_1_down = true;
         }
         else
         {
-            ++button_down_counts;
+            ++button_1_down_counts;
         }
     }
     else
     {
-        g_button_down = false;
-        button_down_counts = 0;
+        g_button_1_down = false;
+        button_1_down_counts = 0;
+    }
+
+    static uint8_t button_2_down_counts = 0;
+
+    if ( ( PINC & ( 1 << PC4 ) ) == 0 )
+    {
+        if ( button_2_down_counts > 20 )
+        {
+            g_button_2_down = true;
+        }
+        else
+        {
+            ++button_2_down_counts;
+        }
+    }
+    else
+    {
+        g_button_2_down = false;
+        button_2_down_counts = 0;
     }
 }
 
@@ -203,17 +249,22 @@
 
 // ----------------------------------------------------------------------------------------
 
-bool button_down()
+bool button_1_down()
 {
-    return g_button_down;
+    return g_button_1_down;
+}
+
+bool button_2_down()
+{
+    return g_button_2_down;
 }
 
 // ----------------------------------------------------------------------------------------
 
-uint8_t joystick_convert_raw_value( uint16_t value )
+uint8_t joystick_x_convert_raw_value( uint16_t value )
 {
-    const prog_uint16_t* conversion_table = g_joystick_conversion;
-    for ( uint8_t i = 0; i < array_sizeof( g_joystick_conversion ) - 1; ++i )
+    const prog_uint16_t* conversion_table = g_joystick_x_conversion;
+    for ( uint8_t i = 0; i < array_sizeof( g_joystick_x_conversion ) - 1; ++i )
     {
         uint16_t limit = pgm_read_word_near( conversion_table++ );
         if ( value >= limit )
@@ -221,8 +272,40 @@
             return i;
         }
     }
-    return array_sizeof( g_joystick_conversion ) - 1;
+    return array_sizeof( g_joystick_x_conversion ) - 1;
 }
 
 // ----------------------------------------------------------------------------------------
 
+uint8_t joystick_y_convert_raw_value( uint16_t value )
+{
+    const prog_uint16_t* conversion_table = g_joystick_y_conversion;
+    for ( uint8_t i = 0; i < array_sizeof( g_joystick_y_conversion ) - 1; ++i )
+    {
+        uint16_t limit = pgm_read_word_near( conversion_table++ );
+        if ( value >= limit )
+        {
+            return i;
+        }
+    }
+    return array_sizeof( g_joystick_y_conversion ) - 1;
+}
+
+// ----------------------------------------------------------------------------------------
+
+uint8_t joystick_z_convert_raw_value( uint16_t value )
+{
+    const prog_uint16_t* conversion_table = g_joystick_z_conversion;
+    for ( uint8_t i = 0; i < array_sizeof( g_joystick_z_conversion ) - 1; ++i )
+    {
+        uint16_t limit = pgm_read_word_near( conversion_table++ );
+        if ( value >= limit )
+        {
+            return i;
+        }
+    }
+    return array_sizeof( g_joystick_z_conversion ) - 1;
+}
+
+// ----------------------------------------------------------------------------------------
+
--- a/main/projects/robocam/controls.h	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/controls.h	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2010 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -31,6 +31,12 @@
 
 // ----------------------------------------------------------------------------------------
 
+#define JOYSTICK_ADC_CHANNEL_X  5
+#define JOYSTICK_ADC_CHANNEL_Y  4
+#define JOYSTICK_ADC_CHANNEL_Z  2
+
+// ----------------------------------------------------------------------------------------
+
 void led_red_off();
 void led_red_on();
 void led_red_blink();
@@ -41,9 +47,12 @@
 void led_green_blink();
 void led_green_pulse();
 
-bool button_down();
+bool button_1_down();
+bool button_2_down();
 
-uint8_t joystick_convert_raw_value( uint16_t value );
+uint8_t joystick_x_convert_raw_value( uint16_t value );
+uint8_t joystick_y_convert_raw_value( uint16_t value );
+uint8_t joystick_z_convert_raw_value( uint16_t value );
 
 void controls_interrupt_routine();
 
--- a/main/projects/robocam/diag.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/diag.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2011 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -59,15 +59,15 @@
 
     bool update_display = true;
 
-    uint16_t last_joystick_x = adc_read( 0 );
-    uint16_t last_joystick_y = adc_read( 1 );
-    uint16_t last_joystick_z = adc_read( 2 );
+    uint16_t last_joystick_x = adc_read( JOYSTICK_ADC_CHANNEL_X );
+    uint16_t last_joystick_y = adc_read( JOYSTICK_ADC_CHANNEL_Y );
+    uint16_t last_joystick_z = adc_read( JOYSTICK_ADC_CHANNEL_Z );
 
     for ( ;; )
     {
-        uint16_t  joystick_x = adc_read( 0 );
-        uint16_t  joystick_y = adc_read( 1 );
-        uint16_t  joystick_z = adc_read( 2 );
+        uint16_t  joystick_x = adc_read( JOYSTICK_ADC_CHANNEL_X );
+        uint16_t  joystick_y = adc_read( JOYSTICK_ADC_CHANNEL_Y );
+        uint16_t  joystick_z = adc_read( JOYSTICK_ADC_CHANNEL_Z );
 
         if ( joystick_x != last_joystick_x )
         {
@@ -113,15 +113,21 @@
 
     bool update_display = true;
 
-    uint8_t last_joystick_x = joystick_convert_raw_value( adc_read( 0 ) );
-    uint8_t last_joystick_y = joystick_convert_raw_value( adc_read( 1 ) );
-    uint8_t last_joystick_z = joystick_convert_raw_value( adc_read( 2 ) );
+    uint8_t last_joystick_x
+        = joystick_x_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_X ) );
+    uint8_t last_joystick_y
+        = joystick_y_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_Y ) );
+    uint8_t last_joystick_z
+        = joystick_z_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_Z ) );
 
     for ( ;; )
     {
-        uint8_t joystick_x = joystick_convert_raw_value( adc_read( 0 ) );
-        uint8_t joystick_y = joystick_convert_raw_value( adc_read( 1 ) );
-        uint8_t joystick_z = joystick_convert_raw_value( adc_read( 2 ) );
+        uint8_t joystick_x
+            = joystick_x_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_X ) );
+        uint8_t joystick_y
+            = joystick_y_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_Y ) );
+        uint8_t joystick_z
+            = joystick_z_convert_raw_value( adc_read( JOYSTICK_ADC_CHANNEL_Z ) );
 
         if ( joystick_x != last_joystick_x )
         {
@@ -238,39 +244,59 @@
     led_green_off();
 
     printf_P( PSTR("testing leds\n") );
-    printf_P( PSTR("on ") );
+
+    printf_P( PSTR("green: on ") );
+    led_green_on();
+    spinwait_delay_ms( 1500 );
+
+    printf_P( PSTR("blink ") );
+    led_green_blink();
+    spinwait_delay_ms( 1500 );
+
+    printf_P( PSTR("pulse ") );
+    led_green_pulse();
+    spinwait_delay_ms( 1500 );
+
+    printf_P( PSTR("off\n") );
+    led_green_off();
+    spinwait_delay_ms( 1500 );
+
+    printf_P( PSTR("red: on ") );
     led_red_on();
-    led_green_on();
     spinwait_delay_ms( 1500 );
 
     printf_P( PSTR("blink ") );
     led_red_blink();
-    led_green_blink();
     spinwait_delay_ms( 1500 );
 
     printf_P( PSTR("pulse ") );
     led_red_pulse();
-    led_green_pulse();
     spinwait_delay_ms( 1500 );
 
     printf_P( PSTR("off\n") );
     led_red_off();
-    led_green_off();
     spinwait_delay_ms( 1500 );
 }
 
 // ----------------------------------------------------------------------------------------
 
-static void test_button()
+static void test_buttons()
 {
-    printf_P( PSTR("testing the button (q to exit)\n") );
+    printf_P( PSTR("testing buttons (q to exit)\n") );
     for ( ;; )
     {
-        if ( button_down() )
+        if ( button_1_down() )
         {
-            printf_P( PSTR("button down\n") );
-            while ( button_down() ) ;
-            printf_P( PSTR("button up\n") );
+            printf_P( PSTR("button 1 down\n") );
+            while ( button_1_down() ) ;
+            printf_P( PSTR("button 1 up\n") );
+        }
+
+        if ( button_2_down() )
+        {
+            printf_P( PSTR("button 2 down\n") );
+            while ( button_2_down() ) ;
+            printf_P( PSTR("button 2 up\n") );
         }
 
         if ( getchar() == 'q' )
@@ -533,7 +559,7 @@
         printf_P( PSTR("3. dump sdcard sector zero\n") );
         printf_P( PSTR("4. test audio trigger\n") );
         printf_P( PSTR("5. test leds\n") );
-        printf_P( PSTR("6. test the button\n") );
+        printf_P( PSTR("6. test buttons\n") );
         printf_P( PSTR("7. test steppers\n") );
         printf_P( PSTR("8. data playback\n") );
         printf_P( PSTR("9. data playback (reverse)\n") );
@@ -574,7 +600,7 @@
                     break;
 
                 case '6':
-                    test_button();
+                    test_buttons();
                     did_cmd = true;
                     break;
 
--- a/main/projects/robocam/errorcondition.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/errorcondition.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2010 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -134,17 +134,17 @@
 
     cli(); // no interrupts
 
-    DDRB = ( 1 << PB0 ) | ( 1 << PB1 );
-    DDRC = 0;
+    DDRB = 0;
+    DDRC = ( 1 << PC0 ) | ( 1 << PC1 );
     DDRD = 0;
 
-    PORTB = ( 1 << PB0 );
+    PORTC = ( 1 << PC0 );
 
     for ( ;; )
     {
-        PORTB ^= ( 1 << PB0 );
+        PORTC ^= ( 1 << PC0 );
         spinwait_delay_ms( 75 );
-        PORTB ^= ( 1 << PB1 );
+        PORTC ^= ( 1 << PC1 );
         spinwait_delay_ms( 75 );
     }
 }
--- a/main/projects/robocam/jamfile	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/jamfile	Fri Apr 06 12:18:49 2012 -0700
@@ -1,7 +1,7 @@
 # -----------------------------------------------------------------------------------------
 #
 #   projects/robocam/jamfile
-#   Copyright (C) 2011 Bob Cook
+#   Copyright (C) 2012 Bob Cook
 #
 #   Bob Cook Development, Robotics Library
 #   http://www.bobcookdev.com/rl/
@@ -33,7 +33,7 @@
 # -----------------------------------------------------------------------------------------
 
 avr_executable
-    robocam atmega328p
+    robocam atmega128
     : main.cpp
       controls.cpp
       data.cpp
@@ -42,6 +42,7 @@
       steppers.cpp
       trigger.cpp
       packages.avr.device.pkg
+      packages.avr.lcd.hd44780.pkg
       packages.avr.redir.pkg
       packages.avr.sdcard.pkg
     ;
--- a/main/projects/robocam/main.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/main.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -46,6 +46,7 @@
 #include "packages/avr/device/int_helpers.h"
 #include "packages/avr/device/spinwait.h"
 #include "packages/avr/device/uart.h"
+#include "packages/avr/lcd/hd44780/hd44780.h"
 #include "packages/avr/redir/redir.h"
 #include "packages/avr/sdcard/sdcard.h"
 
@@ -85,6 +86,7 @@
     mode_playback,
     mode_reverse,
     mode_record,
+    mode_test_trigger,
     mode_diagnostics
 
 }   modes_t;
@@ -102,93 +104,91 @@
     cli();
     interrupts_clear_all();
 
-    //--    Indicator LEDs on PORTB.0 and PORTB.1
+    //--    Indicator LEDs on PORTC.0, PORTC.1, and PORTC.2
 
-    DDRB |= ( 1 << PB0 ) | ( 1 << PB1 );
+    DDRC |= ( 1 << PC0 ) | ( 1 << PC1 ) | ( 1 << PC2 );
 
     //--    Stepper controls on PORTD:
     //
-    //          PD2: x step
-    //          PD3: x direction
-    //          PD4: y step
-    //          PD5: y direction
-    //          PD6: z step
-    //          PD7: z direction
+    //          PA0: x step
+    //          PA1: x direction
+    //          PA2: y step
+    //          PA3: y direction
+    //          PA4: z step
+    //          PA5: z direction
 
-    DDRD |= ( 1 << PD2 ) | ( 1 << PD3 ) 
-          | ( 1 << PD4 ) | ( 1 << PD5 ) 
-          | ( 1 << PD6 ) | ( 1 << PD7 );
+    DDRA |= ( 1 << PA0 ) | ( 1 << PA1 ) 
+         |  ( 1 << PA2 ) | ( 1 << PA3 ) 
+         |  ( 1 << PA4 ) | ( 1 << PA5 );
 
     //--    STDIO goes out to the serial port.
 
     redir_initialize();
 
-    //--    Joystick and audio input on ADC.
+    //--    Initialize the LCD package.
+    
+    hd44780_init();
+
+    //--    Joystick and audio input on ADC:
+    //
+    //          ADC0: audio input right
+    //          ADC1: audio input left
+    //          ADC2: joystick x
+    //          ADC3: joystick y
+    //          ADC4: joystick z
+    //          ADC5: (not used)
     
     adc_init();
 
-    //--    Button on PORTC.5 so set it as an input with a pull-up
+    //--    Buttons on PORTC.3 and PORTC.4, set as an input with a pull-up
 
-    DDRC  &= ~( 1 << PC5 );
-    PORTC |=  ( 1 << PC5 );
+    DDRC  &= ~( ( 1 << PC3 ) | ( 1 << PC4 ) );
+    PORTC |=  ( ( 1 << PC3 ) | ( 1 << PC4 ) );
 
-    //--    Set up a 100 Hz (approximate) interrupt timer.
+    //--    Set up Timer0 as a 100 Hz (approximate) interrupt timer.
 
-    TCCR0A = 0
-        | ( 0 << COM0A1 ) | ( 0 << COM0A0 )     // OC0A not used
-        | ( 0 << COM0B1 ) | ( 0 << COM0B0 )     // OC0B not used
-        | ( 1 << WGM01  ) | ( 0 << WGM00  )     // CTC mode
+    TCCR0 = 0
+        | ( 0 << WGM00 )                                    // CTC mode
+        | ( 0 << COM01 ) | ( 0 << COM00 )                   // OC0 not used
+        | ( 1 << WGM01 )                                    // CTC mode
+        | ( 1 << CS02  ) | ( 1 << CS01 ) | ( 1 << CS00 )    // clk/1024
         ;
 
-    TCCR0B = 0
-        | ( 0 << FOC0A ) | ( 0 << FOC0B )                   // no force output compare
-        | ( 0 << WGM02 )                                    // CTC mode
-        | ( 1 << CS02  ) | ( 0 << CS01 ) | ( 1 << CS00 )    // clk/1024
-        ;
+    OCR0 = 156;
 
-    OCR0A = 195;
+    TIMSK |= ( 1 << OCIE0 );
 
-    TIMSK0 |= ( 1 << OCIE0A );
-
-    //--    Set up a 50 Hz interrupt timer.
+    //--    Set up Timer1 as a 50 Hz interrupt timer.
 
     TCCR1A = 0
         | ( 0 << COM1A1 ) | ( 0 << COM1A0 )     // OC1A not used
         | ( 0 << COM1B1 ) | ( 0 << COM1B0 )     // OC1B not used
+        | ( 0 << COM1C1 ) | ( 0 << COM1C0 )     // OC1C not used
         | ( 0 << WGM11  ) | ( 0 << WGM10  )     // CTC mode
         ;
 
     TCCR1B = 0
-        | ( 0 << ICNC1 )                                    // no input capture
-        | ( 0 << ICES1 )                                    // no input capture
-        | ( 0 << WGM13 )                                    // CTC mode
-        | ( 1 << WGM12 )                                    // CTC mode
-        | ( 0 << CS12  ) | ( 1 << CS11 ) | ( 1 << CS10 )    // clk/64
+        | ( 0 << ICNC1 ) | ( 0 << ICES1 )                   // no input capture
+        | ( 0 << WGM13 ) | ( 1 << WGM12 )                   // CTC mode
+        | ( 0 << CS12  ) | ( 1 << CS11  ) | ( 1 << CS10 )   // clk/64
         ;
 
-    OCR1A = 6250;
+    OCR1A = 5000;
 
-    TIMSK1 |= ( 1 << OCIE1A );
+    TIMSK |= ( 1 << OCIE1A );
+
+    //--    Set up Timer2 as a 62.5 kHz interrupt timer.
 
-    //--    Set up a 32.5 kHz interrupt timer.
-
-    TCCR2A = 0
-        | ( 0 << COM2A1 ) | ( 0 << COM2A0 )     // OC2A not used
-        | ( 0 << COM2B1 ) | ( 0 << COM2B0 )     // OC2B not used
-        | ( 1 << WGM21  ) | ( 0 << WGM20  )     // CTC mode
+    TCCR2 = 0
+        | ( 0 << WGM20 )                                    // CTC mode
+        | ( 0 << COM21 ) | ( 0 << COM20 )                   // OC2 not used
+        | ( 1 << WGM21 )                                    // CTC mode
+        | ( 0 << CS22  ) | ( 1 << CS21 ) | ( 1 << CS20 )    // clk/8
         ;
 
-    TCCR2B = 0
-        | ( 0 << FOC2A )                                    // no force output compare
-        | ( 0 << FOC2B )                                    // no force output compare
-        | ( 0 << WGM22 )                                    // CTC mode
-        | ( 0 << CS22  ) | ( 1 << CS21 ) | ( 1 << CS20 )    // clk/32
-        ;
+    OCR2 = 32;
 
-    //OCR2A = 10;
-    OCR2A = 10;
-
-    TIMSK2 |= ( 1 << OCIE2A );
+    TIMSK |= ( 1 << OCIE2 );
 
     //--    Re-enable interrupts.
 
@@ -197,7 +197,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-ISR( TIMER0_COMPA_vect )
+ISR( TIMER0_COMP_vect )
 {
     controls_interrupt_routine();
 }
@@ -214,13 +214,13 @@
 
         case state_recording_read_x:
             g_temp_x = adc_get_result();
-            adc_start_read( 1 /* y axis */ );
+            adc_start_read( JOYSTICK_ADC_CHANNEL_Y /* y axis */ );
             g_state = state_recording_read_y;
             break;
 
         case state_recording_read_y:
             g_temp_y = adc_get_result();
-            adc_start_read( 2 /* z axis */ );
+            adc_start_read( JOYSTICK_ADC_CHANNEL_Z /* z axis */ );
             g_state = state_recording_read_z;
             break;
 
@@ -252,9 +252,9 @@
 
         case state_recording_update:
             {
-                uint8_t  stepper_x = joystick_convert_raw_value( g_temp_x );
-                uint8_t  stepper_y = joystick_convert_raw_value( g_temp_y );
-                uint8_t  stepper_z = joystick_convert_raw_value( g_temp_z );
+                uint8_t  stepper_x = joystick_x_convert_raw_value( g_temp_x );
+                uint8_t  stepper_y = joystick_y_convert_raw_value( g_temp_y );
+                uint8_t  stepper_z = joystick_z_convert_raw_value( g_temp_z );
                 // save the new values
                 data_save_values( stepper_x, stepper_y, stepper_z );
                 // update the steppers
@@ -262,7 +262,7 @@
                 stepper_y_set( stepper_y );
                 stepper_z_set( stepper_z );
                 // kick off reading new joystick values
-                adc_start_read( 0 /* x axis */ );
+                adc_start_read( JOYSTICK_ADC_CHANNEL_X /* x axis */ );
                 g_state = state_recording_read_x;
             }
             break;
@@ -337,89 +337,146 @@
 
 // ----------------------------------------------------------------------------------------
 
-ISR( TIMER2_COMPA_vect )
+ISR( TIMER2_COMP_vect )
 {
     steppers_interrupt_routine();
 }
 
 // ----------------------------------------------------------------------------------------
 
+static void display_show_mode( modes_t the_mode )
+{
+    hd44780_set_position( 0, 0 );
+
+    if ( the_mode == mode_playback )
+    {
+        hd44780_write_pgm( PSTR("PLAY ") );
+    }
+    else
+    {
+        hd44780_write_pgm( PSTR("play ") );
+    }
+
+    if ( the_mode == mode_record )
+    {
+        hd44780_write_pgm( PSTR("RECORD ") );
+    }
+    else
+    {
+        hd44780_write_pgm( PSTR("record ") );
+    }
+
+    if ( the_mode == mode_test_trigger )
+    {
+        hd44780_write_pgm( PSTR("TEST") );
+    }
+    else
+    {
+        hd44780_write_pgm( PSTR("test") );
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
 static modes_t do_startup_mode_selector()
 {
-    bool playback_not_record = true;
+    modes_t current_mode = mode_playback;
+
+    hd44780_clear_screen();
+
+    led_green_off();
+    led_red_off();
+
+    display_show_mode( current_mode );
 
-    led_red_off();
-    led_green_pulse();
+    if ( current_mode == mode_playback )
+    {
+        led_green_pulse();
+    }
+    else
+    {
+        led_red_pulse();
+    }
+
+    hd44780_set_position( 0, 1 );
+    hd44780_write_pgm( PSTR("(change)(select)") );
 
     for ( ;; )
     {
         if ( getchar() == 'd' )
         {
+            led_green_off();
             led_red_off();
-            led_green_off();
-            return mode_diagnostics;
+            current_mode = mode_diagnostics;
+            break;
         }
 
-        if ( button_down() )
+        if ( button_1_down() )
         {
-            if ( playback_not_record )
+            if ( current_mode == mode_playback )
             {
+                led_green_off();
+                current_mode = mode_record;
+                led_red_on();
+            }
+            else if ( current_mode == mode_record )
+            {
+                led_red_off();
+                current_mode = mode_test_trigger;
                 led_green_on();
             }
             else
             {
+                current_mode = mode_playback;
+                led_red_on();
+                led_green_on();
+            }
+
+            display_show_mode( current_mode );
+
+            while ( button_1_down() ) ;
+
+            if ( current_mode == mode_playback )
+            {
+                led_green_pulse();
+            }
+            else if ( current_mode == mode_record )
+            {
+                led_red_pulse();
+            }
+            else
+            {
+                led_green_pulse();
+                led_red_pulse();
+            }
+        }
+
+        if ( button_2_down() )
+        {
+            if ( current_mode == mode_playback )
+            {
+                led_green_on();
+            }
+            else if ( current_mode == mode_record )
+            {
+                led_red_on();
+            }
+            else
+            {
+                led_green_on();
                 led_red_on();
             }
 
-            bool flip_mode = true;
-            for ( uint8_t i = 0; i < 100; ++i )
-            {
-                if ( ! button_down() )
-                {
-                    flip_mode = false;
-                    break;
-                }
-                spinwait_delay_ms( 20 );
-            }
-
-            if ( flip_mode )
-            {
-                playback_not_record = !playback_not_record;
+            while ( button_2_down() ) ;
 
-                if ( playback_not_record )
-                {
-                    led_red_off();
-                    led_green_on();
-                }
-                else
-                {
-                    led_red_on();
-                    led_green_off();
-                }
-
-                while ( button_down() ) ;
-                spinwait_delay_ms( 20 );
+            led_green_off();
+            led_red_off();
 
-                if ( playback_not_record )
-                {
-                    led_green_pulse();
-                }
-                else
-                {
-                    led_red_pulse();
-                }
-            }
-            else
-            {
-                break;
-            }
+            break;
         }
     }
 
-    led_red_off();
-    led_green_off();
-
-    return ( playback_not_record ? mode_playback : mode_record );
+    return current_mode;
 }
 
 // ----------------------------------------------------------------------------------------
@@ -431,7 +488,7 @@
 
 static void do_start_recording_machine()
 {
-    adc_start_read( 0 /* x axis */ );
+    adc_start_read( JOYSTICK_ADC_CHANNEL_X /* x axis */ );
     g_state = state_recording_read_x;
     ADCSRA |= ( 1 << ADIE );
 }
@@ -458,26 +515,37 @@
     led_red_blink();
     printf_P( PSTR("record mode selected\n") );
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("preparing") );
+
     if ( ! data_prepare_to_record() )
     {
+        hd44780_clear_line( 1 );
+        hd44780_write_pgm( PSTR("failed prep") );
         error_fatal( error_recording_prep_failed );
     }
     printf_P( PSTR("record prep complete\n") );
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("trigger?  (skip)") );
+
     printf_P( PSTR("waiting for audio trigger\n") );
     if ( ! wait_for_audio_trigger() )
     {
         // button was pressed to exit trigger wait
-        while ( button_down() ) ;
+        while ( button_2_down() ) ;
         spinwait_delay_ms( 500 );
     }
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("(done)") );
+
     led_red_on();
     do_start_recording_machine();
 
     printf_P( PSTR("recording started\n") );
 
-    while ( ! button_down() )
+    while ( ! button_1_down() )
     {
         if ( ! data_recording_update() )
         {
@@ -498,6 +566,9 @@
         error_fatal( error_recording_complete_failed );
     }
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("saved...") );
+
     printf_P( PSTR("recording saved\n") );
     led_red_off();
     led_green_off();
@@ -512,20 +583,31 @@
     led_green_blink();
     printf_P( PSTR("playback mode\n") );
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("preparing") );
+
     if ( ! data_prepare_to_playback() )
     {
+        hd44780_clear_line( 1 );
+        hd44780_write_pgm( PSTR("failed prep") );
         error_fatal( error_playback_prep_failed );
     }
     printf_P( PSTR("playback prep complete\n") );
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("trigger?  (skip)") );
+
     printf_P( PSTR("waiting for audio trigger\n") );
     if ( ! wait_for_audio_trigger() )
     {
         // button was pressed to exit trigger wait
-        while ( button_down() ) ;
+        while ( button_2_down() ) ;
         spinwait_delay_ms( 500 );
     }
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("(done)") );
+
     led_green_on();
     do_start_playback_machine();
 
@@ -547,6 +629,9 @@
 
     do_stop_machine();
 
+    hd44780_clear_line( 1 );
+    hd44780_write_pgm( PSTR("done...") );
+
     printf_P( PSTR("playback finished\n") );
     led_red_off();
     led_green_off();
@@ -608,7 +693,7 @@
 
     hw_init();
 
-    printf_P( PSTR("\n\nRobotic Camera Platform project (version 1.0.2)\n") );
+    printf_P( PSTR("\n\nRobotic Camera Platform project (version 1.1.0)\n") );
     printf_P( PSTR("firmware written by Bob Cook (bob@bobcookdev.com)\n\n") );
 
     stepper_x_off();
@@ -618,18 +703,38 @@
     led_red_off();
     led_green_off();
 
+    //--    Say hello.
+
+    hd44780_display_on();
+
+    hd44780_clear_screen();
+    hd44780_write_pgm( PSTR("Robotic Camera") );
+
+    hd44780_set_position( 0, 1 );
+    for ( uint8_t i = 0; i < 16; ++i )
+    {
+        hd44780_write( '*' );
+        spinwait_delay_ms( 75 );
+    }
+
     //--    Select the operation mode, then do it.
 
     modes_t the_mode = do_startup_mode_selector();
 
     if ( the_mode == mode_playback )
     {
+        hd44780_clear_screen();
+        hd44780_write_pgm( PSTR("Playback") );
+        
         if ( ! do_playback() )
         {
             printf_P( PSTR("playback failed\n") );
         }
 
         led_green_blink();
+        hd44780_clear_screen();
+        hd44780_write_pgm( PSTR("Reverse") );
+        
         spinwait_delay_ms( 5000 );
         led_red_off();
 
@@ -640,22 +745,54 @@
     }
     else if ( the_mode == mode_record )
     {
+        hd44780_clear_screen();
+        hd44780_write_pgm( PSTR("Record") );
+        
         if ( ! do_recording() )
         {
             printf_P( PSTR("recording failed\n") );
         }
 
         led_red_blink();
+
         spinwait_delay_ms( 5000 );
+
+        hd44780_clear_line( 1 );
+        hd44780_write_pgm( PSTR("reverse...") );
+        
         led_red_off();
 
         if ( ! do_reverse() )
         {
             printf_P( PSTR("reverse playback failed\n") );
         }
+        
+        hd44780_clear_line( 1 );
+        hd44780_write_pgm( PSTR("complete") );
+    }
+    else if ( the_mode == mode_test_trigger )
+    {
+        printf_P( PSTR("testing the audio trigger...\n") );
+
+        hd44780_clear_screen();
+        hd44780_write_pgm( PSTR("Test Trigger") );
+        hd44780_set_position( 8, 1 );
+        hd44780_write_pgm( PSTR("(cancel)") );
+        hd44780_set_position( 0, 1 );
+
+        if ( wait_for_audio_trigger() )
+        {
+            hd44780_write_pgm( PSTR("triggered!      ") );
+        }
+        else
+        {
+            hd44780_write_pgm( PSTR("cancelled       ") );
+        }
     }
     else
     {
+        hd44780_clear_screen();
+        hd44780_write_pgm( PSTR("Diagnostics") );
         printf_P( PSTR("diagnostics mode\n") );
         do_diagnostics();
     }
--- a/main/projects/robocam/project_defs.h	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/project_defs.h	Fri Apr 06 12:18:49 2012 -0700
@@ -1,7 +1,7 @@
 // ----------------------------------------------------------------------------------------
 //
 //  projects/robocam/project_defs.h
-//  Copyright (C) 2011 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //
 //  Permission is hereby granted, free of charge, to any person obtaining a copy
 //  of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@
 // ----------------------------------------------------------------------------------------
 //  packages/avr/common
 
-#define PRJ_CPU_FREQ    20000000L
+#define PRJ_CPU_FREQ    16000000L
 
 // ----------------------------------------------------------------------------------------
 //  packages/avr/device/adc
@@ -45,6 +45,7 @@
 #define PRJ_ADC_USE_CHANNEL_2
 #define PRJ_ADC_USE_CHANNEL_3
 #define PRJ_ADC_USE_CHANNEL_4
+#define PRJ_ADC_USE_CHANNEL_5
 
 // ----------------------------------------------------------------------------------------
 //  packages/avr/device/spi
@@ -57,13 +58,36 @@
 // ----------------------------------------------------------------------------------------
 //  packages/avr/device/uart
 
-#define PRJ_UART0_USE_POLLED_MODE
-#define PRJ_UART0_INITIAL_BAUDRATE 19200
+#define PRJ_UART1_USE_POLLED_MODE
+#define PRJ_UART1_INITIAL_BAUDRATE 19200
+
+// ----------------------------------------------------------------------------------------
+//  packages/avr/lcd/hd44780
+
+#define PRJ_HD44780_ENABLE
+
+#define PRJ_HD44780_INC_WRITE_CSTRINGS
+#define PRJ_HD44780_INC_WRITE_PGM_CSTRINGS
+
+#define PRJ_HD4470_DISPLAY_COLUMNS  16
+#define PRJ_HD4470_DISPLAY_ROWS     2
+
+#define PRJ_HD44780_CONTROL_SELECT_PORT  PORTD
+#define PRJ_HD44780_CONTROL_SELECT_PIN   PD0
+#define PRJ_HD44780_CONTROL_SELECT_DDR   DDRD
+
+#define PRJ_HD44780_CONTROL_CLOCK_PORT   PORTD
+#define PRJ_HD44780_CONTROL_CLOCK_PIN    PD1
+#define PRJ_HD44780_CONTROL_CLOCK_DDR    DDRD
+
+#define PRJ_HD44780_DATA_USE_PORT_HI_BITS
+#define PRJ_HD44780_DATA_PORT   PORTD
+#define PRJ_HD44780_DATA_DDR    DDRD
 
 // ----------------------------------------------------------------------------------------
 //  packages/avr/redir
 
-#define PRJ_REDIR_VIA_UART0
+#define PRJ_REDIR_VIA_UART1
 #define PRJ_REDIR_OUTPUT_DO_AUTO_CRLF
 
 // ----------------------------------------------------------------------------------------
@@ -74,7 +98,7 @@
 
 #define PRJ_SDCARD_SELECT_DDR  DDRB
 #define PRJ_SDCARD_SELECT_PORT PORTB
-#define PRJ_SDCARD_SELECT_PIN  PB2
+#define PRJ_SDCARD_SELECT_PIN  PB0
 
 #endif // #if !defined( PROJECT_DEFS_H )
 // ----------------------------------------------------------------------------------------
--- a/main/projects/robocam/steppers.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/steppers.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2010 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -108,26 +108,26 @@
 {
     if ( g_stepper_x_current != 0 && --g_stepper_x_counter == 0 )
     {
-        PORTD |= ( 1 << PD2 ); // stepper x pin
+        PORTA |= ( 1 << PA0 ); // stepper x pin
         g_stepper_x_counter = g_stepper_x_current;
     }
 
     if ( g_stepper_y_current != 0 && --g_stepper_y_counter == 0 )
     {
-        PORTD |= ( 1 << PD4 ); // stepper y pin
+        PORTA |= ( 1 << PA2 ); // stepper y pin
         g_stepper_y_counter = g_stepper_y_current;
     }
 
     if ( g_stepper_z_current != 0 && --g_stepper_z_counter == 0 )
     {
-        PORTD |= ( 1 << PD6 ); // stepper z pin
+        PORTA |= ( 1 << PA4 ); // stepper z pin
         g_stepper_z_counter = g_stepper_z_current;
     }
 
     spinwait_delay_us( 3 );
-    PORTD &= ~( 1 << PD2 ); // stepper x pin
-    PORTD &= ~( 1 << PD4 ); // stepper y pin
-    PORTD &= ~( 1 << PD6 ); // stepper z pin
+    PORTA &= ~( 1 << PA0 ); // stepper x pin
+    PORTA &= ~( 1 << PA2 ); // stepper y pin
+    PORTA &= ~( 1 << PA4 ); // stepper z pin
 }
 
 // ----------------------------------------------------------------------------------------
@@ -144,11 +144,11 @@
 
     if ( g_stepper_x_setpoint >= g_stepper_counts_ccw_limit )
     {
-        PORTD &= ~( 1 << PD3 ); // stepper x dir
+        PORTA &= ~( 1 << PA1 ); // stepper x dir
     }
     else
     {
-        PORTD |= ( 1 << PD3 ); // stepper x dir
+        PORTA |= ( 1 << PA1 ); // stepper x dir
     }
 }
 
@@ -176,7 +176,7 @@
 void stepper_x_off()
 {
     stepper_x_set( g_stepper_counts_zero );
-    PORTD &= ~( 1 << PD3 ); // stepper x dir
+    PORTA &= ~( 1 << PA1 ); // stepper x dir
 }
 
 // ----------------------------------------------------------------------------------------
@@ -193,11 +193,11 @@
 
     if ( g_stepper_y_setpoint >= g_stepper_counts_ccw_limit )
     {
-        PORTD &= ~( 1 << PD5 ); // stepper y dir
+        PORTA &= ~( 1 << PA3 ); // stepper y dir
     }
     else
     {
-        PORTD |= ( 1 << PD5 ); // stepper y dir
+        PORTA |= ( 1 << PA3 ); // stepper y dir
     }
 }
 
@@ -225,7 +225,7 @@
 void stepper_y_off()
 {
     stepper_y_set( g_stepper_counts_zero );
-    PORTD &= ~( 1 << PD5 ); // stepper y dir
+    PORTA &= ~( 1 << PA3 ); // stepper y dir
 }
 
 // ----------------------------------------------------------------------------------------
@@ -242,11 +242,11 @@
 
     if ( g_stepper_z_setpoint >= g_stepper_counts_ccw_limit )
     {
-        PORTD &= ~( 1 << PD7 ); // stepper z dir
+        PORTA &= ~( 1 << PA5 ); // stepper z dir
     }
     else
     {
-        PORTD |= ( 1 << PD7 ); // stepper z dir
+        PORTA |= ( 1 << PA5 ); // stepper z dir
     }
 }
 
@@ -274,6 +274,7 @@
 void stepper_z_off()
 {
     stepper_z_set( g_stepper_counts_zero );
+    PORTA &= ~( 1 << PA5 ); // stepper z dir
 }
 
 // ----------------------------------------------------------------------------------------
--- a/main/projects/robocam/trigger.cpp	Thu Jan 12 21:29:18 2012 -0800
+++ b/main/projects/robocam/trigger.cpp	Fri Apr 06 12:18:49 2012 -0700
@@ -1,6 +1,6 @@
 // ----------------------------------------------------------------------------------------
 //
-//  Copyright (C) 2010 Bob Cook
+//  Copyright (C) 2012 Bob Cook
 //    
 //  Bob Cook Development, Robotics Library
 //  http://www.bobcookdev.com/rl/
@@ -31,7 +31,7 @@
 #include <avr/io.h>
 #include <avr/pgmspace.h>
 
-//#include <stdio.h>
+#include <stdio.h>
 //#include <string.h>
 
 #include "project_defs.h"
@@ -50,13 +50,24 @@
 
 // ----------------------------------------------------------------------------------------
 
+static bool is_silence( uint16_t value )
+{
+    //--    Silence is considered to be the mid-point of the analog input (the amplifier
+    //      circuitry shifts the audio scale upwards by half scale). We use 10-bit analog
+    //      input values. The delta value was determined experimentally.
+    
+    const uint16_t silence_level_low  = ( 1024 / 2 ) - 75;
+    const uint16_t silence_level_high = ( 1024 / 2 ) + 75;
+
+    return ( value > silence_level_low && value < silence_level_high );
+}
+
+// ----------------------------------------------------------------------------------------
+
 bool wait_for_audio_trigger()
 {
     //--    Loop waiting for our trigger.
 
-    const uint16_t silence_level_left  = 80;
-    const uint16_t silence_level_right = 80;
-
     uint16_t last_value_left = 0;
     bool     increasing = true;
     uint8_t  peaks = 0;
@@ -68,7 +79,7 @@
 
     for ( ;; )
     {
-        if ( button_down() )
+        if ( button_2_down() )
         {
             return false;
         }
@@ -118,12 +129,13 @@
             }
         }
 
-        uint16_t value_left  = adc_read( 3 );
-        uint16_t value_right = adc_read( 4 );
+        uint16_t value_left  = adc_read( 1 );
+        uint16_t value_right = adc_read( 0 );
 
         //printf_P( PSTR("left: %d right: %d\n"), value_left, value_right );
 
-        if ( value_right > silence_level_right )
+//        if ( value_right > silence_level_right )
+        if ( ! is_silence( value_right ) )
         {
             // we require silence on the right channel
             peaks = 0;
@@ -131,7 +143,8 @@
             continue;
         }
 
-        if ( value_left < silence_level_left )
+        if ( is_silence( value_left ) )
+//        if ( value_left < silence_level_left )
         {
             continue; // looking for a signal on the left channel
         }