Hi,
I'm trying to implement a PRE_KERNEL1 timer (with top priority 0) to toggle an LED.
I’m able to control the LED using registers, and now I want to add a timer layer.
I've tried using both registers and NRFX for this task. Both solutions compiled and flashed successfully, but they don’t seem to do anything. :(
In the NRFX solution, it looks like the program gets stuck during timer initialization (code below).
What do you think might be the issue?
// Base addresses - NRF5340 #define TIMER1_BASE 0x50010000UL #define CLOCK_BASE 0x50005000UL #define OSC_BASE 0x50004000UL #define NRF_P0_BASE 0x50842500UL // LED definitions #define NRF_GPIO_DIRSET (*(volatile uint32_t *)(NRF_P0_BASE + 0x018)) #define NRF_GPIO_DIRCLR (*(volatile uint32_t *)(NRF_P0_BASE + 0x01C)) #define NRF_GPIO_OUTSET (*(volatile uint32_t *)(NRF_P0_BASE + 0x008)) #define NRF_GPIO_OUTCLR (*(volatile uint32_t *)(NRF_P0_BASE + 0x00C)) #define NRF_GPIO_IN (*(volatile uint32_t *)(NRF_P0_BASE + 0x010)) #define NRF_GPIO_PIN_CNF(PIN) (*(volatile uint32_t *)(NRF_P0_BASE + 0x700 + PIN * 4)) #define PIN_LED 3 // P0.03 // Timer registers (offsets from TIMER1_BASE) #define TIMER_TASKS_START (*(volatile uint32_t *)(TIMER1_BASE + 0x000)) #define TIMER_TASKS_STOP (*(volatile uint32_t *)(TIMER1_BASE + 0x004)) #define TIMER_TASKS_CLEAR (*(volatile uint32_t *)(TIMER1_BASE + 0x008)) #define TIMER_TASKS_CAPTURE0 (*(volatile uint32_t *)(TIMER1_BASE + 0x018)) #define TIMER_TASKS_CAPTURE1 (*(volatile uint32_t *)(TIMER1_BASE + 0x01C)) #define TIMER_EVENTS_COMPARE0 (*(volatile uint32_t *)(TIMER1_BASE + 0x140)) #define TIMER_EVENTS_COMPARE1 (*(volatile uint32_t *)(TIMER1_BASE + 0x144)) #define TIMER_SHORTS (*(volatile uint32_t *)(TIMER1_BASE + 0x200)) #define TIMER_INTENSET (*(volatile uint32_t *)(TIMER1_BASE + 0x304)) #define TIMER_INTENCLR (*(volatile uint32_t *)(TIMER1_BASE + 0x308)) #define TIMER_MODE (*(volatile uint32_t *)(TIMER1_BASE + 0x504)) #define TIMER_BITMODE (*(volatile uint32_t *)(TIMER1_BASE + 0x508)) #define TIMER_PRESCALER (*(volatile uint32_t *)(TIMER1_BASE + 0x510)) #define TIMER_CC0 (*(volatile uint32_t *)(TIMER1_BASE + 0x514)) #define TIMER_CC1 (*(volatile uint32_t *)(TIMER1_BASE + 0x518)) // Clock registers (offsets from CLOCK_BASE) #define CLOCK_TASKS_HFCLKSTART (*(volatile uint32_t *)(CLOCK_BASE + 0x000)) #define CLOCK_HFCLKSTAT (*(volatile uint32_t *)(CLOCK_BASE + 0x40C)) // NVIC_BASE comes from <core_cm33.h> #define NVIC_ISER0 (*(volatile uint32_t *)(NVIC_BASE + 0x000)) // Interrupt Set Enable Register 0 #define NVIC_ICER0 (*(volatile uint32_t *)(NVIC_BASE + 0x080)) // Interrupt Clear Enable Register 0 #define NVIC_IPR0 (*(volatile uint8_t *)(NVIC_BASE + 0x400)) // Interrupt Priority Register 0 (byte access) #define SCB_SCR (*(volatile uint32_t *)(SCB_BASE + 0x010)) // System Control Register //////// Register test /////// - please run just one at the time // Interrupt handler for TIMER1 void TIMER1_IRQHandler(void) { static bool led_status = false; NRF_GPIO_OUTSET = (1 << PIN_LED); // Check if COMPARE0 event caused the interrupt if (TIMER_EVENTS_COMPARE0) { // Clear the event TIMER_EVENTS_COMPARE0 = 0; // Toggle the LED led_status = !led_status; if (led_status) { NRF_GPIO_OUTSET = (1 << PIN_LED); } else { NRF_GPIO_OUTCLR = (1 << PIN_LED); } } } void timer_init() { // Start high-frequency clock (if not already running) CLOCK_TASKS_HFCLKSTART = 1; while (!(CLOCK_HFCLKSTAT & 1)) ; // Wait for HFCLK to start // NRF_GPIO_OUTSET = (1 << PIN_LED); // for testing, can be removed // Configure Timer TIMER_TASKS_STOP = 1; // Ensure timer is stopped before configuring TIMER_TASKS_CLEAR = 1; // Clear timer TIMER_MODE = 0x00; // Timer mode TIMER_BITMODE = 0x02; // 32-bit timer TIMER_PRESCALER = 0x04; // Prescaler. 32MHz / (2^4) = 2MHz timer clock. Each tick is 0.5 us. TIMER_CC0 = 2000000; // Compare value for 1 second (2MHz * 1 second = 2000000) // Enable shortcut to clear timer on COMPARE0 event TIMER_SHORTS = (1 << 0); // Enable interrupt on COMPARE0 event TIMER_INTENSET = (1 << 16); NVIC_IPR0 |= (0x40 << (17 % 8) * 8); // Set priority to 0x40 (adjust as needed) // Enable TIMER1 interrupt in NVIC NVIC_ISER0 = (1 << 17); // Enable interrupt number 17 (TIMER1) TIMER_TASKS_START = 1; // Start timer } /////// NRFX Test //////// - please run just one at the time #define TIMER_INSTANCE_ID 1 static const nrfx_timer_t TIMER_INSTANCE = NRFX_TIMER_INSTANCE(TIMER_INSTANCE_ID); #define TIMER_IRQ_NUM TIMER1_IRQn // IRQ number for TIMER1 #define TIMER_CC_VALUE (16000000 * 5) // 5 seconds (16 MHz clock) void timer_event_handler(nrf_timer_event_t event_type, void *context) { static bool led_status = false; led_status = !led_status; if (led_status) { NRF_GPIO_OUTSET = (1 << PIN_LED); } else { NRF_GPIO_OUTCLR = (1 << PIN_LED); } // Reset the timer nrfx_timer_clear(&TIMER_INSTANCE); } void timer_init() { // Timer configuration structure nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG(NRF_TIMER_FREQ_16MHz); timer_cfg.frequency = NRF_TIMER_FREQ_16MHz; timer_cfg.mode = NRF_TIMER_MODE_TIMER; timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32; timer_cfg.interrupt_priority = 1; // Initialize Timer nrfx_timer_init(&TIMER_INSTANCE, &timer_cfg, timer_event_handler); // The next 2 lines are led testing - if we reach this point. // It looks like we stuck here, because the led is not turned on, // but it doest turn on if i place it before 'nrfx_timer_init' line NRF_GPIO_OUTSET = (1UL << PIN_LED); // for testing, should be removed return; // for testing, should be removed // Set CC0 for 5-second interval nrfx_timer_extended_compare(&TIMER_INSTANCE, NRF_TIMER_CC_CHANNEL0, TIMER_CC_VALUE, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); // Enable Timer Interrupt NVIC_ClearPendingIRQ(TIMER_IRQ_NUM); NVIC_EnableIRQ(TIMER_IRQ_NUM); // Start Timer nrfx_timer_enable(&TIMER_INSTANCE); } ///// Register function to run before kernel 1 - MCUBOOT ///// - This should run all the time static int gpio_early_read_write(void) { // Set LED gpio as output NRF_GPIO_DIRSET = (1UL << PIN_LED); NRF_GPIO_OUTCLR = (1UL << PIN_LED); // LED Test to see if the system powered NRF_GPIO_OUTSET = (1UL << PIN_LED); for (volatile int i = 0; i < 1000000; i++){}; NRF_GPIO_OUTCLR = (1UL << PIN_LED); timer_init(); // Wait for timer for (;;){}; return 0; } SYS_INIT(gpio_early_read_write, PRE_KERNEL_1, 0);