CVS: examples/libraries/eventhandler README.txt, 1.2, 1.3 main.c, 1.1, 1.2 makefile, 1.1, 1.2

Chris Liechti <[email protected]> Wed, 14 Jun 2006 15:18:26 -0700
Newsgroups gmane.comp.hardware.texas-instruments.msp430.gcc.cvs
Message-ID <[email protected]>
Update of /cvsroot/mspgcc/examples/libraries/eventhandler
In directory sc8-pr-cvs7.sourceforge.net:/tmp/cvs-serv31319/examples/libraries/eventhandler

Modified Files:
	README.txt main.c makefile 
Log Message:
add profiling code

Index: README.txt
===================================================================
RCS file: /cvsroot/mspgcc/examples/libraries/eventhandler/README.txt,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -d -r1.2 -r1.3
--- README.txt	13 Mar 2006 18:22:52 -0000	1.2
+++ README.txt	14 Jun 2006 22:18:23 -0000	1.3
@@ -12,6 +12,8 @@
 
 - shows how the scheduler from libmspgcc is used
 
+- shows how the idle function can be overriden to implement simple profiling
+
 - Makefile
 
   - compile and link with libmspgcc
@@ -123,6 +125,8 @@
 - One LED on P1.0 (470 Ohms series resistor to GND), The FET kits from TI
   should be compatible.
 
+- The profiling example uses 5 switches and an additional LED array
+
 
 Source
 ------

Index: main.c
===================================================================
RCS file: /cvsroot/mspgcc/examples/libraries/eventhandler/main.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -d -r1.1 -r1.2
--- main.c	27 Dec 2005 20:51:14 -0000	1.1
+++ main.c	14 Jun 2006 22:18:23 -0000	1.2
@@ -3,6 +3,8 @@
  * A LED is flashed, using the watchdog as timing source for the
  * scheduler, which launches the event that blinks the LED.
  *
+ * Simple variant:
+ *
  *                 MSP430F1121
  *              -----------------
  *          /|\|                 |
@@ -11,7 +13,22 @@
  *             |                 |
  *             |                 |
  *
- * (c) 2005,  chris <[email protected]>
+ * With profiling:
+ *                 MSP430F133
+ *              -----------------
+ *          /|\|                 |
+ *           | |                 |
+ *           --|RST          P1.0|-->LED        blinking 
+ *             |             P1.1|<--KEY        100% CPU load
+ *             |             P1.2|<--KEY        \
+ *             |             P1.3|<--KEY        | CPU load switch
+ *             |             P1.4|<--KEY        |
+ *             |             P1.5|<--KEY        /
+ *             |             P1.7|-->LED        CPU load
+ *             |                 |
+ *             |             P2.x|--> 8 LED array as bargraph
+ *
+ * (c) 2006,  chris <[email protected]>
  */
 
 #include <io.h>
@@ -21,56 +38,127 @@
 
 #define EVENT_scheduler         EVENT00_bits
 #define EVENT_led               EVENT01_bits
+#define EVENT_cpu_load          EVENT02_bits
 
-// the watchdog is programmed as intervall timer. this function is called
-// periodicaly and it launches the scheduler
+// switch to enable profiling demo code
+#define ENABLE_EVENTHANDLER_PROFILING
+
+
+// The watchdog is programmed as intervall timer. This function is called
+// periodicaly and it launches the scheduler.
 wakeup interrupt(WDT_VECTOR) intervallTimer(void) {
     scheduler_increment();
     EVENTHANDLER_LAUNCH(EVENT_scheduler);
 }
 
-// this event is launched by the scheduler
-// it flashes once with the LED on P1.0
+// This event is launched by the scheduler.
+// It flashes once with the LED on P1.0
 static void event_led(void) {
     P1OUT |= BIT0;                              // LED on
     delay(20000);
     P1OUT &= ~BIT0;                             // LED off
 }
 
-// table with the event handlers
+// This event is used to generate a variable CPU load. It reads
+// switches on P1IN and generates a delay depending on them.
+// Usefull to watch the profiler at work.
+static void event_cpu_load(void) {
+    if (P1IN & BIT1) EVENTHANDLER_LAUNCH(EVENT_cpu_load);       //restart self
+    delay((P1IN & 0x3c) << 6);                  // variable delay
+}
+
+// Table with the event handlers
 // NOTE: must keep it in sync with the EVENT_* defines above!
 const EVENTHANDLER_TABLE eventhandler_table[] = {
     event_scheduler,
     event_led,
+    event_cpu_load,
     0 // sentinel, marks end of list
 };
 
-// table with the events that are started by the scheduler.
+#ifdef ENABLE_EVENTHANDLER_PROFILING
+// An implementation of the following function is provided by libmspgcc.
+// That implementation simply enters the lowpowermode LPM0. We're overriding
+// the function here to implement run/idle measurements.
+
+// This function is called when no event bits are set. It typically enters
+// a lowpower mode. Setting event bits then also involves waking up the CPU.
+void eventhandler_idle(void) {
+    P1OUT &= ~BIT7;             // P1.7 is used to display idle/run -> going to idle
+    LPM0;                       // enter lowpower mode, wait for wakeup
+    P1OUT |= BIT7;              // P1.7 is used to display idle/run -> going to run
+}
+
+// Statistical approach...
+// Make samples of cpu activity and analyze display activity/idle as LED bar
+// 8 samples are made and summed up. Every 8 samples is the counter passed
+// to a lowpass filter. The filtered value is output as bargraph with eight
+// levels on a port.
+interrupt(TIMERA0_VECTOR) taccr0(void) {
+    static unsigned char load = 0;
+    static unsigned char count = 0;
+    static unsigned char activity = 0;
+    if (count == 0) {
+        // fixed point arithmetics. 3 bits after the point
+        // lowpass filter 7/8 old value + 1/8 new value
+        // load already has the right scale, while activity hasn't
+        load = ((unsigned short)load * 7 + (activity * 8)) / 8;
+        P2OUT = (1 << load) - 1;                // bargraph
+        //~ P2OUT = 1 << (load-1);                  // moving dot only
+        activity = 0;
+        count = 7;
+    } else {
+        count--;
+    }
+    // It would be better to use an internal variable, as reading the out bit
+    // back requires that this pin is used as CPU load display which may not
+    // be desired for a final product.
+    if (P1OUT & BIT7) activity++;
+    // Also note that interrupts are not visible here and thus are not
+    // included in the CPU load calculation. Interrupts however can have
+    // an indirect influence as the event handlers get a longer runtime
+    // because they are interrupted.
+}
+#endif //ENABLE_EVENTHANDLER_PROFILING
+
+// Table with the events that are started by the scheduler.
 // Two led events are set up close together so that a double blink
 // pattrern is generated. something like this:
 //      _   _                                _   _
 // ____| |_| |______________________________| |_| |___
 //
-// as the event is also lauched on startup, use a shift of 10 and 20 ->
-// triple blink the first time
+// As the event is also launched on startup, use a shift of 10 and 20 ->
+// triple blink the first time.
 const SCHEDULER_TABLE scheduler_table[] = {
     {modulo: 150, shift: 10, eventbits: EVENT_led},
     {modulo: 150, shift: 20, eventbits: EVENT_led},
+    {modulo:   1, shift:  0, eventbits: EVENT_cpu_load},
     {0} // sentinel, marks the end of the table
 };
 
-// program entry. set up the hardware and launch the eventhandler
+// Program entry. Set up the hardware and launch the eventhandler.
 int main(void) {
-    WDTCTL = WDTPW|WDTTMSEL|WDTCNTCL;   // Init watchdog as intervall timer
+    WDTCTL = WDTPW|WDTTMSEL|WDTCNTCL;   // Init watchdog as interval timer
     IE1 = WDTIE;
 
     // DCO (~1.5MHz on a F1xx)
-    BCSCTL1 = XT2OFF|DIVA1|RSEL0|RSEL2;
+    BCSCTL1 = XT2OFF|RSEL0|RSEL2;
     BCSCTL2 = 0;
     DCOCTL = 0x92;
     
     P1OUT = 0;                          // LED off
-    P1DIR = BIT0;                       // enable pin with LED
+    P1DIR = BIT0|BIT7;                  // enable pins with LEDs
+    
+#ifdef ENABLE_EVENTHANDLER_PROFILING
+    P2OUT = 0;
+    P2DIR = 0xff;                       // LED bar used to display CPU load
+    
+    TACTL = TACLR|TASSEL_SMCLK|MC_UPTO_CCR0;  // PWM mode
+    TACCR0 = 10027;                     // random time, should not be synchronous to scheduler time base
+    TACCTL0 = CCIE;                     // enable capture interrupts for CPU load supervision
+    
+    P1OUT |= BIT7;                      // P1.7 is used to display idle/run -> going to run
+#endif //ENABLE_EVENTHANDLER_PROFILING
     
     eint();
     eventhandler(EVENT_led);            // enter eventhandler, start event for a first time

Index: makefile
===================================================================
RCS file: /cvsroot/mspgcc/examples/libraries/eventhandler/makefile,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -d -r1.1 -r1.2
--- makefile	27 Dec 2005 20:51:14 -0000	1.1
+++ makefile	14 Jun 2006 22:18:23 -0000	1.2
@@ -2,7 +2,8 @@
 NAME            = eventhandler_demo
 CSOURCES        = main.c
 #~ ASOURCES        = 
-CPU             = msp430x1121
+#~ CPU             = msp430x1121
+CPU             = msp430x133
 
 
 ASFLAGS         = -mmcu=${CPU} -D_GNU_ASSEMBLER_ -I .