程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> uboot中timer定時器的設置

uboot中timer定時器的設置

編輯:C++入門知識

uboot中timer定時器的設置,uboot匯編部分沒有對timer初始化,而是在C中。在C入口函數void start_armboot(void)中,首先是通過如下代碼方式調用: [cpp]   typedef int (init_fnc_t) (void);   [html]  init_fnc_t *init_sequence[] = {    a/a/l/board.c                                                                                                                         #if defined(CONFIG_ARCH_CPU_INIT)       arch_cpu_init,      /* basic arch cpu dependent setup */   #endif       board_init,     /* basic board dependent setup */   #if defined(CONFIG_USE_IRQ)       interrupt_init,     /* set up exceptions */   #endif       timer_init,     /* initialize timer */   #ifdef CONFIG_FSL_ESDHC       get_clocks,   #endif       env_init,       /* initialize environment */       init_baudrate,      /* initialze baudrate settings */       serial_init,        /* serial communications setup */       console_init_f,     /* stage 1 init of console */       display_banner,     /* say that we are here */   #if defined(CONFIG_DISPLAY_CPUINFO)       print_cpuinfo,      /* display cpu info (and speed) */   #endif   #if defined(CONFIG_DISPLAY_BOARDINFO)       checkboard,     /* display board info */   #endif   #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)       init_func_i2c,   #endif       dram_init,      /* configure available RAM banks */   #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)       arm_pci_init,   #endif       display_dram_config,       NULL,   };   這裡是u-boot的C代碼部分的入口: [cpp]   void start_armboot (void)   {       init_fnc_t **init_fnc_ptr;                 。                 。                 。             for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {           if ((*init_fnc_ptr)() != 0) {               hang ();           }       }   上面的函數調用很復雜,不是討論這個所以暫時不深究,直接看它調用arch/arm/cpu/arm920t/s3c24x0/timer.c文件中的函數int timer_init (void),代碼如下:     [cpp]   int timer_init(void)   {       struct s3c24x0_timers *timers = s3c24x0_get_base_timers();       ulong tmr;          /* use PWM Timer 4 because it has no output */       /* prescaler for Timer 4 is 16 */       writel(0x0f00, &timers->TCFG0);       if (timer_load_val == 0) {           /*           * for 10 ms clock period @ PCLK with 4 bit divider = 1/2           * (default) and prescaler = 16. Should be 10390           * @33.25MHz and 15625 @ 50 MHz           */           timer_load_val = get_PCLK() / (2 * 16 * 100);           timer_clk = get_PCLK() / (2 * 16);       }       /* load value for 10 ms timeout */       lastdec = timer_load_val;       writel(timer_load_val, &timers->TCNTB4);       /* auto load, manual update of Timer 4 */       tmr = (readl(&timers->TCON) & ~0x0700000) | 0x0600000;       writel(tmr, &timers->TCON);       /* auto load, start Timer 4 */       tmr = (tmr & ~0x0700000) | 0x0500000;       writel(tmr, &timers->TCON);       timestamp = 0;          return (0);   }     以下是對函數的詳細分析:  1、先看數據結構s3c24x0_timers [cpp]   struct s3c24x0_timers {       u32 TCFG0;       u32 TCFG1;       u32 TCON;       struct s3c24x0_timer    ch[4];       u32 TCNTB4;       u32 TCNTO4;    };     有引出來了另一個結構s3c24x0_timer [cpp]   struct s3c24x0_timer {       u32 TCNTB;       u32 TCMPB;       u32 TCNTO;   };   看下這兩個結構是不是涵蓋了所有timer的寄存器,對照s3c2440的datasheet得出結論是:timer寄存器地址空間從(0x51000000~0x51000040)依次對應的寄存器名是卻是是上面的結構體中的寄存器,總共是17個寄存器. 為什麼會有4個結構s3c24x0_timer呢?因為2440有5個timer,其中前四個timer0~timer3工作方式類似,都有外部引腳引出,而第五個timer4不同與他們,第一個就是它沒有TCMPB寄存器,具體的區別可以看看這個文檔或是datasheet:   2、s3c24x0_get_base_timers()函數返回的就是timer寄存器空間的起始地址0x51000000 [cpp]   static inline struct s3c24x0_timers *s3c24x0_get_base_timers(void)   {          return (struct s3c24x0_timers *)S3C24X0_TIMER_BASE;   }     3、 [cpp]   /* use PWM Timer 4 because it has no output */      /* prescaler for Timer 4 is 16 */   這個注釋是不是有問題呢,我怎麼查不到timer4預分頻器是16位的,都是8位。是不是要表達計數器是16位的呢? 4、writel(0x0ff,&timers->TCFG0)的作用是什麼呢?在arch/arm/include/asm/io.h文件中既然有3處定義了這個函數,考察了一下只有下面被編譯: [cpp]  #define writel(v,a)         __arch_putl(v,a)   [cpp]   #define __arch_putl(v,a)        (*(volatile unsigned int *)(a) = (v))   分析:就是往a寄存器寫入v. 這裡就是往寄存器TCFG0寫入0x0ff,先看下TCFG0寄存器信息:    將timer0、1的預分頻器的值寫ff就是255,         其值N為: 0~255        輸出頻率為:PCLK ÷(N+1) 這時候N = 255,結合這篇文檔http://blog.csdn.net/sonbai/article/details/8687858知道PCLK的頻率是101.25MHz,輸出頻率就出來了,這時候最低,同時沒有用到他們,所以不考慮了。t只考慮imer4,這時候N = 0,輸出頻率最大就是PCLK。為什麼要設最大,先放著 5、timer_load_val是一個全局變量,顧名思義它是裝入TCNTB4寄存器的值。看下面的注釋: [cpp]   /*   * for 10 ms clock period @ PCLK with 4 bit divider = 1/2   * (default) and prescaler = 16. Should be 10390   * @33.25MHz and 15625 @ 50 MHz   */   它的意思是如果要將timer4的時鐘周期設置為10ms的話,要通過PCLK、分配器divider默認的值1/2和prescaler = 16來設置如何設置(?)來看一下下面這個函數 [cpp]  /* return PCLK frequency */   ulong get_PCLK(void)   {          struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();              return (readl(&clk_power->CLKDIVN) & 1) ? get_HCLK() / 2 : get_HCLK();   }      看看結構s3c24x0_clock_power [cpp]   /* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */   /*                          (see S3C2410 manual chapter 7) */   struct s3c24x0_clock_power {       u32 LOCKTIME;       u32 MPLLCON;       u32 UPLLCON;       u32 CLKCON;       u32 CLKSLOW;       u32 CLKDIVN;   #if defined(CONFIG_S3C2440)       U32 CAMDIVN;   #endif   };       涵蓋了所有時鐘設置的寄存器,s3c24x0_get_base_clock_power();返回的是(struct s3c24x0_clock_power *)0x4C000000也就是時鐘設置寄存器的起始地址 [cpp]  return (readl(&clk_power->CLKDIVN) & 1) ? get_HCLK() / 2 : get_HCLK();   判斷一下CLKDIVN是不是被設置成了1,如果是說明PCLK = 1/2HCLK,不在去看get_HCLK了。前面我已經說過PCLK = 101.25MHz,至於timer_load_val = 101.25MHz / (2*16*100);這個公式,分析如下: 我們要設置timer4的時鐘周期是T = 10ms; 又  T = [1 /(PCLK / (預分頻器的值(prescaler)*分頻器的值(div)))] *timer_load_val 已知T、PCLK、perscaler、div,就可以求的 timer_load_val = PCLK / (perscaler * div) 但是這裡為什麼會有100呢?(暫時不清楚,望大家給我一個解釋) timer_clk下面暫時沒有遇到,先不考慮。 6、 [cpp]    /* load value for 10 ms timeout */       lastdec = timer_load_val;       writel(timer_load_val, &timers->TCNTB4);   然後將timer_load_val的值寫入TCNTB4寄存器中 7、下面是要配置TCON寄存器,也就是timer控制寄存器 [cpp]   /* auto load, manual update of Timer 4 */      tmr = (readl(&timers->TCON) & ~0x0700000) | 0x0600000;      writel(tmr, &timers->TCON);   先來看看TCON寄存器信息:   TCON現實與(~0x0700000)與運算,即TCON = TCON & F8FFFFF,也就是將TCON的20、21、21這幾個位清零,然後TCON = TCON | 0X0600000將位21、20設置為1,對照datasheet知道將timer4設置為自動裝載,和手動更新.這就有一個矛盾既然自動轉載干嘛還要手動更新呢?看下8就知道了。writel()函數已經介紹過了。 8、你看下面這個代碼就很有趣,他和上面的那個代碼很類似 [cpp]   /* auto load, start Timer 4 */      tmr = (tmr & ~0x0700000) | 0x0500000;      writel(tmr, &timers->TCON);   起始2440定時器第一次往TCONTB裝入初始值是要手動更新的,如果沒有更新初值自動更新那更新什麼呢,他不知道,TCONTB默認是0,更新0有什麼用呢。所以需要手動更新,然後關掉手動更新,設置好後,再啟動timer4就完成了timer4的設置和運行。 9、timestamp = 0,這句我們暫時還沒涉及到,他是後面要用的。   10、然後返回 [cpp]   return (0);    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved