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