tr_port.h

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

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