NRF5340 - PRE KERNEL1 timer

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);

Parents Reply Children
No Data
Related