Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Bare metal interrupts on A13

13 views
Skip to first unread message

Federico Fusco

unread,
Jan 19, 2025, 8:46:25 AMJan 19
to linux...@googlegroups.com
Hello,
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