STBee mini システムクロックの設定

Last-modified: 2010-09-04 (土) 22:42:30

STBee mini

システムクロック

StrawberryLinux 作成のマニュアルによれば、STBee mini は水晶発信器12MHzを PLL で 6 倍し、72MHz をシステムクロックにしている(はず)。
ソースでそれを確かめる。

BordInit()

サンプルコードでは最初に BordInit() という関数を呼んでいる。

int main(void)
{
 BoardInit();				// Configure board specific setting
 RCC_Configuration();		/* System Clocks re-configuration */
 NVIC_Configuration();		/* NVIC Configuration */
 TIM2_Configuration();		/* TIM2 Configuration*/
 GPIO_Configuration();		/* GPIO Configuration*/
 while (1){}
}

こんな感じ。STBee, STBee mini, CQ付録のARMボードなど、CPUボードごとの設定を
行っているはず。「マイコン徹底入門」のディレクトリ構成だと

  • /lib/platform/bordinit.c
  • /lib/platform/STBee.h
  • /lib/platform/STBee_Mini.h
  • /lib/platform/CQ_STARM.h
    がそれにあたる。
void BoardInit(void)
{
 /* System Clocks Configuration **********************************************/
 SystemInit();
 // Clock re-configuration for boards with 12MHz xtal
 #ifdef XTAL_12MHZ
 Use_12MHz_Xtal();
 #endif
 // Set vector table location
 NVIC_SetVectorTable(NVIC_VectTab_FLASH, VECTOR_OFFSET);
 // Remap JTAG for boards with DFU feature
 Remap_JTAG();
}

SystemInit()

では SystemInit() はどこにあるかというと

/lib/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.h
/lib/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c

SystemInit() はこんな内容。

void SystemInit (void)
{
 /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
 /* Set HSION bit */
 RCC->CR |= (uint32_t)0x00000001;
 /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
 RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
 RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
 /* Reset HSEON, CSSON and PLLON bits */
 RCC->CR &= (uint32_t)0xFEF6FFFF;
 /* Reset HSEBYP bit */
 RCC->CR &= (uint32_t)0xFFFBFFFF;
 /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
 RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
 /* Reset PLL2ON and PLL3ON bits */
 RCC->CR &= (uint32_t)0xEBFFFFFF;
 /* Disable all interrupts and clear pending bits  */
 RCC->CIR = 0x00FF0000;
 /* Reset CFGR2 register */
 RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
 /* Disable all interrupts and clear pending bits  */
 RCC->CIR = 0x009F0000;
 /* Reset CFGR2 register */
 RCC->CFGR2 = 0x00000000;
#else
 /* Disable all interrupts and clear pending bits  */
 RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
#if defined (STM32F10X_HD) || (defined STM32F10X_XL)
 #ifdef DATA_IN_ExtSRAM
   SystemInit_ExtMemCtl();
 #endif /* DATA_IN_ExtSRAM */
#endif
 /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
 /* Configure the Flash Latency cycles and enable prefetch buffer */
 SetSysClock();
}

SetSysClock()

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
 SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
 SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
 SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
 SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
 SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
 SetSysClockTo72();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
   source (default after reset) */
}

ということで、BoardInit()が終わった段階では周辺機器用のクロックは
システムクロックと同じものに設定されているようだ。

RCC_Configuration(Reset and Clock Control)

で、そのRCC_Configuration()は
void RCC_Configuration(void)
{
 /* PCLK1 = HCLK/4 */
 RCC_PCLK1Config(RCC_HCLK_Div4);
}

となっている。で、RCC_PCLK1Config() は /lib/STM32F10x_StdPeriph_Driver/inc/stm32f10x_rcc.h
にプロトタイプ宣言が、/src/stm32f10x_rcc.c に定義されている。

/**
 * @brief  Configures the Low Speed APB clock (PCLK1).
 * @param  RCC_HCLK: defines the APB1 clock divider. This clock is derived from
 *   the AHB clock (HCLK).
 *   This parameter can be one of the following values:
 *     @arg RCC_HCLK_Div1: APB1 clock = HCLK
 *     @arg RCC_HCLK_Div2: APB1 clock = HCLK/2
 *     @arg RCC_HCLK_Div4: APB1 clock = HCLK/4
 *     @arg RCC_HCLK_Div8: APB1 clock = HCLK/8
 *     @arg RCC_HCLK_Div16: APB1 clock = HCLK/16
 * @retval None
 */

RCCとは Reset and Clock Control のことらしい。リファレンスマニュアル 6章を参照。

Clock Tree

クロックの種類が多くてわかりづらかったが、よい図を発見。

リファレンスマニュアル p115 Figure 11 Clock Tree
AHBmax 72MHz
APB1High speed APBmax 72MHz
APB2Low speed APBmax 32MHz

Coretex System Timer(SysTick)

Cortex-M3 には SysTimer というものがある。システムタイマはOSの時間管理用らしい。

SysTick := HCLK / 8

で定義されている。

STMicro が提供している datasheet STM32F103xB.pdf Figure 2 Clock Tree をみると、
STBee Mini に使われている STM32F103CBT のタイマとクロックの関係が読み取れる。

TIM1APB2TIM1CLKHCLK x 1/1,2,4,8,16
TIM2,3,4APB1TIMxCLKHCLK x 1 or 1/2

周辺機器とクロックの関係は

/lib/STM32F10xStdPeriph_Drive/inc/stm32f10x_rcc.h

に定義されている。

AHB に接続される周辺機器

/** @defgroup AHB_peripheral
 * @{
 */
#define RCC_AHBPeriph_DMA1               ((uint32_t)0x00000001)
#define RCC_AHBPeriph_DMA2               ((uint32_t)0x00000002)
#define RCC_AHBPeriph_SRAM               ((uint32_t)0x00000004)
#define RCC_AHBPeriph_FLITF              ((uint32_t)0x00000010)
#define RCC_AHBPeriph_CRC                ((uint32_t)0x00000040)
#ifndef STM32F10X_CL
 #define RCC_AHBPeriph_FSMC              ((uint32_t)0x00000100)
 #define RCC_AHBPeriph_SDIO              ((uint32_t)0x00000400)
 #define IS_RCC_AHB_PERIPH(PERIPH) ((((PERIPH) & 0xFFFFFAA8) == 0x00) && ((PERIPH) != 0x00))

APB1 に接続される周辺機器

/** @defgroup APB1_peripheral
 * @{
 */
#define RCC_APB1Periph_TIM2              ((uint32_t)0x00000001)
#define RCC_APB1Periph_TIM3              ((uint32_t)0x00000002)
#define RCC_APB1Periph_TIM4              ((uint32_t)0x00000004)
#define RCC_APB1Periph_TIM5              ((uint32_t)0x00000008)
#define RCC_APB1Periph_TIM6              ((uint32_t)0x00000010)
#define RCC_APB1Periph_TIM7              ((uint32_t)0x00000020)
#define RCC_APB1Periph_TIM12             ((uint32_t)0x00000040)
#define RCC_APB1Periph_TIM13             ((uint32_t)0x00000080)
#define RCC_APB1Periph_TIM14             ((uint32_t)0x00000100)
#define RCC_APB1Periph_WWDG              ((uint32_t)0x00000800)
#define RCC_APB1Periph_SPI2              ((uint32_t)0x00004000)
#define RCC_APB1Periph_SPI3              ((uint32_t)0x00008000)
#define RCC_APB1Periph_USART2            ((uint32_t)0x00020000)
#define RCC_APB1Periph_USART3            ((uint32_t)0x00040000)
#define RCC_APB1Periph_UART4             ((uint32_t)0x00080000)
#define RCC_APB1Periph_UART5             ((uint32_t)0x00100000)
#define RCC_APB1Periph_I2C1              ((uint32_t)0x00200000)
#define RCC_APB1Periph_I2C2              ((uint32_t)0x00400000)
#define RCC_APB1Periph_USB               ((uint32_t)0x00800000)
#define RCC_APB1Periph_CAN1              ((uint32_t)0x02000000)
#define RCC_APB1Periph_CAN2              ((uint32_t)0x04000000)
#define RCC_APB1Periph_BKP               ((uint32_t)0x08000000)
#define RCC_APB1Periph_PWR               ((uint32_t)0x10000000)
#define RCC_APB1Periph_DAC               ((uint32_t)0x20000000)
#define RCC_APB1Periph_CEC               ((uint32_t)0x40000000)
#define IS_RCC_APB1_PERIPH(PERIPH) ((((PERIPH) & 0x81013600) == 0x00) && ((PERIPH) != 0x00))

APB2 に接続される周辺機器

/** @defgroup APB2_peripheral
 * @{
 */
#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)
#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)
#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)
#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)
#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)
#define RCC_APB2Periph_GPIOE             ((uint32_t)0x00000040)
#define RCC_APB2Periph_GPIOF             ((uint32_t)0x00000080)
#define RCC_APB2Periph_GPIOG             ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)
#define RCC_APB2Periph_ADC2              ((uint32_t)0x00000400)
#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)
#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)
#define RCC_APB2Periph_TIM8              ((uint32_t)0x00002000)
#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)
#define RCC_APB2Periph_ADC3              ((uint32_t)0x00008000)
#define RCC_APB2Periph_TIM15             ((uint32_t)0x00010000)
#define RCC_APB2Periph_TIM16             ((uint32_t)0x00020000)
#define RCC_APB2Periph_TIM17             ((uint32_t)0x00040000)
#define RCC_APB2Periph_TIM9              ((uint32_t)0x00080000)
#define RCC_APB2Periph_TIM10             ((uint32_t)0x00100000)
#define RCC_APB2Periph_TIM11             ((uint32_t)0x00200000)
#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))

クロックの設定

「6.2 Clock 」によると、システムクロック(SYSCLK)ソースは次の3つ

  • HSI Oscillator clock ==> High Speed Internal Clock signal
  • HSE Oscillator clock ==> High Speed External Clock signal
  • PLL clock

HSI は内蔵の 8MHz RC 発信器を PLL で逓倍して高速化するらしい。

STBee mini は 12MHzの水晶発信子が接続されているので HSEなクロックソースになる。

あと、2次的なクロックソースとして、

  • 内蔵 RC 発信器
  • 外付けRTC用発信器 32.768kHz
    を使用可能。

PLL の元のクロックには 内蔵、外付けどちらの信号も使えるらしい。

STBee mini の場合は外部から 12MHz を入力し、内部では PLL で 6逓倍して 72MHz にしているはず。
(Strawberry Linux のマニュアルより)

PLLの設定は Clock Control Register (RCC_CR) で行う。

外部クロックを使う場合に必要となる設定ビットは

bit24PLL ONPLL を有効にする
bit16HSE ON外部クロックを有効にする

制約として、
USBを使用する場合は PLL の出力周波数は 48MHz or 72MHz でなければならない
USBCLK 48MHz を生成するためである。

Clock Configuration Register RCC_CFGR

bit21:18(4bit)PLLMULPLL の倍率。2-16
bit17PLLXTPREPLLの分周率。1 or 1/2
bit16PLLSRCPLLの入力信号選択。入力信号の 1 or 1/2 を選択可能
bit13:11PPRE2APB 高速分周器1, 1/2, 1/4, 1/8, 1/16 から選択
bit7:4HPREAHB 高速分周器1, 1/2,... 1/512 から選択

関連するレジスタ

TIM2-TIM5 の汎用タイマは

TIMx_CNTカウンターレジスタクロックを数えてカウントアップ・ダウンする
TIMx_PSCプリスケーラレジスタシステムクロックを逓倍・分周する
TIMx_ARRオートリロードレジスタアウトプットコンペア。この値とカウンタが同じになるとカウンタをリセットする

プリスケーラの設定範囲は 1 ~ 65535。