Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Bare metal interrupts (A13)

22 views
Skip to first unread message

Federico Fusco

unread,
Jan 19, 2025, 8:46:25 AMJan 19
to linux-sunxi
Hello,

I've already sent this message, but it doesn't seem to appear on the Google groups interface for some reason so I'm sending it again, sorry if you receive it twice.

I would like to preface this by saying that I'm completely new to bare metal (but have a lot of experience in more high-level programming) so please correct any errors.

I'm trying to set up interrupts for my A13 SoC, specifically the sync timer 0 interrupt.
For some reason my interrupt handler isn't running, and I'm not sure if it's due to a misconfigured interrupt table or if I haven't correctly configured the sync timer.

This is my linker script (derived from the sunxi-tools repo):

ENTRY(_start)

SECTIONS {
. = 0x0000;
.start       : { KEEP(*(.start)) }

. = 0x0100;
.isr_vectors : { *(.isr_vectors) }
.text        : { *(.text) }
/DISCARD/    : { *(.dynstr*) }
/DISCARD/    : { *(.dynamic*) }
/DISCARD/    : { *(.plt*) }
/DISCARD/    : { *(.interp*) }
/DISCARD/    : { *(.gnu*) }
/DISCARD/    : { *(.note*) }
}

This is my main.c (I know it's messy, but I didn't want to write any functions before I know that the core logic works):

#include "gpio/gpio.h"

// If I call this directly in main, it works so I know it's correct
void timer_handler(void) {

    // Initializes GPIO
    struct gpio_reg cfg = gpio_reg_init(GPIO_G_BANK, GPIO_CFG1_REG);
    struct gpio_reg dat = gpio_reg_init(GPIO_G_BANK, GPIO_DAT_REG);

    // Sets the PG9 mode to output and state to high
    gpio_set_pin_mode(&cfg, 4, GPIO_MODE_OUTPUT);
    gpio_set_pin_state(&dat, 9, GPIO_STATE_HIGH);
}

__attribute__((section(".isr_vectors"))) void (*const interrupt_vectors[96])(void) = {
    [82] = &timer_handler,
};

int main(void) {

    /*
     * Initialize interrupts
     */

    #define INTC_BASE (uintptr_t) 0x01c20400

    // Set the isr vector interrupt base addr
    // I load the binary at 0x48000000 with the command: fatload mmc 0:1 0x48000000 firmware.bin
    volatile uint32_t *intc_addr = (volatile uint32_t*) (INTC_BASE + 0x04);
    *intc_addr |= 0x48000000 + 0x100;

    // Enables the sync timer interrupt
    volatile uint32_t *int_en = (volatile uint32_t*) (INTC_BASE + 0x48);
    *int_en |= 7UL << 17;

    // Sets the interrupt priority
    volatile uint32_t *prio = (volatile uint32_t*) 0x01c20494;
    *prio |= 3UL << 4;


    /*
     * Initialize sync timer 0
     */

    #define TMR_BASE (uintptr_t) 0x01c60000

    // Enables interrupts for sync timer 0
    volatile uint32_t *tmr_irq_en = (volatile uint32_t*) (TMR_BASE);
    *tmr_irq_en |= 1UL;

    // Loads the counter value
    volatile uint32_t *low = (volatile uint32_t*) (TMR_BASE + 0x14);
    *low = 0xF44AA200;

    volatile uint32_t *high = (volatile uint32_t*) (TMR_BASE + 0x18);
    *high &= ~((1UL << 23) - 1);
    *high |= 0UL;

    // Set the sync timer AHB gating
    volatile uint32_t *ahb_gating = (volatile uint32_t*) 0x01c20060;
    *ahb_gating |= 1UL << 28;

    // Starts the counter
    volatile uint32_t *cntr = (volatile uint32_t*) (TMR_BASE + 0x10);
    *cntr |= 1UL;

    volatile uint32_t v = 0;
    while(1) { v++; } // Infinite loop

    return 0;
}

Any help is appreciated,
Federico


Reply all
Reply to author
Forward
0 new messages