Home arrow Support arrow Forums

Luminary Micro Forums

dereksoftstuff

Expert Boarder

2008/10/01 06:00

HowTo : Locks

I've had a trawl around trying to find some 'locks' - a way of disabling interrupts on single thread embedded systems, and have only found the usual disable everything. Whereas the ARM blurb says that proirity level setting is a better way of doing this, so that you can restrict the disable to a narrower set of interrupts.

So here's my take :-
locks.h & locks.c

Code:

  #ifndef LOCKS_H_ #define LOCKS_H_ #include <systemDefs.h> #include <string.h> #ifdef __cplusplus extern "C" { #endif      // comment/uncomment as required  #define USE_LOCKS #if defined(USE_LOCKS)      //---------------------------------------------------------------------- // Simple lock/unlock mechanism for single thread systems,  // to implement shared memory between program and ISR(s). // The only way that a single thread program can be descheduled is by interrupts (ISRs), // so the lock disables interrupts and the unlock re-enables them. //     // IMPORTANT - locks must be used as a pair around your shared data access code (can be nested) //     // Simply decide on the strategy you need for your system // choose ONE :-  // 1) ignore locks completely - comment out USE_LOCKS // 2) LOCK_ALL - disable all interrupts  // 3) LOCK_PRIORITY - disable interrupts based on priority level  // 4) LOCK_GROUP - disable a specific group of interrupts  // Note that you can still use NO_LOCKS with any of 2), 3) or 4) for different resources // i.e. UART data - NO_LOCKS, PWM data - LOCK_PRIORITY ... // // each can be nested.  // e.g. 4 nested locks will require 4 unlocks before interrupts are re-enabled //----------------------------------------------------------------------                     // ************* pick ONE ******************** //#define USE_LOCK_ALL //#define USE_LOCK_PRIORITY #define USE_LOCK_GROUP               typedef enum lockClassType NO_LOCKSLOCKS }; // available for direct access for all options void lockAll(void);    //  no interrupts possible void unLockAll(void);  #if defined(USE_LOCK_ALL) //---------------------------------------------------------------------- //  LOCK ALL //---------------------------------------------------------------------- // ALL interrupts disabled  //---------------------------------------------------------------------- typedef struct lockType {     enum lockClassType     lockClass; }; #elif defined(USE_LOCK_PRIORITY)      //---------------------------------------------------------------------- //  LOCK PRIORITY //---------------------------------------------------------------------- // interrupts are disabled based on their priority level  // (which you must have previously setup - using setInterruptPriorityLevel() ) // there are 7 levels 1 .. 7 (for max 3 bits used) // DONT USE : 0 = turn facility off - ALL interrupts ENABLED - this is the default // i.e. will always return to 0 after equal number of call pairs // // 1 = highest priority mask = ALL interrupts disabled // 2 = interrupts of priority 2..7 disabled, priority 1 interrupts enabled // ... // 7 = lowest priority mask = only interrupts of this priority are disabled, all others are enabled // // nesting -> lockPriority() can be called multiple times before calling equal number of  unLockPriority() // only successive higher priority masks are accepted :- // e.g. 7, 4, 3, 1 ok     7, 4, 5, 3, 1  -> 5 ignored, continue with 4 // unLockPriority will reset to previous priority in list (like a stack) //---------------------------------------------------------------------- boolean setInterruptPriorityLevel(UINT interruptIdBYTE priority); typedef struct lockType {     enum lockClassType     lockClass;     UINT                priorityMask; }; void lockPriority(UINT priorityMask); // returns previous priorityMask void unLockPriority(void); #elif defined(USE_LOCK_GROUP) //---------------------------------------------------------------------- //  LOCK GROUP //---------------------------------------------------------------------- // LOCK_GROUP allows a user subset of interrupts to be locked/unlocked e.g INT_GPIOA, INT_GPIOB ... // LOCK_GROUP is more flexible than LOCK_PRIORITY, but will be slower. // LOCK_GROUP only disables the interrupts you specify. // interruptIds array MUST be terminated with NULL (0) - like a string. //---------------------------------------------------------------------- typedef struct lockType {     enum lockClassType     lockClass;     BYTE                 *interruptIds;   // **** NULL (0) terminator  ***** }; void lockGroup(BYTE *interruptIds);     void unLockGroup(BYTE *interruptIds); #else #error "Lock type not defined" #endif // LOCK TYPE //---------------------------------------------------------------------- //  LOCK wrapper //---------------------------------------------------------------------- // general purpose wrapper of above functions :- // getLockId() must be called once at initialisation/start to  // obtain LOCK_ID to use with lock/unLock //---------------------------------------------------------------------- typedef void *LOCK_ID#define LOCK_ID_FAILED   0 LOCK_ID getLockId(struct lockType lockInfo); // call first to get LOCK_ID LOCK_ID deleteLock(LOCK_ID lockId); void lock(LOCK_ID lockId);   void unLock(LOCK_ID lockId); //utility enum lockClassType getLockClass(LOCK_ID lockId); #endif // USE_LOCKS           #ifdef __cplusplus } #endif #endif // LOCKS_H_




Code:

  #include <locks.h> #include <systemRAM.h> #include <hw_ints.h> #include <hw_nvic.h> #include <malloc.h> #include <stdlib.h> #ifdef __cplusplus extern "C" { #endif           #if defined(USE_LOCKS) //---------------------------------------------------------------------- //  LOCK ALL //---------------------------------------------------------------------- static UINT lockAllCount 0;   // prevents the processor from responding to ALL interrupts // no effect on NVIC (interrupt(s) will be waiting for the processor re-enable) void lockAll(void) {         __asm(  "    mov r0,         #1         n"             "    msr PRIMASK,     r0        ");        // disable all interrupts     lockAllCount++; } // Allows the processor to respond to interrupts  void unLockAll(void) {     lockAllCount--;          if (lockAllCount == 0) {             __asm(  "    mov r0,         #0         n"                 "    msr PRIMASK,     r0        ");            // enable all interrupts             } } #if defined(USE_LOCK_PRIORITY) //---------------------------------------------------------------------- //  LOCK PRIORITY //---------------------------------------------------------------------- // only 3 bits used by stellaris (bits 7..5) // user values 1 .. 7  -> 1 = highest .. 7 = lowest priority static const UINT priorityRegisterMap[15] = {     0NVIC_SYS_PRI1NVIC_SYS_PRI2NVIC_SYS_PRI3NVIC_PRI0NVIC_PRI1,     NVIC_PRI2NVIC_PRI3NVIC_PRI4NVIC_PRI5NVIC_PRI6NVIC_PRI7,     NVIC_PRI8NVIC_PRI9NVIC_PRI10 }; // Sets the priority grouping of the interrupt controller to max number of priority levels. // i.e. split between preemptable priority levels and subpriority levels   // 3 bits available for hardware interrupt prioritization - so setup 3-5 split // only used locally void setMaxInterruptPriorityLevels(void) {     HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY NVIC_APINT_PRIGROUP_3_5; } // sets priority of an interrupt and sets max number of levels (i.e. 7) boolean setInterruptPriorityLevel(UINT interruptIdBYTE priority) {     UINT priorityReg;     UINT value;     BYTE formattedPriority;     boolean setStatus FALSE;          setMaxInterruptPriorityLevels();          if ((interruptId >= 4) && (interruptId NUM_INTERRUPTS) &&         (priority && priority NUM_PRIORITY) ) {                  formattedPriority priority << (NUM_PRIORITY_BITS);                  priorityReg priorityRegisterMap[interruptId >> 2];         value HWREG(priorityReg);         value &= ~(0xFF << (* (interruptId 3)));         value |= formattedPriority << (* (interruptId 3));         HWREG(priorityReg) = value;                  setStatus TRUE;     }          return setStatus; } #define PRIORITY_MASK_STACK_SIZE   16 BYTE priorityMaskStackPtr 0; BYTE priorityMaskStack[PRIORITY_MASK_STACK_SIZE] =      { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}; void lockPriority(UINT priorityMask) {              __asm(              "    push    {r1-r4}                            n"                          "    mov.w     r3,                r0                n"        // priorityMask                          "    lsl.w     r3,    r3,            #5                n"        // << 5             "    msr     BASEPRI_MAX,     r3                n"        // raise base priority (only higher priorities accepted)                              "    ldr     r1,        =priorityMaskStackPtr    n"                  "    ldrb    r3,     [r1]                    n"        // priorityMaskStackPtr++             "    add        r3,        r3, #1                    n"                                 "    strb    r3,        [r1]                    n"                               "    mrs        r4,                BASEPRI            n"        // readback    current priority             "    lsr.w     r4,    r4,            #5                n"        // >> 5             "    ldr        r2,     =priorityMaskStack        n"             "    strb    r4,        [r2, r3]                n"     // priorityMaskStack[priorityMaskStackPtr] = BASEPRI             "    pop        {r1-r4}                            n"     );  } void unLockPriority(void) {                      __asm(             "    push    {r1-r4}                                    n"                          "    ldr     r1,                =priorityMaskStackPtr    n"                  "    ldr        r2,             =priorityMaskStack        n"             "    ldrb    r3,             [r1]                    n"        // priorityMaskStackPtr //            "    mov     r4,                 #0                        n" //            "    strb    r4,                [r2, r3]                n"     // clear current entry                          "    sub        r3,                r3, #1                    n"        // priorityMaskStackPtr--                         "    strb    r3,                [r1]                    n"                  "    ldrb    r4,                [r2, r3]                n"        // priorityMaskStack[priorityMaskStackPtr]                 "    lsl     r4,    r4,            #5                        n"        // << 5             "    msr     BASEPRI,         r4                        n"        // BASEPRI = priorityMaskStack[priorityMaskStackPtr]             "    pop        {r1-r4}                                    n"     );              } #elif defined(USE_LOCK_GROUP) //---------------------------------------------------------------------- //  LOCK GROUP //---------------------------------------------------------------------- #define USER_ISR_BASE_OFFSET         INT_GPIOA #define USER_ISR_OFFSET_INTERVAL    32 #define USER_ISR_SECOND_OFFSET        ( USER_ISR_BASE_OFFSET + USER_ISR_OFFSET_INTERVAL ) #define MAX_NUM_USER_ISRS              ( NUM_INTERRUPTS - USER_ISR_BASE_OFFSET )  static BYTE ISRLockCounts[MAX_NUM_USER_ISRS]; void lockGroup(BYTE *interruptIds) {     BYTE offset;          while (*interruptIds != NULL) {                  if((*interruptIds >= USER_ISR_BASE_OFFSET) && (*interruptIds USER_ISR_SECOND_OFFSET)) {              offset = *interruptIds USER_ISR_BASE_OFFSET;             ISRLockCounts[offset]++;             // disable             HWREG(NVIC_DIS0) = << offset;         } else {             if((*interruptIds >= USER_ISR_SECOND_OFFSET) && (*interruptIds NUM_INTERRUPTS)) {                 offset = *interruptIds USER_ISR_BASE_OFFSET;                 ISRLockCounts[offset]++;                 // disable                 HWREG(NVIC_DIS1) = << (offset USER_ISR_OFFSET_INTERVAL);                     }         }                      interruptIds++;              } // loop } void unLockGroup(BYTE *interruptIds) {     BYTE offset;     while (*interruptIds != NULL) {                  if((*interruptIds >= USER_ISR_BASE_OFFSET) && (*interruptIds USER_ISR_SECOND_OFFSET)) {              offset = *interruptIds USER_ISR_BASE_OFFSET;             ISRLockCounts[offset]--;             if (ISRLockCounts[offset] == 0) {                 // enable                 HWREG(NVIC_EN0) = << offset;             }         } else {             if((*interruptIds >= USER_ISR_SECOND_OFFSET) && (*interruptIds NUM_INTERRUPTS)) {                 offset = *interruptIds USER_ISR_BASE_OFFSET;                 ISRLockCounts[offset]--;                 if (ISRLockCounts[offset] == 0) {                     // enable                     HWREG(NVIC_EN1) = << (offset USER_ISR_OFFSET_INTERVAL);                 }             }         }                      interruptIds++;                  } // loop } #endif // LOCK TYPE //---------------------------------------------------------------------- //  LOCK wrapper //---------------------------------------------------------------------- #define PRIORITY_MASK_DISABLED    0 LOCK_ID getLockId(struct lockType lockInfo) {          boolean error FALSE;          struct lockType *lockId =              (struct lockType*)malloc(sizeof(struct lockType));          if (lockId != NULL) {              lockId->lockClass lockInfo.lockClass;                  switch (lockInfo.lockClass) {                  #if defined(USE_LOCK_ALL)                      case NO_LOCKS :         case LOCKS :             break;          #elif defined(USE_LOCK_PRIORITY)                      case NO_LOCKS :             lockId->priorityMask PRIORITY_MASK_DISABLED;             break;                      case LOCKS :                          if ((lockInfo.priorityMask PRIORITY_MASK_DISABLED) &&                  (lockInfo.priorityMask NUM_PRIORITY)) {                                  lockId->priorityMask lockInfo.priorityMask;                             } else {                 error TRUE;             }             break;          #elif defined(USE_LOCK_GROUP)                      case NO_LOCKS :             lockInfo.interruptIds NULL;             break;                      case LOCKS :                                      if (lockInfo.interruptIds != NULL) {                                  BYTE size strlen((char*)lockInfo.interruptIds) + 1;                 lockId->interruptIds = (BYTE*)malloc(size);                                  if (lockId->interruptIds != NULL) {                             memcpy(lockId->interruptIdslockInfo.interruptIdssize);                             } else {                     error TRUE;                 }                                              } else {                 error TRUE;             }                                      break;          #endif // LOCK TYPE                          break;                      default :             error TRUE;             break;             } // switch                          if (error) {             lockId freeMemory(lockId);          }     }              return lockId; } LOCK_ID deleteLock(LOCK_ID lockId) {          struct lockType *id = (struct lockType*)lockId;          if (id->lockClass == LOCKS) {          #if defined(USE_LOCK_GROUP)         id->interruptIds freeMemory(id->interruptIds); #endif // LOCK TYPE     }          lockId freeMemory(lockId);          return lockId; } void lock(LOCK_ID lockId) {          struct lockType *id = (struct lockType *)lockId;              if (id->lockClass == LOCKS) {              #if defined(USE_LOCK_ALL)              lockAll();      #elif defined(USE_LOCK_PRIORITY)                  lockPriority(id->priorityMask);                  #elif defined(USE_LOCK_GROUP)                  lockGroup(id->interruptIds);              #endif // LOCK TYPE              } } void unLock(LOCK_ID lockId) {          struct lockType *id = (struct lockType *)lockId;     if (id->lockClass == LOCKS) {              #if defined(USE_LOCK_ALL)              unLockAll();      #elif defined(USE_LOCK_PRIORITY)                  unLockPriority();              #elif defined(USE_LOCK_GROUP)                  unLockGroup(id->interruptIds);              #endif // LOCK TYPE              } } //utility enum lockClassType getLockClass(LOCK_ID lockId) {         struct lockType *id = (struct lockType *)lockId;             return id->lockClass;      } #endif // USE_LOCKS #ifdef __cplusplus } #endif




Feel free to improve/add/subtract and post bug fixes ...

You may need to use information from these links also :

systemRAM

login or register to reply