tr_port.h

Go to the documentation of this file.
00001 /** \file
00002  * @brief MSP430/GCC port of the RTOS
00003  * 
00004  * @page msp430gcc_port  HAL for MSP430 family with  mspgcc compiler
00005  *
00006  * This is the TiROS hardware abstraction layer for the Texas
00007  * Instruments MSP430x family of embedded microcontrollers. This
00008  * microcontroller family can support software interrupts. These
00009  * microcontrollers can be driven from a 32kHz crystal oscillator.
00010  * The time functions have been written assuming such an oscillator
00011  * drives the timer. If this is not the case, modify the functions in porttime.h
00012  * and the timer initialization functions in tr_port.c.
00013  *
00014  * Note that in the MSP430 architecture, the low-power state of the
00015  * processor is stored in the status register.  Since this is part of
00016  * the context, per-task power control is automatic.  To keep the
00017  * processor in low-power state during idle time, simple define
00018  * the idle task as
00019  * \code
00020  * void idle_task(void *dummy) 
00021  * {
00022  *   while(1) {
00023  *       _BIS_SR(LPM3_bits);
00024  *   }
00025  * }
00026  * \endcode
00027  * 
00028  * Tested with TI MSP430x1611
00029  *
00030  * <H2> Configuration Options: </H2>
00031  * <DL>
00032  *    <DT>  TRPORT_MSP_OSTIMER [A | B] : <DD>Options are A or B.  The MSP430 family
00033  * supports two timers, TimerA and TimerB.  TimerA is available on the
00034  * entire family line. TimerB is only available on some.  By default,
00035  * if this configuration option is not set, TimerA is used as source
00036  * for the timer interrupt.
00037  *    <DT>  TIROS_KERNEL_TRAP_ENABLED [0|1]: <DD>  If this define is set to 1,  OS
00038  * kernel context switches  from ISRs are made using a software trap
00039  * (i.e.) by causing an interrupt under software control.  This makes
00040  * ISRs very efficient.  The MSP430/GCC port supports kernel traps. So
00041  * this is enabled as a default.   To disable it, set
00042  * TIROS_KERNEL_TRAP_ENABLED to 0 in proj_config.h.
00043  *    <DT>  USER_DEFINED_KERNEL_TRAP : <DD> If TIROS_KERNEL_TRAP_ENABLED is set
00044  * to 1, kernel traps are enabled.  The default implementation uses
00045  * Port 2,  pins.  By setting a specific pin, an interrupt is forced.
00046  * The user  can override this default and specify a different
00047  * interrupt handler for this purpose.  In this case, create user
00048  * definitions for isr_kernel_trap and OS_KERNEL_TRAP, and
00049  * hal_setup_kernel_trap() .   Do not define or set these functions if
00050  * TIROS_KERNEL_TRAP_ENABLED is set to 0.
00051  * </DL>
00052  * <H2> Writing ISRs. </H2>
00053  *
00054  *   If no TiROS API functions will be called, interrupts will stay
00055  *  disabled, then the ISR can be
00056  *  written very simply. See the requirements in \ref isr.
00057  * \code
00058  *  interrupt (IVECTOR) ISR_function(void)
00059  * {
00060  *  // do stuff
00061  * }
00062  * \endcode
00063  *
00064  * If TiROS API calls have to be used, 
00065  * the form of the ISR depends on whether TIROS_KERNEL_TRAP_ENABLED is set
00066  * (It is set as a default).  If TIROS_KERNEL_TRAP_ENABLED is set to 1, the
00067  * ISR is simple
00068  * \code
00069  * interrupt (IVECTOR) ISR_function(void) 
00070  * {
00071  *   int x;
00072  *   OS_CRITICAL_ENABLE();   // Only needed if any critical sections
00073  *                           // will be used and interrupt nesting is enabled.
00074  *
00075  *   OS_ISR_BEGIN();         // Mark the beginning of an ISR. Note
00076  *                           // that if OS_CRITICAL_ENABLE() is also
00077  *                           // present, then this comes after 
00078  *                           // that. 
00079  *  
00080  *  x = 3;
00081  *    Do more stuff ....
00082  *  
00083  *  OS_ISR_END();
00084  * }
00085  * \endcode
00086  * 
00087  *
00088  *  If TIROS_KERNEL_TRAP_ENABLED is set to 0, the ISR would look as below.
00089  *  Use the ISR implementation in tr_port.c as a reference.
00090  * \code
00091  * interrupt (IVECTOR) ISR_function(void) __attribute__ ( (naked))
00092  * interrupt (IVECTOR) ISR_function(void) 
00093  * {
00094  *    HALINT_ISR_ENTRY();
00095  *    OS_ISR_BEGIN();
00096  *    perform_actions();
00097  *    OS_ISR_END();
00098  *    HALINT_ISR_EXIT();
00099  * }
00100  * \endcode
00101  *
00102  *
00103  */
00104 
00105 /* Author: Ratish J. Punnoose, 2006
00106  * This file is part of TiROS, the Tickless Real-Time Operating System.
00107  * Copyright(c) 2006, 2007: Ratish J. Punnoose.
00108  * Copyright(c) 2006 Sandia Corporation. Under the terms of Contract
00109  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
00110  * certain rights in this software. 
00111  * 
00112  * TiROS is free software; you can redistribute it and/or modify it under
00113  * the terms of the GNU General Public License as published by the Free
00114  * Software Foundation; either version 2 or (at your option) any later version.
00115  *
00116  * TiROS is distributed in the hope that it will be useful, but WITHOUT ANY
00117  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00118  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00119  * for more details.
00120  *
00121  * You should have received a copy of the GNU General Public License along
00122  * with TiROS; if not, write to the Free Software Foundation, Inc.,
00123  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00124  *
00125  * As a special exception, if other files instantiate templates or use macros
00126  * or inline functions from this file, or you compile this file and link it
00127  * with other works to produce a work based on this file, this file does not
00128  * by itself cause the resulting work to be covered by the GNU General Public
00129  * License. However the source code for this file must still be made available
00130  * in accordance with section (3) of the GNU General Public License.
00131  *
00132  * This exception does not invalidate any other reasons why a work based on
00133  * this file might be covered by the GNU General Public License.
00134  *
00135  */
00136 
00137 
00138 #ifndef __MSP430GCC_TIROS_PORT_H
00139 #define __MSP430GCC_TIROS_PORT_H
00140 /*@ignore@*/
00141 #include "proj_config.h"
00142 /*@end@*/
00143 
00144 #include <io.h>
00145 #include <signal.h>
00146 #include <stdint.h>
00147 
00148 /* The data type used by this port for subtime_t */
00149 #define subtime_t uint16_t
00150 #define LT_INLINE static inline 
00151 
00152 
00153 
00154 #include <tiros/tr_time.h>
00155 /* Insert your port for time functions for your hardware */
00156 #include "porttime.h"
00157 
00158 /* Define the value of infinite time for this port */
00159 #define TRPORT_INF_TIME {~0 , ~0 }
00160 
00161 
00162 
00163 /* The msp port can use registers for passing return values to
00164     blocked tasks */
00165 #define TIROS_REGISTER_PASSING
00166 
00167 
00168 
00169 /* Define basic types for   the hardware word, boolean, and pointer */
00170 typedef uintptr_t osword_t;
00171 typedef void*     osptr_t;
00172 typedef osword_t*  osstkptr_t;
00173 typedef void (* osfnptr_t)(void *);
00174 typedef uintptr_t  osptrword_t;
00175 
00176 #define ILLEGAL_STACK ((osstkptr_t) ~0)
00177 #define ILLEGAL_ADDR  ((osptr_t)    ~0)
00178 
00179 
00180 
00181 /* Port specific function implemented in tr_port.c */
00182 
00183 /* \name Context_switching_functions
00184  * @{ */
00185 
00186 /* Initialize the stack for a task.
00187  * @param stk  Pointer to the stack.
00188  * @param stacksize  Size of the stack.
00189  * @param PC   Program counter.
00190  * @param init_arg   Initial argument passed to the task */
00191 /*@shared@*/
00192 osstkptr_t hal_stk_init(osword_t *stk, osword_t stacksize, osfnptr_t pc,
00193                         osptr_t init_arg); 
00194 
00195 
00196 #ifdef TIROS_REGISTER_PASSING
00197 /* Set a return value for a task whose context is stored.
00198  *
00199  * This injects a return value into the context of a task that is currently frozen.
00200  * @param stackptr  Pointer to the stack.  The stack should also contain the context.
00201  * @param retval    The return value to be injected into the task context */
00202 static inline void hal_retval_set(osstkptr_t stackptr, 
00203                                   /*@null@*/ osptr_t retval)
00204 {
00205         /* GCC passes the return value in register 15, which is what
00206          * stackptr points to */  
00207         *stackptr = (osword_t)retval;
00208 }
00209 #endif
00210 
00211 
00212 
00213 void hal_init(void);
00214 
00215 
00216 void hal_time_get(/*@out@*/ trtime_t *t);
00217 int hal_time_set(const trtime_t *t);
00218 
00219 
00220 
00221 /* Set an alarm.
00222  *  When the alarm is reached, osint_alarm_reached is called
00223  * @param lt Pointer to time */
00224 void  hal_alarm_set(/*@null@*/ const trtime_t *lt);
00225 
00226 
00227 
00228 
00229 
00230 
00231 /* Enable critical section calls in the the called function
00232  *
00233  *  This has to be called at the beginning of the function before
00234  *  calling OS_CRITICAL_BEGIN or OS_CRITICAL_END.  This should be the
00235  *  first call after variable declaration.  These section should not
00236  *  be added within an ISR if Interrupt nesting is turned on, because
00237  *  the interrupt nesting adds this in automatically, and duplication
00238  *  will result in compiler complaints. */
00239 #define OS_PORT_CRITICAL_ENABLE()   /*@unused@*/ osword_t osint_int_status
00240 #define OS_PORT_ISR_BEGIN()                                     \
00241         extern uint8_t os_isr_nesting;                          \
00242         os_isr_nesting++;
00243 
00244 
00245 
00246 
00247 #ifndef S_SPLINT_S
00248 /* Begin a critical section 
00249  * 
00250  * The current interrupt state is saved in osint_int_status and then
00251  * interrupts are disabled */
00252 #define OS_PORT_CRITICAL_BEGIN() \
00253     asm volatile("mov   r2, %0  \n\t"  \
00254                  "dint          \n\t" :  "=r" (osint_int_status)  : ); \
00255     osint_int_status &= GIE;
00256 
00257 
00258 /* End a critical section
00259  *
00260  * The saved interrupt state is restored */
00261 #define OS_PORT_CRITICAL_END()  \
00262     asm volatile("bis  %0, r2   \n\t" : : "r" (osint_int_status) );
00263 
00264 /* Enable interrupts
00265  * This allows the user to explicitly enable interrupts */
00266 #define OS_PORT_INT_ENABLE()      _EINT()
00267 
00268 /* Disable interrupts
00269  * This allows the user to explicitly disable interrupts */
00270 #define OS_PORT_INT_DISABLE()       _DINT()
00271 
00272 
00273 
00274 
00275 /* Context switch from user level (non-ISR)
00276  *  This function is called from within an OS call, to switch the
00277  *  running process.  It also provides a return value. This is a
00278  *  pseudo return-value.  This function does not actually determine
00279  *  the value returned.  The return value is set by hal_retval_set
00280  *  which is often invoked when waking the process up from a blocked
00281  *  state. 
00282  * In this mspgcc port, the hal_ctxt_switch has the naked attribute to
00283  * prevent gcc from adding miscellaneous header code to the
00284  * function. This happens when compiling without optimization.
00285  *    
00286  * @return  Return value.  */
00287 osstkptr_t hal_ctxt_switch(void)  __attribute__ ( (naked) ) ;
00288 
00289 /* Initially 14 words are used to store MSP430 register intialization,
00290  * R0 - R15 , without R1, R3*/
00291 #define MSP430_INIT_STACK_OCCUPANCY      14
00292 
00293 #define TRPORT_MIN_CTXT_SZ   (MSP430_INIT_STACK_OCCUPANCY + 1 )
00294 
00295 
00296 /* Load the given context
00297  * @param ctxt_ptr   Pointer to task context */
00298 static inline void hal_ctxt_load(osstkptr_t ctxt_ptr) 
00299 {
00300         /* In this port, the stack pointer provides the contest */
00301         asm volatile (  
00302                 "mov.w  %0, r1 \n\t"
00303                 "pop    r15     \n\t"
00304                 "pop    r14     \n\t"
00305                 "pop    r13     \n\t"
00306                 "pop    r12     \n\t"
00307                 "pop    r11     \n\t"
00308                 "pop    r10     \n\t"
00309                 "pop    r9      \n\t"
00310                 "pop    r8      \n\t"
00311                 "pop    r7      \n\t"
00312                 "pop    r6      \n\t"
00313                 "pop    r5      \n\t"
00314                 "pop    r4      \n\t"
00315                 "reti           \n\t"
00316                 : /* no output registers */
00317                 : "r" (ctxt_ptr)
00318                 );
00319 } 
00320 
00321 
00322 
00323 /* HAL Internal macro used to save the registers.
00324  * This can be called from an interrupt function. It does not save the
00325  * status register.  If being called from non-interrupt code, the
00326  * status register should be saved before calling this function */
00327 #define HALINT_CTXT_SAVE() \
00328                 "push   r4    \n\t"     \
00329                 "push   r5    \n\t"     \
00330                 "push   r6    \n\t"     \
00331                 "push   r7    \n\t"     \
00332                 "push   r8    \n\t"     \
00333                 "push   r9    \n\t"     \
00334                 "push   r10   \n\t"     \
00335                 "push   r11   \n\t"     \
00336                 "push   r12   \n\t"     \
00337                 "push   r13   \n\t"     \
00338                 "push   r14   \n\t"     \
00339                 "push   r15   \n\t"     \
00340                 "mov.w  r1, r15 \n\t"   
00341 
00342 
00343 
00344 #endif /* Bypass SPLINT verification */
00345 
00346 /* @} End context switching functions  */       
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354 #ifndef TRPORT_RESPONSE_TIME
00355 #define PORT_WAKEUP_RESPONSE_SUBUNITS  40
00356 #define TRPORT_RESPONSE_TIME  {0, PORT_WAKEUP_RESPONSE_SUBUNITS }
00357 #endif
00358 
00359 
00360 
00361 
00362 
00363 
00364 #ifndef TRPORT_MSP_OSTIMER
00365 /* Which timer on the MSP430 should be used for servicing the ticks.
00366  * For a default use TIMER A since it is available on all the MSP430x
00367  * family. */
00368 #define TRPORT_MSP_OSTIMER  A
00369 #endif
00370 
00371 
00372 #ifndef TIROS_KERNEL_TRAP_ENABLED
00373 /* This port can support kernel traps and is thus enabled as a
00374  * default. The user can override this by setting 
00375  * \code
00376  * #define TIROS_KERNEL_TRAP_ENABLED 0
00377  * \endcode
00378  * in the proj_config.h file */
00379 #define TIROS_KERNEL_TRAP_ENABLED  1
00380 #endif
00381 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389 #if (TIROS_KERNEL_TRAP_ENABLED == 1)
00390 /* -------------------------------------------------- */
00391 
00392 
00393 
00394 
00395 #ifndef USER_DEFINED_KERNEL_TRAP
00396 
00397 /* Function to setup a kernel trap.  If a user defined kernel trap is
00398  * used, then define USER_DEFINED_KERNEL_TRAP and implement
00399  * hal_setup_kernel_trap within user code.  The declaration can be
00400  * placed in proj_config.h . */
00401 void hal_setup_kernel_trap(void);
00402 
00403 /* We will use one of the pins on port 1 as our kernel trap.  Feel
00404  * free to override this if you want to use a different kernel trap. 
00405  * We will use P2.5.  See section 9-5 of the MSP430 family
00406  * documentation for use of this as a software interrupt.
00407  */
00408 #define KTRAP_PIN  BIT5
00409 /* Force a software interrupt */
00410 static inline void OS_KERNEL_TRAP(void)  { P2IFG |= KTRAP_PIN; }
00411 #endif
00412 
00413 
00414 
00415 
00416 #else  /* TIROS_KERNEL_TRAP_ENABLED == 0 -------------------- */
00417 /* Undefine USER_DEFINED_KERNEL_TRAP */
00418 #ifdef USER_DEFINED_KERNEL_TRAP
00419 #undef USER_DEFINED_KERNEL_TRAP
00420 #endif
00421 
00422 extern int halint_kernel_trap_flagged;
00423 
00424 
00425 /* Force a software interrupt */
00426 static inline void OS_KERNEL_TRAP(void)  
00427 { halint_kernel_trap_flagged = 1;}
00428 
00429 
00430 
00431 /* -------------------------------------------------- */
00432 #endif  /* End of TIROS_KERNEL_TRAP_ENABLED */
00433 
00434 
00435 
00436 
00437 #ifdef TIROSINT_DATA_DEBUG
00438 /* Compute the program counter, from the stored context (stack
00439  * pointer)
00440  * This function is used for debugging.  Implement this by extracting
00441  * the program counter out of the stack pointer if possible.
00442  *
00443  * @param ctxt_ptr  The context of the current task
00444  * @return The program counter */
00445 osptrword_t hal_pc_from_ctxt(osstkptr_t ctxt_ptr);
00446 
00447 
00448 
00449 
00450 #ifdef TIROS_STK_CHECK
00451 /* Return the maximum stack occupancy of the task.
00452  * This hal implemented function should provide the 
00453  * maximum stack occupancy of the task whose context is given.
00454  * This is used for debugging.  It is valid for this function to
00455  * return 0, if this information is not readily extractable.
00456  * @param ctxt_ptr        Context of the task.
00457  * @param base_stkptr   The initialization stack value for this task
00458  *                       that was passed to hal_stk_init
00459  * @param stksize        The initial stack size for this task that was 
00460  *                       passed to hal_stk_init
00461  * @return The maximum stack occupancy */
00462 osword_t hal_stkusage_max(osstkptr_t ctxt_ptr, osstkptr_t base_stkptr,
00463                           osword_t stksize);
00464 
00465 /* Return the current stack occupancy of the task.
00466  * This hal implemented function should provide the 
00467  * current stack occupancy of the task whose context is given.
00468  * This is used for debugging.  It is valid for this function to
00469  * return 0, if this information is not readily extractable.
00470  * @param ctxt_ptr   Context of the task.
00471  * @param base_stkptr   The initialization stack value for this task
00472  *                       that was passed to hal_stk_init
00473  * @param stksize        The initial stack size for this task that was 
00474  *                       passed to hal_stk_init
00475  * @return The current stack occupancy */
00476 osword_t hal_stkusage_curr(osstkptr_t ctxt_ptr, osstkptr_t base_stkptr,
00477                            osword_t stksize);
00478 #endif /*TIROS_STK_CHECK */
00479 
00480 #endif
00481 
00482 
00483 
00484 
00485 
00486 
00487 /* End of tr_port.h  ======================================== */
00488 #endif   

TiROS User Manual: Last Updated on Fri Jul 20 10:52:23 2007