天天看點

mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖

環境搭建

    硬體環境:J-link v8、mini2440、J-link轉接闆、序列槽轉USB線

    軟體環境:windows7(32位)、開發闆uboot(NandFlash)、J-link驅動(J-Link ARM V4.10i)、SecureCRT、ADS1.2

    其中ADS裡的AXD設定:加載JlinkRDI.dll+Options->Configure Interface...,在Session File一頁中選擇“Run Configuration Script”,将該name.txt文本檔案作為一個腳本加進來,确定。

name.txt内容

Setmem 0x53000000 0x00000000 32
Setmem 0x4A000008 0xFFFFFFFF 32
Setmem 0x4A00001C 0x000007FF 32
Setmem 0x53000000 0x00000000 32
Setmem 0x56000050 0x000055AA 32
Setmem 0x4C000014 0x00000007 32
Setmem 0x4C000000 0x00FFFFFF 32
Setmem 0x4C000004 0x00061012 32
Setmem 0x4C000008 0x00040042 32
Setmem 0x48000000 0x22111120 32
Setmem 0x48000004 0x00002F50 32
Setmem 0x48000008 0x00000700 32
Setmem 0x4800000C 0x00000700 32
Setmem 0x48000010 0x00000700 32
Setmem 0x48000014 0x00000700 32
Setmem 0x48000018 0x0007FFFC 32
Setmem 0x4800001C 0x00018005 32
Setmem 0x48000020 0x00018005 32
Setmem 0x48000024 0x008E0459 32
Setmem 0x48000028 0x00000032 32
Setmem 0x4800002C 0x00000030 32
Setmem 0x48000030 0x00000030 32

           

RTC實作功能

    RTC開節拍中斷、鬧鐘中斷。

    節拍中斷——序列槽輸出時間  XXXX年XX月XX日XX時XX分XX秒  和  LED閃亮

    鬧鐘中斷——beep聲  和 LED亮  5秒

RTC概述

    實時時鐘(RTC)單元可以在當系統電源關閉後通過備用電池工作。RTC可以通過使用STRB/LDRB ARM操

    作發送8位二-十進制交換碼(BCD)值資料給CPU。這些資料包括年、月、日、星期、時、分和秒的時間資訊。

    RTC單元工作在外部32.768kHz晶振并且可以執行鬧鐘功能。

特性

–  BCD數:年、月、日、星期、時、分和秒

–  閏年發生器

–  鬧鐘功能:鬧鐘中斷或從掉電模式喚醒

–  已解決的2000年問題

–  獨立電源引腳(RTCVDD)

–  支援RTOS核心時鐘節拍(tick)的毫秒節拍時間中斷

mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖

    由圖可知由于RTC秒有RTCRST複位寄存器,當RTC寄存器被指派後,秒寄存器數值自動1s(1s=(1/1HZ),

1HZ為2^15時鐘分頻器産生的1HZ)加一,秒寄存器到60時被複位寄存器置零,分寄存器加一,以此類推。

RTC實時時鐘

    實時時鐘的值是存放在BCD寄存器裡(BCD碼),BCD碼是4位二進制碼表示1位十進制數。

實時時鐘初始化(指派) RTCCON寄存器的使用

讀寫BCD 寄存器的時候隻需要将RTCCON寄存器RTCEN(讀寫)使能,其他為初始值

mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖

實時時鐘初始化代碼

開BCD讀寫使能

rRTCCON |=0x01;  //RTCCON隻控制BCD寄存器,ALM資料寄存器就不需要讀寫使能了
           

BCD寄存器指派。

rBCDSEC    =0x0;   //14年6月12日1點1分0秒 星期4
    rBCDMIN    =0x01;
    rBCDHOUR   =0x01;
    rBCDDAY    =0x4;    //星期
    rBCDDATE   =0x12;
    rBCDMON    =0x6;
    rBCDYEAR   =0x14;
           

BCD寄存器指派完成後必須将讀寫關閉,防止資料異常

rRTCCON &=~0x01;
           

之後BCD寄存器裡的值開始計時

節拍中斷使能

    始終節拍發生器可以産生節拍中斷,據使用者手冊:

RTC節拍時間是用于中斷請求。TICNT寄存器有一個中斷使能位和中斷的計數值。當節拍時間中斷發生時計

數值達到'0'。然後中斷周期如下:

—  周期 = ( n+1 ) / 128 秒

—  n:節拍時間計數值(1至127)

此RTC時間節拍可能被用于實時作業系統(RTOS)核心時間節拍。如果時間節拍是由RTC時間節拍所産生的,RTOS與時間的功能将通常同步到實際時間。

由此可知節拍中斷産生的時間可以精确到(n+1 ) / 128 秒,n為1-127區間的取值。

TICNT   [7]    節拍時間中斷使能。

TICNT   [6:0]   節拍時間計數值(1至127)。

節拍中斷使能代碼

rTICNT |= (1<<7) | 127; //節拍中斷使能 計時寄節拍設定1s  1s=(127+1)/128
           

注意:這裡隻是開了中斷使能産生節拍中斷INT_TICK,并沒有開中斷

鬧鐘中斷使能

鬧鐘功能

RTC在掉電模式中或正常工作模式中的指定時間産生一個鬧鐘信号。在正常工作模式中,隻激活鬧鐘中斷(INT_RTC)信号。在掉電模式中,除了INT_RTC 之外還激活電源管理喚醒(PMWKUP)信号。RTC鬧鐘寄存器(RTCALM)決定了鬧鐘使能/禁止狀态和鬧鐘時間設定的條件。

   我們是在正常模式中産生INT_RTC(鬧鐘)中斷信号源的。使能鬧鐘中斷,當ALM寄存器(年、月、日、時、分、秒)的值與BCD寄存器(年、月、日、時、分、秒)值相等時産生中斷信号。RTCALM寄存器是決定ALM鬧鐘使能和鬧鐘時間的,當RTCALM使能分秒的時候,隻确認ALM寄存器(分、秒)的值與BCD寄存器(分、秒)值是否相等即産生中斷信号。

    ALM寄存器是需要指派的,但并沒有BCD寄存器那樣的讀寫使能,而是直接指派的。

鬧鐘中斷使能

rRTCALM = 0x41;        //全局鬧鐘使能,秒鬧鐘使能(0b1000001)
           

ALM鬧鐘寄存器指派

rALMYEAR =0x14;  //年
    rALMMON  =0x06;  //月
    rALMDATE =0x12;  //日
    rALMHOUR =0x01;  //時
    rALMMIN  =0x01;  //分
    rALMSEC  =0x03;  //秒
           

中斷函數

概述

    S3C2440A中的中斷控制器接受來自60個中斷源的請求。提供這些中斷源的是内部外設,如DMA控制器、UART、IIC等等。在這些中斷源中,UARTn、AC97和EINTn中斷對于中斷控制器而言是“或”關系。當從内部外設和外部中斷請求引腳收到多個中斷請求時,中斷控制器在仲裁步驟後請求ARM920T核心的FIQ或IRQ。仲裁步驟由硬體優先級邏輯決定并且寫入結果到幫助使用者通告是各種中斷源中的哪個中斷發生了的中斷挂起寄存器中。

mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖

鬧鐘中斷和節拍中斷是沒有sub寄存器的,通過圖14-1可以看出中斷發生是:

中斷請求中斷服務>>SRCPND>>仲裁>> INTPND>>irq中斷

中斷挂起寄存器

S3C2440A有兩個中斷挂起寄存器:源挂起寄存器(SRCPND)和中斷挂起寄存器(INTPND)。這些挂起寄存器表明一個中斷請求是否為挂起。當中斷源請求中斷服務,SRCPND寄存器的相應位被置位為1,并且同時在仲裁步驟後INTPND 寄存器僅有1位自動置位為1。如果屏蔽了中斷,則SRCPND寄存器的相應位被置位為1。這并不會引起INTPND 寄存器的位的改變。當INTPND 寄存器的挂起位為置位,每當I 标志或F标志被清除為0中斷服務程式将開始。SRCPND和INTPND寄存器可以被讀取和寫入,是以服務程式必須首先通過寫1到SRCPND寄存器的相應位來清除挂起狀态并且通過相同方法來清除INTPND寄存器中挂起狀态。

最後一句話可以知道開啟中斷需要SRCPND和INTPND寄存器清除挂起狀态

中斷屏蔽開啟可服務代碼

                                            // 注意點(二)

rINTMSK &= ~(0x1<<8);  // 中斷屏蔽開啟可服務(此中斷使能不能放在中斷入口函數内,因

                                            // 為中斷使能并不是中斷的操作,而是進中斷前的一個控制)

節拍中斷函數入口代碼

pISR_TICK=(unsigned)tick_interrupt; //告訴中斷進行中斷函數的入口位址  
           
void __irq alm_interrupt(){   //中斷入口函數  
    rSRCPND|=0x1<<30; //清除中斷挂起狀态
    rINTPND|=0x1<<30; //清除中斷挂起狀态   
    //中斷功能代碼塊
    Uart_Printf("\n\n ************************************* ");
    Uart_Printf("\n           鬧鐘時刻!5秒 ");
    Uart_Printf("\n ************************************* \n");
    rGPBDAT=LED_ON;        //點亮LED
Beep(2000, 4000);      //  由于産生中斷會有一秒的時間,是以實際是用了4+1秒這個中斷
   
                               //  注意點(一)
    rSRCPND &=(0x1<<30);   //  當産生中斷的時候,必須在開了中斷功能後關閉中斷清除
    rINTPND &=(0x1<<30);   //  而且關閉中斷清除的控制必須在此中斷入口函數由此中斷控制
                           //  (rSRCPND rINTPND置零,包括沒用到的rSUBSRCPND)都應該在中斷
                           //  入口函數裡操作,而且入口函數最後也别忘了關閉中斷清除
                           //  (rSRCPND rINTPND,rSUBSRCPND置零)
                           //  如果沒有關閉中斷,将無限實作鬧鐘中斷功能,其他中斷不能進行
     }
           

調試總結

(一)  RTC非中斷序列槽列印時間不連續問題(BCD碼)

       由來:之前寫了一個非中斷列印RTC實時時鐘的代碼,發現時間由9跳到16,後面發現是列印格式是十進制的原因,

       解決方法:資料在RTC裡是BCD碼存儲,十進制的,但是取出來的時候,BCD碼是四位二進制表示,最高位隻是9,

     10時BCD碼(大端存儲)是0001 0000,在這時如果采取進制轉換成10進制就是16,但是如果繼續使用16進制顯示就沒

     問題了,還是10

(二)  調試程式,中斷沒問題卻發生序列槽代碼while(!(rUTRSTAT0 & 0x2));出不來問題

     解決方法:

     main函數增加:

U32 mpll_val = 0,consoleNum;
    Port_Init();        //定義在2440lib.c
    mpll_val = (92<<12)|(1<<4)|(1);  
    //init FCLK=400M,
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //定義在2440lib.c
    ChangeClockDivider(14, 12);   //the result of rCLKDIVN [0:1:0:1] 3-0 bit 定義在2440lib.c
    cal_cpu_bus_clk();            //HCLK=100M   PCLK=50M
   
    consoleNum = 0;   // Uart 1 select for debug.
    Uart_Init( 0,115200 );           //定義在2440lib.c
    Uart_Select( consoleNum );      //定義在2440lib.c
           

cal_cpu_bus_clk()定義如下:

static U32 UPLL;
static U32 cpu_freq;
           
//************************[ HCLK=100M   PCLK=50M ]***************************
void cal_cpu_bus_clk(void)
{
    U32 val;
    U8 m, p, s;
    
    val = rMPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;

    //(m+8)*FIN*2 不要超出32位數!
    FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;
    
    val = rCLKDIVN;
    m = (val>>1)&3;
    p = val&1;  
    val = rCAMDIVN;
    s = val>>8;
    
    switch (m) {
    case 0:
        HCLK = FCLK;
        break;
    case 1:
        HCLK = FCLK>>1;
        break;
    case 2:
        if(s&2)
            HCLK = FCLK>>3;
        else
            HCLK = FCLK>>2;
        break;
    case 3:
        if(s&1)
            HCLK = FCLK/6;
        else
            HCLK = FCLK/3;
        break;
    }
    
    if(p)
        PCLK = HCLK>>1;
    else
        PCLK = HCLK;
    
    if(s&0x10)
        cpu_freq = HCLK;
    else
        cpu_freq = FCLK;
        
    val = rUPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;
    UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
    UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
}

           

RTC鬧鐘中斷,節拍中斷代碼

Main函數代碼

#define GLOBAL_CLK      1       
#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"  //函數聲明
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"


//功能代碼聲明處
extern void RTC_Display_TICK_ALM(void);            

void Main(void)
{   
    U32 mpll_val = 0,consoleNum;
    Port_Init();
   
    mpll_val = (92<<12)|(1<<4)|(1);
    
    //init FCLK=400M,
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
    ChangeClockDivider(14, 12);   //the result of rCLKDIVN [0:1:0:1] 3-0 bit
    cal_cpu_bus_clk();            //HCLK=100M   PCLK=50M
   
    consoleNum = 0;   // Uart 1 select for debug.
    Uart_Init( 0,115200 );
    Uart_Select( consoleNum );
    
    Beep(2000, 100);           

//>>>>>>>>>>>>>>以下是功能代碼塊入口<<<<<<<<<<<<<<<<<<<
    RTC_Display_TICK_ALM();     //鬧鐘中斷顯示實時時鐘,報警中斷(調試成功!)
}
           

RTC_Display_TICK_ALM函數代碼

#include "2440addr.h"     //引腳宏定義
#include "def.h"          // U8 U32宏定義
#include "2440lib.h"      //使用Uart_Printf,Dalay聲明,Uart_Printf定義在2440lib.c檔案
#include "option.h"
#include "mmu.h"

#define LED_OFF  (0x0f<<5)
#define LED_ON   (~0x0f<<5)

struct Time{          //RTC時間結構
    U32 year;
    U8 month;
    U8 day;
    U8 week;
    U8 hour;
    U8 mi;
    U8 sec;
}ttime_rtc;

void RTC_set()
{
    rRTCCON |=0x01;

    rBCDSEC    =0x0;   //14年6月12日1點1分0秒 星期4
    rBCDMIN    =0x01;
    rBCDHOUR   =0x01;
    rBCDDAY    =0x4;    //星期
    rBCDDATE   =0x12;
    rBCDMON    =0x6;
    rBCDYEAR   =0x14;

    rRTCCON &=~0x01;
}

void Led_Init(){
    rGPBCON=0x015400;  //GPB5 GPB6 GPB7 GPB8 初始化為輸出
    rGPBDAT=LED_OFF;   //熄滅狀态
}

//從RTC讀取值
void read_for_rtc()
{
    rRTCCON |=0x01;  //RTCCON隻控制BCD寄存器,ALM資料寄存器就不需要讀寫控制了

    ttime_rtc.year  =0x2000+rBCDYEAR;
    ttime_rtc.month =rBCDMON;
    ttime_rtc.day   =rBCDDATE;
    ttime_rtc.week  =rBCDDAY;
    ttime_rtc.hour  =rBCDHOUR;
    ttime_rtc.mi    =rBCDMIN;
    ttime_rtc.sec   =rBCDSEC;

    rRTCCON &=~0x01;
}

void ALM_set(){      // 鬧鐘指派
   

    rALMYEAR =0x14;
    rALMMON  =0x06;
    rALMDATE =0x12;
    rALMHOUR =0x01;
    rALMMIN  =0x01;
    rALMSEC  =0x03;
    
}

void RTC_display(){
    Uart_Printf("\n");
    Uart_Printf("\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n");
    Uart_Printf("**************HELLO RTC鬧鐘中斷、節拍中斷*****************\n\n");
    Uart_Printf("#rTICNT:   (1<<7) | 127   允許節拍使能\n",rTICNT);
    Uart_Printf("#rRTCALM:  0b1000001      允許鬧鐘使能 秒精度鬧鐘\n",rRTCALM);
    Uart_Printf("#rINTMSK:  ~(0x1<<8)      開啟INT_TICK中斷源服務\n");
    Uart_Printf("#rINTMSK:  ~(0x1<<30)     開啟INT_RTC 中斷源服務\n");
    Uart_Printf("#rSRCPND    rINTPND        中斷控制器清除相應位再關閉\n");
    Uart_Printf("#\n#通過RTC節拍中斷,序列槽輸出開發闆系統時間\n");   
    Uart_Printf("#XXXX年XX月XX日XX時XX分XX秒 | LED閃亮\n");
    Uart_Printf("#并且可設定鬧鐘,鬧鐘到時,beep聲|LED亮\n");    
    Uart_Printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n\n\n");        
}

void __irq tick_interrupt(){
    rSRCPND|=0x1<<8;   //清除中斷挂起狀态
    rINTPND|=0x1<<8;
    
    //中斷功能代碼塊
    
    
    rGPBDAT =~(rGPBDAT>>5)<<5 ; //LED燈 亮閃狀态切換(這樣運算不會影響到蜂鳴器)
    read_for_rtc();
    Uart_Printf("\n  RTC time: %x年%2x月%02x日--%02x:%02x:%02x   星期%d",ttime_rtc.year,ttime_rtc.month,ttime_rtc.day,ttime_rtc.hour,ttime_rtc.mi,ttime_rtc.sec,ttime_rtc.week);
     
    //rTICNT  &= ~(1<<7); //當隻使用一次中斷的時候關閉子產品使能
    rSRCPND &=(0x1<<8);
    rINTPND &=(0x1<<8);
    
     }

void __irq alm_interrupt(){   //中斷入口函數
    
    rSRCPND|=0x1<<30;
    rINTPND|=0x1<<30;
    
    //中斷功能代碼塊
    
    Uart_Printf("\n\n ************************************* ");
    Uart_Printf("\n           鬧鐘時刻!5秒 ");
    Uart_Printf("\n ************************************* \n");
    rGPBDAT=LED_ON;        //點亮LED
    Beep(2000, 4000);      //  由于産生中斷會有一秒的時間,是以實際是用了4+1秒這個中斷
    
    
                           //  注意點(一)
    rSRCPND &=(0x1<<30);   //  當産生中斷的時候,必須在開了中斷功能後關閉中斷清除
    rINTPND &=(0x1<<30);   //  而且關閉中斷清除的控制必須在此中斷入口函數由此中斷控制
                           //  (rSRCPND rINTPND置零,包括沒用到的rSUBSRCPND)都應該在中斷
                           //  入口函數裡操作,而且入口函數最後也别忘了關閉中斷清除
                           //  (rSRCPND rINTPND,rSUBSRCPND置零)
                           //  如果沒有關閉中斷,将無限實作鬧鐘中斷功能,其他中斷不能進行
     }


void RTC_TICK(){
    
    rTICNT |= (1<<7) | 127; //節拍中斷使能 計時寄節拍設定1s
    
                          //  注意點(二)
    rINTMSK &= ~(0x1<<8); //  中斷屏蔽開啟可服務(此中斷使能不能放在中斷入口函數内,因
                          //  為中斷使能并不是中斷的操作,而是進中斷前的一個控制)
                          
    pISR_TICK=(unsigned)tick_interrupt; //告訴中斷進行中斷函數的入口位址                                                     
    }
    
void RTC_ALM(){

    rRTCALM = 0x41;        //全局鬧鐘使能,秒鬧鐘使能(0b1000001)
    
    rINTMSK &= ~(0x1<<30);
    pISR_RTC =(unsigned)alm_interrupt;
            
    }
    
void RTC_Display_TICK_ALM()   //    子main函數
{
    //MMU_EnableICache();這一點至關重要, 不要關閉mmu,否則中斷不能正常使用
    MMU_Init();
    Led_Init();        //led1 2 3 4輸出,初始化熄滅狀态
    RTC_display();     //列印相應資訊
    
    RTC_set();         //rtc指派
    ALM_set();         // ALM鬧鐘指派    
 
    RTC_TICK();        //節拍中斷
    RTC_ALM();         //鬧鐘中斷      
    
    while(1)
    {           
     
    }
}

           

輸出截圖

mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖
mini2440裸機試煉之—RTC鬧鐘中斷,節拍中斷環境搭建name.txt内容RTC實作功能中斷函數 調試總結 RTC鬧鐘中斷,節拍中斷代碼輸出截圖

繼續閱讀