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)Do 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
Hi Paul,
You should enable the TICKINT bit in SYST_CSR, which will trigger an exception once the timer counts down (from SYST_RVR to zero), which will cause the processor to automatically jump to 0x3C, the SysTick exception in the vector table.
https://developer.arm.com/documentation/dui0497/a/the-cortex-m0-processor/exception-model/vector-table
You have not said which device and/or toolchain you are using. Most likely there are example projects available. Note that CMSIS provides an easy to use SysTick init function:
https://arm-software.github.io/CMSIS_5/Core/html/group__SysTick__gr.html
If you do not use an exception, you could use the COUNTFLAG bit of SYST_CSR to see if the counter has hit zero since you last checked... it is virtually impossible that your code would read _CVR to be exactly zero, as it just rolls back to _RVR and keeps counting down again. However this will be asynchronous to the timer, and hence rather defeats the purpose of using it as a timer...
You may find the below article useful:
https://www.sciencedirect.com/topics/engineering/systick-interrupt
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 RonanAs 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?
Can you determine what address NVIC_ENABLE0 is at? Is should be the ISER [0xE000E100], but could it mistakenly be the ICER [0xE000E180]?
https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/nested-vectored-interrupt-controller?lang=en
https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/nested-vectored-interrupt-controller/interrupt-set-enable-register?lang=en
https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/nested-vectored-interrupt-controller/interrupt-clear-enable-register?lang=en
NVIC_ENABLE0 is at [0xE000E100]