ARM bare metal timer interrupt

Publisher:TranquilVibesLatest update time:2016-06-06 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
       This article uses mini2440 as the development environment to achieve the goal of: implementing a timer interrupt on a bare metal machine to make LED0 flash for 1 second.

        int.c function

/*
 * init.c: do some initialization
 */

#include "s3c24xx.h"

void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void copy_steppingstone_to_sdram(void);
void init_led(void);
void timer0_init(void);
void init_irq(void);

/*
 * Turn off WATCHDOG, otherwise the CPU will restart continuously
 */
void disable_watch_dog(void)
{
    WTCON = 0; // Turning off WATCHDOG is very simple, just write 0 to this register
}

#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
/*
 * For the MPLLCON register, [19:12] is MDIV, [9:4] is PDIV, and [1:0] is SDIV
 * The calculation formula is as follows:
 * S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
 * S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
 * Where: m = MDIV + 8, p = PDIV + 2, s = SDIV
 * For this development board, Fin = 12MHz
 * Set CLKDIVN to make the division ratio: FCLK:HCLK:PCLK=1:2:4,
 * FCLK=200MHz, HCLK=100MHz, PCLK=50MHz
 */
void clock_init(void)
{
    // LOCKTIME = 0x00ffffff; // Use the default value
    CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

    /* If HDIVN is non-zero, the CPU's bus mode should be changed from "fast bus mode" to "asynchronous bus mode" */
__asm__(
    "mrc p15, 0, r1, c1, c0, 0\n" /* Read control register*/
    "orr r1, r1, #0xc0000000\n" /* Set to "asynchronous bus mode" */
    "mcr p15, 0, r1, c1, c0, 0\n" /* Write control register*/
    );

    /* Determine whether it is S3C2410 or S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        MPLLCON = S3C2410_MPLL_200MHZ; /* Now, FCLK=200MHz, HCLK=100MHz, PCLK=50MHz */
    }
    else
    {
        MPLLCON = S3C2440_MPLL_200MHZ; /* Now, FCLK=200MHz, HCLK=100MHz, PCLK=50MHz */
    }
}

/*
 * Set up the memory controller to use SDRAM
 */
void memsetup(void)
{
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

    /* This function is assigned in this way, instead of assigning the configuration value like the previous experiment (such as the mmu experiment)
     * It is written in an array because it is used to generate "position-independent code" so that this function can be used in
     * SDRAM can run in steppingstone before
     */
    /* Storage controller 13 register values ​​*/
    p[0] = 0x22011110; //BWSCON
    p[1] = 0x00000700; //BANKCON0
    p[2] = 0x00000700; //BANKCON1
    p[3] = 0x00000700; //BANKCON2
    p[4] = 0x00000700; //BANKCON3
    p[5] = 0x00000700; //BANKCON4
    p[6] = 0x00000700; //BANKCON5
    p[7] = 0x00018005; //BANKCON6
    p[8] = 0x00018005; //BANKCON7

    /* REFRESH,
     * HCLK=12MHz: 0x008C07A3,
     * HCLK=100MHz: 0x008C04F4
     */
    p[9] = 0x008C04F4;
    p[10] = 0x000000B1; //BANKSIZE
    p[11] = 0x00000030; //MRSRB6
    p[12] = 0x00000030; //MRSRB7
}

void copy_steppingstone_to_sdram(void)
{
    unsigned int *pdwSrc = (unsigned int *)0;
    unsigned int *pdwDest = (unsigned int *)0x30000000;

    while (pdwSrc < (unsigned int *)4096)
    {
        *pdwDest = *pdwSrc;
        pdwDest++;
        pdwSrc++;
    }
}

/*
 * LED1, LED2, LED4 correspond to GPB5, GPB6, GPB7, GPB8
 */
#define GPB5_out (1<<(5*2))
#define GPB6_out (1<<(6*2))
#define GPB7_out (1<<(7*2))
#define GPB8_out (1<<(8*2))

#define GPB5_msk (3<<(5*2))
#define GPB6_msk (3<<(6*2))
#define GPB7_msk (3<<(7*2))
#define GPB8_msk (3<<(8*2))

void init_led(void)
{
	// Set the 4 pins corresponding to LED1, LED2, LED3, and LED4 as output
	GPBCON &= ~(GPB5_msk | GPB6_msk | GPB7_msk | GPB8_msk);
	GPBCON |= GPB5_out | GPB6_out | GPB7_out | GPB8_out;
}

/*
 * Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
 * {prescaler value} = 0~255
 * {divider value} = 2, 4, 8, 16
 * The clock frequency of Timer0 in this experiment = 100MHz/(99+1)/(16)=62500Hz
 * Set Timer0 to trigger an interrupt every 0.5 seconds:
 */
void timer0_init(void)
{
    TCFG0 = 99; // Prescaler 0 = 99
    TCFG1 = 0x03; // Select 16-division
    TCNTB0 = 62500; // Trigger an interrupt every 0.5 seconds
    TCON |= (1<<1); // Manual update
    TCON = 0x09; // Automatically load, clear the "manual update" bit, and start timer 0
}

/*
 * Timer 0 interrupt enable
 */
void init_irq(void)
{
    // Timer 0 interrupt enable
    INTMSK &= (~(1<<10));
}
Interrupt function interrupt.c
#include "s3c24xx.h"

void Timer0_Handle(void)
{
    /*
     * Each interruption causes the 4 LEDs to change state, alternating between on and off
     */
    if(INTOFFSET == 10)
    {
        GPBDAT = ~(GPBDAT & (0xf << 5));
    }
    // Clear interrupt
    SRCPND = 1 << INTOFFSET;
    INTPND = INTPND;
}
Main function main.c
int main(void)
{
    while(1);
    return 0;
}

This program is modified based on Wei Dongshan's embedded Linux application development and is suitable for mini2440 to do timer interrupt experiments.
Reference address:ARM bare metal timer interrupt

Previous article:ARM learning timer Timer0 experiment
Next article:Arm learning process

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号