This is a more advanced example that shows how to configure a timer interrupt on Raspberry Pi 2 “bare metal”. You will need IAR Embedded Workbench for ARM, and follow the Project Options steps described in the Raspberry Pi 2 Bare Metal with IAR Embedded Workbench example.
This example blinks the two on-board LEDs, so no need for extra hardware.
This is main.c
#include <stdint.h> #include <string.h> #include <intrinsics.h> #include "bcm2836.h" #define DELAYCNT 2500000 #define TIMERCNT 0x400 static void delay(uint32_t cnt); static void timer_config(void); volatile uint32_t toggle; /*--------------------------------------------------*/ int main(void) { GPFSEL4_bit.FSEL47 = GPFSEL_OUT; // GPIO pin 47 = Output GPFSEL3_bit.FSEL35 = GPFSEL_OUT; // GPIO pin 35 = Output timer_config(); while (1) { GPSET1 = GPSET_47; // Set GPIO pin 47 delay(DELAYCNT); GPCLR1 = GPCLR_47; // Clear GPIO pin 47 delay(DELAYCNT); } } /*--------------------------------------------------*/ static void delay(uint32_t cnt) { uint32_t i; volatile uint32_t a; for (i = 0; i < cnt; i++) { a = i; } } /*--------------------------------------------------*/ static void timer_config(void) { // Copy reset vector to address 0x0 for interrupts to work memcpy((char*)&Reset_vector, (char*)BCM_START_ADDR, sizeof(struct reset_struct)); // Enable timer and interrupts Base_IRQ_enable_bit.ARM_Timer = 1; Timer_load = TIMERCNT; Timer_ctrl_bit.count16_23 = TIMER_CNT_23BIT; Timer_ctrl_bit.enable = 1; Timer_ctrl_bit.irq_enable = 1; Timer_ctrl_bit.prescale = TIMER_PRESCALE_256; __enable_interrupt(); } /*--------------------------------------------------*/ __irq __arm void IRQ_Handler(void) { Timer_irq_clear = 1; if (toggle) { GPSET1 = GPSET_35; toggle = 0; } else { GPCLR1 = GPCLR_35; toggle = 1; } }
This is the header file bcm2836.h
#ifndef _BCM2836_H_ #define _BCM2836_H_ /* GPIO Function Select */ #define GPFSEL_IN 0x0; #define GPFSEL_OUT 0x1; #define GPFSEL_ALT0 0x4; #define GPFSEL_ALT1 0x5; #define GPFSEL_ALT2 0x6; #define GPFSEL_ALT3 0x7; #define GPFSEL_ALT4 0x3; #define GPFSEL_ALT5 0x2; #define GPSET0_ADDR 0x3F20001C #define GPSET1_ADDR 0x3F200020 #define GPFSEL0_ADDR 0x3F200000 #define GPFSEL1_ADDR 0x3F200004 #define GPFSEL2_ADDR 0x3F200008 #define GPFSEL3_ADDR 0x3F20000C #define GPFSEL4_ADDR 0x3F200010 #define GPCLR0_ADDR 0x3F200028 #define GPCLR1_ADDR 0x3F20002C /* GPIO Function Select 0 */ volatile __no_init union { uint32_t GPFSEL0; struct GPFSEL0_bits { uint32_t FSEL0 : 3; uint32_t FSEL1 : 3; uint32_t FSEL2 : 3; uint32_t FSEL3 : 3; uint32_t FSEL4 : 3; uint32_t FSEL5 : 3; uint32_t FSEL6 : 3; uint32_t FSEL7 : 3; uint32_t FSEL8 : 3; uint32_t FSEL9 : 3; uint32_t reserved : 2; } GPFSEL0_bit; } @ GPFSEL0_ADDR; /* GPIO Function Select 2 */ volatile __no_init union { uint32_t GPFSEL2; struct GPFSEL2_bits { uint32_t FSEL20 : 3; uint32_t FSEL21 : 3; uint32_t FSEL22 : 3; uint32_t FSEL23 : 3; uint32_t FSEL24 : 3; uint32_t FSEL25 : 3; uint32_t FSEL26 : 3; uint32_t FSEL27 : 3; uint32_t FSEL28 : 3; uint32_t FSEL29 : 3; uint32_t reserved : 2; } GPFSEL2_bit; } @ GPFSEL2_ADDR; /* GPIO Function Select 3 */ volatile __no_init union { uint32_t GPFSEL3; struct GPFSEL3_bits { uint32_t FSEL30 : 3; uint32_t FSEL31 : 3; uint32_t FSEL32 : 3; uint32_t FSEL33 : 3; uint32_t FSEL34 : 3; uint32_t FSEL35 : 3; uint32_t FSEL36 : 3; uint32_t FSEL37 : 3; uint32_t FSEL38 : 3; uint32_t FSEL39 : 3; uint32_t reserved : 2; } GPFSEL3_bit; } @ GPFSEL3_ADDR; /* GPIO Function Select 4 */ volatile __no_init union { uint32_t GPFSEL4; struct GPFSEL4_bits { uint32_t FSEL40 : 3; uint32_t FSEL41 : 3; uint32_t FSEL42 : 3; uint32_t FSEL43 : 3; uint32_t FSEL44 : 3; uint32_t FSEL45 : 3; uint32_t FSEL46 : 3; uint32_t FSEL47 : 3; uint32_t FSEL48 : 3; uint32_t FSEL49 : 3; uint32_t reserved : 2; } GPFSEL4_bit; } @ GPFSEL4_ADDR; /* GPIO Pin Output Set 0 */ volatile __no_init uint32_t GPSET0 @ GPSET0_ADDR; #define GPSET_0 (1<<0) #define GPSET_1 (1<<1) #define GPSET_2 (1<<2) #define GPSET_3 (1<<3) #define GPSET_4 (1<<4) #define GPSET_5 (1<<5) #define GPSET_6 (1<<6) #define GPSET_7 (1<<7) #define GPSET_8 (1<<8) #define GPSET_9 (1<<9) #define GPSET_10 (1<<10) #define GPSET_11 (1<<11) #define GPSET_12 (1<<12) #define GPSET_13 (1<<13) #define GPSET_14 (1<<14) #define GPSET_15 (1<<15) #define GPSET_16 (1<<16) #define GPSET_17 (1<<17) #define GPSET_18 (1<<18) #define GPSET_19 (1<<19) #define GPSET_20 (1<<20) #define GPSET_21 (1<<21) #define GPSET_22 (1<<22) #define GPSET_23 (1<<23) #define GPSET_24 (1<<24) #define GPSET_25 (1<<25) #define GPSET_26 (1<<26) #define GPSET_27 (1<<27) #define GPSET_28 (1<<28) #define GPSET_29 (1<<29) #define GPSET_30 (1<<30) #define GPSET_31 (1<<31) /* GPIO Pin Output Set 1 */ volatile __no_init uint32_t GPSET1 @ GPSET1_ADDR; #define GPSET_32 (1<<0) #define GPSET_33 (1<<1) #define GPSET_34 (1<<2) #define GPSET_35 (1<<3) #define GPSET_36 (1<<4) #define GPSET_37 (1<<5) #define GPSET_38 (1<<6) #define GPSET_39 (1<<7) #define GPSET_40 (1<<8) #define GPSET_41 (1<<9) #define GPSET_42 (1<<10) #define GPSET_43 (1<<11) #define GPSET_44 (1<<12) #define GPSET_45 (1<<13) #define GPSET_46 (1<<14) #define GPSET_47 (1<<15) #define GPSET_48 (1<<16) #define GPSET_49 (1<<17) #define GPSET_50 (1<<18) #define GPSET_51 (1<<19) #define GPSET_52 (1<<20) #define GPSET_53 (1<<21) /* GPIO Pin Output Clear 0 */ volatile __no_init uint32_t GPCLR0 @ GPCLR0_ADDR; #define GPCLR_0 (1<<0) #define GPCLR_1 (1<<1) #define GPCLR_2 (1<<2) #define GPCLR_3 (1<<3) #define GPCLR_4 (1<<4) #define GPCLR_5 (1<<5) #define GPCLR_6 (1<<6) #define GPCLR_7 (1<<7) #define GPCLR_8 (1<<8) #define GPCLR_9 (1<<9) #define GPCLR_10 (1<<10) #define GPCLR_11 (1<<11) #define GPCLR_12 (1<<12) #define GPCLR_13 (1<<13) #define GPCLR_14 (1<<14) #define GPCLR_15 (1<<15) #define GPCLR_16 (1<<16) #define GPCLR_17 (1<<17) #define GPCLR_18 (1<<18) #define GPCLR_19 (1<<19) #define GPCLR_20 (1<<20) #define GPCLR_21 (1<<21) #define GPCLR_22 (1<<22) #define GPCLR_23 (1<<23) #define GPCLR_24 (1<<24) #define GPCLR_25 (1<<25) #define GPCLR_26 (1<<26) #define GPCLR_27 (1<<27) #define GPCLR_28 (1<<28) #define GPCLR_29 (1<<29) #define GPCLR_30 (1<<30) #define GPCLR_31 (1<<31) /* GPIO Pin Output Clear 1 */ volatile __no_init uint32_t GPCLR1 @ GPCLR1_ADDR; #define GPCLR_32 (1<<0) #define GPCLR_33 (1<<1) #define GPCLR_34 (1<<2) #define GPCLR_35 (1<<3) #define GPCLR_36 (1<<4) #define GPCLR_37 (1<<5) #define GPCLR_38 (1<<6) #define GPCLR_39 (1<<7) #define GPCLR_40 (1<<8) #define GPCLR_41 (1<<9) #define GPCLR_42 (1<<10) #define GPCLR_43 (1<<11) #define GPCLR_44 (1<<12) #define GPCLR_45 (1<<13) #define GPCLR_46 (1<<14) #define GPCLR_47 (1<<15) #define GPCLR_48 (1<<16) #define GPCLR_49 (1<<17) #define GPCLR_50 (1<<18) #define GPCLR_51 (1<<19) #define GPCLR_52 (1<<20) #define GPCLR_53 (1<<21) #define BASE_IRQ_ADDR 0x3F00B218 /* Base Interrupt enable register */ volatile __no_init union { uint32_t Base_IRQ_enable; struct Base_IRQ_enable_bits { uint32_t ARM_Timer : 1; uint32_t ARM_Mailbox : 1; uint32_t ARM_Doorbell_0 : 1; uint32_t ARM_Doorbell_1 : 1; uint32_t GPU_0_Halted : 1; uint32_t GPU_1_Halted : 1; uint32_t Access_err_type_1 : 1; uint32_t Access_err_type_0 : 1; } Base_IRQ_enable_bit; } @ BASE_IRQ_ADDR; #define TIMER_CNT_23BIT 1 #define TIMER_CNT_16BIT 0 #define TIMER_PRESCALE_256 2 #define TIMER_LOAD_ADDR 0x3F00B400 #define TIMER_CLR_ADDR 0x3F00B40C #define TIMER_CTRL_ADDR 0x3F00B408 /* Timer Load register */ volatile __no_init uint32_t Timer_load @ TIMER_LOAD_ADDR; /* Timer IRQ clear register */ volatile __no_init uint32_t Timer_irq_clear @ TIMER_CLR_ADDR; /* Timer control register */ volatile __no_init union { uint32_t Timer_ctrl; struct Timer_ctrl_bits { uint32_t unused1 : 1; uint32_t count16_23 : 1; uint32_t prescale : 2; uint32_t unused2 : 1; uint32_t irq_enable : 1; uint32_t unused3 : 1; uint32_t enable : 1; uint32_t debug_halt : 1; uint32_t free_run : 1; uint32_t unused4 : 6; uint32_t free_prescale : 8; } Timer_ctrl_bit; } @ TIMER_CTRL_ADDR; #define BCM_START_ADDR 0x00008000 #define BCM_VECT_ADDR 0x00000000 volatile __no_init struct reset_struct { uint32_t Reset; uint32_t Undefined; uint32_t SWI; uint32_t Prefetch; uint32_t Abort; uint32_t Reserved; uint32_t IRQ; uint32_t FIQ; uint32_t jump_table[7]; } Reset_vector @ BCM_VECT_ADDR; #endif
More reading / details / thanks to:
https://github.com/dwelch67/raspberrypi
http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/
Tags: GPIO, Programming
4 February, 2016 at 03:38 |
Hello,
I have tried this example but interrupt is not working however timer is working fine. If just skip the __enable_interrupt(); function call then LED is working fine but when interrupt is enabled then when interrupt is called system is hang-up. It seems that something wrong with vector table. Can you help me to resolve this issue? Which steps I am missing?
Thanks
5 February, 2016 at 03:46 |
Hi, it is difficult to say what’s wrong. Perhaps you forgot to call memcpy in timer_config – the one that has the comment “Copy reset vector to address 0x0 for interrupts to work”. Or, maybe you got the addresses mixed up. I recommend using a debugger to find the issue.