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 ;☆変更