1. 程式人生 > >STM32F系列ARM Cortex-M3核微控制器基礎之系統時鐘二

STM32F系列ARM Cortex-M3核微控制器基礎之系統時鐘二

  STM32F系列ARM Cortex-M3核微控制器基礎之系統時鐘 問題一:STM32 BIT_BAND 位段位帶別名區使用:什麼是位段、位帶別名區? 它有什麼好處?  記得MCS51嗎? MCS51就是有位操作,以一位(BIT)為資料物件的操作,MCS51可以簡單的將P1口的第2位獨立操作: P1.2=0;P1.2=1 ; 就是這樣把P1口的第三個腳(BIT2)置0置。而現在STM32的位段、位帶別名區就為了實現這樣的功能。物件可以是SRAM,I/O外設空間。實現對這些地方的某一位的操作。 它是這樣的。在定址空間(32位地址是 4GB )另一地方,取個別名區空間,從這地址開始處,每一個字(32BIT)就對應SRAM或I/O的一位。 這樣呢,1MB SRAM就 可以有32MB的對應別名區空間,就是1位膨脹到32位(1BIT 變為1個字)。我們對這個別名區空間開始的某一字操作,置0或置1,就等於它對映的SRAM或I/O相應的某地址的某一位的操作。  簡單來說,可以把程式碼縮小, 速度更快,效率更高,更安全。一般操作要6條指令,而使用 位帶別名區只要4條指令。一般操作是  讀-改-寫  的方式, 而位帶別名區是 寫 操作。防止中斷對讀-改-寫  的方式的影響。    CM3支援了位帶操作(bit_band),可以使用普通的載入/儲存指令來對單一的位元進行讀寫。CM3中有兩個區中實現了位帶。其中一個是SRAM 區的最低1MB 範圍,第二個則是片內外設區的最低1MB 範圍。這兩個區中的地址除了可以像普通的RAM 一樣使用外,它們還都有自己的“位帶別名區”,位帶別名區把每個位元膨脹成一個32 位的字 每個位元膨脹成一個32 位的字,就是把  1M  擴充套件為 32M ,於是;RAM地址 0X200000000(一個位元組)擴充套件到8個32 位的字,它們是:0X220000000 ,0X220000004,0X220000008,0X22000000C,0X220000010,0X220000014, 0X220000018,0X22000001C 。支援位帶操作的兩個記憶體區的範圍是:0x2000_0000‐0x200F_FFFF(SRAM 區中的最低1MB)0x4000_0000‐0x400F_FFFF(片上外設區中的最低1MB)。
對SRAM 位帶區的某個位元,記它所在位元組地址為A,位序號為n(0<=n<=7),在別名區的地址為:AliasAddr= 0x22000000 +((A‐0x20000000)*8+n)*4 =0x22000000+ (A‐0x20000000)*32 + n*4。對於片上外設位帶區的某個位元,記它所在位元組的地址為A,位序號為n(0<=n<=7),則該位元在別名區的地址為:AliasAddr= 0x42000000+((A‐0x40000000)*8+n)*4 =0x42000000+ (A‐0x40000000)*32 + n*4。上式中,“*4”表示一個字為4 個位元組,“*8”表示一個位元組中有8 個位元。 把“位帶地址+位序號”轉換別名地址巨集 #define  BITBAND(addr, bitnum) ((addr & 0xF000 0000)+0x200 0000+((addr &0xF FFFF)<<5)+(bitnum<<2)), 注:addr & 0xF000 0000取出0x2000 0000或0x4000 0000高位,addr &0xF FFFF取出bit-band區地址變化的部分 把該地址轉換成一個指標,並解索引 #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))      使用: MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;




對庫函式中的該部分地址的組織規則的探討:

第一次劃分: #define FLASH_BASE                ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
#define SRAM_BASE                 ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
        //別名區SRAM基地址
#define PERIPH_BASE              ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
        //別名區外設基地址 #define SRAM_BB_BASE          ((uint32_t)0x22000000) /*!< SRAM base address in the bit-band region */
        //位帶區SRAM基地址
#define PERIPH_BB_BASE       ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
        //位帶區外設基地址
#define FSMC_R_BASE             ((uint32_t)0xA0000000) /*!< FSMC registers base address */

第二次劃分  /*!< Peripheral memory map 外設儲存映像*/
#define APB1PERIPH_BASE       PERIPH_BASE                                                     //APB1匯流排基地址((uint32_t)0x4000 0000)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)                              //APB2匯流排基地址((uint32_t)0x4001 0000)
#define AHBPERIPH_BASE         (PERIPH_BASE + 0x20000)                                //AHB 匯流排基地址((uint32_t)0x4002 0000)
第三次劃分
#define TIM2_BASE                       (APB1PERIPH_BASE + 0x0000)                                 //TIM2定時器基地址((uint32_t)0x4000 0000)
#define TIM3_BASE                       (APB1PERIPH_BASE + 0x0400)                                 //TIM3定時器基地址((uint32_t)0x4000 0400)
#define TIM4_BASE                       (APB1PERIPH_BASE + 0x0800)                                 //TIM4定時器基地址((uint32_t)0x4000 0800)
#define TIM5_BASE                       (APB1PERIPH_BASE + 0x0C00)                                //TIM5定時器基地址((uint32_t)0x4000 0C00)
#define TIM6_BASE                       (APB1PERIPH_BASE + 0x1000)                                 //TIM6定時器基地址((uint32_t)0x4000 1000)
#define TIM7_BASE                       (APB1PERIPH_BASE + 0x1400)                                 //TIM7定時器基地址((uint32_t)0x4000 1400)
#define TIM12_BASE                    (APB1PERIPH_BASE + 0x1800)
#define TIM13_BASE                    (APB1PERIPH_BASE + 0x1C00)
#define TIM14_BASE                    (APB1PERIPH_BASE + 0x2000)
#define RTC_BASE                       (APB1PERIPH_BASE + 0x2800)                                 //RTC基地址       ((uint32_t)0x4000 2800)
#define WWDG_BASE                  (APB1PERIPH_BASE + 0x2C00)                            //視窗看門狗基地址((uint32_t)0x4000 2C00)
#define IWDG_BASE                     (APB1PERIPH_BASE + 0x3000)                               //獨立看門狗基地址((uint32_t)0x4000 3000) ...... #define RCC_BASE              (AHBPERIPH_BASE + 0x1000)                                  //復位和時鐘控制基地址((uint32_t)0x4002 1000)

下面是各暫存器的地址參考:




我們可以看到韌體庫中的外設地址巨集定義是按照先整體後部分的模式來組織的。 先定義在儲存器中外設別名和位帶的基地址,然後在外設別名區此基礎上分割出AHB,APB1,APB2的基地址。最後對各個匯流排下掛載的外設暫存器的基地址進行巨集定義。
韌體V3.5.0中對位帶操作的使用: /* ------------ RCC registers bit address in the alias region ----------- */   
//復位和時鐘控制暫存器別名區位地址
#define RCC_OFFSET                (RCC_BASE - PERIPH_BASE)                          //RCC暫存器組在外設儲存映像中的偏移
//RCC_BASE = (AHBPERIPH_BASE + 0x1000) AHBPERIPH_BASE = (PERIPH_BASE + 0x20000)
//PERIPH_BASE = ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
//RCC_BASE = ((uint32_t)0x40021000)  RCC_OFFSET = ((uint32_t)0x0002 1000)                               

/* --- CR Register ---*/
//時鐘控制暫存器
#define CR_OFFSET                 (RCC_OFFSET + 0x00)                                         //CR暫存器在外設儲存映像中的偏移
//CR_OFFSET = (RCC_OFFSET + 0x00) = ((uint32_t)0x0002 1000)

/* Alias word address of HSION bit */                                                                         //外部高速時鐘使能位的別名
#define HSION_BitNumber           0x00                                                                     //HSION在CR暫存器中處於第0位
#define CR_HSION_BB               (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4))        //將位帶區的位轉換為別名區的字
//PERIPH_BB_BASE = ((uint32_t)0x42000000)              /* Peripheral base address in the bit-band region */

操作舉例:
/**
  * @brief  Enables or disables the Internal High Speed oscillator (HSI).
            使能或失能內部高速晶振
  * @note   HSI can not be stopped if it is used directly or through the PLL as system clock.
            HSI不能被停止如果HSI直接作為系統時鐘或通過PLL間接作為系統時鐘
  * @param  NewState: new state of the HSI. This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_HSICmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  //typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
  //#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
  *(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState;
  /* Alias word address of HSION bit */
  //#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
  //#define CR_OFFSET (RCC_OFFSET + 0x00)   #define HSION_BitNumber  0x00
  //#define CR_HSION_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4))
}
*(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState;                //這邊即是寫別名區的字
上面是自己的理解,下面看看Cortex-M3權威指南上關於該部分的內容: