システムクロック
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
AHB | max 72MHz | |
APB1 | High speed APB | max 72MHz |
APB2 | Low speed APB | max 32MHz |
Coretex System Timer(SysTick)
Cortex-M3 には SysTimer というものがある。システムタイマはOSの時間管理用らしい。
SysTick := HCLK / 8
で定義されている。
STMicro が提供している datasheet STM32F103xB.pdf Figure 2 Clock Tree をみると、
STBee Mini に使われている STM32F103CBT のタイマとクロックの関係が読み取れる。
TIM1 | APB2 | TIM1CLK | HCLK x 1/1,2,4,8,16 |
TIM2,3,4 | APB1 | TIMxCLK | HCLK 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) で行う。
外部クロックを使う場合に必要となる設定ビットは
bit24 | PLL ON | PLL を有効にする |
bit16 | HSE ON | 外部クロックを有効にする |
制約として、
USBを使用する場合は PLL の出力周波数は 48MHz or 72MHz でなければならない
USBCLK 48MHz を生成するためである。
Clock Configuration Register RCC_CFGR
bit21:18(4bit) | PLLMUL | PLL の倍率。2-16 |
bit17 | PLLXTPRE | PLLの分周率。1 or 1/2 |
bit16 | PLLSRC | PLLの入力信号選択。入力信号の 1 or 1/2 を選択可能 |
bit13:11 | PPRE2 | APB 高速分周器 | 1, 1/2, 1/4, 1/8, 1/16 から選択 |
bit7:4 | HPRE | AHB 高速分周器 | 1, 1/2,... 1/512 から選択 |
関連するレジスタ
TIM2-TIM5 の汎用タイマは
TIMx_CNT | カウンターレジスタ | クロックを数えてカウントアップ・ダウンする |
TIMx_PSC | プリスケーラレジスタ | システムクロックを逓倍・分周する |
TIMx_ARR | オートリロードレジスタ | アウトプットコンペア。この値とカウンタが同じになるとカウンタをリセットする |
プリスケーラの設定範囲は 1 ~ 65535。