Files
diplomarbeit/Tester/SW/Eclipse/lib/Drivers/dio.c
T
Matthias 6cc948eef8 Moved remotely
git-svn-id: file:///srv/dev-disk-by-uuid-17e88007-4d0c-45e0-8757-cacfcc458630/repositories/svn/Diplomarbeit@113 9fe90eed-be63-e94b-8204-d34ff4c2ff93
2009-01-12 08:38:14 +00:00

717 lines
22 KiB
C

/* ---------------------------------------------------------------------------
* dio.c - v0.1 (c) 2007 Micro-key bv
* ---------------------------------------------------------------------------
* Micro-key bv
* Industrieweg 28, 9804 TG Noordhorn
* Postbus 92, 9800 AB Zuidhorn
* The Netherlands
* Tel: +31 594 503020
* Fax: +31 594 505825
* Email: support@microkey.nl
* Web: www.microkey.nl
* ---------------------------------------------------------------------------
* Description: Digital inputs/outputs interface.
* ---------------------------------------------------------------------------
* Version(s): 0.1, 28-11-2007, fvds.
* Creation.
* ---------------------------------------------------------------------------
*/
/* ---------------------------------------------------------------------------
* System include files
* ---------------------------------------------------------------------------
*/
/* Compiler includes */
#include <stdio.h>
#include <stdlib.h>
/* Hardware Includes */
#include "LPC23xx.h"
#include "types.h"
/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "Task.h"
#include "queue.h"
/* ---------------------------------------------------------------------------
* Application include files
* ---------------------------------------------------------------------------
*/
#include "dio.h"
#include "dioISR.h"
#include "armVIC.h"
#include "ElecStatusCache.h"
/* ---------------------------------------------------------------------------
* Local constant and macro definitions
* ---------------------------------------------------------------------------
*/
#define PORT0_BASE_ADDR FIO_BASE_ADDR
#define PORT1_BASE_ADDR (FIO_BASE_ADDR + 0x20)
#define PORT2_BASE_ADDR (FIO_BASE_ADDR + 0x40)
#define PORT3_BASE_ADDR (FIO_BASE_ADDR + 0x60)
#define PORT4_BASE_ADDR (FIO_BASE_ADDR + 0x80)
#define DIR_OFFSET (0x00)
#define MASK_OFFSET (0x10)
#define PIN_OFFSET (0x14)
#define SET_OFFSET (0x18)
#define CLR_OFFSET (0x1C)
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DIO_MUX_DIR FIO3DIR
#define DIO_MUX_SET FIO3SET
#define DIO_MUX_CLR FIO3CLR
#define DIN_MUX_BIT BIT(25)
#define DIN_MUX_SET (DIO_MUX_SET = DIN_MUX_BIT)
#define DIN_MUX_CLR (DIO_MUX_CLR = DIN_MUX_BIT)
#define DOUT_MUX_BIT BIT(26)
#define DOUT_MUX_SET (DIO_MUX_SET = DOUT_MUX_BIT)
#define DOUT_MUX_CLR (DIO_MUX_CLR = DOUT_MUX_BIT)
#endif
#define DISPATCH_TASK_PRIO (tskIDLE_PRIORITY + 5)
#define DISPATCH_QUEUE_SIZE 10
#define Int_queue_time 3 /* In Miliseconds */
/* ---------------------------------------------------------------------------
* Global variable definitions
* ---------------------------------------------------------------------------
*/
/* ---------------------------------------------------------------------------
* Local variable definitions
* ---------------------------------------------------------------------------
*/
portTickType dechatterStopTime[maxDI_Channels]; /* Contains tickcount Value, where*/
/* dechattering timeout occours */
UINT8 dechatterLockFlag[maxDI_Channels] = /* Channel Lock Flag */
{
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
UINT32 dechatterTime[maxDI_Channels] = /* TimeDelay until dechatter timeout*/
{
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10
};
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
t_output outputPins[maxDO_Channels] =
{
{ PORT4_BASE_ADDR, BIT(8) }, // DOUT0
{ PORT4_BASE_ADDR, BIT(9) }, // DOUT1
{ PORT4_BASE_ADDR, BIT(10) }, // DOUT2
{ PORT4_BASE_ADDR, BIT(11) }, // DOUT3
{ PORT4_BASE_ADDR, BIT(12) }, // DOUT4
{ PORT4_BASE_ADDR, BIT(13) }, // DOUT5
{ PORT4_BASE_ADDR, BIT(14) }, // DOUT6
{ PORT4_BASE_ADDR, BIT(15) } // DOUT7
};
#else
t_output outputPins[maxDO_Channels] =
{
{ PORT1_BASE_ADDR, BIT(0) }, // DOUT0
{ PORT1_BASE_ADDR, BIT(1) }, // DOUT1
{ PORT1_BASE_ADDR, BIT(4) }, // DOUT2
{ PORT1_BASE_ADDR, BIT(8) }, // DOUT3
{ PORT1_BASE_ADDR, BIT(9) }, // DOUT4
{ PORT1_BASE_ADDR, BIT(10) }, // DOUT5
{ PORT1_BASE_ADDR, BIT(14) }, // DOUT6
{ PORT1_BASE_ADDR, BIT(15) } // DOUT7
};
#endif
t_input inputPins[maxDI_Channels] =
{
{ PORT0_BASE_ADDR, BIT(15), NULL }, // DIN0
{ PORT0_BASE_ADDR, BIT(16), NULL }, // DIN1
{ PORT0_BASE_ADDR, BIT(17), NULL }, // DIN2
{ PORT0_BASE_ADDR, BIT(18), NULL }, // DIN3
{ PORT0_BASE_ADDR, BIT(24), NULL }, // DIN4
{ PORT0_BASE_ADDR, BIT(25), NULL }, // DIN5
{ PORT0_BASE_ADDR, BIT(26), NULL }, // DIN6
{ PORT0_BASE_ADDR, BIT(27), NULL }, // DIN7
{ PORT0_BASE_ADDR, BIT(28), NULL }, // DIN8
{ PORT0_BASE_ADDR, BIT(29), NULL }, // DIN9
{ PORT0_BASE_ADDR, BIT(30), NULL } // DIN10
};
BOOLEAN dioActive = FALSE;
xQueueHandle dispatchedIsrQueue= 0;
/* ---------------------------------------------------------------------------
* Local function definitions
* ---------------------------------------------------------------------------
*/
static void setMaskDirRegisters(void);
static void enableChannelInterrupt(UINT8 channel);
static void disableChannelInterrupt(UINT8 channel);
static void isrDispatchTask(void *pvParameters);
static BOOLEAN hasTimeoutPast( UINT32 endTick );
static void startDechatterInput (UINT8 ChannelNumber, t_di_mode Edge);
static void endDechatterInput (void);
static void callAllCallbacks(t_callbackListItem *pCallbackList, t_di_mode detectedEdge);
void dioInit(void)
{
SCS |= (1UL<<0); /* GPIOM in SCS to fast IO */
setMaskDirRegisters(); /* Init channel Registers */
dioActive= TRUE; /* Set global dioAcitve */
/* Create queue and Task for ISR-displatching */
dispatchedIsrQueue = xQueueCreate( DISPATCH_QUEUE_SIZE, sizeof(t_IsrDispatchQueueItem));
xTaskCreate(isrDispatchTask, ( signed portCHAR * ) "dioIsrDispatcher",
configMINIMAL_STACK_SIZE, NULL, DISPATCH_TASK_PRIO, NULL);
/* Enable GPIO interrupt */
portENTER_CRITICAL();
{
VICIntSelect &= ~(VIC_CHAN_TO_MASK(VIC_CHAN_NUM_EINT3));
VICIntEnClr = VIC_CHAN_TO_MASK(VIC_CHAN_NUM_EINT3);
VICVectAddr17 = (void *)gpioISR;
VICVectCntl7 = 0x01;
VICIntEnable = VIC_CHAN_TO_MASK(VIC_CHAN_NUM_EINT3);
}
portEXIT_CRITICAL();
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
/* Init both MUX lines as Outputs */
DIO_MUX_DIR |= (DIN_MUX_BIT | DOUT_MUX_BIT);
#endif
}
void dio_inMuxEn (BOOLEAN mode)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
if (mode == TRUE)
{
DIN_MUX_SET;
}
else
{
DIN_MUX_CLR;
}
#endif
}
void dio_outMuxEn (BOOLEAN mode)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
if (mode == TRUE)
{
DOUT_MUX_SET;
}
else
{
DOUT_MUX_CLR;
}
#endif
}
BOOLEAN dio_inMuxRB (void)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
if (DIO_MUX_SET & DIN_MUX_BIT)
{
/* MUX of digital input is switched to Extension Board */
return (TRUE);
}
else
{
/* MUX of digital input is switched to Main Board */
return (FALSE);
}
#endif
}
BOOLEAN dio_outMuxRB (void)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
if (DIO_MUX_SET & DOUT_MUX_BIT)
{
/* MUX of digital input is switched to Extension Board */
return (TRUE);
}
else
{
/* MUX of digital input is switched to Main Board */
return (FALSE);
}
#endif
}
RESULT dioRegisterCallback (t_dio_callbackfunc pFunc, UINT8 channel, t_di_mode mode)
{
RESULT result = OK;
disableChannelInterrupt(channel);
// Create item
t_callbackListItem *newCallbackListItem =
(t_callbackListItem *) pvPortMalloc(sizeof(t_callbackListItem));
if (newCallbackListItem == NULL)
{
result = ERROR;
} else
{
if (inputPins[channel].pCallbackList == NULL)
{
enableChannelInterrupt(channel);
}
// Fill list item
newCallbackListItem->pCallback = pFunc;
newCallbackListItem->mode = mode;
// Add to front of list
newCallbackListItem->next = inputPins[channel].pCallbackList;
inputPins[channel].pCallbackList = newCallbackListItem;
}
enableChannelInterrupt(channel);
return result;
}
/** \brief Remove register callback function for digital input
* \retval OK Callback was removed succesfully
* \retval ERROR Failed to remove Callback-function from channel
*/
RESULT dioRemoveCallback(t_dio_callbackfunc pFunc, UINT8 channel)
{
RESULT result = OK;
disableChannelInterrupt(channel);
// Check if channel has callback list
if (inputPins[channel].pCallbackList == NULL)
{
result = ERROR;
} else
{
BOOLEAN callbackFound = FALSE;
t_callbackListItem * previousItem= NULL;
t_callbackListItem * currentItem = inputPins[channel].pCallbackList;
// Find callbackfunc
while ((!callbackFound) && (currentItem != NULL))
{
callbackFound = (currentItem->pCallback == pFunc);
if (!callbackFound)
{
previousItem = currentItem;
currentItem = currentItem->next;
}
}
if (callbackFound)
{
if (previousItem == NULL)
{
// Remove first item from list
inputPins[channel].pCallbackList = currentItem->next;
} else
{
// Remove list item
previousItem->next = currentItem->next;
}
vPortFree(currentItem); // Release resources of listitem
} else
{
result = FALSE;
}
}
if (inputPins[channel].pCallbackList != NULL)
{
enableChannelInterrupt(channel);
}
return result;
}
/** \brief Read digital input.*/
BOOLEAN dioRead(UINT8 device, /**< 0 = Self, 1..32 = Remote device */
UINT8 channel /**< 0..10 = valid, 11..255 = future use */
)
{
BOOLEAN Result;
volatile UINT32 *gpioRegister;
if (device == 0)
{
gpioRegister = (UINT32 *)(inputPins[channel].portBaseAddr + PIN_OFFSET);
// device is now ignored, future implementation
// Get result
if (*gpioRegister & inputPins[channel].pinMask)
{
Result = FALSE;
} else
{
Result = TRUE;
}
}
else
{
Result = bpecDioRead( device, channel );
}
return Result;
}
/** \brief Readback digital outputs.*/
BOOLEAN dioReadBack(UINT8 device, /**< 0 = Self, 1..32 = Remote device */
UINT8 channel /**< 0..7 = valid, 8..255 = future use */
)
{
BOOLEAN Result;
volatile UINT32 *gpioRegister;
if (device == 0)
{
gpioRegister = (UINT32 *)(outputPins[channel].portBaseAddr + PIN_OFFSET);
// device is now ignored, future implementation
// Get result
// NOTE: Input signal is inverted
if (*gpioRegister & outputPins[channel].pinMask)
{
Result = TRUE;
} else
{
Result = FALSE;
}
}
else
{
Result = bpecDioReadBack( device, channel );
}
return Result;
}
/** \brief Write digital outputs.*/
void dioWrite(UINT8 device, /**< 0 = Self, 1..32 = Remote device */
UINT8 channel, /**< 0..7 = valid, 8..255 = future use */
BOOLEAN data)
{
volatile UINT32 *gpioRegister;
if (device == 0)
{
if (data == TRUE)
{
gpioRegister = (UINT32 *)(outputPins[channel].portBaseAddr
+ SET_OFFSET);
*gpioRegister = outputPins[channel].pinMask;
}
else
{
gpioRegister = (UINT32 *)(outputPins[channel].portBaseAddr
+ CLR_OFFSET);
*gpioRegister = outputPins[channel].pinMask;
}
} else
{
bpecWriteDioValue(device, channel, data);
}
}
void setMaskDirRegisters()
{
int i;
volatile UINT32 *gpioRegister;
for (i=0; i< maxDO_Channels; i++)
{
// Clear bit in mask Register
gpioRegister = (UINT32 *)(outputPins[i].portBaseAddr + MASK_OFFSET);
*gpioRegister &= ~(outputPins[i].pinMask);
// Set direction bit to output
gpioRegister = (UINT32 *)(outputPins[i].portBaseAddr + DIR_OFFSET);
*gpioRegister |= outputPins[i].pinMask;
}
for (i=0; i< maxDI_Channels; i++)
{
// Clear bit in maskRegister
gpioRegister = (UINT32 *)(inputPins[i].portBaseAddr + MASK_OFFSET);
*gpioRegister &= ~(inputPins[i].pinMask);
// Set direction bit to input
gpioRegister = (UINT32 *)(inputPins[i].portBaseAddr + DIR_OFFSET);
*gpioRegister &= ~(inputPins[i].pinMask);
// Reset callback functions
inputPins[i].pCallbackList = NULL;
}
}
void enableChannelInterrupt(UINT8 channel)
{
if (inputPins[channel].portBaseAddr == PORT0_BASE_ADDR)
{
IO0_INT_CLR = inputPins[channel].pinMask;
IO0_INT_EN_R |= inputPins[channel].pinMask;
IO0_INT_EN_F |= inputPins[channel].pinMask;
}
else
{
IO2_INT_CLR = inputPins[channel].pinMask;
IO2_INT_EN_R |= inputPins[channel].pinMask;
IO2_INT_EN_F |= inputPins[channel].pinMask;
}
}
void disableChannelInterrupt(UINT8 channel)
{
if (inputPins[channel].portBaseAddr == PORT0_BASE_ADDR)
{
IO0_INT_EN_R &= ~BIT(inputPins[channel].pinMask);
IO0_INT_EN_F &= ~BIT(inputPins[channel].pinMask);
}
else
{
IO2_INT_EN_R &= ~BIT(inputPins[channel].pinMask);
IO2_INT_EN_F &= ~BIT(inputPins[channel].pinMask);
}
}
void isrDispatchTask(void *pvParameters)
{
t_IsrDispatchQueueItem dispatchItem;
UINT32 channelcnt;
do /* As long as active */
{
/* If an Input Interrupt occures, enter if Statement */
if (xQueueReceive(dispatchedIsrQueue, &dispatchItem, Int_queue_time))
{
/* Check for each single Channel, which one is active */
for (channelcnt=0; channelcnt < maxDI_Channels; channelcnt++)
{
/* Go further if CallBack exists for corresponding Channel */
if (inputPins[channelcnt].pCallbackList != NULL)
{
/* Check if this bit is active */
int portIndex = (inputPins[channelcnt].portBaseAddr
== PORT0_BASE_ADDR ? 0 : 1);
/* Check if Interrupt occured from a RISING EDGE */
if (dispatchItem.riseInterrupts[ portIndex ]
& inputPins[channelcnt].pinMask)
{ /* Rising Edge Interrupt detected */
if (dechatterTime[channelcnt] == 0)
{ /* If dechatterTime is set to ZERO */
/* call Callback directly */
callAllCallbacks(
inputPins[channelcnt].pCallbackList,
RISING_EDGE);
}
else /* If there is a dechattering Time */
{ /* Start dechattering the Input */
startDechatterInput(channelcnt, RISING_EDGE);
}
}
/* Check if Interrupt occured from a FALLING EDGE */
if (dispatchItem.fallInterrupts[ portIndex ]
& inputPins[channelcnt].pinMask)
{ /* Falling Edge Interrupt detected */
if (dechatterTime[channelcnt] == 0)
{ /* If dechatterTime is set to ZERO */
/* call Callback directly */
callAllCallbacks(
inputPins[channelcnt].pCallbackList,
FALLING_EDGE);
}
else /* if there is a dechattering Time */
{ /* Start dechattering the Input */
startDechatterInput(channelcnt, FALLING_EDGE);
}
}
} /* EndIf CallBack exists Check */
} /* End of FOR Loop */
} /* End Check for occuring Interrupt */
endDechatterInput(); /* Call dechatter monitor Function */
} while (dioActive == TRUE);
}
void startDechatterInput(UINT8 ChannelNumber, t_di_mode Edge)
{
/* If corresponding Channel is currently not monitored */
if (dechatterLockFlag[ChannelNumber] == 0)
{
/* Set dechatter Timer */
dechatterStopTime[ChannelNumber] = xTaskGetTickCount()
+ dechatterTime[ChannelNumber];
/* Handle type of detected Edge in channel Lock Flag */
switch (Edge)
{
case RISING_EDGE:
dechatterLockFlag[ChannelNumber] = 1;
break;
case FALLING_EDGE:
dechatterLockFlag[ChannelNumber] = 2;
break;
// case BOTH_EDGES:
default:
break;
}
}
/* If come here, an already monitored Channel causes a new Interrupt
* (which means, within the Timer a new Edge occured)
* This is a chatter!
* Reload the Timer!
*/
else
{
dechatterStopTime[ChannelNumber] = xTaskGetTickCount()
+ dechatterTime[ChannelNumber];
}
}
void endDechatterInput(void)
{
UINT32 channelcnt;
/* Check every single Channel */
for (channelcnt = 0; channelcnt < maxDI_Channels; channelcnt++)
{
/* If Timeout for corresponding channel occured */
if (hasTimeoutPast( dechatterStopTime[channelcnt]) )
{
/* Switch corresponding to the former detected Edge */
switch (dechatterLockFlag[channelcnt])
{
case 1: /* a Rising Edge was dechattered */
/* Is Input still High? If Yes, channel is dechattered */
if (dioRead(0, channelcnt) == TRUE)
{ /* Call Callback Functions */
callAllCallbacks(inputPins[channelcnt].pCallbackList,
RISING_EDGE);
}
dechatterLockFlag[channelcnt] = 0; /* release Lock Flag */
break;
case 2: /* a Falling Edge was dechattered */
/* Is Input still Low? If Yes, channel is dechattered */
if (dioRead(0, channelcnt) == FALSE)
{ /* Call Callback Functions */
callAllCallbacks(inputPins[channelcnt].pCallbackList,
FALLING_EDGE);
}
dechatterLockFlag[channelcnt] = 0;
break;
}
}
}
}
void callAllCallbacks(t_callbackListItem *pCallbackList, t_di_mode detectedEdge)
{
while (pCallbackList != NULL)
{
if ( (pCallbackList->mode == detectedEdge) || (pCallbackList->mode
== BOTH_EDGES))
{
// Call the callback
pCallbackList->pCallback();
}
// Check next item
pCallbackList = pCallbackList->next;
}
}
void dioSetDechatterTime(UINT8 channel, UINT32 time)
{
dechatterTime[channel] = time;
}
BOOLEAN hasTimeoutPast( UINT32 endTick )
{
UINT32 nowTick = xTaskGetTickCount();
if (nowTick >= endTick)
{
if ((nowTick - endTick) > 0x0000FFFF)
{
// the endTick has gone through 0 point, nowTick is at end of range
return FALSE;
}
else
{
// nowTick passed endTick.
return TRUE;
}
}
else
{
if ((endTick - nowTick) > 0x0000FFFF)
{
// the endTick was at end of range, nowTick has gone through 0 point
return TRUE;
}
else
{
// nowTick still has to pass endTick
return FALSE;
}
}
}