/*
*********************************************************************************************************
*                                               Philips LPC3000
*                                 LPC2138 Kick Start Card Board Support Package
*
*                                    (c) Copyright 2005, Micrium, Weston, FL
*                                              All Rights Reserved
*
*
* File : BSP.C
* By   : Eric Shufro
*********************************************************************************************************
*/

#define  BSP_GLOBALS
#include <includes.h>


/*
*********************************************************************************************************
*                                              CONSTANTS
*********************************************************************************************************
*/

#define  BSP_UNDEF_INSTRUCTION_VECTOR_ADDR   (*(INT32U *)0x00000004L)
#define  BSP_SWI_VECTOR_ADDR                 (*(INT32U *)0x00000008L)
#define  BSP_PREFETCH_ABORT_VECTOR_ADDR      (*(INT32U *)0x0000000CL)
#define  BSP_DATA_ABORT_VECTOR_ADDR          (*(INT32U *)0x00000010L)
#define  BSP_IRQ_VECTOR_ADDR                 (*(INT32U *)0x00000018L)
#define  BSP_FIQ_VECTOR_ADDR                 (*(INT32U *)0x0000001CL)

#define  BSP_IRQ_ISR_ADDR                    (*(INT32U *)0x00000038L)
#define  BSP_FIQ_ISR_ADDR                    (*(INT32U *)0x0000003CL)

#define  LED_1                               (INT32U)(1 <<  9)
#define  LED_2                               (INT32U)(1 << 10)

/*
*********************************************************************************************************
*                                               DATA
*********************************************************************************************************
*/

INT8U  const  BSP_BitIxTbl[256] = {
    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,                         /* 0x00 to 0x0F                                         */
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,                         /* 0x10 to 0x1F                                         */
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,                         /* 0x20 to 0x2F                                         */
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,                         /* 0x30 to 0x3F                                         */
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,                         /* 0x40 to 0x4F                                         */
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,                         /* 0x50 to 0x5F                                         */
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,                         /* 0x60 to 0x6F                                         */
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,                         /* 0x70 to 0x7F                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0x80 to 0x8F                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0x90 to 0x9F                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xA0 to 0xAF                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xB0 to 0xBF                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xC0 to 0xCF                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xD0 to 0xDF                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xE0 to 0xEF                                         */
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,                         /* 0xF0 to 0xFF                                         */
};

/*
*********************************************************************************************************
*                                              VARIABLES
*********************************************************************************************************
*/

    INT32U  Tmr_ReloadCnts;                                                 /* Global variable for OS Ticker Match Compare Value    */
    PFNCT   BSP_IntVectTbl[3][32];                                          /* Array of function pointers to ISR Handler            */

/*
*********************************************************************************************************
*                                              PROTOTYPES
*********************************************************************************************************
*/

static  void  BSP_PLL_Init(void);
static  void  Tmr_TickInit(void);

static  INT8U BSP_Get_HighOrderBit(INT32U  reg_val);

/*
*********************************************************************************************************
*                                         BSP INITIALIZATION
*
* Description : This function should be called by your application code before you make use of any of the
*               functions found in this module.
*
* Arguments   : none
*********************************************************************************************************
*/

void  BSP_Init (void)
{
    INT8U  i;


    BOOT_MAP                          = 1;                                  /* Remap IRAM to address 0x00                           */

    BSP_IRQ_VECTOR_ADDR               = 0xE59FF018;                         /* LDR PC,[PC,#0x18] instruction                        */
    BSP_IRQ_ISR_ADDR                  = (INT32U)OS_CPU_IRQ_ISR;             /* IRQ exception vector address                         */

    BSP_FIQ_VECTOR_ADDR               = 0xE59FF018;                         /* LDR PC,[PC,#0x18] instruction                        */
    BSP_FIQ_ISR_ADDR                  = (INT32U)OS_CPU_FIQ_ISR;             /* FIQ exception vector address                         */

    BSP_UNDEF_INSTRUCTION_VECTOR_ADDR = 0xEAFFFFFE;                         /* Jump to itself                                       */
    BSP_SWI_VECTOR_ADDR               = 0xEAFFFFFE;
    BSP_PREFETCH_ABORT_VECTOR_ADDR    = 0xEAFFFFFE;
    BSP_DATA_ABORT_VECTOR_ADDR        = 0xEAFFFFFE;
    BSP_FIQ_VECTOR_ADDR               = 0xEAFFFFFE;

    for (i = 0; i < 32; i++) {                                              /* Initialize the Interrupt Handler lookup table        */
        BSP_IntVectTbl[0][i] = (PFNCT)0;
        BSP_IntVectTbl[1][i] = (PFNCT)0;
        BSP_IntVectTbl[2][i] = (PFNCT)0;
    }

    BSP_PLL_Init();                                                         /* Initialize the PLL                                   */

    LED_Init();                                                             /* Initialize the I/Os for the LED controls             */

    Tmr_TickInit();                                                         /* Initialize the uC/OS-II tick interrupt               */
}

/*
*********************************************************************************************************
*                                      Set the CPU Clock Frequency
*
* Description: This function sets up and activates the PLL that drives the peripherals and cpu core.
*
* Notes      : 1) PLL Output frequency when in DIRECT MODE, HCLKPLL_CTRL[15:14] = '01', is calculated by:
*                 FCLKOUT = (M * FCLKIN) / N
*
*              2) FCLKIN  = CPU_OSC_FREQ = 13MHZ CRYSTAL ON THE LPC3000 EVALUATION BOARD by Philips
*
*              3) PLL SUMMARY
*                   FCLKOUT           = ((46 * 13MHZ) / 3) = 199.33MHZ
*                   HCLK              =  (FCLKOUT / HCLK Divider)        = (199.33 /  2)  =   99.66MHZ
*                   PERIPH_CLK        =  (FCLKOUT / PERIPH_CLK Divider)  = (199.33 / 16)  =   12.46MHZ
*
*                                         NOTE: DO NOT CHANGE THE PERIPHERAL DIVIDER TO 1 if OS-View
*                                         is configued to use a high-speed UART. This is due to the
*                                         fact that the high-speed UART divider cannot reach lower
*                                         baud rates (38,400) when the PERIPH_CLK is running at 199MHZ.
*                                         However, a FCLKOUT divided by 2, this baud rate can be set.
*
*              4) WARNING: HCLK must never exceed 104MHZ!
*
*              5) Clock Chain Relationships
*                     1) OSC_CLK is called SYSCLK when SYSCLK_CTRL[0] = '0'.
*                     2) OSC_CLK is selected for SYSCLK (shown above), then feeds into the HCLK_PLL.
*                     3) The output of the HCLK_PLL is called FCLKOUT.
*                     4) By setting PWR_CTRL[2], the PERIPH_CLK = FCLKOUT / PERIPH_CLK Divider,
*                        and, HCLK COULD be selected as FCLKOUT / HCLK Divider. The HCLK Divider is set by HCLKDIV_CTRL[1:0] which is set for 2.
*                     5) By setting PWR_CTRL[10], the HCLK IS selected as FCLKOUT / HCLK Divider. (As opposed to being from PERIPH_CLK)
*                        Additionally, ARMCLK = FCLKOUT.
*                     7) When everything is done, three clocks exist: HCLK, PERIPH_CLK, and ARMCLK and their values are shown above.
*
*                 PLL Definitions
*                       FCLKIN the frequency of the PLL input clock, we know from above that this equals SYSCLK = OSCCLK.
*                       FCLKOUT the output frequency of the PLL, we know from above that this is also called HCLK.
*                       N PLL pre-divider setting based on the bits in the relevant control register. N can have the values 1, 2, 3, or 4.
*                       M PLL feedback divider setting based on bits in the relevant control register. M is an integer from 1 through 256.
*                       P PLL post-divider setting based on the bits in the relevant control register. P can have the values 1, 2, 4, or 8.
*********************************************************************************************************
*/

void  BSP_PLL_Init (void)
{
    INT32U  HCLKDiv;


    PWR_CTRL      =    0x00000012;                                          /* Ensure that PWR_CTRL is reset with its initial value */
                                                                            /* This way we are in a known mode after a warm reboot  */

    SYSCLK_CTRL  &=  ~(1 <<  0);                                            /* Ensure the SYSCLK MUX selects the Main OSC as SYSCLK */

    HCLKDiv       =   (0x1F << 2);                                          /* Define the Peripheral Clock Divider bit mask [6:2]   */
    HCLKDIV_CTRL &=   ~HCLKDiv;                                             /* Clear the Periph. Clk Divider bits ensuring defaults */
    HCLKDIV_CTRL |=   (0x0F << 2);                                          /* Set HCLKDIV_CTRL[6:2] = 15, which divides by 16      */

    HCLKDIV_CTRL |=   (1 << 0);                                             /* Set the HCLK divider bits (HCLK = FCKOUT / 2)        */
                                                                            /* [06:02] Peripheral Clk Div = (0 + 1)                 */
                                                                            /* [01:00] HCLK Divider Control, (HCLK = FCKOUT / 2)    */

    HCLKPLL_CTRL  =    0x645A;                                              /* Set divider ratios (200mhz output), M=46, N=3, P=1   */
                                                                            /* [16:16] PLL Power Down = 0, PLL in power down mode   */
                                                                            /* [15:15] Bypass Control = 0, CC0 Clk sent to post div */
                                                                            /* [14:14] CCO clock = PLL CLK, bypassing post divider  */
                                                                            /* [13:13] Feedback Divider clocked by PLL_CLKOUT       */
                                                                            /* [12:11] PLL Post Divider (P)  =  0 + 1               */
                                                                            /* [10:09] PLL Pre Divider (N)   =  2 + 1               */
                                                                            /* [08:01] PLL Feedback Divider (M) = 45 + 1            */
                                                                            /* [00:00] PLL Locked Status, 1 = locked (Read Only)    */

    PWR_CTRL     &=  ~(1 << 10);                                            /* Set HCLK to be derived by FCKOUT / HCK Divider       */

    HCLKPLL_CTRL |=   (1 << 16);                                            /* Power up PLL                                         */

    while ((HCLKPLL_CTRL & (1 << 0)) == 0) {                                /* Wait for PLL to Lock                                 */
        ;
    }

    PWR_CTRL     |=  (1 <<  2);                                             /* Enter Normal Run mode                                */
}

/*
*********************************************************************************************************
*                                      Get the HCLK PLL frequency, FCLKOUT
*                                 In this particular case, this is also the ARMCLK
*
* Description: This function reads CPU registers to determine the CPU clock frequency of the chip.
*
*              Where ARMCPUCLK = FCLKOUT = (M * FCLKIN) / N
*                    and FCLKIN is defined by CPU_OSC_FREQ in BSP.H
*                    and M, N are PLL configuration settings.
*
* Returns    : The CPU frequency (HZ), assuming the PLL is on in Direct Mode, and the CPU is running
*              in 'Normal Run Mode'
*********************************************************************************************************
*/

INT32U  BSP_CPU_ClkFrq (void)
{

    INT32U  PLLCtl;
    INT32U  PLL_m;
    INT32U  PLL_n;
    FP32    cpu_clk_frq;


    PLLCtl            =   HCLKPLL_CTRL;                                     /* Get the value of the PLL control register            */
    PLLCtl            = ((PLLCtl >> 14) & 0x03);                            /* Isolate bits [15:14], shift over to positions [1:0]  */

                                                                            /* If the PLL in direct Mode (bit 15 = 0, bit 14 = 1)   */
    if ((PLLCtl  == 0x01) && ((PWR_CTRL & 0x02) == 0x02)) {                 /* and the CPU is running in 'Normal Run Mode'          */
        PLL_m         =  ((HCLKPLL_CTRL >> 1) & 0xFF) + 1;                  /* Determine the PLL value for M                        */
        PLL_n         =  ((HCLKPLL_CTRL >> 9) & 0x03) + 1;                  /* Determine the PLL value for N                        */
        cpu_clk_frq   =  ((PLL_m * CPU_OSC_FREQ) / PLL_n);                  /* Calculate the operating frequency                    */
    } else {
        cpu_clk_frq   =    0;                                               /* If we are not in Direct Mode, return 0               */
    }

    return ((INT32U)cpu_clk_frq);                                           /* Return the operating frequency                       */
}

/*
*********************************************************************************************************
*                                   Get the Peripheral Clock Frequency
*
* Description: This function determines the peripheral clock frequency of the chip.
*              It relies on the existance of BSP_CPU_ClkFrq() which assumes the chip is in
*              'Normal Run Mode', and that the PLL is running under 'Direct Mode'.
*              If these conditions are not met, this function will return 0 since
*              BSP_CPU_ClkFrq() will return 0.
*********************************************************************************************************
*/

INT32U  BSP_ClkFrqPeripheral (void)
{
    INT32U  cpu_frq;
    INT32U  periphClkDiv;
    FP32    periphClkFrq;


    cpu_frq          =    BSP_CPU_ClkFrq();                                 /* Get the FCLKOUT (HCLK PLL) output frequency               */
    periphClkDiv     =  ((HCLKDIV_CTRL >> 2) & 0x1F) + 1;                   /* Read the Peripheral Clock Divider Value                   */

    periphClkFrq     =   (cpu_frq / periphClkDiv);                          /* Calculate the Peripheral Clock Frequency in hz            */

    return ((INT32U)periphClkFrq);                                          /* Return the Peripheral Clock Frequency                     */
}

/*
*********************************************************************************************************
*                                   Get the HCLK Frequency
*
* Description: This function determines the peripheral clock frequency of the chip.
*              It relies on the existance of BSP_CPU_ClkFrq() which assumes the chip is in
*              'Normal Run Mode', and that the PLL is running under 'Direct Mode'.
*              If these conditions are not met, this function will return 0 since
*              BSP_CPU_ClkFrq() will return 0.
*
* Note       : HCLK is the system BUS clock source
*********************************************************************************************************
*/

INT32U  BSP_ClkFrqHCLK (void)
{
    INT32U  cpu_frq;
    INT32U  HCLKDiv;
    FP32    HCLKFrq;


    cpu_frq          =    BSP_CPU_ClkFrq();                                 /* Get the FCLKOUT (HCLK PLL) output frequency               */
    HCLKDiv           =   (HCLKDIV_CTRL & 0x03) + 1;                        /* Read the HCLK Divider Value                               */

    if (HCLKDiv == 0) {                                                     /* If the divider  value = 0, then we have a divider of 1    */
        HCLKDiv       =   1;
    } else {
         HCLKDiv     *=   2;                                                /* Calculate the correct divider from the register value     */
    }

    HCLKFrq           =   (cpu_frq / HCLKDiv);                              /* Calculate the HCLK Frequency in hz                        */

    return ((INT32U)HCLKFrq);                                               /* Return the Peripheral Clock Frequency                     */
}

/*
*********************************************************************************************************
*                                     BSP INTERRUPT ENABLE
*
* Description : This function enables and configures interrupt handlers for the 64 possible interrupts
*
* Arguments   : IntCont -  Specify which sub controller block to enable the interrupt on. Possible values: 0, 1, 2.
*                          where sub interrupt controller 0 is the main interrupt enable register
*               IntNum  -  Specify which sub controller interrupt number to enable. Possible values: 0-31
*               IntPol  -  Specify the Interrupt Polarity
*                              0 = Active low level or falling edge
*                              1 = Active high level or rising edge
*               IntAct  -  Specify whether an interrupt source is either level or edge sensitive
*                              0 = Interrupt is level sensitive
*                              1 = Interrupt is edge sensitive
*               Handler -  Specify a function pointer to the associated interrupt handler
*
* Notes       : 1) This function is only intended to enable Normal Interrupts, not FIQ's
*               2) Edge Sensitive interrupts must be cleared not only at the source but in the
*                  Raw Interrupt Status Register as well.
*               3) Setting polarity or edge sensitivity for any of the SUB INTERRUPT CONTROLLERS is
*                  possible, but only for the entire sub controller and all attached devices as a whole.
*                  If this function is called twice, once enabling level sensitivity for a sub1 device,
*                  and a second time enabling edge sensitivity for a different device on the same sub
*                  controller, then level sensitivity will be cancelled by the settings specified in
*                  the second call to BSP_IntEn(SUBn, x, x, x, x).
*********************************************************************************************************
*/

void  BSP_IntEn (INT8U IntCont, INT8U IntNum, INT8U IntPol, INT8U IntAct, PFNCT pfnct)
{
    if ((IntNum < 32) && (pfnct != (PFNCT)0)) {                             /* If the IntNum and ISR Handler pointer are valid      */
        switch (IntCont) {
            case 0:
                 if (IntPol == BSP_INT_LOW_LEVEL) {
                     MIC_APR  &= ~(1 << IntNum);                            /* Set the interrupt number as low level / falling edge */
                 } else {
                     MIC_APR  |=  (1 << IntNum);                            /* Set the interrupt number as high level / rising edge */
                 }

                 if (IntAct == BSP_INT_LEVEL_SENSITIVE) {
                     MIC_ATR  &= ~(1 << IntNum);                            /* Set the interrupt number as level sensitive          */
                 } else {
                     MIC_ATR  |=  (1 << IntNum);                            /* Set the interrupt number as edge sensitive           */
                 }

                 BSP_IntVectTbl[BSP_MAIN_INT_CTL][IntNum] = pfnct;          /* Save the ISR Handler function pointer                */
                 MIC_ER  |= (1 << IntNum);                                  /* Enable the IntNum on the main interrupt controller   */
                 break;

            case 1:
                 if (IntPol == BSP_INT_LOW_LEVEL) {
                     MIC_APR  &= ~(1 << 0);                                 /* Set the interrupt number as low level / falling edge */
                 } else {
                     MIC_APR  |=  (1 << 0);                                 /* Set the interrupt number as high level / rising edge */
                 }

                 if (IntAct == BSP_INT_LEVEL_SENSITIVE) {
                     MIC_ATR  &= ~(1 << 0);                                 /* Set the interrupt number as level sensitive          */
                 } else {
                     MIC_ATR  |=  (1 << 0);                                 /* Set the interrupt number as edge sensitive           */
                 }

                 BSP_IntVectTbl[BSP_SUB1_INT_CTL][IntNum] = pfnct;          /* Save the ISR Handler function pointer                */
                 MIC_ER  |= (1 << 0);                                       /* Ensure that Sub1IRQn (sub interrupts 1) are enabled  */
                 SIC1_ER |= (1 << IntNum);                                  /* Enable the IntNum on the sub interrupt controller 1  */
                 break;

            case 2:
                 if (IntPol == BSP_INT_LOW_LEVEL) {
                     MIC_APR  &= ~(1 << 1);                                 /* Set the interrupt number as low level / falling edge */
                 } else {
                     MIC_APR  |=  (1 << 1);                                 /* Set the interrupt number as high level / rising edge */
                 }

                 if (IntAct == BSP_INT_LEVEL_SENSITIVE) {
                     MIC_ATR  &= ~(1 << 1);                                 /* Set the interrupt number as level sensitive          */
                 } else {
                     MIC_ATR  |=  (1 << 1);                                 /* Set the interrupt number as edge sensitive           */
                 }

                 BSP_IntVectTbl[BSP_SUB2_INT_CTL][IntNum] = pfnct;          /* Save the ISR Handler function pointer                */
                 MIC_ER  |= (1 << 1);                                       /* Ensure that Sub2IRQn (sub interrupts 2) are enabled  */
                 SIC2_ER |= (1 << IntNum);                                  /* Enable the IntNum on the sub interrupt controller 2  */
                 break;
        }
    }
}

/*
*********************************************************************************************************
*                                     BSP INTERRUPT DISABLE
*
* Arguments   : IntCont -  Specify which sub controller block to disable the interrupt on. Possible values: 0, 1, 2.
*                          where sub interrupt controller 0 is the main interrupt enable register
*             : IntNum  -  Specify which sub controller interrupt number to disable. Possible values: 0-31
*********************************************************************************************************
*/

void  BSP_IntDis (INT8U IntCont, INT8U IntNum)
{
    if (IntNum < 32) {
        switch (IntCont) {
            case 0:
                 MIC_ER &= ~(1 << IntNum);                                  /* Disable the IntNum on the main interrupt controller  */
                 break;

            case 1:
                 SIC1_ER &= ~(1 << IntNum);                                 /* Disable the IntNum on the sub interrupt controller 1 */
                 break;

            case 2:
                 SIC2_ER &= ~(1 << IntNum);                                 /* Disable the IntNum on the sub interrupt controller 2 */
                 break;
        }
    }
}

/*
*********************************************************************************************************
*                                     DISABLE ALL INTERRUPTS
*
* Description : This function disables all interrupts from the interrupt controller.
*
* Arguments   : none
*********************************************************************************************************
*/

void  BSP_IntDisAll (void)
{
    MIC_ER  = 0;                                                            /* Disable ALL interrupts                               */
}

/*
*********************************************************************************************************
*                                           IRQ ISR HANDLER
*
* Description : This function is called by OS_CPU_IRQ_ISR() to determine the source of the interrupt
*               and process it accordingly.
*
* Arguments   : none
*
* Notes       : 1) This function first services MIC interrupts, followed by Sub1IRQn interrupts,
*                  and then Sub2IRQn.
*
*               2) This routine works without 'polling' for set bits by means
*                  of calling BSP_Get_HighOrderBit() which relies on checking byte-wise for set bits and
*                  then using a lookup table in order to find the highest order bit set in the 32 bit status
*                  register.
*********************************************************************************************************
*/

void  OS_CPU_IRQ_ISR_Handler (void)
{
    PFNCT   pfnct;
    INT8U   bit;


    while (MIC_SR > 0) {                                                    /* While at least 1 Master interrupt is still pending   */
        bit     =  BSP_Get_HighOrderBit(MIC_SR);                            /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[0][bit];                            /* Retrieve the interrupt handler function pointer      */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
    }

    while (SIC1_SR > 0) {                                                   /* While at least 1 Secondary-1 Int. is still pending   */
        bit     =  BSP_Get_HighOrderBit(SIC1_SR);                           /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[1][bit];                            /* Retrieve the interrupt handler function pointer      */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
    }

    while (SIC2_SR > 0) {                                                   /* While at least 1 Secondary-2 Int. is still pending   */
        bit     =  BSP_Get_HighOrderBit(SIC2_SR);                           /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[2][bit];                            /* Retrieve the interrupt handler function pointer      */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
    }
}


/*
*********************************************************************************************************
*                                           FIQ ISR HANDLER
*
* Description : This function is called by OS_CPU_FIQ_ISR() to determine the source of the interrupt
*               and process it accordingly.
*
* Arguments   : none
*********************************************************************************************************
*/

void  OS_CPU_FIQ_ISR_Handler (void)
{
    PFNCT   pfnct;
    INT32U  MIC_Status;
    INT32U  SIC1_Status;
    INT32U  SIC2_Status;
    INT8U   bit;


    MIC_Status  =  MIC_SR;                                                  /* Read the interrupt status register                   */
    SIC1_Status =  SIC1_SR;                                                 /* Get the status register for SIC1 Interrupts          */
    SIC2_Status =  SIC2_SR;                                                 /* Get the status register for SIC2 Interrupts          */

    while (MIC_Status > 0) {
        bit     =  BSP_Get_HighOrderBit(MIC_Status);                        /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[0][bit];                            /* Retrieve the interrupt handlers function pointer     */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
        MIC_Status &= ~bit;                                                 /* Clear the recently serviced bit, then check again    */
    }

    while (SIC1_Status > 0) {
        bit     =  BSP_Get_HighOrderBit(SIC1_Status);                       /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[1][bit];                            /* Retrieve the interrupt handlers function pointer     */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
        SIC1_Status &= ~bit;                                                /* Clear the recently serviced bit, then check again    */
    }

    while (SIC2_Status > 0) {
        bit     =  BSP_Get_HighOrderBit(SIC2_Status);                       /* Get the highest order bit that is set                */
        pfnct   = (PFNCT)BSP_IntVectTbl[2][bit];                            /* Retrieve the interrupt handlers function pointer     */
        if (pfnct != (PFNCT)0) {                                            /* If the function pointer is not NULL ...              */
            (*pfnct)();                                                     /* Execute the ISR handler                              */
        }
        SIC2_Status &= ~bit;                                                /* Clear the recently serviced bit, then check again    */
    }
}

/*
*********************************************************************************************************
*
*
* Description : This function returns the bit position of the highest order bit that is set
*               in the 32 bit parameter, reg_val.
*
* Arguments   : reg_val, the 32 bit data value to determine the most significant set bit position from.
*
* Returns     : The highest order bit position that is set in reg_val.
*
* Note        : THIS FUNCTION WILL RETURN 0 (bit 0) IF REG_VAL = 0, AND IF REG_VAL = 1.
*               Be sure to call this function only if reg_val is > 0 to obtain the correct result.
*********************************************************************************************************
*/

static  INT8U BSP_Get_HighOrderBit (INT32U  reg_val)
{
    INT8U  bit;


    if (reg_val > 65535) {
        if (reg_val > 0xFFFFFF) {
            bit = BSP_BitIxTbl[reg_val >> 24] + 24;
        } else {
            bit = BSP_BitIxTbl[(reg_val >> 16) & 0xFF] + 16;
        }
    } else {
        if (reg_val > 255) {
            bit = BSP_BitIxTbl[(reg_val >> 8) & 0xFF] + 8;
        } else {
            bit = BSP_BitIxTbl[reg_val & 0xFF];
        }
    }

    return (bit);
}

/*
*********************************************************************************************************
*                                         BSP INITIALIZATION
*
* Description : This function should be called by your application code before you make use of any of the
*               functions found in this module.
*
* Arguments   : none
*********************************************************************************************************
*/

void  LED_Init (void)
{
    PIO_DIR_SET           =  (LED_1 | LED_2);                               /* Configure LED pins for output                        */
    LED_Off(0);                                                             /* Turn OFF all the LEDs                                */
}

/*
*********************************************************************************************************
*                                             LED ON
*
* Description : This function is used to control any or all the LEDs on the board.
*
* Arguments   : led    is the number of the LED to control
*                      0    indicates that you want ALL the LEDs to be ON
*                      1    turns ON LED1  on the board
*                      2    turns ON LED2  on the board
*********************************************************************************************************
*/

void  LED_On (INT8U led)
{
    switch (led) {
        case 0:
             PIO_OUTP_CLR  = LED_1;                                         /* Turn on LED 1                                        */
             PIO_OUTP_CLR  = LED_2;                                         /* Turn on LED 2                                        */
             break;

        case 1:
             PIO_OUTP_CLR  = LED_1;                                         /* Turn on LED 1                                        */
             break;

        case 2:
             PIO_OUTP_CLR  = LED_2;                                         /* Turn on LED 2                                        */
             break;
    }
}

/*
*********************************************************************************************************
*                                             LED OFF
*
* Description : This function is used to control any or all the LEDs on the board.
*
* Arguments   : led    is the number of the LED to turn OFF
*                      0    indicates that you want ALL the LEDs to be OFF
*                      1    turns OFF LED1  on the board
*                      2    turns OFF LED2  on the board
*********************************************************************************************************
*/

void  LED_Off (INT8U led)
{
    switch (led) {
        case 0:
             PIO_OUTP_SET  = LED_1;                                         /* Turn off LED 1                                       */
             PIO_OUTP_SET  = LED_2;                                         /* Turn off LED 2                                       */
             break;

        case 1:
             PIO_OUTP_SET  = LED_1;                                         /* Turn off LED 1                                       */
             break;

        case 2:
             PIO_OUTP_SET  = LED_2;                                         /* Turn off LED 2                                       */
             break;
    }
}

/*
*********************************************************************************************************
*                                             LED TOGGLE
*
* Description : This function is used to toggle any or all the LEDs on the board.
*
* Arguments   : led    is the number of the LED to control
*                      0    indicates that you want to toggle ALL the LEDs
*                      1    toggles LED1  on the board
*                      2    toggles LED2  on the board
*********************************************************************************************************
*/

void  LED_Toggle (INT8U led)
{
    INT32U  status;


    status                 =  PIO_OUTP_STATE & (LED_1 | LED_2);             /* Get the current LED status                           */

    switch (led) {
        case 0:
             status       ^=  (LED_1 | LED_2);                              /* Toggle the bits for LED_1 and LED_2                  */
             PIO_OUTP_SET  =   status;                                      /* If the LEDs are on, turn them off by setting bits    */
             PIO_OUTP_CLR  = (~status & (LED_1 | LED_2));                   /* If the LEDs are off, turn them on by clearing bits   */
             break;

        case 1:
             status       ^=  (LED_1);                                      /* Toggle the bit for LED_1                             */
             PIO_OUTP_SET  =   status;                                      /* If the LED is on, turn it off by setting the bit     */
             PIO_OUTP_CLR  = (~status & LED_1);                             /* If the LED is off, turn it on by clearing the bit    */
             break;

        case 2:
             status       ^=  (LED_2);                                      /* Toggle the bit for LED_2                             */
             PIO_OUTP_SET  =   status;                                      /* If the LED is on, turn it off by setting the bit     */
             PIO_OUTP_CLR  = (~status & LED_2);                             /* If the LED is off, turn it on by clearing the bit    */
             break;
    }
}

/*
*********************************************************************************************************
*                                     INITIALIZE TIMER FOR uC/OS-View
*
* Description : This function is called to by uC/OS-View to initialize the free running timer that is
*               used to make time measurements.
*
* Arguments   : none
*
* Returns     ; none
*
* Note(s)     : This function is EMPTY because the timer is initialized elsewhere.
*********************************************************************************************************
*/

#if OS_VIEW_MODULE > 0
void  OSView_TmrInit (void)
{
}
#endif

/*
*********************************************************************************************************
*                                     READ TIMER FOR uC/OS-View
*
* Description : This function is called to read the current counts of a 32 bit free running timer.
*
* Arguments   : none
*
* Returns     : The 32 bit counts of the timer assuming the timer (MUST be an UP counter).
*********************************************************************************************************
*/

#if OS_VIEW_MODULE > 0
INT32U  OSView_TmrRd (void)
{
    if (OSRunning == TRUE) {
        return ((INT32U)HSTIM_COUNTER);
    } else {
        return (0);
    }
}
#endif

/*
*********************************************************************************************************
*                                       TICKER INITIALIZATION
*
* Description : This function is called to initialize uC/OS-II's tick source (typically a timer generating
*               interrupts every 1 to 100 mS).
*
* Arguments   : none
*
* Note(s)     : 1) The timer is setup for output compare and is allowed to free-run from 0x00000000
*                  to 0xFFFFFFFF. This mode of operation is ideal for making accurate time measurements
*                  in the OS Statistics task and OS-View.
*
*               2) The High Speed Timer clock MUST be enabled before any HST register reads or writes
*
*               3) The High Speed Timer clock is the 'Peripheral Clock'
*********************************************************************************************************
*/

static  void  Tmr_TickInit (void)
{
    INT32U  peripheral_clk_frq;


    TIMCLK_CTRL           |=  (1 << 1);                                     /* Enable the High Speed Timer Clock                    */
    HSTIM_CTRL            &= ~(1 << 0);                                     /* Stop the Timer                                       */
    HSTIM_CTRL            |=  (1 << 1);                                     /* Set the Timer Reset bit (set counter to 0x00000000   */
    HSTIM_CTRL            &= ~(1 << 1);                                     /* Clear the Reset bit (software must release reset)    */


    BSP_IntEn(BSP_MAIN_INT_CTL, 5, BSP_INT_HIGH_LEVEL,                      /* Configure the Interrupt Handler for Timer Int's      */
              BSP_INT_LEVEL_SENSITIVE, Tmr_TickISR_Handler);                /* Interrupt is part of the Main Int. Controller (0)    */
                                                                            /* The interrupt source is bit 5                        */
                                                                            /* the interrupt handler is Tmr_TickISR_Handler()       */

    peripheral_clk_frq     =   BSP_ClkFrqPeripheral();                      /* Get the Peripheral operating frequency               */

    Tmr_ReloadCnts         =  (peripheral_clk_frq / OS_TICKS_PER_SEC) - 1;  /* Determine the number of timer ticks necessary in     */
                                                                            /* order to achieve a tick rate of OS_TICKS_PER_SEC     */
#if BSP_OS_TMR_SEL == 0
    HSTIM_MATCH0           =   Tmr_ReloadCnts;                              /* Set the match compare value if using match reg. 0    */
    HSTIM_INT             |=  (1 << 0);                                     /* Clear the match interrupt for match register 0       */
    HSTIM_MCTRL           |=  (1 << 0);                                     /* Enable Interrupt generation for Match Register  0    */
#endif

#if BSP_OS_TMR_SEL == 1
    HSTIM_MATCH1           =   Tmr_ReloadCnts;                              /* Set the match compare value if using match reg. 1    */
    HSTIM_INT             |=  (1 << 1);                                     /* Clear the match interrupt for match register 1       */
    HSTIM_MCTRL           |=  (1 << 3);                                     /* Enable Interrupt generation for Match Register  1    */
#endif

#if BSP_OS_TMR_SEL == 2
    HSTIM_MATCH2           =   Tmr_ReloadCnts;                              /* Set the match compare value if using match reg. 2    */
    HSTIM_INT             |=  (1 << 2);                                     /* Clear the match interrupt for match register 2       */
    HSTIM_MCTRL           |=  (1 << 6);                                     /* Enale Interrupt generation for Match Register  2     */
#endif

    HSTIM_PCOUNT           =   0;                                           /* Set the Timer Prescaler to 0                         */
    HSTIM_CTRL            |=  (1 << 2);                                     /* Timer stops when the CPU is in debug mode            */
    HSTIM_CTRL            |=  (1 << 0);                                     /* Start the Timer                                      */
}


/*
*********************************************************************************************************
*                                         TIMER #0 IRQ HANDLER
*
* Description : This function handles the timer interrupt that is used to generate TICKs for uC/OS-II.
*
* Arguments   : none
*
* Note(s)     : 1) The timer is 'reloaded' with the count at compare + the time for the next interrupt.
*                  Since we are using 'unsigned' integer math, overflows are irrelevant.
*
*               2) Updating the Match Compare Register MUST be done before clearing the interrupt.
*********************************************************************************************************
*/

void  Tmr_TickISR_Handler (void)
{
#if BSP_OS_TMR_SEL == 0
    HSTIM_MATCH0          +=   Tmr_ReloadCnts;                              /* Update the match register w/ the next compare value  */
    HSTIM_INT             |=  (1 << 0);                                     /* Clear the match interrupt for match register 0       */
#endif

#if BSP_OS_TMR_SEL == 1
    HSTIM_MATCH1          +=   Tmr_ReloadCnts;                              /* Update the match register w/ the next compare value  */
    HSTIM_INT             |=  (1 << 1);                                     /* Clear the match interrupt for match register 1       */
#endif

#if BSP_OS_TMR_SEL == 2
    HSTIM_MATCH2          +=   Tmr_ReloadCnts;                              /* Update the match register w/ the next compare value  */
    HSTIM_INT             |=  (1 << 2);                                     /* Clear the match interrupt for match register 2       */
#endif

    OSTimeTick();                                                           /* Call uC/OS-II's OSTimeTick()                         */
}


