#ifndef LOCKS_H_#define LOCKS_H_#include #include #ifdef __cplusplusextern "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_LOCKS, LOCKS };// available for direct access for all optionsvoid lockAll(void); // no interrupts possiblevoid 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 interruptId, BYTE priority);typedef struct lockType { enum lockClassType lockClass; UINT priorityMask;};void lockPriority(UINT priorityMask); // returns previous priorityMaskvoid 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 0LOCK_ID getLockId(struct lockType lockInfo); // call first to get LOCK_IDLOCK_ID deleteLock(LOCK_ID lockId);void lock(LOCK_ID lockId); void unLock(LOCK_ID lockId);//utilityenum lockClassType getLockClass(LOCK_ID lockId);#endif // USE_LOCKS #ifdef __cplusplus}#endif#endif // LOCKS_H_
#include #include #include #include #include #include #ifdef __cplusplusextern "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 prioritystatic const UINT priorityRegisterMap[15] ={ 0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3, NVIC_PRI0, NVIC_PRI1, NVIC_PRI2, NVIC_PRI3, NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7, NVIC_PRI8, NVIC_PRI9, NVIC_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 locallyvoid 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 interruptId, BYTE priority) { UINT priorityReg; UINT value; BYTE formattedPriority; boolean setStatus = FALSE; setMaxInterruptPriorityLevels(); if ((interruptId >= 4) && (interruptId <>NUM_INTERRUPTS) && (priority > 0 && priority <>NUM_PRIORITY) ) { formattedPriority = priority <>8 - NUM_PRIORITY_BITS); priorityReg = priorityRegisterMap[interruptId >> 2]; value = HWREG(priorityReg); value &= ~(0xFF <>8 * (interruptId & 3))); value |= formattedPriority <>8 * (interruptId & 3)); HWREG(priorityReg) = value; setStatus = TRUE; } return setStatus;}#define PRIORITY_MASK_STACK_SIZE 16BYTE priorityMaskStackPtr = 0;BYTE priorityMaskStack[PRIORITY_MASK_STACK_SIZE] = { 0,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" // <> " 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" // <> " 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) = 1 <>offset; } else { if((*interruptIds >= USER_ISR_SECOND_OFFSET) && (*interruptIds <>NUM_INTERRUPTS)) { offset = *interruptIds - USER_ISR_BASE_OFFSET; ISRLockCounts[offset]++; // disable HWREG(NVIC_DIS1) = 1 <>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) = 1 <>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) = 1 <>offset - USER_ISR_OFFSET_INTERVAL); } } } interruptIds++; } // loop}#endif // LOCK TYPE//----------------------------------------------------------------------// LOCK wrapper//----------------------------------------------------------------------#define PRIORITY_MASK_DISABLED 0LOCK_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->interruptIds, lockInfo.interruptIds, size); } 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 }}//utilityenum lockClassType getLockClass(LOCK_ID lockId) { struct lockType *id = (struct lockType *)lockId; return id->lockClass; }#endif // USE_LOCKS#ifdef __cplusplus}#endif