S3C2440 timer 4 interrupt test program

Publisher:WhisperingRainLatest update time:2020-06-19 Source: eefocusKeywords:S3C2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

__irq is an identifier used to indicate whether a function is an interrupt function. For different compilers, the position of __irq in the function name is different, for example:
In the ADS compiler: void __irq IRQ_Eint0(void);
In the Keil compiler: void IRQ_Eint0(void) __irq;
But its meaning is the same, it completes the task of identifying the function as an interrupt function. When the compiler compiles and calls this function, it first protects the function entry scene, then executes the interrupt function, and after the function is executed, restores the interrupt scene. This whole process does not require the user to rewrite the code to complete, and is automatically completed by the compiler. Therefore, this also brings problems to ARM systems that do not have the interrupt nesting function. If interrupt nesting occurs when using __irq, the scene protection will be chaotic. For interrupt nesting processing, you can write the interrupt entry scene protection code yourself, and do not use the __irq identifier. (Xiao Dai: How to write nested interrupts is not studied here for the time being.


The summary is as follows
: 1. If you do not want to write the interrupt entry site protection code yourself, and there is no interrupt nesting during use, use __irq to identify our interrupt function in the interrupt function, otherwise an error will occur;


2. If you want to use interrupt nesting in the program, for ARM without interrupt nesting function, you must write the interrupt entry field protection code yourself, and you cannot use __irq to identify your interrupt function, otherwise an error will occur.


In the ADS compiler, the __irq keyword
is used to declare an IRQ interrupt service routine. If you use __irq to declare a function, the function represents an IRQ interrupt service routine, and the compiler will automatically add interrupt context protection code to the function. For the same function, if the keyword "__irq" is removed, the compiler will not add context protection code, but will just treat it as a normal function.


Now everyone should have a certain understanding of the "__irq" keyword. So, do all IRQ interrupt service routines need to be declared using the "__irq" keyword? In fact, it depends on the method of obtaining the "interrupt service routine address":
if the interrupt site is not protected before executing the interrupt service function, then the interrupt service function must be declared using the "__irq" keyword. For example, when the instruction "LDR PC, [PC, #-0xff0]" is executed at 0x0000 0018, the corresponding interrupt service function must be declared using the "__irq" keyword; if the interrupt site has been protected before executing the interrupt service function, then the interrupt service function cannot be declared using the "__irq" keyword.

 

//==========================================
// NAME: main.c
// DESC: Internal timer 4LED light delay
//==============================================

#define U32 unsigned int


#define _ISR_STARTADDRESS 0x33ffff00

#define pISR_TIMER4 (*(unsigned *)(_ISR_STARTADDRESS+0x58))

#define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status source pending register
#define rINTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control interrupt mask register
#define rINTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status interrupt pending register

#define rTCFG0 (*(volatile unsigned *)0x51000000) //Timer 0 configuration
#define rTCFG1 (*(volatile unsigned *)0x51000004) //Timer 1 configuration
#define rTCON (*(volatile unsigned *)0x51000008) //Timer control
#define rTCNTB4 (*(volatile unsigned *)0x5100003c) //Timer count buffer 4

#define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control
#define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data
#define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B

void led_init(void)
{
 //The onboard LED is GPB[5:8]
 rGPBCON = (rGPBCON & ~(0xff<<10)) | (0x55<<10); //rGPBCON is 01, configured as output
 rGPBUP = rGPBUP | (0xf<<5); //rGPBUP is 1, disable pull-up
 rGPBDAT = rGPBDAT | (0xf<<5); //LED lights are all off
}

void led_display(unsigned char data)
{
 //0x0 all off 0xf all on 0x01 0x02 0x04 0x80 each light is on
 rGPBDAT = (rGPBDAT & ~(0xf<<5)) | ((~data) <<5);
}

void timer4_init(void)
{
 rSRCPND = rSRCPND | (0x1<<14); //Clear timer 4 source request
    rINTPND = rINTPND | (0x1<<14); //Clear timer 4 interrupt request
    rINTMSK = rINTMSK & ~(0x1<<14); //Turn on timer 4 interrupt    
    //Timer configuration register 0 
    //Timer input clock frequency = PCLK / {prescaler value + 1} / {divider value}
    //{prescaler value} = 0~255 {divider value} = 2, 4, 8, 16 
    //25KHz:50MHz/(250*8)=50MHz/(2000)
    rTCFG0 = (rTCFG0 & ~(0xff<<8)) | (249<<8); // prescaler1:249
    rTCFG1 = (rTCFG1 & ~(0xf<<16)) | (0x2<<16); //divider:8,0b0010
    
    rTCNTB4 = 25000; //Let timer 4 interrupt once every 1 second 25000=1*25000
    rTCON = (rTCON & ~(0x7<<20)) | (0x7<<20); //Automatically reload, manually update, start timer 4
    rTCON = (rTCON & ~(0x2<<20)); //Turn off manual update
}

void __irq timer4_ISR(void)
{
 static int count;
 rSRCPND = rSRCPND | (0x1<<14);
 rINTPND = rINTPND | (0x1<<14);
 //The LED turns on every 0.5 seconds
 if (count == 0)
 {
  led_display(0xf); //LED turns on
  count = 1;
 }
 else if (count == 1)
 {
    led_display(0x0); //LED turns off
    count = 0;
 } 
}

void Main(void)
{
 led_init();
 timer4_init();
 
    pISR_TIMER4 = (U32)timer4_ISR;  
 while(1); 
}

-------------------------------------

pISR_UNDEF=(unsigned)HaltUndef;

Any address can be regarded as a pointer to a variable. pISR_UNDEF is equivalent to a pointer variable. pISR_UNDEF=(unsigned)HaltUndef; is equivalent to storing the address of the function HaltUndef in this pointer variable. That is to say, the address of HaltUndef is stored in the address _ISR_STARTADDRESS+0x4. The purpose of this code is to assign a value to the interrupt function. When an interrupt occurs, the system will fetch the address of the interrupt function, that is, the address of HaltUndef, from the address defined by pISR_UNDEF and then execute it. It is equivalent to executing the HaltUndef function when an interrupt occurs. 

Keywords:S3C2440 Reference address:S3C2440 timer 4 interrupt test program

Previous article:S3C2440 interrupt architecture: external interrupt experiment
Next article:ARM study notes 020: _asm_, CPSR, SPSR, position-independent code and other issues

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号