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.

CCS/TM4C123GH6PM: Periodic interrupts, blinking blue LED every second

Part Number: TM4C123GH6PM

Tool/software: Code Composer Studio

Hello,

I am trying to generate a periodic intereupt to drive the blue LED (make it blink every second). 
I have initialized the clock to 12.5 MHZ and therefore calculated a reload value according to it so the systick ticks "reload value" times before generating an interrupt.
In addition i have created a handler to service the interrupt where i ask it to blink. I wanted to ask if this is right, I am waiting for my board but in the meanwhile I was able to code this,
i was hoping if someone could point out any errors as i dont have a board yet so i cannot test it. Below is the code for reference. Thanks #include <stdint.h> #include <stdbool.h> #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "inc/tm4c123gh6pm.h" void systick_initialize(unsigned long reload_value) { NVIC_ST_CTRL_R = 0; // disable systick NVIC_ST_RELOAD_R=reload_value ; // systick interupt time period= (SysTick_load+1)* Clock period NVIC_ST_CURRENT_R = 0; NVIC_SYS_PRI3_R = NVIC_SYS_PRI3_R&0x00FFFFFF; // priority 0 NVIC_ST_CTRL_R = 0x07; // enable systick } void systick_handler(void) { if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2)) { GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0); } else { GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4); } } int main(void) { systick_initialize(12499999); SysCtlClockSet(SYSCTL_SYSDIV_16|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); // clock at 12.5MHZ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); GPIOPinTypeGPIOInput(GPIO_PORTF_BASE,GPIO_PIN_4); GPIO_PORTF_LOCK_R = 0x4C4F434B; GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); // enable F4's pullup, the drive strength won't affect the input GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2); }

  • a couple suggestions:

    1) pay attention to how embedded code flows. generally you will need to have a while (1) loop somewhere to hold the execution;

    2) think about a more generic approach where you can install your handler in the systick isr and blink the led from there. this will create a couple modules (on gpio and systick) that you can use in future programs.

    Personally, I tend to keep systick free running.

  • What could justify your use of "DRM" to perform a simple/unrushed, "Peripheral Set-Up/Configuration?" This DOES add (unneeded/unwanted) complexity - does it not? Again - to "what" possible purpose?

    You "attempt" to "Unlock PortF" - yet is it not (only) PF0 which requires such? (and which appears "unused" w/in your application.)
  • To follow-up on my post, two approaches that show the same behavior: PF2 high for 0.5s and low for 0.5s and high for 0.5s ....

    the first approach is to use systick as a 10ms time base. In the systick isr, we call a user installed handler that flips PF2 every 50 times: 50x10ms = 500ms.

    //blinking PF2.
    //time base: systick
    #include "tm4c123.h"								//tm4c123
    
    //hardware configuration
    #define LED_PORT			GPIOF
    #define LED					(1<<2)					//1=R, 2=B, 3=G
    #define LED_DLY				(SystemCoreClock / 100)	//1s/100 = 10ms interrupt interval
    
    //end hardware configuration
    
    //global defines
    #define IO_OUT(port, pins)		do {port->DEN |= (pins); port->ODR &=~(pins); port->DIR |= (pins);} while (0)
    #define IO_FLP(port, pins)		port->DATA ^= (pins)					//MAP_GPIOPinWrite(port, (pins), ~IO_GET(port, pins))
    
    //empty handler
    static void empty_handler(void) {
    	//do nothing
    }
    
    //global variables
    //user isr ptr
    static void (* _isrptr_systick)(void)=empty_handler;				//tmr_ptr pointing to empty_handler by default
    volatile uint32_t systickovf_counter=1ul<<24;				//systick counter
    
    //systick handler
    //SysTick_Handler inserted into the vector table
    void SysTick_Handler(void) {
    	//clear the flag
    	//systickovf_counter += 1ul<<24;						//increment systick counter - 24bit, 1:1 prescaler
    	_isrptr_systick();										//execute systick handler
    }
    
    //reset systick to a period specified by user
    void systick_init(uint32_t period) {
    	systickovf_counter = 1ul<<24;											//SysTick is a 24-bit downcounter
    	//for chips where SysTick_Config() is not defined in cmsis
    	SysTick->LOAD  = 	(period-1)/*ticks*/ & SysTick_LOAD_RELOAD_Msk;      /* set reload register */
    	NVIC_SetPriority 	(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
    	SysTick->VAL   = 	0;                                          /* Load the SysTick Counter Value */
    	SysTick->CTRL  = 	SysTick_CTRL_CLKSOURCE_Msk |
    						SysTick_CTRL_TICKINT_Msk   |
    						SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
    
    	//alternative - for CMSIS-equip'd chips
    	//SysTick_Config(SysTick_LOAD_RELOAD_Msk);			//reload all 24 bits
    
    }
    
    //install user handler for systick
    void systick_act(void (*isrptr)(void)) {
    	_isrptr_systick = isrptr;							//install user handler
    }
    //flip led every 50th invocation = 50x10ms = 500ms
    void led_flp(void) {
    	static int i=0;
    	if (i++ == 50) {IO_FLP(LED_PORT, LED); i=0;}
    }
    
    //reset the mcu
    void mcu_init(void) {
    	SYSCTL->RCGC2 |= (1<<5);						//5->GPIOF	//MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	SystemCoreClockUpdate();						//update systemcoreclock
    
    }
    int main(void) {
    
    	mcu_init();									//reset the  mcu - default clock setting
    	//reset systick
    	systick_init(LED_DLY);							//set up systick to interrupt periodically
    	systick_act(led_flp);							//flip the led
    
    	IO_OUT(LED_PORT, LED);							//led as output
    
    	//ei();											//enable interrupts
    	while(1) {
    	}
    
    	return 0;
    }
    
    
    

    I generally prefer a free-running systick, like in the 2nd approach below. it has a free-running systick. we read the time stamp in the main loop. if enough time has passed we flip PF2.

    //blinking PF2.
    //time base: systick
    #include "tm4c123.h"								//tm4c123
    
    //hardware configuration
    #define LED_PORT			GPIOF
    #define LED					(1<<2)					//1=R, 2=B, 3=G
    #define LED_DLY				(SystemCoreClock / 2)	//1s/2 = 500ms interrupt interval
    
    //end hardware configuration
    
    //global defines
    #define IO_OUT(port, pins)		do {port->DEN |= (pins); port->ODR &=~(pins); port->DIR |= (pins);} while (0)
    #define IO_FLP(port, pins)		port->DATA ^= (pins)					//MAP_GPIOPinWrite(port, (pins), ~IO_GET(port, pins))
    
    //empty handler
    static void empty_handler(void) {
    	//do nothing
    }
    
    //global variables
    //user isr ptr
    static void (* _isrptr_systick)(void)=empty_handler;				//tmr_ptr pointing to empty_handler by default
    volatile uint32_t systickovf_counter=1ul<<24;				//systick counter
    
    //systick handler
    //SysTick_Handler inserted into the vector table
    void SysTick_Handler(void) {
    	//clear the flag
    	systickovf_counter += 1ul<<24;						//increment systick counter - 24bit, 1:1 prescaler
    	//_isrptr_systick();										//execute systick handler
    }
    
    //reset systick to a period specified by user
    void systick_init(uint32_t period) {
    	systickovf_counter = 1ul<<24;											//SysTick is a 24-bit downcounter
    	//for chips where SysTick_Config() is not defined in cmsis
    	SysTick->LOAD  = 	(period-1)/*ticks*/ & SysTick_LOAD_RELOAD_Msk;      /* set reload register */
    	NVIC_SetPriority 	(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
    	SysTick->VAL   = 	0;                                          /* Load the SysTick Counter Value */
    	SysTick->CTRL  = 	SysTick_CTRL_CLKSOURCE_Msk |
    						SysTick_CTRL_TICKINT_Msk   |
    						SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
    
    	//alternative - for CMSIS-equip'd chips
    	//SysTick_Config(SysTick_LOAD_RELOAD_Msk);			//reload all 24 bits
    
    }
    
    //install user handler for systick
    void systick_act(void (*isrptr)(void)) {
    	_isrptr_systick = isrptr;							//install user handler
    }
    
    //read back systick count, 32-bit
    uint32_t systick_get(void) {
    	uint32_t m, f;
    
    	//perform a double read
    	do {
    		m = systickovf_counter;
    		f = SysTick->VAL;
    	} while (m ^ systickovf_counter);					//maintain atomicity
    
    	return m - f;
    }
    
    //flip led every 10th invocation = 10x10ms = 100ms
    void led_flp(void) {
    	static int i=0;
    	if (i++ == 10) {IO_FLP(LED_PORT, LED); i=0;}
    }
    
    //reset the mcu
    void mcu_init(void) {
    	SYSCTL->RCGC2 |= (1<<5);						//5->GPIOF	//MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	SystemCoreClockUpdate();						//update systemcoreclock
    
    }
    int main(void) {
    	uint32_t time0=0;									//time stamp
    
    	mcu_init();										//reset the  mcu - default clock setting
    	//reset systick
    	systick_init(1ul<<24);							//set up systick to interrupt periodically
    	//systick_act(led_flp);							//flip the led
    
    	IO_OUT(LED_PORT, LED);							//led as output
    
    	//ei();											//enable interrupts
    	while(1) {
    		if (systick_get() - time0 >= LED_DLY) {
    			IO_FLP(LED_PORT, LED);					//blink the led
    			time0 += LED_DLY;						//advance time0
    		}
    	}
    
    	return 0;
    }
    
    
    

    both approaches are done under CMSIS. However the same concept applies if you opt to implement it using driverlib. The beauty of a cmsis implementation is that it is portable to other CMx chips where systick timers are available.

  • THANK YOU FOR THE COMPREHENSIVE REASONING AND METHOD . I did not have complete understanding about interrupts and hadlers when i made this post, spending some time in classes i understond how this works also this above templte for interuupt is great thanks again