This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Hibernation and Tamper

Other Parts Discussed in Thread: TM4C1292NCPDT, TM4C129XNCZAD

Hello,


using the TM4C1292 (NCPDT), I have a problem with the hibernation module. I configured it to wake up when a tamper event is asserted. The processor performs a wake-up (I can see that from the LED I connected to the processor's HIB output) but there is no code executed. Even if I delete the while(1) commands in the NmiSR(), FaultISR() and IntDefaultHandler() handlers.

Seems like the __iar_program_start() is not called...

If I try to reset the processor, it doesn't work. Only disconnecting the power supply works.

  • Hello Daniel,

    When the tamper event is asserted till the source of the event is not cleared, the CPU will try to execute the NMI interrupt handler. Removing the while(1) will only cause the processor to exit and re-enter the NMI Handler. You have to clear the cause of the NMI as well and the corresponding status bits in Hibernate module

    Regards

    Amit

  • A good illustration of the dangers of an NMI

    Robert

     

    Although, to be fair, this can happen with level triggered interrupts as well if you are not careful.

  • Robert Adsett said:
    A good illustration of the dangers of an NMI

    Monsieur - you are in danger of being as "anal" as cb1!   (and - of course - you are correct, Sir!)  (poor Amit)

  • It helps that I've had to deal with the consequences of having an NMI wired to a limit input.

    Once bitten, twice shy.

    Robert

  • Robert Adsett said:
    Once bitten, twice shy.

    True - but might there be bit more to, "this story?"  (i.e. especially, unhighlighted, "PF0/PD7 - locked to NMI" issue)

    "NMI" to too many here - is essentially meaningless!  (they'd never relate that to PF0/PD7 - those two are their issue!)

    Cb1 corollary: "Multiply bitten may suggest inadequate/improper warning and/or correction strategy."  A well thought strategy - improperly/ineffectively, "roadmarked" may induce ongoing such, "bites!"  (i.e. many "PF0/PD7 corpses" piled/heaped at foot of famed, (yet badly marked, Mount NMI...)

  • Yes, it worked! Thanks for your help!

    The problem with the SW achitecture is, that my NMI_Handler() will be regitered in the main() function. So I had to call my NMI_Handler() during the TivaWare default NmiSR(). ;)

    Next question: Now, there is no Tamper Event asserted, why?

  • Hello Daniel,

    Are you checking the HIBTPLOG registers?

    Regards

    Amit

  • Hi Amit.

    Yes, by using the HibernateTamperEventsGet() api, witch is called in my NMI_Handler(). If that function returns a non-zero value a struct, containing the tamper event cause and the time stamp, is placed in a ring buffer. Main programm checks if there is data in the ring buffer and makes some UART debug output.

    Regards

    Daniel

  • Hello Daniel,

    So is it returning a non-zero value when the tamper condition causes the device to wakeup?

    Regards

    Amit

  • Hi,

    It would be useful to tell us if and how did you initialized the RTC and its mode - if in calendar mode there is a small bug in processing the calendar data.

    Petrei

  • Hi Amit, hi Petrei.

    Yes, the api returns true if there was a tamper event. Currently I don't use the calendar mode...
    Can you tell me about the bug or is it documented in the TivaWare driver library user's guide?
    Could be useful information.... ;)

    Note that I check the Hibernation's active state before calling Bi_HibernationInit() so the tamper ring buffer and the tamper events register schoould not be cleared after a wake-up condition.

    Here's my configuration:

    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationInit
    *
    * \brief    Initialize hibernation module.
    *
    * Enable external 32,768 Hz crystal, enable real time clock (RTC) and set
    * it to 0 (using HIBERNATE_COUNTER_RTC from Bi_Hibernation.h).
    * The tamper module is also enabled, therefore it is neccessary to register
    * the NMI_Handler() by calling Bi_SysCtlInit(). Otherwise the standard NmiSR()
    * from startup_ewarm.c loops the CPU for ever, when a tamper event occures.
    * Other interrupts from this processor module are handled by
    * ISR_Hibernation(). If you don't want to have these events handled by
    * interrupts (or the NMI), set the \e IntEnable parameter to \e false. \n
    * Following wake conditions are enabled by this function:
    *   - Wake pin asserted
    *   - RTC match asserted
    *   - Low battery detected
    *   - RST pin asserted (currently deactivated for battery test)
    *
    * \param    TamperEnable    determines if tamper events are enabled.
    *
    * \return   void
    *
    * \pre      This module uses Bi_RingBuf and Bi_Timer fcuntionality.
    *           Bi_TimerInit() must be called before using Bi_HibernationInit().
    *           For managing Tamper events a ring buffer is used. Therefore
    *           Bi_RingBuf.c has to be included.
    *
    * \note     Bi_HibernationInit() must not be called after a wake-up
    *           condition witch can be determined by calling the
    *           Bi_HibernationGetWakeStatus() function.
    *
    * \warning  This function needs to wait for approximately 1.5 s until the
    *           external 32,768 Hz crystal stabilizes. This wait time is
    *           determined by using the ::Timer_base software timer. Additional
    *           waits are not neccessary!
    *
    ****************************************************************************/
    void Bi_HibernationInit(const bool TamperEnable)
    {
        U32 Wait;
        U32 TimeBase;
        U32 ClkFreq = Bi_SysCtlGetClkFreq();
        
        TamperEvent TamperDummy;
        
        SysCtlPeripheralPowerOn(SYSCTL_PERIPH_HIBERNATE);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
        
        while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE)) );
        
        if ( HibernateIsActive() == 0 )
        {
            // Make a dummy write to HIBCTL Register due to HIB#19 (see Errata)
            HibernateRTCDisable();
            
            // Power on and activate clock gating ---------------
            SysCtlPeripheralPowerOn(SYSCTL_PERIPH_GPIOM);
            SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
            // --------------------------------------------------
            
            // Wait for peripherals to be ready
            while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) & 
                      SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOM)) );
            
            // Enable external 32.768 kHz crystal and wait for it to stabalize
            TimeBase = (U32)( (float)TimerLoadGet(TIMER1_BASE, TIMER_A) / (float)(1e-6*ClkFreq) );
            Wait = Bi_TimerGetVal(Timer_base);
            HibernateEnableExpClk(ClkFreq);    
            while( Bi_TimerGetVal(Timer_base) < (Wait+(HIB_WAIT*TimeBase)) );
            // note: max. 1500ms for stabilization (refer to Datasheet p. 1772)
            
            // Make clock configuration
            HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE); // Use external crystal
            
            // Enable and set default time to real time clock
            HibernateRTCEnable();
            HibernateCounterMode(HIBERNATE_COUNTER_RTC);
            HibernateRTCSet(RTC_DEFAULT);
            
            // Configure wake conditions
            HibernateWakeSet(HIBERNATE_WAKE_PIN        |    // wake pin asserted
                             HIBERNATE_WAKE_RTC        |    // RTC match asserted
                             HIBERNATE_WAKE_LOW_BAT /* |    // low battery detected
                             HIBERNATE_WAKE_RESET   */ );   // RST pin asserted
            
            // Set the low battery interrupt to 2.5V
            HibernateLowBatSet(HIBERNATE_LOW_BAT_DETECT | HIBERNATE_LOW_BAT_2_5V);
            
            if (TamperEnable)
            {
                
                // Initialize tamper function and the corresponding GPIO (PM6)
                HibernateTamperIOEnable(HIB_TAMPER_IO,                          // Use TMPR1 input (PM6)
                                        HIBERNATE_TAMPER_IO_MATCH_SHORT     |   // Trigger matches after 2 hib clocks
                                        HIBERNATE_TAMPER_IO_WPU_DISABLED    |   // Weak pull up is disabled
                                        HIBERNATE_TAMPER_IO_TRIGGER_LOW     );  // Tamper event is active low
                HibernateTamperEventsConfig(HIBERNATE_TAMPER_EVENTS_HIB_WAKE);  // Wake up after tamper event
                HibernateTamperEnable();
                // note: After calling TamperEnable() HIBCTL Register is locked and cannot be modified.
                //       all tamper events will be handled by the NMI_Handler() in Bi_SysCtl.c.
                
                // Clear tamper events and tamper ring buffer.
                HibernateTamperEventsClear();
                while( Bi_RingBufGet(&TamperBuf, &TamperDummy) );
            }
            
            // Enable interrupt and register interrupt handler
            HibernateIntEnable(HIBERNATE_INT_PIN_WAKE       |
                               HIBERNATE_INT_LOW_BAT        |
                               HIBERNATE_INT_RTC_MATCH_0    |
                               HIBERNATE_INT_VDDFAIL        |
                               HIBERNATE_INT_RESET_WAKE     );
            HibernateIntClear(HIBERNATE_INT_PIN_WAKE        |
                              HIBERNATE_INT_LOW_BAT         |
                              HIBERNATE_INT_RTC_MATCH_0     |
                              HIBERNATE_INT_VDDFAIL         |
                              HIBERNATE_INT_RESET_WAKE      );
            
            // Interrupt Handler is also registered in Bi_HibernationGetWakeStatus() function
            HibernateIntRegister(ISR_Hibernation);
        }
    }

  • Hi,

    As I can see from your code, you configured for counter mode so not to warry (or at least must be checked - returning a value other than zero would be OK)

    As for bug is in calendar processing - file hibernate.c

    - line 1538: remove the "-100"  (_HibernateCalendarSet() function)

    - line 1707: modify "+100" to "+2000" (HibernateCalendarGet() function)

    (And when programming set the year as 2014-2000).

    In this expression: HibernateRTCSet(RTC_DEFAULT) what is the value of RTC_DEFAULT? is this returned back when you read it?

    Petrei

    EDIT: please review also Errata#13 - Tamper events may be missed in log - check if it is your case

  • Hello Petrei,
    RTC_DEFAULT is 0 and works perfectly. RTC is intitialized and keeps on counting as long I don't cut the power supply. In the latter case the hibernation module is not active at programm start and thus (re-) initialized.

    HIB#13 Errata does not match my case. Tamper events are always set to the ring buffer and cleard in the NMI_Handler(), immediately. It is not possible to trigger multible tamper events because it is done by pressing a button. The tamper IO filter configuration has no effect on the observed behavior.


    Regards

    Daniel

  • Hello Daniel,

    For Tamper mode the Hibernate module needs to be in VDD3ON Mode. However I do not see in the code that the VDD3ON bit in the HIBCTL is being set?

    Regards

    Amit

  • VDD3ON mode is enabled automatically during HibernateWakeSet() api, when either the WAKE pin or the RESET pin are wake-up sources.

    Regards

    Daniel

  • Hello Daniel,

    In the code post the HibernateWakeSet does not have RESET nor GPIO wakeup set.

    Please note that the GPIO wakeup is different from WAKE pin.

    Regards

    Amit

  • I see, but the VDD3ON bit is set anyway. I just checked it. Any idea why there is no tamper event set to the harware buffer when waking up by a tamper event?

  • Hello Daniel,

    Let me spin a simple test code for Hibernate Tamper for TM4C1292NCPDT, which we can use to debug the issue of tamper not being logged (as I do not have access to the full code you are using).

    Will get back in a day or two.

    Regards

    Amit

  • Hi Amit,

    i can proviede more code if you like! I attached the SysCtl module (with the NMI_Handler() and the ring buffer, witch is used to store tamper events. Also the timer module witch is used to poll for the 1.5s time to stabalize the external 32.768 kHz crystal.

    /** \file
    ****************************************************************************
                                                                                   
    \b      Siemens AG  Electronic Design										/n
                                                                                   
    ****************************************************************************
                                                                                   
            This document is the property of Siemens AG Electronic Design and      
            Manufacturing Services, Hannover.                                      
            Confidential, for internal use only. It may not be reproduced,         
            disclosed, or distributed outside Siemens or outside its business      
            partner and its subsidiaries as well without written authorisation.    
            Any unauthorised reproduction, disclosure, or distribution of          
            copies by any person of any portion of this document may be a          
            violation of the copyright law and may result in further civil and     
            criminal penalties. All rights reserved.                               
            COPYRIGHT     Siemens AG Electronic Design and Manufacturing Services  
                          2008                                                     
                                                                                   
    ****************************************************************************
                                                                                   
    \b      Project:	D2 CM4 Snowflake										\n
                                                                             
    \b      Module:		IBS Software											\n
    \b      Origin:																\n
    \b      Editor:		Daniel Schweizer										\n
    \b      Department: I IA CE SE R&D ED										\n
                                                                                  
    \b      Identification:	A5E32344507											\n
                                                                                   
    ****************************************************************************
                                                                                   
    \brief	Hibernation, battery, real time clock (RTC) and tamper
                                                                                   
    ****************************************************************************
                                                                                   
    \note   History                                                             \n
            
    Version | Date       | Comment
    ------- | ---------- | --------------------
    v1.0    | 06.06.2014 | created file
    v1.1    | 17.06.2014 | Bi_SysCtlGetClkFreq() use added
    v1.2    | 30.06.2014 | fixed doxygen errors, added some comments
    v1.3    | 03.07.2014 | fixed Bi_HibernationGetTamperEvent()
    v1.4    | 04.07.2014 | changed ISR_Hibernation(), Bi_HibernationInit() and Bi_HibernationGetWakeStatus()
    v1.5    | 08.07.2014 | deleted diagnostig UART output
                                                                                   
    ***************************************************************************/
    
    // modul definitions
    
    
    // include files --------------------------------------------------------------
    
    // Type definitions ------------
    #include "Typedef.h"
    #include "stdint.h"
    #include "stdbool.h"
    
    // Modules ---------------------
    #include "Bi_SysCtl.h"
    #include "Bi_Timer.h"
    #include "Bi_Hibernation.h"
    #include "Bi_RingBuf.h"
    
    // Libaries --------------------
    #include <string.h>
    #include <stdio.h>
    #include <time.h>
    #include "inc\hw_memmap.h"
    #include "driverlib\sysctl.h"
    #include "driverlib\timer.h"
    #include "driverlib\hibernate.h"
    
    #ifdef HIB_WORKAROUND
    #include "inc\hw_types.h"
    #include "inc\hw_hibernate.h"
    #endif
    
    // -------------------------------------------------------------------------
    
    // modul global variables and type definitions.
    
    /**
    ****************************************************************************
    * \var      extern RingBuf TamperBuf
    *//*
    * This is a extern declared variable from Bi_SysCtl.c. Pleas refer to that
    * file for further information.
    *
    ***************************************************************************/
    extern RingBuf TamperBuf;
    
    /*~
    section: local functions and definitions
    ~*/
    
    
    /*~
    section: Interrupts
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    ISR_Hibernation
    *
    * \brief    Hibernation interrupt handler.
    *
    * This function simply gets the interrupt status, clears pending interrupts.
    * The interrupt handle will allways be called, when one of the wake sources
    * is asserted. Even if this has not caued a wake-up.
    * - Wake from WAKE pin
    * - Wake from low battery
    * - Wake from RTC match
    * - Wake from supply failure
    * - Wake from RST pin
    *
    * \return   void
    *
    * \note     Due to the processor's errata sheet there is a problem clearing
    *           the VDDFAIL interrupt (HIB#15). To fix this the workaround sets
    *           a reserved bit in the Hibernation Interrupt Clear Register (HIBIC).
    *
    * \warning  This function loops for ever to preserve CPU status if there
    *           was an unexpected interrupt.
    *
    ****************************************************************************/
    void ISR_Hibernation()
    {
        // Get interrupt status and clear all pending interrupts
        U32 IntStatus = HibernateIntStatus(true);
        HibernateIntClear(IntStatus);
    
        if ( IntStatus & HIBERNATE_INT_PIN_WAKE )            // Wake from pin interrupt
        {
            
        }
        else if ( IntStatus & HIBERNATE_INT_LOW_BAT )        // Wake from low battery
        {
            
        }
        else if ( IntStatus & HIBERNATE_INT_RTC_MATCH_0 )    // Wake from RTC match
        {
    
        }
        else if ( IntStatus & HIBERNATE_INT_VDDFAIL )        // Wake from supply failure
        {
    #ifdef HIB_WORKAROUND
            // Set a reserved bit and the VDDFAIL bit to clear the interrupt.
            HWREG(HIB_IC) |= (HIBERNATE_INT_VDDFAIL|0x02);
            // Please refer to the processor's errata sheet HIB#13 for further
            // information.
    #endif        
        }
        else if ( IntStatus & HIBERNATE_INT_RESET_WAKE )     // Wake from RST pin
        {
            
        }
        else     // Unexpected interrupt
        {
           while(1);
        }
    }
    
    /*~
    section: body functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationInit
    *
    * \brief    Initialize hibernation module.
    *
    * Enable external 32,768 Hz crystal, enable real time clock (RTC) and set
    * it to 0 (using HIBERNATE_COUNTER_RTC from Bi_Hibernation.h).
    * The tamper module is also enabled, therefore it is neccessary to register
    * the NMI_Handler() by calling Bi_SysCtlInit(). Otherwise the standard NmiSR()
    * from startup_ewarm.c loops the CPU for ever, when a tamper event occures.
    * Other interrupts from this processor module are handled by
    * ISR_Hibernation(). If you don't want to have these events handled by
    * interrupts (or the NMI), set the \e IntEnable parameter to \e false. \n
    * Following wake conditions are enabled by this function:
    *   - Wake pin asserted
    *   - RTC match asserted
    *   - Low battery detected
    *   - RST pin asserted (currently deactivated for battery test)
    *
    * \param    TamperEnable    determines if tamper events are enabled.
    *
    * \return   void
    *
    * \pre      This module uses Bi_RingBuf and Bi_Timer fcuntionality.
    *           Bi_TimerInit() must be called before using Bi_HibernationInit().
    *           For managing Tamper events a ring buffer is used. Therefore
    *           Bi_RingBuf.c has to be included.
    *
    * \note     Bi_HibernationInit() must not be called after a wake-up
    *           condition witch can be determined by calling the
    *           Bi_HibernationGetWakeStatus() function.
    *
    * \warning  This function needs to wait for approximately 1.5 s until the
    *           external 32,768 Hz crystal stabilizes. This wait time is
    *           determined by using the ::Timer_base software timer. Additional
    *           waits are not neccessary!
    *
    ****************************************************************************/
    void Bi_HibernationInit(const bool TamperEnable)
    {
        U32 Wait;
        U32 TimeBase;
        U32 ClkFreq = Bi_SysCtlGetClkFreq();
        tm  InitTime;
        
        TamperEvent TamperDummy;
        
        SysCtlPeripheralPowerOn(SYSCTL_PERIPH_HIBERNATE);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
        
        while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE)) );
        
        if ( HibernateIsActive() == 0 )
        {
            // Make a dummy write to HIBCTL Register due to HIB#19 (see Errata)
            HibernateRTCDisable();
            
            // Power on and activate clock gating ---------------
            SysCtlPeripheralPowerOn(SYSCTL_PERIPH_GPIOM);
            SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
            // --------------------------------------------------
            
            // Wait for peripherals to be ready
            while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) & 
                      SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOM)) );
            
            // Enable external 32.768 kHz crystal and wait for it to stabalize
            TimeBase = (U32)( (float)TimerLoadGet(TIMER1_BASE, TIMER_A) / (float)(1e-6*ClkFreq) );
            Wait = Bi_TimerGetVal(Timer_base);
            HibernateEnableExpClk(ClkFreq);    
            while( Bi_TimerGetVal(Timer_base) < (Wait+(HIB_WAIT*TimeBase)) );
            // note: max. 1500ms for stabilization (refer to Datasheet p. 1772)
            
            // Make clock configuration
            HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE); // Use external crystal
            
            // Enable and set default time to real time clock
            HibernateRTCEnable();
            HibernateCounterMode(HIBERNATE_COUNTER_24HR);
            HibernateRTCSet(RTC_DEFAULT);
            
            // Configure wake conditions
            HibernateWakeSet(HIBERNATE_WAKE_PIN        |    // wake pin asserted
                             HIBERNATE_WAKE_RTC        |    // RTC match asserted
                             HIBERNATE_WAKE_LOW_BAT /* |    // low battery detected
                             HIBERNATE_WAKE_RESET   */ );   // RST pin asserted
            
            // Set the low battery interrupt to 2.5V
            HibernateLowBatSet(HIBERNATE_LOW_BAT_DETECT | HIBERNATE_LOW_BAT_2_5V);
            
            if (TamperEnable)
            {
                
                // Initialize tamper function and the corresponding GPIO (PM6)
                HibernateTamperIOEnable(HIB_TAMPER_IO,                          // Use TMPR1 input (PM6)
                                        HIBERNATE_TAMPER_IO_MATCH_LONG      |   // Trigger matches after 2 hib clocks
                                        HIBERNATE_TAMPER_IO_WPU_DISABLED    |   // Weak pull up is disabled
                                        HIBERNATE_TAMPER_IO_TRIGGER_LOW     );  // Tamper event is active low
                HibernateTamperEventsConfig(HIBERNATE_TAMPER_EVENTS_HIB_WAKE);  // Wake up after tamper event
                HibernateTamperEnable();
                // note: After calling TamperEnable() HIBCTL Register is locked and cannot be modified.
                //       all tamper events will be handled by the NMI_Handler() in Bi_SysCtl.c.
                
                // Clear tamper events and tamper ring buffer.
                HibernateTamperEventsClear();
                while( Bi_RingBufGet(&TamperBuf, &TamperDummy) );
            }
            
            // Enable interrupt and register interrupt handler
            HibernateIntEnable(HIBERNATE_INT_PIN_WAKE       |
                               HIBERNATE_INT_LOW_BAT        |
                               HIBERNATE_INT_RTC_MATCH_0    |
                               HIBERNATE_INT_VDDFAIL        |
                               HIBERNATE_INT_RESET_WAKE     );
            HibernateIntClear(HIBERNATE_INT_PIN_WAKE        |
                              HIBERNATE_INT_LOW_BAT         |
                              HIBERNATE_INT_RTC_MATCH_0     |
                              HIBERNATE_INT_VDDFAIL         |
                              HIBERNATE_INT_RESET_WAKE      );
            
            // Interrupt Handler is also registered in Bi_HibernationGetWakeStatus() function
            HibernateIntRegister(ISR_Hibernation);
        }
    }
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationCyc
    *
    * \brief    Cyclic hibernation function.
    *
    * \return   void
    *
    * \remark   Does nothing.
    *
    ****************************************************************************/
    void Bi_HibernationCyc()
    {
        // Does nothing
    }
    
    
    /*~
    section: I/O functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationGetWakeStatus
    *
    * \brief    Determine if CPU was waked up from sleep or not.
    *
    * To determine the reason for the power on reset (POR) this function checks
    * the status of the hibernation module and the reset cause register by
    * calling SysCtlResetCauseGet(). The Bi_HibernationInit() function must not
    * be called after a wake-up condition, so check the status with this function. \n
    * If the interrupt mode is enabled the ISR_Hibernation() handler will be
    * registered and thus called if there are interrupts pending. Otherwise, when
    * hibernation interrupts are disabled, the raw interrupt status register will
    * be cleared after saving its value for returning it.
    *
    * \param    ClearResetCause determines if the reset cause register schould
    *                           be cleared. Set this parameter to \e true if you
    *                           want to do so.
    *
    * \return   Possible returns are (refer to Bi_Hibernation.h for details):
    * - 0 => hibernation module is not active so no wake-up was asserted
    * - HIB_STATE_ACTIVE      => hibernation module is active so there was a wake-up
    * - HIB_STATE_WAKE_PIN    => WAKE pin asserted
    * - HIB_STATE_WAKE_BAT    => low battery detected
    * - HIB_STATE_WAKE_RTC    => real time clock match asserted
    * - HIB_STATE_WAKE_PWR    => power fail detected
    * - HIB_STATE_WAKE_RST    => RST pin asserted
    *
    * \note     This function is also used in the NMI_Handler() (Bi_SysCtl.c) to
    *           register ISR_Hibernation() but the reset cause register is not
    *           cleared at this point.
    *
    ****************************************************************************/
    U32 Bi_HibernationGetWakeStatus(const bool ClearResetCause)
    {
        U32 WakeStatus = 0;
        U32 ResetCause;
            
        // Need to enable hibernation peripheral first
        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
        while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE)) );
        
        // If hibernation module is active and there was a reset by hibernation or external RST pin...
        if ( HibernateIsActive() /*&& (ResetCause & (SYSCTL_CAUSE_HIB|SYSCTL_CAUSE_EXT))*/ )
        {
            // Get reset cause and clear it
            if (ClearResetCause)
            {
                ResetCause = SysCtlResetCauseGet();
                SysCtlResetCauseClear(ResetCause);
            }
            
            WakeStatus = HibernateIntStatus(false);
            WakeStatus |= HIB_STATE_ACTIVE;
            WakeStatus &= ~(HIBERNATE_INT_WR_COMPLETE);
            
            // Register interrupt handler to service interrupts
            HibernateIntRegister(ISR_Hibernation);
            // Interrupts are disabled: clear pending interrupts and return WakeStatus
        }
        
        return WakeStatus;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationSleep
    *
    * \brief    Set CPU to hibernation mode.
    *
    * This function requests a hibernation. CPU will proceed working until
    * it is possible to hibernate. To make shure that CPU does not execute any
    * of your code after the request, set the \e WaitForSleep parameter to
    * \e true.
    *
    * \param   	WaitForSleep    if true function loops until CPU sleeps.
    *
    * \return   void
    *
    * \warning  During hibernation mode all peripherals are disabled except the
    *           hibernation module. A wake-up condition leads to a power on
    *           reset (POR) with all its consequences.
    *
    ****************************************************************************/
    void Bi_HibernationSleep(const bool WaitForSleep)
    {
        // Request hibernation module to power off and wait until that is done
        HibernateRequest();
        
        if (WaitForSleep)
            while(1);
    }
    
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationSaveAndSleep
    *
    * \brief    Save up to 16 words of data and set CPU to hibernation mode
    *           afterwards.
    *
    * The hibernation processor module includes a battery-backed RAM. This may
    * be used for saving the application status or any data you want. The size
    * of this memory is limited to 16 32 bit words.
    *
    * \param   	WaitForSleep    determines if function loops until CPU sleeps.
    *                           Set it to \e true if you want to do so.
    * \param    DataPtr         is the pointer to the data witch will be stored
    *                           in battery-backed RAM.
    * \param    DataLen         is the number of 32 bit words to save in battery-
    *                           backed RAM (max. 16).
    *
    * \return   void
    *
    * \warning  During hibernation mode all peripherals are disabled except the
    *           hibernation module. A wake-up condition leads to a power on
    *           reset (POR) with all its consequences. Therefore any
    *           initializations, except the hibernation module, need to be done
    *           as on any power on reset.
    *
    ****************************************************************************/
    void Bi_HibernationSaveAndSleep(const bool WaitForSleep, U32* DataPtr,
                                    const U32 DataLen)
    {
        U8 NumWords = DataLen;
        
        if ( NumWords > HIB_MEM_LEN)
            NumWords = HIB_MEM_LEN;
        
        // Set data to battery-backed hibernation memory
        HibernateDataSet(DataPtr, NumWords);
        
        // Request hibernation module to power off and wait until that is done
        HibernateRequest();
        
        if (WaitForSleep)
        {
            while(1);
        }
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationAutoWakeUp
    *
    * \brief    Set CPU to wake-up automatically after \e WakeUpTime [s].
    *
    * This functions programs the watchdog timer 0 match register to generate
    * a real timme clock match, witch wakes up the CPU from sleep mode. The
    * wake sources are configured in Bi_HibernationInit().
    *
    * \param   	WakeUpTime  determines in how many seconds CPU should wake-up.
    *
    * \return   void
    *
    ****************************************************************************/
    void Bi_HibernationAutoWakeUp(const U32 WakeUpTime)
    {
        U32 CurrRTCVal = HibernateRTCGet();
        
        HibernateRTCMatchSet(HIB_MATCH_REG, (CurrRTCVal+WakeUpTime) );
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationGetWakeTime
    *
    * \brief    Get the remaining time until auto wake-up will occure.
    *
    * This functions reads the current RTC value and the RTC match register.
    * The remaining time until a RTC match will be returned.
    *
    * \return   Returns the number of seconds until wake-up match will occure.
    *           In case RTC match was in the past a negative value will be
    *           returned.
    *
    ****************************************************************************/
    S32 Bi_HibernationGetWakeTime()
    {
        S32 WakeUpTime = ( HibernateRTCMatchGet(HIB_MATCH_REG) - HibernateRTCGet() );
        
        return WakeUpTime;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationGetSavedData
    *
    * \brief    Get Data from battery-backed RAM.
    *
    * Use this function to get the data from the battery-backed RAM witch was
    * saved using Bi_HibernationSaveAndSleep().
    *
    * \param   	DataPtr determines where the RAM data will be copied to.
    * \param    DataLen is the number of 32 bit words to get from RAM.
    *
    * \return   Returns the number of 32Bit words read from battery-backed RAM.
    *
    * \warning  Maximum is 16 32Bit words.
    *
    ****************************************************************************/
    U32 Bi_HibernationGetSavedData(U32* DataPtr,const U32 DataLen)
    {
        U8 NumWords = DataLen;
        
        if (NumWords > HIB_MEM_LEN)
            NumWords = HIB_MEM_LEN;
        
        // Get data from battery-backed hibernation memory
        HibernateDataGet(DataPtr, NumWords);
        
        return NumWords;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_HibernationGetTamperEvent
    *
    * \brief    Get all tamper events and their time stamps.
    *
    * \param    TamperData  is the pointer to the memory to store the cause of
    *                       the tamper event and its time stamp. Tamper cause
    *                       can be one of the following values:
    *                       - HIB_TAMPER_XOSC_FAIL
    *                       - HIB_TAMPER_EVENT1
    *                       The time stamp's bitfields are defined via HIB_STAMP_*
    *                       in Bi_Hibernation.h.
    * \param    NumEvents   is number of tamper events to get.
    *
    * \return   Returns the number of events stored in \e TamperData.
    *
    * \remark   Only the TAMPER1 is used witch is an GPIO on PM6.
    *
    * \warning  A tamper event causes a NMI witch is handled by NMI_Handler()
    *			(see Bi_SysCtl.h). In that function the tamper data will be
    *           stored in ::TamperBuf witch is a global ring buffer declared in
    *           Bi_SysCtl.c.
    *
    ****************************************************************************/
    U32 Bi_HibernationGetTamperEvent(TamperEvent* TamperData, const U32 NumEvents)
    {
        bool    DataAvail;
        U32     Events = 0;
        
        do 
        {
            DataAvail = Bi_RingBufGet(&TamperBuf, TamperData);
            
            if (DataAvail)
                Events++;
            
        } while( (Events < NumEvents) && DataAvail );
        
        return Events;
    }

    /** \file
    ****************************************************************************
                                                                                   
    \b      Siemens AG  Electronic Design										/n
                                                                                   
    ****************************************************************************
                                                                                   
            This document is the property of Siemens AG Electronic Design and      
            Manufacturing Services, Hannover.                                      
            Confidential, for internal use only. It may not be reproduced,         
            disclosed, or distributed outside Siemens or outside its business      
            partner and its subsidiaries as well without written authorisation.    
            Any unauthorised reproduction, disclosure, or distribution of          
            copies by any person of any portion of this document may be a          
            violation of the copyright law and may result in further civil and     
            criminal penalties. All rights reserved.                               
            COPYRIGHT     Siemens AG Electronic Design and Manufacturing Services  
                          2008                                                     
                                                                                   
    ****************************************************************************
                                                                                   
    \b      Project:	D2 CM4 Snowflake										\n
                                                                             
    \b      Module:		IBS Software											\n
    \b      Origin:																\n
    \b      Editor:		Daniel Schweizer										\n
    \b      Department: I IA CE SE R&D ED										\n
                                                                                  
    \b      Identification:	A5E32344507											\n
                                                                                   
    ****************************************************************************
                                                                                   
    \brief	Ring Buffer for any data tyes.
    
    This module provides the type RingBuf and functions to manage a ring buffer.
    Anyway, the memory to hold the ring buffer data must be provided by the user
    of this module. Use the Bi_RingBufInit() function to set RingBuf pointers
    to your memory region, witch should by managed as a ring buffer.
                                                                                   
    ****************************************************************************
                                                                                   
    \note   History                                                             \n
            
    Version | Date       | Comment
    ------- | ---------- | --------------------
    v1.0	| 27.06.2014 | created file
    v1.1    | 01.07.2014 | added doxygen comments
                                                                           
    ****************************************************************************/
    
    // modul definitions
    
    
    
    
    
    // include files --------------------------------------------------------------
    
    // Type definitions ------------
    #include "Typedef.h"
    #include "stdint.h"
    #include "stdbool.h"
    
    
    // Modules ---------------------
    #include "Bi_RingBuf.h"
    
    
    // Libaries --------------------
    
    // -------------------------------------------------------------------------
    
    
    // modul global variables and type definitions.
    
    
    /*~
    section: local functions and definitions
    ~*/
    /* add a * for doxygen
    ****************************************************************************
    *
    \b Name:    
    *
    * \brief    
    *         
    * \return   void
    *
    
    *
    ****************************************************************************/
    
    
    
    /**
    ****************************************************************************
    *
    \b Name:    PointerEqual
    *
    * \brief    Check if pointers of ring buffer are equal.
    *
    * This function can be used to check if RingBuf::BufIn and RingBuf::BufOut
    * pointers are equal.
    * If they are it is neccessary to move one of them one step backwards. Then
    * the ring buffer is either full or empty, depending witch one was
    * incremeented and therefore equal to the other.
    *
    * \param    Buffer  is a pointer to a RingBuf type (see Bi_RingBuf.h) witch
    *                   holds the data for managing a ring buffer.
    *
    * \return   Returns \e true if RingBuf::BufIn and RingBuf::BufOut pointers of
    *           \e Buffer are equal, otherwise \e false.
    *
    * \remark   This is a local function.
    *
    * \note     Buffer Empty: 	RingBuf::BufOut = RingBuf::BufIn  + 1 \n
    *			Buffer Full:	RingBuf::BufIn	= RingBuf::BufOut + 1
    *
    ****************************************************************************/
    bool PointerEqual(RingBuf *Buffer)
    {
    	bool Ret = false;
    	
    	if (Buffer->BufIn == Buffer->BufOut)
    		Ret = true;
    	
    	return Ret;	
    }
    
    
    /*~
    section: Interrupts
    ~*/
    
    
    
    
    /*~
    section: body functions
    ~*/
    /* add * for doxygen
    ****************************************************************************
    *
    \b Name:    
    *
    * \brief    
    *
    * \param   	
    *
    * \return   
    *
    * \remark   
    *
    ****************************************************************************/
    
    
    
    /*~
    section: I/O functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufInit
    *
    * \brief    Initialize a ring buffer.
    *
    * Use this function to initialize the pointers of \e Buffer, witch is used
    * to manage \e BufData as a ring buffer. You still have to provide this
    * module with a memory region (\e BufData) where the ring buffer data can
    * be stored.
    *
    * \param   	Buffer      is a pointer to a RingBuf type (see Bi_Ringbuf.h)
    *                       witch holds the data for managing a ring buffer.
    * \param	BufData	    is the pointer to the memory region, witch will hold
    *                       the buffer data and be managed as a ring buffer.
    * \param	DataLen     is the length of \e BufData.
    * \param    DataSize    is the size of your datatype of \e BufData.
    *
    * \return   Returns \e true if initialization was succcessful.
    *
    ****************************************************************************/
    bool Bi_RingBufInit(RingBuf *Buffer, void* BufData, const U32 DataLen,
                        const U32 DataSize)
    {
        bool ret = false;
        
        if ( (DataLen >= 3) && (BufData != 0) )
        {
            Buffer->ElementSize = DataSize;
            
            Buffer->BufStart= BufData;
            Buffer->BufEnd 	= (char*)BufData + ((DataLen-1) * Buffer->ElementSize);
            
            Buffer->BufOut	= BufData;
            Buffer->BufIn  	= (char*)BufData + Buffer->ElementSize;
            
            ret = true;
        }
        
        return ret;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufGet
    *
    * \brief    Get a single element from ring buffer.
    *
    * This function reads a single element from the ring buffer determined by
    * \e Buffer. Afterwards this element is clear to be overwirtten by "new" data,
    * witch can by done by calling Bi_RingBufSet() or Bi_RingBufSetAll().
    *
    * \param   	Buffer  is a pointer to a RingBuf type (see Bi_RingBuf.h) witch
    *                   holds the data for managing a ring buffer.
    * \param	DataPtr	is the pointer to the memory to store an element from buffer.
    *
    * \return   Returns \e false if there is no new data ring buffer available.
    *
    ****************************************************************************/
    bool Bi_RingBufGet(RingBuf *Buffer, void* DataPtr)
    {
    	bool    DataAvail = true;
        char*   Data = DataPtr;
        char*   CurrByte;
    	
    	// Increment BufOut for next character
    	Buffer->BufOut = (char*)(Buffer->BufOut) + Buffer->ElementSize;
    	
    	// Check if BufOut pointer needs to be reset
    	if ( Buffer->BufOut > Buffer->BufEnd )
    	{
    		Buffer->BufOut = Buffer->BufStart;
    	}
    	
    	// if pointers are not equal there is something in buffer
    	if ( !PointerEqual(Buffer) )
    	{
            CurrByte = Buffer->BufOut;
            
    		// Get data from ring buffer to DataPtr
    		for (U32 Byte=0; Byte<Buffer->ElementSize; Byte++)
            {
                Data[Byte] = *( CurrByte + Byte );
            }
    	}
    	else
    	{
    		// There was no data to transfer from buffer so decrement BufOut
    		Buffer->BufOut = (char*)Buffer->BufOut - Buffer->ElementSize;
    
    		// Check if BufOut needs to be reset
    		if ( Buffer->BufOut < Buffer->BufStart )
    		{
    			Buffer->BufOut = Buffer->BufEnd;
    		}
    		
    		DataAvail = false;
    	}
    	
    	return DataAvail;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufGetAll
    *
    * \brief    Get all data from a ring buffer.
    *
    * Ring buffer data is copied to \e DataPtr until the buffer is empty or
    * user data array full. By reading from ring buffer this "old" data is clear
    * to be overwritten by "new" data. Use Bi_RingBufSetAll() or
    * Bi_RingBufSetByte() to write data to the buffer.
    *
    * \param   	Buffer  is a pointer to a RingBuf type (see Bi_RingBuf.h) witch
    *                   holds the data for managing a ring buffer.
    * \param	DataPtr	is the pointer to the memory to store buffer data.
    * \param	DataLen	is the number of elements to get from buffer.
    *
    * \return   Returns the number of bytes read from ring buffer.
    *
    ****************************************************************************/
    U32 Bi_RingBufGetAll(RingBuf *Buffer, void* DataPtr, const U32 DataLen)
    {
    	bool    DataAvail;
    	U32     NumElements = 0; // Number of elements transferred to buffer
        char*   Data = DataPtr;
    
        // Transfer data to ring buffer until there is no space or all data has
        // been transferred
        do
        {
            DataAvail = Bi_RingBufGet(Buffer, Data);
            
            if (DataAvail)
            {
                NumElements++;
                Data = Data + Buffer->ElementSize;
            }
            
        }while ( DataAvail && (NumElements < DataLen) );
        
        // Return number of transferred elements
    	return NumElements;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufSet
    *
    * \brief    Set a single byte to a ring buffer.
    *
    * This function writes the single byte \e Data to the ring buffer. \e Buffer
    * only holds the pointers to manage a memory region, witch has to be
    * provieded by user, as a ring buffer. \e Buffer can be initialized by the
    * Bi_RingBufInit() function.
    *
    * \param   	Buffer  is a pointer to a RingBuf type (see Bi_RingBuf.h) witch
    *                   holds the data for managing a ring buffer.
    * \param	DataPtr	is the pointer to the data to write to ring buffer.
    *
    * \return   Returns \e true if \e DataPtr was set to ring buffer successfully.
    *
    ****************************************************************************/
    bool Bi_RingBufSet(RingBuf *Buffer, const void* DataPtr)
    {
    	bool        SpaceAvail = false;
        const char* Data = DataPtr;
        char*       Destination;
    	
    	// Check if ring buffer can hold one more byte
    	if ( !PointerEqual(Buffer) )
    	{
    		// Buffer is not full
    		SpaceAvail = true;
    		
    		// Copy data to ring buffer
    		for (U32 Byte=0; Byte<Buffer->ElementSize; Byte++)
            {
                Destination = (char*)(Buffer->BufIn) + Byte;
                
                *Destination = *(Data + Byte);
            }
    		
    		// Increment BufIn for next byte
    		Buffer->BufIn = (char*)(Buffer->BufIn) + Buffer->ElementSize;
    		
    		// Check if BufIn pointer needs to be reset
    		if ( Buffer->BufIn > Buffer->BufEnd )
    		{
    			Buffer->BufIn = Buffer->BufStart;
    		}
    	}
    	
    	return SpaceAvail;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufSetAll
    *
    * \brief    Set all available data to a ring buffer.
    *
    * This function writes all bytes represented by \e DataPtr to the ring buffer
    * determined by \e Buffer until either this buffer is full or all data has
    * been set. \e Buffer only holds the pointers to manage a memory region,
    * witch has to be provieded by user, as a ring buffer. \e Buffer can be
    * initialized by the Bi_RingBufInit() function.
    *
    * \param   	Buffer  is a pointer to a RingBuf type (see Bi_RingBuf.h) witch
    *                   holds the data for managing a ring buffer.
    * \param	DataPtr	is the pointer to the data to write to ring buffer.
    * \param	DataLen	is the number of elements desired to set to ring buffer.
    *
    * \return   Returns the number of elements set.
    *
    ****************************************************************************/
    U32 Bi_RingBufSetAll(RingBuf *Buffer, const void* DataPtr, const U32 DataLen)
    {
    	bool        bSpaceAvail;
    	U32         NumElements = 0; // Number of elements transferred to  buffer
    	const char* Data = DataPtr;
    	
    	// Transfer data to ring buffer until there is no space or all data has
    	// been transferred
    	do 
    	{
    		bSpaceAvail = Bi_RingBufSet(Buffer, Data);
    		
    		if (bSpaceAvail)
            {
    			NumElements++;
                Data = Data + Buffer->ElementSize;
            }
    		
    	}while ( bSpaceAvail && (NumElements < DataLen) );
    	
    	// Return number of transferred bytes
    	return NumElements;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufElementsInBuffer
    *
    * \brief    Get the number of elements in ring buffer.
    *
    * This functions returns how many elements there are left in the ring buffer.
    * This can also be used to determine how many space there is left by
    * subtracting the number of elements in the buffer from the buffer size. 
    *
    * \param   	Buffer  is a pointer to a RingBuf type (see Bi_Ringbuf.h) witch
    *                   holds the data for managing a ring buffer.
    *
    * \return   Returns the number bytes in ring buffer.
    *
    ****************************************************************************/
    U32 Bi_RingBufElementsInBuffer(RingBuf *Buffer)
    {
        char*   BufOutCpy      = Buffer->BufIn;
        U32     NumElements    = 0;
        
        while (BufOutCpy != Buffer->BufOut)
        {
           BufOutCpy -= Buffer->ElementSize;
            
            // Check if pointer needs to be reset
    		if ( BufOutCpy < Buffer->BufStart )
    		{
    			BufOutCpy = Buffer->BufEnd;
    		}
            
            if ( BufOutCpy != Buffer->BufOut )
                NumElements++;
        }
        
        return NumElements;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_RingBufGetSize
    *
    * \brief    Get the size of a ring buffer.
    *
    * This function returns how many elements of memory are occupied by the ring
    * buffer determined by \e Buffer. But the maximum number of elements, witch can
    * be stored in the ring buffer is 1 element less! The reason is RingBuf::BufIn
    * and RingBuf::BufOut must not be equal.
    *
    * \param   	Buffer      is a pointer to a RingBuf type (see Bi_RingBuf.h)
    *                       witch holds the data for managing a ring buffer.
    * \param    SizeInBytes detemines if the buffer size is returned in bytes.
    *                       Set this parameter to \e false to get how many
    *                       elements can be stored in the ring buffer.
    *
    * \return   Returns how many bytes or elements are occupied by the ring
    *           buffer. The size of an element was determined by the
    *           \e  DataSize parameter of the Bi_RingBufInit() function and
    *           saved in the RingBuf::ElementSize field.
    *
    * \warning  The maximum number of elements, witch can be stored in the ring
    *           buffer is 1 less than returned. The ring buffer needs that to
    *           check if it's full or empty. \n
    *           In case of getting the byte size of the ring buffer, the maximum
    *           number of bytes, witch can be stored in the ring buffer is
    *           1*sizeof(datatype) less than returned.
    *
    ****************************************************************************/
    U32 Bi_RingBufGetSize(RingBuf* Buffer, bool SizeInBytes)
    {
        U32 BufSize = (U32)(Buffer->BufEnd) - (U32)(Buffer->BufStart);
        
        if ( !SizeInBytes )
            BufSize = BufSize / Buffer->ElementSize;
        
        return BufSize;
    }
    
    

    /** \file
    ****************************************************************************
                                                                                   
    \b      Siemens AG  Electronic Design										/n
                                                                                   
    ****************************************************************************
                                                                                   
            This document is the property of Siemens AG Electronic Design and      
            Manufacturing Services, Hannover.                                      
            Confidential, for internal use only. It may not be reproduced,         
            disclosed, or distributed outside Siemens or outside its business      
            partner and its subsidiaries as well without written authorisation.    
            Any unauthorised reproduction, disclosure, or distribution of          
            copies by any person of any portion of this document may be a          
            violation of the copyright law and may result in further civil and     
            criminal penalties. All rights reserved.                               
            COPYRIGHT     Siemens AG Electronic Design and Manufacturing Services  
                          2008                                                     
                                                                                   
    ****************************************************************************
                                                                                   
    \b      Project:	D2 CM4 Snowflake										\n
                                                                             
    \b      Module:		IBS Software											\n
    \b      Origin:																\n
    \b      Editor:		Daniel Schweizer										\n
    \b      Department: I IA CE SE R&D ED										\n
                                                                                  
    \b      Identification:	A5E32344507											\n
                                                                                   
    ****************************************************************************
                                                                                   
    \brief  System control: clock/pll configuration, NMI and master interrupt enable
                                                                                   
    ****************************************************************************
                                                                                   
    \note   History                                                             \n
            
    Version | Date       | Comment
    ------- | ---------- | --------------------
    v1.0	| 23.09.2013 | created file
    v1.1	| 27.03.2014 | doxygen modification, function and variable names changed
    v1.2    | 31.03.2014 | interrupt mask changed because of new driver library
    v1.3    | 12.06.2014 | ISR_SysCtl modified, NMI_Handler added, Bi_SysCtlNMIStatusWorkaround added
    v1.4    | 17.06.2014 | function Bi_SysCtlGetClkFreq() and global variable ::SysCtl_ClockFreq added
    v1.5    | 03.07.2014 | fixed doxygen errors, added some comments
    v1.6    | 04.07.2014 | NMI_Handler() have to call Bi_HibernationGetWakeStatus()
                                                                                   
    ****************************************************************************/
    
    // modul definitions
    
    
    // include files --------------------------------------------------------------
    
    // Type definitions ------------
    #include "Typedef.h"
    #include "stdint.h"
    #include "stdbool.h"
    
    
    // Modules ---------------------
    #include "Bi_SysCtl.h"
    #include "Bi_RingBuf.h"
    #include "Bi_Hibernation.h"
    
    
    // Libaries --------------------
    #include <stdlib.h>
    #include "driverlib\sysctl.h"
    #include "driverlib\interrupt.h"
    #include "driverlib\hibernate.h"
    #include "inc\hw_ints.h"
    
    #ifdef NMI_STATUS_WORKAROUND
    #include "driverlib\gpio.h"
    #include "driverlib\watchdog.h"
    #include "inc\hw_memmap.h"
    #endif
    // -------------------------------------------------------------------------
    
    
    /*~
    section: local functions and definitions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_SysCtlNMIStatusWorkaround
    *
    * \brief    Workaround function for SysCtlNMIStatus().
    *
    * This is a workaround for the SYSCTL#13 issue in processor's revision 1.
    * It is called in the NMI_Handler() if the NMI_STATUS_WORKAROUND symbol is
    * defined and returns the NMI status just like the SysCtlNMIStatus() api.
    * This function gets the NMI status unlike SysCtlNMIStatus() by reading the
    * SysCtl, GPIO, Watchdog and Hibernate raw interrupt status register.
    *
    * \return   Returns the NMIStatus like the SysCtlNMIStatus() api. See the
    *           SYSCTL_NMI_* bit fields defined in sysctl.h.
    *
    * \remark   Refer to errata sheet SYSCTL#13 for details. \n
    *           This is a local function.
    *
    * \pre      The symbol NMI_STATUS_WORKAROUND have to be defined to include
    *           the neccessary headers from the TivaWare driverlibrary.
    *
    * \todo     If a GPIO port is configured for generating a NMI (NMI input),
    *           this port and pin must be added in this function.
    *
    ****************************************************************************/
    U32 Bi_SysCtlNMIStatusWorkaround(void)
    {
        U32 IntStatus;
        U32 NMIStatus = 0;
        
        // Workaround: NMI Status can not be read correctly => refer to errata sheet
    #ifdef NMI_STATUS_WORKAROUND
        
        
        // Check for oszillator or power fail in system control
        IntStatus = SysCtlIntStatus(false);
        SysCtlIntClear(IntStatus&(SYSCTL_INT_MOSC_FAIL|SYSCTL_INT_BOR0|SYSCTL_INT_BOR1));
        
        if (IntStatus & SYSCTL_INT_MOSC_FAIL)
            NMIStatus |= SYSCTL_NMI_MOSCFAIL;
        
        if (IntStatus & (SYSCTL_INT_BOR0|SYSCTL_INT_BOR1))
            NMIStatus |= SYSCTL_NMI_POWER;
        
        /*
        // For NMI Pin interrupt configure GPIO to generate an interrupt!
        // x is the corresponding GPIO port (A-H and J-Q)
        if ( SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOx) )
        {
            IntStatus = GPIOIntStatus(GPIO_PORTx_BASE, false);
            GPIOIntClear(GPIO_PORTx_BASE, IntStatus&Pin);
            
            if (IntStatus & Pin)
                NMIStatus |= SYSCTL_NMI_EXTERNAL;
        }
        */
        
        if ( SysCtlPeripheralReady(SYSCTL_PERIPH_WTIMER0) )
        {
            IntStatus = WatchdogIntStatus(WATCHDOG0_BASE, false);
            WatchdogIntClear(WATCHDOG0_BASE);
            
            if (IntStatus)
                NMIStatus |= SYSCTL_NMI_WDT0;
        }
        
        if ( SysCtlPeripheralReady(SYSCTL_PERIPH_WTIMER1) )
        {
            IntStatus = WatchdogIntStatus(WATCHDOG1_BASE, false);
            WatchdogIntClear(WATCHDOG1_BASE);
            
            if (IntStatus)
                NMIStatus |= SYSCTL_NMI_WDT1;
        }
        
        if ( SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) )
        {
            IntStatus = HibernateTamperStatusGet();
            
            if (IntStatus & HIBERNATE_TAMPER_STATUS_EVENT)
            {
                NMIStatus |= SYSCTL_NMI_TAMPER;
            }
        }
    #endif
        
        
        // Workaround: NMI Status can not be read correctly => refer to errata sheet
    #ifndef NMI_STATUS_WORKAROUND
    
        NMIStatus = SysCtlNMIStatus();
        
    #endif
    
        return NMIStatus;    
    }
    
    
    
    
    // modul global variables and type definitions
    
    /**
    ******************************************************************************
    * \var      U32 SysCtl_ClockFreq
    *
    * \brief    System's clock frequency.
    *
    * Global variable to save clock frequency for other modules. This value is set
    * once by calling the Bi_SysCtlInit() function. Please refer to the TivaWare
    * API function SysCtlClockFreqSet() for further information.
    *
    * \note This workaround was suggested by the TI E2E Forum:
    * <a href="http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/324695/1130206.aspx">Problems with SysCtrlClockGet()</a>
    *
    ***************************************************************************/
    U32 SysCtl_ClockFreq = 0;
    
    
    /**
    ******************************************************************************
    * \var      RingBuf TamperBuf
    *
    * \brief    Global ring buffer to save tamper events.
    *
    * This ring buffer will be set by the non-maskable interrupt handler
    * NMI_Handler() when a tamper event was asserted. This data can be accessed
    * by using Bi_HibernationGetTamperEvent() from Bi_Hibernation.c. The size of
    * this buffer is defined by HIB_TAMPER_BUF in Bi_Hibernation.h.
    *
    * \warning  This variable schould only be accessed by NMI_Handler() and
    *           Bi_HibernationGetTamperEvent(). Do not write on this variable
    *           avoid data corruption.
    *
    ***************************************************************************/
    RingBuf TamperBuf;
    
    
    /*~
    section: Interrupts
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    ISR_SysCtl
    *
    * \brief    System Control interrupt handler.
    *
    * This handler loops for ever if there is a SysCtl interrupt pending to
    * preserve CPU state.
    *         
    * \return   void
    *
    * \remark   See Bi_SysCtlInit() for active SysCtl interrupts.
    *
    ****************************************************************************/
    void ISR_SysCtl(void)
    {
        U32 IntStatus = SysCtlIntStatus(true);
        SysCtlIntClear(IntStatus);
        
        if ( IntStatus & SYSCTL_INT_BOR )           // Bown-out reset
        {
            while(1);
        }
        else if ( IntStatus & SYSCTL_INT_MOSC_PUP ) // Internal oscillator failure
        {
            while(1);
        }
        else if ( IntStatus & SYSCTL_INT_MOSC_FAIL )// Main oscillator failure
        {
            while(1);
        }
        else if ( IntStatus & SYSCTL_INT_PLL_LOCK ) // PLL Lock failure
        {
            while(1);
        }
        else    // Unexpected interrupt
        {
            while(1);
        }
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    NMI_Handler
    *
    * \brief    Non-maskable interrupt handler (NMI).
    *
    * This handler loops for ever if there is a NMI pending to preserve CPU
    * state. In case of a tamper NMI the tamper events are saved into the global
    * ::TamperBuf and cleared afterwards. Tamper data can be accessed by
    * a Bi_HibernationGetTamperEvent() call.
    *         
    * \return   void
    *
    * \pre      In processor revision 1 the NMI_STATUS_WORKAROUND symbol must be
    *           defined in Bi_SysCtl.h.
    *
    * \note     Function may loop for ever in case of an unexpected interrupt to
    *           preserve CPU state.
    *
    * \warning  Due to the SYSCTL#13 issue in processor's revision 1 (see errata
    *           sheet) a workaround for getting the NMI status was implemented.
    *           To use this workaround the NMI_STATUS_WORKAROUND symbol must be
    *           defined in Bi_SysCtl.h. See the Bi_SysCtlNMIStatusWorkaround()
    *           dokumentation for further information.
    *
    ****************************************************************************/
    void NMI_Handler(void)
    {
        U32         NMIStatus;
        bool        NewTamperEvent;
        TamperEvent Tamper;
        
        // Get interrpt status from workaround function. Please refer to errata
        // sheet and the Bi_SysCtlNMIStatusWorkaround() documentation.
        NMIStatus = Bi_SysCtlNMIStatusWorkaround();
        
        // Main oscillator is not present or did not start
        if ( NMIStatus & SYSCTL_NMI_MOSCFAIL )
        {
            while(1);
        }
        // A tamper event has been detected
        else if ( NMIStatus & SYSCTL_NMI_TAMPER )
        {
            // Need to enable hibernation peripheral first
            // (Reset cause register is not cleared, yet.)
            Bi_HibernationGetWakeStatus(false);
            
            // Get tamper event and set it to the ring buffer
            NewTamperEvent = HibernateTamperEventsGet(HIB_TAMPER_INDEX,
                                                      &Tamper.TimeStamp,
                                                      &Tamper.EventCause);
            if (NewTamperEvent)
            {
                Bi_RingBufSet(&TamperBuf, &Tamper);
                
                // Clear tamper events
                HibernateTamperEventsClear();
                // note that tamper event must be cleared before Tamper NMI can be
                // cleared
            }
        }
        // Watchdog 0 generated a non-maskable time-out interrupt
        else if ( NMIStatus & SYSCTL_NMI_WDT0 )
        {
            while(1);
        }
        // Watchdog 1 generated a non-maskable time-out interrupt
        else if ( NMIStatus & SYSCTL_NMI_WDT1 )
        {
            while(1);
        }
        // A power event occurred
        else if ( NMIStatus & SYSCTL_NMI_POWER )
        {
            while(1);
        }
        // An exernal NMI pin has been asserted
        else if ( NMIStatus & SYSCTL_NMI_EXTERNAL )
        {
            while(1);
        }
        // Unexpected interrupt
        else
        {
            while(1);
        }    
        
        // Keep on clearing the NMI status until it's really done!
        // See the processor's datasheet on page 268 (NMI Cause Register
        // descripion)
        do
        {
            SysCtlNMIClear(NMIStatus);
            NMIStatus = Bi_SysCtlNMIStatusWorkaround();
        } while ( NMIStatus != 0);
    }
    
    
    /*~
    section: body functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_SysCtlInit
    *
    * \brief    System control (CPU clock and interrupt) initialization.
    *
    * Initialize CPU clock using the PLL and enable Nested Vectored Interrupt
    * Controller (NVIC). Interrupts are generally enabled, but each interrupt
    * source must be enabled by its XXXIntEnable() function, witch sets the
    * corresponding interrupt mask register. Interrupt handlers are registered in
    * the interrupt vector table, whitch is stored on processor's
    * flash memory (see startup_ewarm.c), by calling the XXXIntRegister()
    * function. \n
    *
    * This is an example from Bi_TimerInit():
    *
    * \code{.c}
    * // Configure Timer1 interrupt.
    * TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    * TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    *
    * // Register interrupt handler.
    * TimerIntRegister(TIMER1_BASE, TIMER_BOTH, ISR_Timer1);
    * \endcode
    *
    * \param   	ClkFreq     determines the desired clock frequency [Hz]
    *
    * \return   void
    *
    * \note     The configured clock frequency is saved in the global
    *           ::SysCtl_ClockFreq variable, witch can be accessed by calling
    *           the Bi_SysCtlGetClkFreq() function.
    *
    ****************************************************************************/
    void Bi_SysCtlInit(const U32 ClkFreq)
    {
    	// Set variables for clock and interrupt configuration
    	U32 ClockConfig = 	SYSCTL_USE_PLL		|	// use PLL
    						SYSCTL_CFG_VCO_480	|	// PLL = 480MHz
    						SYSCTL_XTAL_12MHZ	|	// external crystal = 12MHz
    						SYSCTL_OSC_MAIN		;	// use main oscillator
    	
    	U32 IntConfig =		SYSCTL_INT_BOR      |	// Current limit interrupt
    						SYSCTL_INT_MOSC_PUP |	// Internal oscillator failure int
    						SYSCTL_INT_MOSC_FAIL |	// Main oscillator failure int
    						SYSCTL_INT_PLL_LOCK	 ;	// PLL failure interrupt
        
        // Variable for tamper events
        TamperEvent* Tamper = malloc(HIB_TAMPER_BUF*sizeof(TamperEvent));
    	
    	// Set CPU clock speed and save it to global variable
    	SysCtl_ClockFreq = SysCtlClockFreqSet(ClockConfig, ClkFreq);
    	// note that SysCtlClockSet() and SysCtlClockGet() won't work on this device
    	
    	// Reset instead of interrupt at brown-out conditions
    	//SysCtlBrownOutConfigSet(SYSCTL_BOR_RESET);
    	// fuction is not implemented in Tiva Ware 2.1, yet
    	
    	// Enable processor interrupts in general
    	IntMasterEnable();
    	// Nevertheless, each interrupt source must be enabled by its IntEnable()-
    	// function, e.g. TimerIntEnable()
    	// Furthermore an interrupt handler should be registered, e.g.
    	// TimerIntRegister(TIMER0_BASE, ISR_Timer0);
        
        
        // Initialize ring buffer for tamper events
        Bi_RingBufInit(&TamperBuf, Tamper, HIB_TAMPER_BUF, sizeof(TamperEvent));
        
        // Registerinterrpt handlers
        IntRegister(FAULT_NMI, NMI_Handler);
        SysCtlIntRegister(ISR_SysCtl);
    	
        // Enable and clear SysCtl interrupts
    	SysCtlIntEnable(IntConfig);
        SysCtlIntClear(IntConfig);
    }
    
    
    /*~
    section: I/O functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_SysCtlGetClkFreq
    *
    * \brief    Get the configured system clock frequency.
    *
    * The system's clock frequency is set once by calling the Bi_SysCtlInit()
    * function and saved into the global variable ::SysCtl_ClockFreq. Refer to the
    * variable documentation and the TivaWare SysCtlClockFreqSet() api more
    * details.
    *
    * \return   Returns the system clock frequency [Hz].
    *
    ****************************************************************************/
    U32 Bi_SysCtlGetClkFreq()
    {
        return SysCtl_ClockFreq;
    }
    

    /** \file
    ****************************************************************************
                                                                                   
    \b      Siemens AG  Electronic Design										/n
                                                                                   
    ****************************************************************************
                                                                                   
            This document is the property of Siemens AG Electronic Design and      
            Manufacturing Services, Hannover.                                      
            Confidential, for internal use only. It may not be reproduced,         
            disclosed, or distributed outside Siemens or outside its business      
            partner and its subsidiaries as well without written authorisation.    
            Any unauthorised reproduction, disclosure, or distribution of          
            copies by any person of any portion of this document may be a          
            violation of the copyright law and may result in further civil and     
            criminal penalties. All rights reserved.                               
            COPYRIGHT     Siemens AG Electronic Design and Manufacturing Services  
                          2008                                                     
                                                                                   
    ****************************************************************************
                                                                                   
    \b      Project:	D2 CM4 Snowflake										\n
                                                                             
    \b      Module:		IBS Software											\n
    \b      Origin:																\n
    \b      Editor:		Daniel Schweizer										\n
    \b      Department: I IA CE SE DS ED										\n
                                                                                  
    \b      Identification:	A5E32344507											\n
                                                                                   
    ****************************************************************************
                                                                                   
    \brief  Harware and Software Timers
                                                                                   
    ****************************************************************************
                                                                                   
    \note   History                                                             \n
            
    Version | Date       | Comment
    ------- | ---------- | --------------------
    v1.0	| 23.09.2013 | created file
    v1.1	| 26.03.2014 | doxygen modification, function and variable names changed
    v1.2	| 08.04.2014 | added doxygen comments
    v1.3	| 16.06.2014 | changed file "\brief"
    v1.4    | 17.06.2014 | Bi_SysCtlGetClkFreq() use added
    v1.5    | 03.07.2014 | fixed doxygen errors, added some comments
                                                                                   
    ****************************************************************************/
    
    // modul definitions
    
    
    // include files --------------------------------------------------------------
    
    // Type definitions ------------
    #include "Typedef.h"
    #include "stdint.h"
    #include "stdbool.h"
    
    
    // Modules ---------------------
    #include "Bi_Timer.h"
    #include "Bi_SysCtl.h"
    
    
    // Libaries --------------------
    #include "driverlib\timer.h"
    #include "driverlib\sysctl.h"
    #include "inc\hw_memmap.h"
    
    // -------------------------------------------------------------------------
    
    
    /*~
    section: local functions and definitions
    ~*/
    
    
    
    // modul global variables and type definitions.
    /**
    ****************************************************************************
    * \var      TimerData swTimers
    *
    * \brief    Global array to save software timer's status.
    *
    * This is a global array of type TimerData to save neccessary data for all
    * software timers. The number of available software timers depends on type
    * definition of ::timerID ::Timer_amount.
    * This variable schould only be accessed by the Bi_TimerStart(),
    * Bi_TimerStop(), Bi_TimerSetVal() and Bi_TimerGetVal() functions. It is
    * initialized during Bi_TimerInit() and the software timer's count is
    * incremented during ISR_Timer1().
    *
    ****************************************************************************/
    TimerData swTimers[Timer_amount];	// Global array of sw-timers.
    
    
    /*~
    section: Interrupts
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    ISR_Timer1
    *
    * \brief    Interrupt handler for Timer 1.
    *
    * This interrupt handler counts up all available software timers in the
    * global ::swTimers array.
    *         
    * \return   void
    *
    * \note     The module using a software timer is responsible for starting,
    *           stopping and resetting its timer. The hardware timer is reloaded
    *           automatically.
    *
    * \warning  Too many software timers and a too short hardware cycle, witch
    *           is set by the Bi_TimerInit() function call, may lead to excessive
    *           interrupt execution!
    *
    ****************************************************************************/
    void ISR_Timer1()
    {
    	// Get interrupt status and clear interrupts
    	U32 IntStatus = TimerIntStatus(TIMER1_BASE, true);
    	TimerIntClear(TIMER1_BASE, IntStatus);
    	
    	// Check interrupt status.
    	if ( IntStatus & TIMER_TIMA_TIMEOUT  )
    	{		
    		// Count up all SW timers if they are "on".
    		for (timerID currTimer = Timer_base; currTimer < Timer_amount; currTimer++)
    		{
    			if (swTimers[currTimer].TimerStatus)
    				swTimers[currTimer].TimerCnt++;
    		}		
    	}
    }
    
    
    /*~
    section: body functions
    ~*/
    /**
    ****************************************************************************
    *
    \b Name:    Bi_TimerInit
    *
    * \brief    Initialize hardware and software timers.
    *
    * In this function the hardware timer is configured as a 32 bit timer
    * generating periodic interrupts after \e TimeBase [�s]. The ISR_Timer1()
    * interrupt handler increments all available software timers, thus the
    * system's cycle time is limited by the \e TimeBase. Feel free to use the
    * HW_TIME_BASE_* parameter from Bi_Timer.h or any other value to determine
    * the time base but remind the warning from ISR_Timer1(). \n
    * The hardware timer's reload value is calculated by
    * - \e TimeBase * 1e-6 * ::SysCtl_ClockFreq
    *
    * The ::SysCtl_ClockFreq is returned by the Bi_SysCtlGetClkFreq() function.
    *
    * \param   	TimeBase    determines the system's time base and thus the
    *                       minimum cycle time of all software timers. The
    *                       parameter's dimension is [�s].
    *
    * \return   void
    *
    * \pre      This module uses interrupts so the Bi_SysCtl module must be
    *           initialized previously by using Bi_SysCtlInit().
    *
    * \note     Maximum time base or system cycle is determined by T_max [s] = 
    *           2^32-1/::SysCtl_ClockFreq. Therefore the maximum software timer
    *           cycle is T [s] = 2^32-1 * T_max.
    *
    ****************************************************************************/
    void Bi_TimerInit(U32 TimeBase)
    {
        U32 StartVal;
        U32 ClkFreq = Bi_SysCtlGetClkFreq();
        
        // Check input parameter
        if ( TimeBase == 0 )
        {
            // Set start value to default 1ms.
            TimeBase = HW_TIME_BASE_1MS;
        }
        
    	// Set default values for all software timers.
    	for (U8 i=0; i < Timer_amount; i++)
    	{
    		swTimers[i].TimerID     = (timerID) i;
    		swTimers[i].TimerStatus = false;
    		swTimers[i].TimerCnt 	= 0;
    	}
    	
    	// Turn base timer on.
    	Bi_TimerStart(Timer_base);
    
    	// Power on and activate clock gating and wait for peripheral to be ready.
    	SysCtlPeripheralPowerOn(SYSCTL_PERIPH_TIMER1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    	while ( !(SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1)) );
    	
    	// Set timer clock source
    	TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_SYSTEM);
    	
    	// Configure periodic 32bit Timer (counts down).
    	TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
        
        // Calculate Timer start value
    	StartVal = (U32) ( (float)(TimeBase) * 1e-6 * (float)(ClkFreq) );
    	// note that the SysCtlClockGet() function can only be used on Blizzard
    	// devices
         
    	// Set Timer1 start value.
    	TimerLoadSet(TIMER1_BASE, TIMER_BOTH, StartVal);
    	
    	// Configure Timer1 interrupt.
    	TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    	TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    	
    	// Register interrupt handler.
    	TimerIntRegister(TIMER1_BASE, TIMER_BOTH, ISR_Timer1);
    	
    	// Enable Timer1
    	TimerEnable(TIMER1_BASE, TIMER_BOTH);
    }
    
    
    /*~
    section: I/O functions
    ~*/
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_TimerGetVal
    *
    * \brief	Get the current count from a software timer.
    *
    * This function simply returns the current count of a software timer
    * determined by the \e TimerName parameter by returning the value from the
    * global ::swTimers variable.
    *
    * \param   	TimerName   determines the software timer. This is an enumerated
    *                       type ::timerID from Bi_Timer.h.
    *
    * \return   Returns the current count of a software timer determined by the
    *           \e TimerName parameter.
    *
    ****************************************************************************/
    U32 Bi_TimerGetVal(const timerID TimerName)
    {
    	U32 TimerVal = 0;
    	
    	if (TimerName < Timer_amount)
    		TimerVal = swTimers[TimerName].TimerCnt;
    	
    	return TimerVal;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_TimerSetVal
    *
    * \brief	Set the \e TimerVal to a software timer.
    *
    * This function simply sets the desired value to the count of a software
    * timer determined by the \e TimerName parameter. The value is set to the
    * global ::swTimers variable and overwrites the "old" timer count.
    *
    * \param   	TimerName   determines the software timer. This is an enumerated
    *                       type ::timerID from Bi_Timer.h.
    * \param    TimerVal    is the value witch overwrites the current count of
    *                       the software timer.
    *
    * \return   Returns the current count of a software timer determined by the
    *           \e TimerName parameter.
    *
    ****************************************************************************/
    U32 Bi_TimerSetVal(const timerID TimerName, const U32 TimerVal)
    {
    	U32 retTimerVal = -1;
    	
    	if (TimerName < Timer_amount)
    	{
    		swTimers[TimerName].TimerCnt = TimerVal;
    		retTimerVal = swTimers[TimerName].TimerCnt;
    	}
    	return retTimerVal;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_TimerStart
    *
    * \brief	Start a software timer.
    *
    * This function starts a software timer by setting the TimerData::TimerStatus
    * bit in the global ::swTimers variable. This bit determines if the ISR_Timer1()
    * interrupt handler increments TimerData::TimerCnt of the corresponding
    * software timer.
    *
    * \param   	TimerName   determines the software timer. This is an enumerated
    *                       type ::timerID from Bi_Timer.h.
    *
    * \return   Returns the TimerData::TimerStatus flag and \e false in case of
    *           falure.
    *
    ****************************************************************************/
    bool Bi_TimerStart(const timerID TimerName)
    {
    	bool TimerOn = false;
    	
    	if (TimerName < Timer_amount)
    	{
    		swTimers[TimerName].TimerStatus = true;
    		TimerOn = swTimers[TimerName].TimerStatus;
    	}
    	
    	return TimerOn;
    }
    
    
    /**
    ****************************************************************************
    *
    \b Name:    Bi_TimerStop
    *
    * \brief	Start a software timer.
    *
    * This function stops a software timer by clearing the TimerData::TimerStatus
    * bit in the global ::swTimers variable. This bit determines if the ISR_Timer1()
    * interrupt handler increments TimerData::TimerCnt of the corresponding
    * software timer.
    *
    * \param   	TimerName   determines the software timer. This is an enumerated
    *                       type ::timerID from Bi_Timer.h.
    *
    * \return   Returns the TimerData::TimerStatus flag and \e true in case of
    *           falure.
    *
    ****************************************************************************/
    bool Bi_TimerStop(const timerID TimerName)
    {
    	bool TimerOn = true;
    	
    	if (TimerName < Timer_amount)
    	{
    		swTimers[TimerName].TimerStatus = false;
    		TimerOn = swTimers[TimerName].TimerStatus;
    	}
    	
    	return TimerOn;
    }

    4705.Bi_Hibernation.h

    3113.Bi_RingBuf.h

    5618.Bi_SysCtl.h

    8306.Bi_Timer.h

  • Hello Daniel,

    Thanks for the code. To debug the issue we need to make sure that boards on both ends are baselined with the same code to ensure we are not seeing a hardware discrepancies.

    Then we can jump to the SW if the baseline is clean. I hope you agree to the approach.

    Regards

    Amit

  • Yes, of cause I do! ;)

    Thanks for your help!

  • Hello Daniel,

    I am using a TM4C129XNCZAD device, so you would need to change the compilation pre-define.

    http://e2e.ti.com/cfs-file.ashx/__key/communityserver-discussions-components-files/908/5367.TM4C129_5F00_Tamper.7z

    Please note that the NMI Handler is called before a main function call. So if the code is storing the events in SRAM, then a Zero-Init will clean it up. So what i have done is that in the Interrupt Handler I copy it to the HIBDATA registers and then use the main code to read it back.

    The project is a CCS project and you can refer to the startup_ccs.c and the main C file in the code.

    Regards

    Amit

  • Hi Amit,

    thx for the code. I'll need some time to test and verify. I will reply as soon as possible.

    Regards
    Daniel

  • Hello Daniel

    Please note that the Tamper is configured on Pin-0 for a low level.

    Regards

    Amit