STM32F103C8T6 が載った基板を購入したので、まずはST社からSTM32CubeF1をダウンロードして開発環境を整えてみます。
流用できるプロジェクトファイルは、STM32F103RB-Nucleoでイケます。main関数は基板固有コードばかりなので空関数にしますが、
使用するソースファイルやヘッダファイル、コンパイルオプションは、まずは同じでOKです。後から精査しましょう。
STM32CubeF1内のDrivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.hに使用するマイコン名を#defineするように記載されていますが、私はコンパイルオプション(-Dプリプロセッサ定義)でSTM32F103xBを指定します。(何故なら敢えてオリジナルファイルを変更しなくても対応可能な方法だから、ソースの変更管理しなくて済みます。
私の統合開発環境(IDE)は、IAR社のEWARMを使用しているから、iarフォルダ下にプロジェクトファイルがあります。このプロジェクトファイルをEWARMで開けば、必要なソースファイルが分かりますが、ココにも載せておきます。本サイトのSTM32F303K8でも取り上げています。
---STM32Cube_F1 フォルダ構成--- STM32Cube_FW_F1_V1.6.0 +Drivers +CMSIS |+Device ||+ST || +STM32F1xx || +Include :includeパスにセットするフォルダ || +Source || +Templates :以下(2)にコピーされている || +iar |+Include +STM32F1xx_HAL_Driver +Inc :includeパスにセットするフォルダ +Src :以下(1)参照 +Projects +STM32F103RB-Nucleo +Templates_LL +EWARM :IAR用ファイルのフォルダ +Inc :includeパスにセットするフォルダ +Src :以下(3)参照 +Middlewares +Third_Party +FreeRTOS :リアルタイムOS ---(1)Drivers\STM32F1xx_HAL_Driver\Src--- stm32f1xx_hal_XXXX.c :HALドライバ stm32f1xx_ll_XXXX.c :LLドライバ ---(2)Projects\STM32F103RB-Nucleo\Templates_LL\EWARM--- startup_stm32f103xb.s :ベクタテーブル、リセットハンドラ stm32f103xb_flash.icf :IARリンカの設定ファイル ---(3)Projects\STM32F103RB-Nucleo\Templates_LL\Src--- main.c stm32f1xx_it.c :割り込みハンドラ(無くても良い。各ハンドラはweakでstartup_stm32f103xb.sに定義済み) system_stm32f1xx.c :boot初期処理
外部クロックHSE(8MHz)を用いて動作させるために必要なファイル一覧を以下に記載します。
ちなみにCMSISのLLドライバを使用しました。
---STM32Cube_F1 外部クロックで動作させるために必要なファイル一覧--- main.c startup_stm32f103xb.s system_stm32f1xx.c (stm32_assert.h) stm32f103x8.icf stm32f1xx_ll_gpio.c stm32f1xx_ll_rcc.c
STM32マイコンは、Power ONで内部クロックHSI(8MHz)により動作します。従って、ベクタテーブルのリセットハンドラさえあればmain()迄実行され、main(){while(1);}だけの空転関数でも動作します。
しかし、次のmain()ではFreeRTOSを盛り込み、外部クロックHSE(8MHz)を用いて動作するように設定した実装例も載せておきます。省電力のため動作クロックはSYSCLK 48MHz、HCLK 24MHzに落としてます。
---main.c--- #include "stm32f1xx_ll_rcc.h" #include "stm32f1xx_ll_system.h" #include "stm32f1xx_ll_gpio.h" #include "stm32f1xx_ll_bus.h" #include "FreeRTOS.h" //FreeRTOS用 #include "task.h" //FreeRTOS用 void SystemClock_Config(void); void createOsResource(void); //FreeRTOS用 /* テストピン(LED1)定義 */ #define LED1_GPIO GPIOC #define LED1_PIN LL_GPIO_PIN_13 /** * @brief Main program * @param None * @retval None */ int main(void) { /* setup system clocks */ SystemClock_Config(); /* テストピン(LED1)をEnable */ LL_APB2_GRP1_EnableClock( LL_APB2_GRP1_PERIPH_GPIOC ); #if 0 // LL_GPIO_Init()にBUGあり { LL_GPIO_InitTypeDef pin_cfg; /* ポートCをEnableにする */ LL_GPIO_DeInit(LED1_GPIO); /* テストピン(LED1)をセットアップする */ pin_cfg.Pin = LED1_PIN; pin_cfg.Mode = LL_GPIO_MODE_OUTPUT; pin_cfg.Speed = LL_GPIO_SPEED_FREQ_LOW; pin_cfg.OutputType = LL_GPIO_OUTPUT_PUSHPULL; pin_cfg.Pull = LL_GPIO_PULL_UP; LL_GPIO_Init(LED1_GPIO, &pin_cfg); } #else /* Pin Mode configuration */ LL_GPIO_SetPinMode( LED1_GPIO, LED1_PIN, LL_GPIO_MODE_OUTPUT ); /* Pull-up Pull down resistor configuration*/ LL_GPIO_SetPinPull( LED1_GPIO, LED1_PIN, LL_GPIO_PULL_UP ); /* Speed mode configuration */ LL_GPIO_SetPinSpeed( LED1_GPIO, LED1_PIN, LL_GPIO_SPEED_FREQ_LOW ); /* Output mode configuration*/ LL_GPIO_SetPinOutputType( LED1_GPIO, LED1_PIN, LL_GPIO_OUTPUT_PUSHPULL ); #endif /* OSリソース生成 */ createOsResource(); //FreeRTOS用 /* Start the scheduler */ vTaskStartScheduler(); //FreeRTOS用 while(1); } /** * @brief System Clock Configuration * The system Clock is configured as follow : * System Clock source = PLL (HSE) * SYSCLK(Hz) = 48000000 * HCLK(Hz) = 24000000 * AHB Prescaler = 2 * APB1 Prescaler = 1 * APB2 Prescaler = 1 * HSE Frequency(Hz) = 8000000 * PLL_MUL = 6 * Flash Latency(WS) = 1 * @param None * @retval None */ void SystemClock_Config(void) { #if 1 // LL_APB2_GRP1_EnableClock( LL_APB2_GRP1_PERIPH_GPIOD ); // LL_RCC_EnableIT_HSERDY(); LL_RCC_HSE_EnableCSS(); /* Enable HSE oscillator */ // LL_RCC_HSE_EnableBypass(); LL_RCC_HSE_Enable(); while( LL_RCC_HSE_IsReady() != 1 ); #endif /* Set FLASH latency */ LL_FLASH_SetLatency( LL_FLASH_LATENCY_2 ); /* Set PLLSRC & PLLMUL */ #if 1 LL_RCC_PLL_ConfigDomain_SYS( LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_6 ); #else LL_RCC_PLL_ConfigDomain_SYS( LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_12 ); #endif LL_RCC_PLL_Enable(); while( LL_RCC_PLL_IsReady() != 1 ); /* Set AHB prescaler */ LL_RCC_SetAHBPrescaler( LL_RCC_SYSCLK_DIV_2 ); /* Select SYSCLK by PLLCLK */ LL_RCC_SetSysClkSource( LL_RCC_SYS_CLKSOURCE_PLL ); while( LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL ); /* Set APB1 & APB2 prescaler */ LL_RCC_SetAPB1Prescaler( LL_RCC_APB1_DIV_1 ); LL_RCC_SetAPB2Prescaler( LL_RCC_APB2_DIV_1 ); /* Set SYSTICK to 10ms */ SysTick_Config( 48000000 / 100 ); /* Set CMSIS variable */ SystemCoreClock = 48000000; } /** * @brief TICKフック of FreeRTOS * @param None * @retval None */ #define TICK_HOOKCNT 20 //= 200ms=20 * os tick=10ms int16_t iHookCnt = TICK_HOOKCNT; void vApplicationTickHook( void ) { if(--iHookCnt <= 0){ iHookCnt = TICK_HOOKCNT; /* テストピン(LED1)にトグル出力 */ LL_GPIO_TogglePin(LED1_GPIO, LED1_PIN); } } /** * @brief 空タスク * @param None * @retval None */ void XXXXTask( void * pvParameters ) { for( ;; ); } /** * @brief create FreeRTOS resorce. * タスクやメッセージキューを生成する * @param None * @retval None */ #define XXXXTask_STACK_SIZE configMINIMAL_STACK_SIZE void createOsResource(void) { static uint8_t ucParameterToPass; TaskHandle_t xHandle = NULL; // Create the task, storing the handle. xTaskCreate( XXXXTask, "TSKNAME", XXXXTask_STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle ); configASSERT( xHandle ); }
FreeRTOSを盛り込むにあたり、startup_stm32f103xb.sの実装例も載せておきます。
PUBWEAK SVC_Handler EXTERN vPortSVCHandler ;☆追加 SECTION .text:CODE:REORDER:NOROOT(1) SVC_Handler B vPortSVCHandler ;☆変更 PUBWEAK DebugMon_Handler SECTION .text:CODE:REORDER:NOROOT(1) DebugMon_Handler B DebugMon_Handler PUBWEAK PendSV_Handler EXTERN xPortPendSVHandler ;☆追加 SECTION .text:CODE:REORDER:NOROOT(1) PendSV_Handler B xPortPendSVHandler ;☆変更 PUBWEAK SysTick_Handler EXTERN xPortSysTickHandler ;☆追加 SECTION .text:CODE:REORDER:NOROOT(1) SysTick_Handler B xPortSysTickHandler ;☆変更