demos_source/code_TestInterrupt.c

Go to the documentation of this file.
00001 /*
00002  * Femto OS v 0.91 - Copyright (C) 2008-2009 Ruud Vlaming
00003  *
00004  * This file is part of the Femto OS distribution.
00005  *
00006  * This program is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, version 3 of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * Please note that, due to the GPLv3 license, for application of this
00019  * work and/or combined work in embedded systems special obligations apply.
00020  * If these are not to you liking, please know the Femto OS is dual
00021  * licensed. A commercial license and support are available.
00022  * See http://www.femtoos.org/ for details.
00023  */
00024 
00025 
00026 /* This file is solely for demonstration purposes.
00027  *
00028  *  Interrupts can for example be used to resume tasks that are waiting for
00029  *  a particular event to happen before they can run. Since interrupts can
00030  *  not be nested, the preferred way to handle external events is to start a
00031  *  high priority task by an interrupt and let the task take further action.
00032  *  Well, in fact interrupts could be nested, but this would take an excessive
00033  *  amount of ram, so we do not want to make use of it.
00034  *
00035  *  The interrupt pin drives a 4 bit counter. The value of the counter
00036  *  determines which leds are allowed to flash. If led Px4 is on, the blinker on
00037  *  Px0 is allowed to run, otherwise it is resumed. The way this works in detail
00038  *  depends on and varies with the setting of the configuration parameters.
00039  *
00040  *  Note that use for different devices requires different connection to the
00041  *  switches, because the location of INT0 cannot be altered by software.
00042  */
00043 
00044 
00045 /* This this the only include needed in your code .*/
00046 #include "femtoos_code.h"
00047 
00048 /* Different delays for the blinkers. */
00049 #define delay03  2229U
00050 #define delay02  1218U
00051 #define delay01   666U
00052 #define delay00   364U
00053 
00054 /* This is called once at system boot, and before the creating of any of
00055  * the tasks. Use it to initialize the hardware. */
00056 void appBoot(void)
00057 { devLedDRR  = 0xFF;
00058   devLedPORT = 0x0F;
00059   devSwitchDRR = 0x00;
00060   devEIR = preBitSet1(0x00,devINT); }
00061 
00062 
00063 /* Different options to play with. Vary this and the cfgIntOsProtected too.
00064  * See the different results. */
00065 #define smallISR  cfgTrue
00066 
00067 /* Protected acces to the display. */
00068 static void setLed(Tuint08 lednr, Tbool state)
00069 { taskEnterGlobalCritical();
00070   if (state) { devLedPORT |= (1 << lednr); }  else { devLedPORT &=  ~(1 << lednr); }
00071   taskExitGlobalCritical(); }
00072 
00073 
00074 /* Four blinker tasks that run independently. */
00075 
00076 void appLoop_LEDtask0(void)
00077 { Tuint08 led  = false;
00078   while (true)
00079   { led = !led;
00080     setLed(0,led);
00081     taskDelayFromNow(delay00);
00082     taskSuspend(defSuspendCheck); } }
00083 
00084 void appLoop_LEDtask1(void)
00085 { Tuint08 led  = false;
00086   while (true)
00087   { led = !led;
00088     setLed(1,led);
00089     taskDelayFromNow(delay01);
00090     taskSuspend(defSuspendCheck); } }
00091 
00092 void appLoop_LEDtask2(void)
00093 { Tuint08 led  = false;
00094   while (true)
00095   { led = !led;
00096     setLed(2,led);
00097     taskDelayFromNow(delay02);
00098     taskSuspend(defSuspendCheck); } }
00099 
00100 void appLoop_LEDtask3(void)
00101 { Tuint08 led  = false;
00102   while (true)
00103   { led = !led;
00104     setLed(3,led);
00105     taskDelayFromNow(delay03);
00106     taskSuspend(defSuspendCheck); } }
00107 
00108 
00109 /* Below are different implementations of interrupt handlers. */
00110 
00111 #if (cfgIntOsProtected == cfgTrue)
00112 
00113   #if (smallISR == cfgTrue)
00114 
00115   void devSigExternalInt(void) __attribute__ ( ( signal, naked, used, externally_visible ) );
00116   void devSigExternalInt(void)
00117   { isrEnter();
00118     Tuint08 uiRunMask =  (~devLedPORT + 0x10);
00119     devLedPORT =  ~(uiRunMask);
00120     isrStackCheck(2);
00121     /* The line below should never be executed, but leave it there as a test */
00122     if (preBitIsSet(devAuxSysReg,devAuxSysRegBit)) { devLedPORT=~0xA5; while(true); }
00123     if ((uiRunMask & 0x10) == 0) { genSuspendOnName(LEDtask0); } else { genResumeOnName(LEDtask0); }
00124     if ((uiRunMask & 0x20) == 0) { genSuspendOnName(LEDtask1); } else { genResumeOnName(LEDtask1); }
00125     if ((uiRunMask & 0x40) == 0) { genSuspendOnName(LEDtask2); } else { genResumeOnName(LEDtask2); }
00126     if ((uiRunMask & 0x80) == 0) { genSuspendOnName(LEDtask3); } else { genResumeOnName(LEDtask3); }
00127     isrExit(); }
00128 
00129   #else
00130 
00131   /* The gcc warning is ok, we misuse the gcc facilities to make sure all registers are saved. */
00132   void HandlePinChange(void) __attribute__ ( ( signal ) );
00133   void HandlePinChange(void)
00134   { isrStackCheck(2);
00135     Tuint08 uiRunMask =  (~devLedPORT + 0x10);
00136     if ((uiRunMask & 0x10) == 0) { genSuspend(preTaskNumberOf(LEDtask0)); } else { genResume(preTaskNumberOf(LEDtask0)); }
00137     if ((uiRunMask & 0x20) == 0) { genSuspend(preTaskNumberOf(LEDtask1)); } else { genResume(preTaskNumberOf(LEDtask1)); }
00138     if ((uiRunMask & 0x40) == 0) { genSuspend(preTaskNumberOf(LEDtask2)); } else { genResume(preTaskNumberOf(LEDtask2)); }
00139     if ((uiRunMask & 0x80) == 0) { genSuspend(preTaskNumberOf(LEDtask3)); } else { genResume(preTaskNumberOf(LEDtask3)); }
00140     devLedPORT = ~uiRunMask; }
00141 
00142   void devSigExternalInt(void) __attribute__ ( ( signal, naked, used, externally_visible ) );
00143   void devSigExternalInt(void)
00144   { isrBegin();
00145     HandlePinChange();
00146     /* This is a dangerous trick, since from reti from HandlePinChange we need to be sure the cli comes
00147      * immediately. taskDisableGlobalInterrupts() may have other business (trace) */
00148     taskDisableGlobalInterrupts();
00149     isrEndYield(); }
00150 
00151   #endif
00152 
00153 
00154 #else
00155 
00156 /* The signal attribute makes sure all registers are properly restored.
00157  * Unfortunately it also stores registers never used, such as r0,r1.
00158  * Further it returns with a reti, where is should be a ret. Therefore
00159  * we must immediately disable interrupts again after return.
00160  * If you program this assembler all these problems are absent. ;-)
00161  * The compiler complains you misspelled your function, now did you?
00162  */
00163 
00164   void HandlePinChange(void) __attribute__ ( ( signal ) );
00165   void HandlePinChange(void)
00166   { devLedPORT =  ~(~devLedPORT + 0x10); }
00167 
00168   void devSigExternalInt(void) __attribute__ ( ( signal, naked, used, externally_visible ) );
00169   void devSigExternalInt(void)
00170   { isrBegin();
00171     /* make sure do not use any registers here, there is nothing to protect you from
00172      * bizarre results. */
00173     HandlePinChange();
00174     taskDisableGlobalInterrupts();
00175     isrEndReturn(); }
00176 
00177 #endif
00178 

Generated on Fri Oct 16 00:05:21 2009 for FemtoOS by  doxygen 1.5.2