#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] =
{
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 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 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 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,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) = 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 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->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
}
}
//utility
enum lockClassType getLockClass(LOCK_ID lockId) {
struct lockType *id = (struct lockType *)lockId;
return id->lockClass;
}
#endif // USE_LOCKS
#ifdef __cplusplus
}
#endif
|