This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Function Called by Current Valure Register(SYST_CVR) with SysTick

Hello guys,
Im trying to use the timer registers of my ARM Cortex M0 while using my pga970EVM. Unfortionally there aren't any files/Commands refering to using the 3 registers SYST_CSR, SYST_RVR, SYST_CVR. I figured out how these registers are working quite easily: SYST_CVR is set to the Reload Value which is defined by SYST_RVR. When SYST_CSR is enabled, SYST_CVR  gets lowered periodically and when reaching 0 its Value is reset to the reload Value. Normally there should be a function which is called as soon as the Current Value Register hits 0 but there is none in my generic firmware. The link provides the information I have on these registers.

Cortex-M0 Devices Generic User Guide (arm.com)

D
o I have to write a function my own? If so how can i do it?
I already tried checking the CVR hitting 0 with an if-function: if(SYST_CVR==0x00000000)  but everything if this loop never got triggered.
Regards, Paul

Parents Reply Children
  • Hi Ronan,
    I activated TICKINT in SYST_CSR by setting it to a value of 0x00000007 as suggested by most guides. My problem seems to be the SysTick exception since my Tick reaches 0 and resets but no function is called what so ever.

    Regarding my device as stated above, im using the PGA970(Texas Instruments).  My latest attempt was to replace the IntDefaultHandler in Line 46 and using a new declared function with a counter. But the Counter always rested at 0 although my value register kept hitting 0.

     

    extern void _c_int00(void);
    
    extern void ADC_Handler(void);
    
    #if (COMBUF_TESTING == 1)
    extern void COMBUF_Handler(void);
    #endif
    
    #if (OWI_TESTING == 1)/* for OWI testing */
    extern void OWI_Activation_Handler(void);
    #endif
    
    
    //*****************************************************************************
    //
    // Linker variable that marks the top of the stack.
    //
    //*****************************************************************************
    extern unsigned long __STACK_TOP;
    //*****************************************************************************
    //
    // The vector table.  Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000 or at the start of
    // the program if located at a start address other than 0.
    //
    //*****************************************************************************
    #pragma DATA_SECTION(g_pfnVectors, ".intvecs")
    void (* const g_pfnVectors[])(void) =
    {
       (void (*)(void))((unsigned long)&__STACK_TOP),
                                                // The initial stack pointer
       ResetISR,                                // The reset handler
       NmiSR,                                   // The NMI handler
       FaultISR,                                // The hard fault handler
       IntDefaultHandler,                       // The MPU fault handler
       IntDefaultHandler,                       // The bus fault handler
       IntDefaultHandler,                       // The usage fault handler
       0,                                       // Reserved
       0,                                       // Reserved
       0,                                       // Reserved
       0,                                       // Reserved
       IntDefaultHandler,                       // SVCall handler
       IntDefaultHandler,                       // Debug monitor handler
       0,                                       // Reserved
       IntDefaultHandler,                       // The PendSV handler
       IntDefaultHandler,                       // The M0 System timer handler
       ADC_Handler,  // ADC handler
       IntDefaultHandler,
    #if(OWI_TESTING == 1) //
       OWI_Activation_Handler, // OWI_Activation_Handler, OWI Activation handler
    #else
       IntDefaultHandler,
    #endif
    #if (COMBUF_TESTING == 1)
       COMBUF_Handler,                          // COMBUF RX handler
    #else
       IntDefaultHandler,                       //
    #endif
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
       IntDefaultHandler,                       //
    };
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor first starts execution
    // following a reset event.  Only the absolutely necessary set is performed,
    // after which the application supplied entry() routine is called.  Any fancy
    // actions (such as making decisions based on the reset cause register, and
    // resetting the bits in that register) are left solely in the hands of the
    // application.
    //
    //*****************************************************************************
    void
    ResetISR(void)
    {
       //
       // Jump to the CCS C initialization routine.
       //
       __asm("    .global _c_int00\n"
             "    bl     _c_int00");
    }
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a NMI.  This
    // simply enters an infinite loop, preserving the system state for examination
    // by a debugger.
    //
    //*****************************************************************************
    static void
    NmiSR(void)
    {
       //
       // Enter an infinite loop.
       //
       while(1)
       {
       }
    }
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a fault
    // interrupt.  This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void
    FaultISR(void)
    {
       //
       // Enter an infinite loop.
       //
       while(1)
       {
       }
    }
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives an unexpected
    // interrupt.  This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void
    IntDefaultHandler(void)
    {
       //
       // Go into an infinite loop.
       //
       while(1)
       {
       }
    }

    The Countflag bit you mentioned hits 1 immediatly after the start of programm and rests there for ever (it could also be swapping so fast that CodeComposerStudio doesn' realise). I realised that my try of reading the register with an if totally wouldnt work like desired but at the moment I am kind of desparate.

  • Hi Paul

    Sorry, I missed the mention of the PGA970 earlier. I'm not familiar with CCS, does it allow you to directly visualize the SysTick registers? For example the Keil MDK shows:

    Can you share your initialization code of SysTick, it should be simple... first setting the reload value (any value up to 0x00FFFFFF), and then enabling by writing 0b__1 to the control register.

    Have you declared these registers as volatile so that the compiler isn't (likely silently) optimizing away your initialization? I found this document [http://www.ti.com/lit/pdf/SLDU024] which mentions (section 4.2) that you should define SYST_TESTING to ensure the init code is added to your code base.

    I see you write 0x7 (0b_111), the upper bit sets the clock source. Again, I am not familiar with this device, but may be worth experimenting with writing 0x3 (0b_011) instead.

    You should indeed have a function to branch to at that location in the vector table, even a simple function that just loops to itself so that you can catch it when it occurs could be useful. Do you have breakpoint capabilities on your device?

    Apologies if some or all of the above are things you have already tried... the SysTick timer is a very simple peripheral, there aren't many things that can go wrong, so I am rather stumped...

  • Hi Ronan,
    Yes CCS does allow me to view the register values. It does look like this.


    I am experimenting in 2 different versions of the firmware since the user guide is outdated, im switching between the version of the user guide and the newest. 
    When using the outdated version which is shown/used in the screenshot above, I am using this function:
    SYST_Config(0x0000FFFF,0x00000007);
    When using the latest version im writing directly into the register. I did that in the outdated version too to test its functionality and both  variants work completly fine

    SYST_CSR=0x00000007;
    SYST_RVR=0x0000FFFF;

    regarding the register declaration i found this:

    #define REG8(x) (*((volatile unsigned char *)(x)))
    #define REG16(x) (*((volatile unsigned short *)(x)))
    #define REG32(x) (*((volatile unsigned long *)(x)))

    /* NVIC Registers */
    #define NVIC_INT_TYPE REG32(0xE000E004)
    #define SYST_CSR REG32(0xE000E010)
    #define ST_ENABLE (1 << 0)
    #define ST_TICKINT (1 << 1)
    #define ST_CLKSOURCE (1 << 2)
    #define ST_COUNTFLAG (1 << 16)
    #define SYST_RVR REG32(0xE000E014)
    #define SYST_CVR REG32(0xE000E018)

    as far as my understanding goes all SYST_... registers are declared as volatile unsigned long.

    Setting 0x00000003 instead of 7 wont do the trick either and nothing changes at all (except the value of CSR).

    I do have breakpoints available, the code i posted in my 2nd post in this thread shows the IntDefaultHandler. According to line 46 it should get executed by the SysTimer. However i wasn't able to trigger it.
    While experimenting with different settings for the SysTimer i managed to crash my pga970 therefore it wasn't responding and held in reset. I might have reached calling the IntDefaultHandler which loops itself and could cause the crash. However when editing the IntDefaultHandler or replacing it, nothing happens again as in  the case before.

  • Hi again Paul

    Thinking about this again, while it looks like SysTick is set up correctly, I suspect that interrupts are not enabled in the core, else (unlikely) the priority of SysTick is very low and never being handled.

    Does PRIMASK = 0? If set to 1, then IRQs are not handled.

    https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/nested-vectored-interrupt-controller/nvic-usage-hints-and-tips

  • Hi Ronan

    As far as i understand the function __enable_irq() should also be setting PRIMASK to 0. The additional command __get_PRIMASK (void) which should be setting PRIMASK according to a post by CMSIS.

    I realized that the COUNTFLAG bit in SYST_CSR gets set but never reset maybe my issue has something to do with that.
    Do you have any more ideas?

  • COUNTFLAG will be cleared if you read SYST_CSR, That it is set shows that the timer counter is going thru 0, and so should be throwing the exception.

    I believe the issue is with your NVIC setup, but I can't see what exactly from the above, sorry :(

  • I found the isr.c file, sadly there is no explanation on the set values not even in the header.
    it might be that NVIC isn't enabled since i never touched these functions before.
    /* ========================================================================== */
    void Interrupt_Config(void)
    {
    /* Clear interrupt pending register */
    NVIC_UNPEND0 = 0xFFFFFFFF;

    /* Set priority of NVIC interrupt */
    NVIC_PRI0 = 0x80400000;
    NVIC_PRI1 = 0xC0C0C0C0;

    /*
    * Enable NVIC interrupts
    * NVIC interrupt for external interrupt 1 i.e. TADC is disabled
    */
    NVIC_ENABLE0 = 0xFFFFFFFD;
    }

    any guesses on that? 

  • NVIC_ENABLE0  is at [0xE000E100]