STM32F3 Discovery、タイマーと割り込みのキホン

STM32F3 Discovery、タイマーと割り込みのキホン


今回のSTM32F3 Discovery企画では、基本的なタイマー動作についての設定と、そのタイマーを割り込みで使うための基本について解説したいと思います。

写真ではわかりづらいですが、タイマーでPWM制御しています。

STM32F303は、タイマーとしてTIM1, TIM2, TIM3, TIM4, TIM6, TIM7, TIM8, TIM15, TIM16, TIM17 と10個のタイマーを持っています。(なぜ番号が飛んでいるのかは不明)
この中で、TIM1と8は高機能なタイマーとして実装されていますが、今回の記事ではTIM1を使ったプログラミングを行いたいと思います。
また、タイマーとともに割り込みでの処理を行いたいので、割り込み設定についても解説していきます。

なお、このサンプルではタイマー設定などについて、直接レジスタ設定で実現しています。

レジスタ、割り込みの定義は、stm32f303xc.hで行われています。他のSTM32を利用する場合、それぞれのMPUに適したヘッダファイルが存在していますので、そちらのヘッダーファイルを参照してください。
stm32f303xc.h 中で、TIM1に関するレジスタのベースアドレスや各操作レジスタが定義されていて、
  1.  TIM1->PSC = 4800;  → TIM1タイマーのプリスケーラーレジスタに4800を設定する
の、ような記述が可能になります。

一般的にMCUのタイマーは、タイマーモジュールに供給されているクロックをカウントすることで、ある時点からどのくらい時間が経過したかを測るものです。
このため、使用するタイマーモジュールに供給されるクロック数を確認しないと正確なタイマー設定を行うことができません。

タイマー1(TIM1)は、STM32F303xB STM32F303xCデーターシート(DS9118.pdf)のブロックダイアグラム(13/149)を確認すると、APB2/72MHzに接続されています。しかし、実際に供給されているクロック設定をCubeMXで確認すると、48MHzとなっています。Eclipse CubeMXのパースペクティブのClockConfigurationを確認してください。
また、各種MCU内臓のペリフェラルやレジスタ設定の詳細に関してはen.DM00043574.pdfドキュメントを参照してください。



作成するプログラムの仕様~その1:
タイマー周期は1秒、タイマー完了で割り込みを発生させ、LEDを4つづつ反転する。
という簡単なものから解説します。

このプログラムでは、タイマーの最も基本的な使い方である「Update Timer」を使います。


main.c  その1
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. ** This notice applies to any and all portions of this file
  8. * that are not between comment pairs USER CODE BEGIN and
  9. * USER CODE END. Other portions of this file, whether
  10. * inserted by the user or by software development tools
  11. * are owned by their respective copyright owners.
  12. *
  13. * COPYRIGHT(c) 2019 STMicroelectronics
  14. *
  15. * Redistribution and use in source and binary forms, with or without modification,
  16. * are permitted provided that the following conditions are met:
  17. * 1. Redistributions of source code must retain the above copyright notice,
  18. * this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * 3. Neither the name of STMicroelectronics nor the names of its contributors
  23. * may be used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  29. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  30. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  32. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  33. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  34. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. ******************************************************************************
  38. */
  39. /* USER CODE END Header */
  40.  
  41. /* Includes ------------------------------------------------------------------*/
  42. #include "main.h"
  43.  
  44. /* Private includes ----------------------------------------------------------*/
  45. /* USER CODE BEGIN Includes */
  46.  
  47. /* USER CODE END Includes */
  48.  
  49. /* Private typedef -----------------------------------------------------------*/
  50. /* USER CODE BEGIN PTD */
  51.  
  52. /* USER CODE END PTD */
  53.  
  54. /* Private define ------------------------------------------------------------*/
  55. /* USER CODE BEGIN PD */
  56.  
  57. /* USER CODE END PD */
  58.  
  59. /* Private macro -------------------------------------------------------------*/
  60. /* USER CODE BEGIN PM */
  61.  
  62. /* USER CODE END PM */
  63.  
  64. /* Private variables ---------------------------------------------------------*/
  65. I2C_HandleTypeDef hi2c1;
  66.  
  67. SPI_HandleTypeDef hspi1;
  68.  
  69. PCD_HandleTypeDef hpcd_USB_FS;
  70.  
  71. /* USER CODE BEGIN PV */
  72.  
  73. /* USER CODE END PV */
  74.  
  75. /* Private function prototypes -----------------------------------------------*/
  76. void SystemClock_Config(void);
  77. static void MX_GPIO_Init(void);
  78. static void MX_I2C1_Init(void);
  79. static void MX_SPI1_Init(void);
  80. static void MX_USB_PCD_Init(void);
  81. /* USER CODE BEGIN PFP */
  82.  
  83. /* USER CODE END PFP */
  84.  
  85. /* Private user code ---------------------------------------------------------*/
  86. /* USER CODE BEGIN 0 */
  87. void TIM1_UP_TIM16_IRQHandler(void){
  88.  
  89. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_9);
  90. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_10);
  91. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_11);
  92. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_12);
  93. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13);
  94. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_14);
  95. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_15);
  96. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8);
  97. TIM1->SR ^= 0x0001;
  98. }
  99.  
  100. void initTimer(void) {
  101.  
  102. RCC->APB2ENR |= 0x00000800; // APB2 TIM1 48MHzクロック供給
  103.  
  104. TIM1->PSC = 4800 - 1; // プリスケーラー = 4800
  105. TIM1->ARR = 10000; // オートリロード = 10000 で1秒の設定
  106.  
  107. TIM1->CR1 |= 0x0001; // カウンタ許可
  108.  
  109. TIM1->DIER |= 0x0001; // アップデートフラグでの割り込み許可
  110.  
  111. // NVIC割り込み設定
  112. NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
  113. NVIC_SetPriority(TIM1_UP_TIM16_IRQn,10);
  114. }
  115.  
  116. /* USER CODE END 0 */
  117.  
  118. /**
  119. * @brief The application entry point.
  120. * @retval int
  121. */
  122. int main(void)
  123. {
  124. /* USER CODE BEGIN 1 */
  125.  
  126. /* USER CODE END 1 */
  127.  
  128. /* MCU Configuration--------------------------------------------------------*/
  129.  
  130. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  131. HAL_Init();
  132.  
  133. /* USER CODE BEGIN Init */
  134.  
  135. /* USER CODE END Init */
  136.  
  137. /* Configure the system clock */
  138. SystemClock_Config();
  139.  
  140. /* USER CODE BEGIN SysInit */
  141.  
  142. /* USER CODE END SysInit */
  143.  
  144. /* Initialize all configured peripherals */
  145. MX_GPIO_Init();
  146. MX_I2C1_Init();
  147. MX_SPI1_Init();
  148. MX_USB_PCD_Init();
  149.  
  150. /* USER CODE BEGIN 2 */
  151. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_10);
  152. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_12);
  153. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_14);
  154. HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8);
  155.  
  156. initTimer();
  157.  
  158. /* USER CODE END 2 */
  159.  
  160. /* Infinite loop */
  161. /* USER CODE BEGIN WHILE */
  162. while (1)
  163. {
  164. /* USER CODE END WHILE */
  165. HAL_Delay(100);
  166. /* USER CODE BEGIN 3 */
  167. }
  168. /* USER CODE END 3 */
  169. }
  170.  
  171. /**
  172. * @brief System Clock Configuration
  173. * @retval None
  174. */
  175. void SystemClock_Config(void)
  176. {
  177. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  178. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  179. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  180.  
  181. /**Initializes the CPU, AHB and APB busses clocks
  182. */
  183. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
  184. RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  185. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  186. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  187. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  188. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  189. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  190. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  191. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  192. {
  193. Error_Handler();
  194. }
  195. /**Initializes the CPU, AHB and APB busses clocks
  196. */
  197. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  198. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  199. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  200. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  201. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  202. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  203.  
  204. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  205. {
  206. Error_Handler();
  207. }
  208. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB|RCC_PERIPHCLK_I2C1;
  209. PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  210. PeriphClkInit.USBClockSelection = RCC_USBCLKSOURCE_PLL;
  211. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  212. {
  213. Error_Handler();
  214. }
  215. }
  216.  
  217. /**
  218. * @brief I2C1 Initialization Function
  219. * @param None
  220. * @retval None
  221. */
  222. static void MX_I2C1_Init(void)
  223. {
  224.  
  225. /* USER CODE BEGIN I2C1_Init 0 */
  226.  
  227. /* USER CODE END I2C1_Init 0 */
  228.  
  229. /* USER CODE BEGIN I2C1_Init 1 */
  230.  
  231. /* USER CODE END I2C1_Init 1 */
  232. hi2c1.Instance = I2C1;
  233. hi2c1.Init.Timing = 0x2000090E;
  234. hi2c1.Init.OwnAddress1 = 0;
  235. hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  236. hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  237. hi2c1.Init.OwnAddress2 = 0;
  238. hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  239. hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  240. hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  241. if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  242. {
  243. Error_Handler();
  244. }
  245. /**Configure Analogue filter
  246. */
  247. if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  248. {
  249. Error_Handler();
  250. }
  251. /**Configure Digital filter
  252. */
  253. if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  254. {
  255. Error_Handler();
  256. }
  257. /* USER CODE BEGIN I2C1_Init 2 */
  258.  
  259. /* USER CODE END I2C1_Init 2 */
  260.  
  261. }
  262.  
  263. /**
  264. * @brief SPI1 Initialization Function
  265. * @param None
  266. * @retval None
  267. */
  268. static void MX_SPI1_Init(void)
  269. {
  270.  
  271. /* USER CODE BEGIN SPI1_Init 0 */
  272.  
  273. /* USER CODE END SPI1_Init 0 */
  274.  
  275. /* USER CODE BEGIN SPI1_Init 1 */
  276.  
  277. /* USER CODE END SPI1_Init 1 */
  278. /* SPI1 parameter configuration*/
  279. hspi1.Instance = SPI1;
  280. hspi1.Init.Mode = SPI_MODE_MASTER;
  281. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  282. hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
  283. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  284. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  285. hspi1.Init.NSS = SPI_NSS_SOFT;
  286. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  287. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  288. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  289. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  290. hspi1.Init.CRCPolynomial = 7;
  291. hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  292. hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  293. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  294. {
  295. Error_Handler();
  296. }
  297. /* USER CODE BEGIN SPI1_Init 2 */
  298.  
  299. /* USER CODE END SPI1_Init 2 */
  300.  
  301. }
  302.  
  303. /**
  304. * @brief USB Initialization Function
  305. * @param None
  306. * @retval None
  307. */
  308. static void MX_USB_PCD_Init(void)
  309. {
  310.  
  311. /* USER CODE BEGIN USB_Init 0 */
  312.  
  313. /* USER CODE END USB_Init 0 */
  314.  
  315. /* USER CODE BEGIN USB_Init 1 */
  316.  
  317. /* USER CODE END USB_Init 1 */
  318. hpcd_USB_FS.Instance = USB;
  319. hpcd_USB_FS.Init.dev_endpoints = 8;
  320. hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
  321. hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_64;
  322. hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
  323. hpcd_USB_FS.Init.low_power_enable = DISABLE;
  324. hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
  325. if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
  326. {
  327. Error_Handler();
  328. }
  329. /* USER CODE BEGIN USB_Init 2 */
  330.  
  331. /* USER CODE END USB_Init 2 */
  332.  
  333. }
  334.  
  335. /**
  336. * @brief GPIO Initialization Function
  337. * @param None
  338. * @retval None
  339. */
  340. static void MX_GPIO_Init(void)
  341. {
  342. GPIO_InitTypeDef GPIO_InitStruct = {0};
  343.  
  344. /* GPIO Ports Clock Enable */
  345. __HAL_RCC_GPIOE_CLK_ENABLE();
  346. __HAL_RCC_GPIOC_CLK_ENABLE();
  347. __HAL_RCC_GPIOF_CLK_ENABLE();
  348. __HAL_RCC_GPIOA_CLK_ENABLE();
  349. __HAL_RCC_GPIOB_CLK_ENABLE();
  350.  
  351. /*Configure GPIO pin Output Level */
  352. HAL_GPIO_WritePin(GPIOE, CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  353. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  354. |LD6_Pin, GPIO_PIN_RESET);
  355.  
  356. /*Configure GPIO pins : DRDY_Pin MEMS_INT3_Pin MEMS_INT4_Pin MEMS_INT1_Pin
  357. MEMS_INT2_Pin */
  358. GPIO_InitStruct.Pin = DRDY_Pin|MEMS_INT3_Pin|MEMS_INT4_Pin|MEMS_INT1_Pin
  359. |MEMS_INT2_Pin;
  360. GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  361. GPIO_InitStruct.Pull = GPIO_NOPULL;
  362. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  363.  
  364. /*Configure GPIO pins : CS_I2C_SPI_Pin LD4_Pin LD3_Pin LD5_Pin
  365. LD7_Pin LD9_Pin LD10_Pin LD8_Pin
  366. LD6_Pin */
  367. GPIO_InitStruct.Pin = CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  368. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  369. |LD6_Pin;
  370. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  371. GPIO_InitStruct.Pull = GPIO_NOPULL;
  372. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  373. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  374.  
  375. /*Configure GPIO pin : B1_Pin */
  376. GPIO_InitStruct.Pin = B1_Pin;
  377. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  378. GPIO_InitStruct.Pull = GPIO_NOPULL;
  379. HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
  380.  
  381. }
  382.  
  383. /* USER CODE BEGIN 4 */
  384.  
  385. /* USER CODE END 4 */
  386.  
  387. /**
  388. * @brief This function is executed in case of error occurrence.
  389. * @retval None
  390. */
  391. void Error_Handler(void)
  392. {
  393. /* USER CODE BEGIN Error_Handler_Debug */
  394. /* User can add his own implementation to report the HAL error return state */
  395.  
  396. /* USER CODE END Error_Handler_Debug */
  397. }
  398.  
  399. #ifdef USE_FULL_ASSERT
  400. /**
  401. * @brief Reports the name of the source file and the source line number
  402. * where the assert_param error has occurred.
  403. * @param file: pointer to the source file name
  404. * @param line: assert_param error line source number
  405. * @retval None
  406. */
  407. void assert_failed(char *file, uint32_t line)
  408. {
  409. /* USER CODE BEGIN 6 */
  410. /* User can add his own implementation to report the file name and line number,
  411. tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  412. /* USER CODE END 6 */
  413. }
  414. #endif /* USE_FULL_ASSERT */
  415.  
  416. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

実行すると、対角線上の4つのLEDが1秒感覚で交互に点滅します。

それでは、コードの内容について解説をしていきたいと思います。
main()中で、initTimer() を呼んでいます。この関数の中でタイマー設定を行っています。

まず、RCCのAPB2ENRレジスタのTIM1ENビットをONにしてTIM1へのクロック供給を行います。

  1. RCC->APB2ENR|= 0x00000800; // APB2 TIM1 48MHzクロック供給

次にタイマーがこの48MHzを元に1秒を作り出すための設定です。
プリスケーラーとオートリロードの2つのレジスタで設定します。
プリスケーラーは供給クロックが何カウントでクロックカウンターをカウントアップするかを設定します。
このソースでは4800としていますので、クロックカウンターは、1/48MHzx 4800 = 0.1ミリ秒に1回カウントアップします。
このクロックカウンターがオートリロードレジスタの値に一致したときにタイムアップが発生し、クロックカウンターはリセットされます。

  1. TIM1->PSC= 4800 - 1; //プリスケーラー= 4800
  2. TIM1->ARR= 10000; //オートリロード= 10000 で1秒の設定

この、クロックカウントを有効とするために、TIM1のCR1(Control Register)のCEN(Counter Enable)ビットをONにします。

  1. TIM1->CR1|= 0x0001; // カウンタ許可

また、今回タイマーのクロックカウンターがタイムアップしたときに割り込みを発生させたいので、TIM1のDIER(DMA/interrupt enableRegister)のUIE(Update interrupt enable)ビットをONにします。

  1. TIM1->DIER|= 0x0001; // アップデートフラグでの割り込み許可

また、STM32の割り込みはNVICと呼ばれていて、発生する割り込みに対して動作する割り込みが決まっています。今回使いたいのはTIM1のUpdate割り込みなので、TIM1_UP_TIM16_IRQnの割り込みを設定します。
割り込みの優先度は、このソースでは10としていますが、多重割り込みなどを考えて設定してください。

  1. //NVIC割り込み設定
  2. NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
  3. NVIC_SetPriority(TIM1_UP_TIM16_IRQn,10);

この、TIM1_UP_TIM16_IRQnもstm32f303xc.h で定義されています。
割り込みが発生した場合、その割り込みを受け取って処理するための割り込みハンドラが必要になります。TIM1のUpdate割り込みハンドラは下記のようにTIM1_UP_TIM16_IRQHandler()として記述しています。
TIM1のUpdate割り込みは、TIM1とTIM16のUpdate割り込みのベクタとなっています。STM32では、割り込み要因に対応するベクタアドレスが決まっていますが、対応するベクタ設定はstm32f303xc.hに定義されています。

  1. void TIM1_UP_TIM16_IRQHandler(void){
  2. // LED反転
  3. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);
  4. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_10);
  5. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_11);
  6. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_12);
  7. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_13);
  8. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_14);
  9. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_15);
  10. HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_8);
  11.  
  12. TIM1->SR^= 0x0001;
  13. }

割り込みハンドラの中では、8つのLEDを反転し、タイマー1のステータスレジスタのUIF: Update interrupt flagをOFFしています。このフラグはMCUによってONされますが、OFFはソフトウェアで行う必要があります。このフラグをOFFすることで、次の割り込みを受けることが可能となります。
割り込みはTIM1_UP_TIM16_IRQHandler が受けますが、この割り込みハンドラ名も元々定義されています。
定義の実態は\SW4STM32\startup_stm32f303xc.s にあります。スタートアップ部分のアセンブラコードですが、この中で割り込みベクタテーブルが定義されており、TIM1のUpdate割り込みハンドラはTIM1_UP_TIM16_IRQHandlerとして定義されています。
このTIM1_UP_TIM16_IRQHandler 実態ですが、このコードの下の方に下記のように定義されています。

  1. .weak TIM1_UP_TIM16_IRQHandler
  2. .thumb_setTIM1_UP_TIM16_IRQHandler,Default_Handler

この、weak とは、”弱い”定義です。
もし、リンク時にweakではない同じ名前のコードが合った場合、そちらが優先される仕組みになっています。
このコードでは、main.c内で TIM1_UP_TIM16_IRQHandlerを定義しているので、こちらの割り込みハンドラがリンクされて動作するようになっています。
では、定義がない場合どうなるか?
Default_Handler が実行されます。
この、Default_Handler は、やはり同じコードの中で下記のように定義されています。

  1. .section
  2. .text.Default_Handler,"ax",%progbitsDefault_Handler:Infinite_Loop:
  3. b Infinite_Loop
  4. .size Default_Handler, .-Default_Handler

無限ループとして定義されているので、ユーザーがちゃんと割り込みハンドラを定義されていない場合には”固まる”ことになりますね。
タイマーを制御するために記述したコードの量は僅かですが、正確に制御するためにはデーターシートを理解して設定する必要があります。



作成するプログラムの仕様~その2:
タイマーを使ったLED制御らしい事を行ってみましょう。
タイマー割り込みでLEDをPWM制御し、徐々に暗くなるように明るさを制御する。
消灯に近くなったら、再度明る状態に戻し、暗くなるを繰り返す。


main.c  その2
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. ** This notice applies to any and all portions of this file
  8. * that are not between comment pairs USER CODE BEGIN and
  9. * USER CODE END. Other portions of this file, whether
  10. * inserted by the user or by software development tools
  11. * are owned by their respective copyright owners.
  12. *
  13. * COPYRIGHT(c) 2019 STMicroelectronics
  14. *
  15. * Redistribution and use in source and binary forms, with or without modification,
  16. * are permitted provided that the following conditions are met:
  17. * 1. Redistributions of source code must retain the above copyright notice,
  18. * this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * 3. Neither the name of STMicroelectronics nor the names of its contributors
  23. * may be used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  29. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  30. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  32. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  33. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  34. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. ******************************************************************************
  38. */
  39. /* USER CODE END Header */
  40.  
  41. /* Includes ------------------------------------------------------------------*/
  42. #include "main.h"
  43.  
  44. /* Private includes ----------------------------------------------------------*/
  45. /* USER CODE BEGIN Includes */
  46.  
  47. /* USER CODE END Includes */
  48.  
  49. /* Private typedef -----------------------------------------------------------*/
  50. /* USER CODE BEGIN PTD */
  51.  
  52. /* USER CODE END PTD */
  53.  
  54. /* Private define ------------------------------------------------------------*/
  55. /* USER CODE BEGIN PD */
  56.  
  57. /* USER CODE END PD */
  58.  
  59. /* Private macro -------------------------------------------------------------*/
  60. /* USER CODE BEGIN PM */
  61.  
  62. /* USER CODE END PM */
  63.  
  64. /* Private variables ---------------------------------------------------------*/
  65. I2C_HandleTypeDef hi2c1;
  66.  
  67. SPI_HandleTypeDef hspi1;
  68.  
  69. PCD_HandleTypeDef hpcd_USB_FS;
  70.  
  71. /* USER CODE BEGIN PV */
  72.  
  73. /* USER CODE END PV */
  74.  
  75. /* Private function prototypes -----------------------------------------------*/
  76. void SystemClock_Config(void);
  77. static void MX_GPIO_Init(void);
  78. static void MX_I2C1_Init(void);
  79. static void MX_SPI1_Init(void);
  80. static void MX_USB_PCD_Init(void);
  81. /* USER CODE BEGIN PFP */
  82.  
  83. /* USER CODE END PFP */
  84.  
  85. /* Private user code ---------------------------------------------------------*/
  86. /* USER CODE BEGIN 0 */
  87.  
  88. void TIM1_UP_TIM16_IRQHandler(void){
  89.  
  90. static int rate = 0;
  91.  
  92. if((TIM1->SR & 0x0001)) {
  93. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_SET);
  94. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_SET);
  95. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
  96. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
  97. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET);
  98. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
  99. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET);
  100. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
  101.  
  102. }
  103.  
  104. ++rate;
  105. if(rate > 5) {
  106. rate = 0;
  107.  
  108. TIM1->CCR1 -= 50;
  109. if(TIM1->CCR1 <= 0)
  110. TIM1->CCR1 = 900;
  111. }
  112.  
  113. TIM1->SR ^= 0x0001;
  114. }
  115.  
  116. void TIM1_CC_IRQHandler(void) {
  117.  
  118. if(TIM1->SR & 0x0002){ // CCR1
  119. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9 ,GPIO_PIN_RESET);
  120. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_RESET);
  121. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
  122. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
  123. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET);
  124. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
  125. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET);
  126. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8 ,GPIO_PIN_RESET);
  127. TIM1->SR ^= 0x0002;
  128. }
  129. }
  130.  
  131. void initTimer(void) {
  132.  
  133. RCC->APB2ENR |= 0x00000800; // APB2 TIM1 48MHzクロック供給
  134.  
  135. TIM1->PSC = 480 - 1; // プリスケーラー = 480
  136. TIM1->ARR = 1000; // オートリロード = 1000 で100ミリ秒の設定
  137.  
  138. TIM1->CCR1 = 900; // 90%
  139.  
  140. TIM1->CR1 |= 0x0001; // カウンタ許可
  141.  
  142. TIM1->DIER |= 0x0003; // アップデート/コンペア割り込み許可
  143.  
  144. // NVIC割り込み設定
  145. NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
  146. NVIC_SetPriority(TIM1_UP_TIM16_IRQn,10);
  147. NVIC_EnableIRQ(TIM1_CC_IRQn);
  148. NVIC_SetPriority(TIM1_CC_IRQn,10);
  149. }
  150.  
  151. /* USER CODE END 0 */
  152.  
  153. /**
  154. * @brief The application entry point.
  155. * @retval int
  156. */
  157. int main(void)
  158. {
  159. /* USER CODE BEGIN 1 */
  160.  
  161. /* USER CODE END 1 */
  162.  
  163. /* MCU Configuration--------------------------------------------------------*/
  164.  
  165. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  166. HAL_Init();
  167.  
  168. /* USER CODE BEGIN Init */
  169.  
  170. /* USER CODE END Init */
  171.  
  172. /* Configure the system clock */
  173. SystemClock_Config();
  174.  
  175. /* USER CODE BEGIN SysInit */
  176.  
  177. /* USER CODE END SysInit */
  178.  
  179. /* Initialize all configured peripherals */
  180. MX_GPIO_Init();
  181. MX_I2C1_Init();
  182. MX_SPI1_Init();
  183. MX_USB_PCD_Init();
  184.  
  185. /* USER CODE BEGIN 2 */
  186.  
  187. initTimer();
  188.  
  189. /* USER CODE END 2 */
  190.  
  191. /* Infinite loop */
  192. /* USER CODE BEGIN WHILE */
  193. while (1)
  194. {
  195. /* USER CODE END WHILE */
  196. HAL_Delay(100);
  197. /* USER CODE BEGIN 3 */
  198. }
  199. /* USER CODE END 3 */
  200. }
  201.  
  202. /**
  203. * @brief System Clock Configuration
  204. * @retval None
  205. */
  206. void SystemClock_Config(void)
  207. {
  208. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  209. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  210. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  211.  
  212. /**Initializes the CPU, AHB and APB busses clocks
  213. */
  214. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
  215. RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  216. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  217. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  218. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  219. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  220. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  221. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  222. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  223. {
  224. Error_Handler();
  225. }
  226. /**Initializes the CPU, AHB and APB busses clocks
  227. */
  228. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  229. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  230. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  231. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  232. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  233. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  234.  
  235. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  236. {
  237. Error_Handler();
  238. }
  239. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB|RCC_PERIPHCLK_I2C1;
  240. PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  241. PeriphClkInit.USBClockSelection = RCC_USBCLKSOURCE_PLL;
  242. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  243. {
  244. Error_Handler();
  245. }
  246. }
  247.  
  248. /**
  249. * @brief I2C1 Initialization Function
  250. * @param None
  251. * @retval None
  252. */
  253. static void MX_I2C1_Init(void)
  254. {
  255.  
  256. /* USER CODE BEGIN I2C1_Init 0 */
  257.  
  258. /* USER CODE END I2C1_Init 0 */
  259.  
  260. /* USER CODE BEGIN I2C1_Init 1 */
  261.  
  262. /* USER CODE END I2C1_Init 1 */
  263. hi2c1.Instance = I2C1;
  264. hi2c1.Init.Timing = 0x2000090E;
  265. hi2c1.Init.OwnAddress1 = 0;
  266. hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  267. hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  268. hi2c1.Init.OwnAddress2 = 0;
  269. hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  270. hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  271. hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  272. if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  273. {
  274. Error_Handler();
  275. }
  276. /**Configure Analogue filter
  277. */
  278. if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  279. {
  280. Error_Handler();
  281. }
  282. /**Configure Digital filter
  283. */
  284. if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  285. {
  286. Error_Handler();
  287. }
  288. /* USER CODE BEGIN I2C1_Init 2 */
  289.  
  290. /* USER CODE END I2C1_Init 2 */
  291.  
  292. }
  293.  
  294. /**
  295. * @brief SPI1 Initialization Function
  296. * @param None
  297. * @retval None
  298. */
  299. static void MX_SPI1_Init(void)
  300. {
  301.  
  302. /* USER CODE BEGIN SPI1_Init 0 */
  303.  
  304. /* USER CODE END SPI1_Init 0 */
  305.  
  306. /* USER CODE BEGIN SPI1_Init 1 */
  307.  
  308. /* USER CODE END SPI1_Init 1 */
  309. /* SPI1 parameter configuration*/
  310. hspi1.Instance = SPI1;
  311. hspi1.Init.Mode = SPI_MODE_MASTER;
  312. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  313. hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
  314. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  315. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  316. hspi1.Init.NSS = SPI_NSS_SOFT;
  317. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  318. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  319. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  320. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  321. hspi1.Init.CRCPolynomial = 7;
  322. hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  323. hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  324. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  325. {
  326. Error_Handler();
  327. }
  328. /* USER CODE BEGIN SPI1_Init 2 */
  329.  
  330. /* USER CODE END SPI1_Init 2 */
  331.  
  332. }
  333.  
  334. /**
  335. * @brief USB Initialization Function
  336. * @param None
  337. * @retval None
  338. */
  339. static void MX_USB_PCD_Init(void)
  340. {
  341.  
  342. /* USER CODE BEGIN USB_Init 0 */
  343.  
  344. /* USER CODE END USB_Init 0 */
  345.  
  346. /* USER CODE BEGIN USB_Init 1 */
  347.  
  348. /* USER CODE END USB_Init 1 */
  349. hpcd_USB_FS.Instance = USB;
  350. hpcd_USB_FS.Init.dev_endpoints = 8;
  351. hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
  352. hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_64;
  353. hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
  354. hpcd_USB_FS.Init.low_power_enable = DISABLE;
  355. hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
  356. if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
  357. {
  358. Error_Handler();
  359. }
  360. /* USER CODE BEGIN USB_Init 2 */
  361.  
  362. /* USER CODE END USB_Init 2 */
  363.  
  364. }
  365.  
  366. /**
  367. * @brief GPIO Initialization Function
  368. * @param None
  369. * @retval None
  370. */
  371. static void MX_GPIO_Init(void)
  372. {
  373. GPIO_InitTypeDef GPIO_InitStruct = {0};
  374.  
  375. /* GPIO Ports Clock Enable */
  376. __HAL_RCC_GPIOE_CLK_ENABLE();
  377. __HAL_RCC_GPIOC_CLK_ENABLE();
  378. __HAL_RCC_GPIOF_CLK_ENABLE();
  379. __HAL_RCC_GPIOA_CLK_ENABLE();
  380. __HAL_RCC_GPIOB_CLK_ENABLE();
  381.  
  382. /*Configure GPIO pin Output Level */
  383. HAL_GPIO_WritePin(GPIOE, CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  384. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  385. |LD6_Pin, GPIO_PIN_RESET);
  386.  
  387. /*Configure GPIO pins : DRDY_Pin MEMS_INT3_Pin MEMS_INT4_Pin MEMS_INT1_Pin
  388. MEMS_INT2_Pin */
  389. GPIO_InitStruct.Pin = DRDY_Pin|MEMS_INT3_Pin|MEMS_INT4_Pin|MEMS_INT1_Pin
  390. |MEMS_INT2_Pin;
  391. GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  392. GPIO_InitStruct.Pull = GPIO_NOPULL;
  393. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  394.  
  395. /*Configure GPIO pins : CS_I2C_SPI_Pin LD4_Pin LD3_Pin LD5_Pin
  396. LD7_Pin LD9_Pin LD10_Pin LD8_Pin
  397. LD6_Pin */
  398. GPIO_InitStruct.Pin = CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  399. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  400. |LD6_Pin;
  401. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  402. GPIO_InitStruct.Pull = GPIO_NOPULL;
  403. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  404. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  405.  
  406. /*Configure GPIO pin : B1_Pin */
  407. GPIO_InitStruct.Pin = B1_Pin;
  408. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  409. GPIO_InitStruct.Pull = GPIO_NOPULL;
  410. HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
  411.  
  412. }
  413.  
  414. /* USER CODE BEGIN 4 */
  415.  
  416. /* USER CODE END 4 */
  417.  
  418. /**
  419. * @brief This function is executed in case of error occurrence.
  420. * @retval None
  421. */
  422. void Error_Handler(void)
  423. {
  424. /* USER CODE BEGIN Error_Handler_Debug */
  425. /* User can add his own implementation to report the HAL error return state */
  426.  
  427. /* USER CODE END Error_Handler_Debug */
  428. }
  429.  
  430. #ifdef USE_FULL_ASSERT
  431. /**
  432. * @brief Reports the name of the source file and the source line number
  433. * where the assert_param error has occurred.
  434. * @param file: pointer to the source file name
  435. * @param line: assert_param error line source number
  436. * @retval None
  437. */
  438. void assert_failed(char *file, uint32_t line)
  439. {
  440. /* USER CODE BEGIN 6 */
  441. /* User can add his own implementation to report the file name and line number,
  442. tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  443. /* USER CODE END 6 */
  444. }
  445. #endif /* USE_FULL_ASSERT */
  446.  
  447. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

このプログラムでは、PWM制御をソフトウェアで実現しています。
PWM制御とは、Pulse Width Modulation:パルス幅変調のことで、パルス幅のデューティー比を変化させてデバイスなどを制御するための方法です。このプログラムでは、このPWMを高速でLEDに与えることで人間の目にはLEDが暗くなったように見せています。

このプログラムでは、1回のPWM制御幅を100ミリ秒とし、最大輝度を90%、そこから5%づつデューティー比を下げていきます。
90%の輝度とは、100ミリ秒のうち90ミリ秒はLED点灯、残り10ミリ秒がLED消灯の状態です。同様に、50%の状態は、100ミリ秒のうち50ミリ秒はLED点灯、残り50ミリ秒がLED消灯の状態となります。

このPWMを実現するためには”その1”のように1つの単純なタイマーでは制御することができません。
そこで、タイマーモジュールのクロックカウンタ・コンペア機能を使って別の割り込みを発生させることができます。

そのためのタイマー設定をinitTimer()で行っています。

Updateに加えて、TIM1の capture/compare register 1 を設定します。

100ミリ秒でUpdate発生

  1. TIM1->PSC = 480 - 1; // プリスケーラー = 480
  2. TIM1->ARR = 1000; // オートリロード = 1000 で100ミリ秒の設定

タイマーコンペアを990カウント(99%)に設定

  1. TIM1->CCR1 = 900; // 90%

割り込みは、UIE: Update interrupt enable に加えて、CC1IE: Capture/Compare 1 interrupt enable を許可

  1. TIM1->DIER |= 0x0003; // アップデート/コンペア割り込み許可

このように設定することで、100ミリ秒毎にUpdate割り込みがだけではなく、クロックカウンタとコンペアレジスタの内容を比較して一致したときにコンペア割り込みが発生するようになります。

また、コンペア割り込みは TIM1_CC_IRQn として定義され、割り込みハンドラも TIM1_CC_IRQHandler() として定義されていますので、NVICでの割り込みを別途有効化する必要があります。

  1. NVIC_EnableIRQ(TIM1_CC_IRQn);
  2. NVIC_SetPriority(TIM1_CC_IRQn,10);

アップデート割り込みのハンドラでは、LEDを点灯し、アップデート割り込みの5回に1回コンペアレジスタの値を50減算します。
コンペアレジスタの値でデューティー比を変化させます。

  1. void TIM1_UP_TIM16_IRQHandler(void) {
  2.  
  3. static int rate = 0;
  4.  
  5. if((TIM1->SR & 0x0001)) {
  6. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_SET);
  7. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_SET);
  8. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
  9. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
  10. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET);
  11. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
  12. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET);
  13. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
  14.  
  15. }
  16.  
  17. ++rate;
  18. if(rate > 5) {
  19. rate = 0;
  20.  
  21. TIM1->CCR1 -= 50;
  22. if(TIM1->CCR1 <= 0)
  23. TIM1->CCR1 = 900;
  24. }
  25.  
  26. TIM1->SR ^= 0x0001;
  27. }

コンペアの割り込みハンドラは、下記のようになります。
コンペア割り込みで、LEDをOFFします。つまり、コンペアレジスタの値が大きいほどLEDの点灯時間は長くなり、明るくみえるということになります。
コンペア割り込みでも、ステータスレジスタのCC1IF: Capture/Compare 1 interrupt flag をOFFして、次の割り込みに備えます。

  1. void TIM1_CC_IRQHandler(void) {
  2.  
  3. if(TIM1->SR & 0x0002){ // CCR1
  4. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9 ,GPIO_PIN_RESET);
  5. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_RESET);
  6. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
  7. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
  8. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET);
  9. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
  10. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET);
  11. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8 ,GPIO_PIN_RESET);
  12. TIM1->SR ^= 0x0002;
  13. }
  14. }

このサンプルでは、1回のPWM周期を100ミリ秒としています。この周期幅が広いとチラツキが目立つようになります。逆に周期幅が小さくなるとなめらかに見えます。デューティー比の変化も同様で、500ミリ秒毎にデューティー比を変更しています。この時間方向の変更幅とデューティー比の変更幅を細かく制御すれば、より滑らかな変化となります。



作成するプログラムの仕様~その3:
”その2”では、8つのLEDを同じPWMで制御していました。
PWMを制御するためにCCR1というレジスタを使用しましたが、このCCRは1~4の4つのレジスタがあり、それぞれ別の割り込みを発生させることができます。
そこで、今回はLEDを100%(つけっぱなし)、25%、5%、1%と別々のPWMデューティー比で制御するプログラムを実現してみましょう。


main.c  その3
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. ** This notice applies to any and all portions of this file
  8. * that are not between comment pairs USER CODE BEGIN and
  9. * USER CODE END. Other portions of this file, whether
  10. * inserted by the user or by software development tools
  11. * are owned by their respective copyright owners.
  12. *
  13. * COPYRIGHT(c) 2019 STMicroelectronics
  14. *
  15. * Redistribution and use in source and binary forms, with or without modification,
  16. * are permitted provided that the following conditions are met:
  17. * 1. Redistributions of source code must retain the above copyright notice,
  18. * this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * 3. Neither the name of STMicroelectronics nor the names of its contributors
  23. * may be used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  29. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  30. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  32. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  33. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  34. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. ******************************************************************************
  38. */
  39. /* USER CODE END Header */
  40.  
  41. /* Includes ------------------------------------------------------------------*/
  42. #include "main.h"
  43.  
  44. /* Private includes ----------------------------------------------------------*/
  45. /* USER CODE BEGIN Includes */
  46.  
  47. /* USER CODE END Includes */
  48.  
  49. /* Private typedef -----------------------------------------------------------*/
  50. /* USER CODE BEGIN PTD */
  51.  
  52. /* USER CODE END PTD */
  53.  
  54. /* Private define ------------------------------------------------------------*/
  55. /* USER CODE BEGIN PD */
  56.  
  57. /* USER CODE END PD */
  58.  
  59. /* Private macro -------------------------------------------------------------*/
  60. /* USER CODE BEGIN PM */
  61.  
  62. /* USER CODE END PM */
  63.  
  64. /* Private variables ---------------------------------------------------------*/
  65. I2C_HandleTypeDef hi2c1;
  66.  
  67. SPI_HandleTypeDef hspi1;
  68.  
  69. PCD_HandleTypeDef hpcd_USB_FS;
  70.  
  71. /* USER CODE BEGIN PV */
  72.  
  73. /* USER CODE END PV */
  74.  
  75. /* Private function prototypes -----------------------------------------------*/
  76. void SystemClock_Config(void);
  77. static void MX_GPIO_Init(void);
  78. static void MX_I2C1_Init(void);
  79. static void MX_SPI1_Init(void);
  80. static void MX_USB_PCD_Init(void);
  81. /* USER CODE BEGIN PFP */
  82.  
  83. /* USER CODE END PFP */
  84.  
  85. /* Private user code ---------------------------------------------------------*/
  86. /* USER CODE BEGIN 0 */
  87. void TIM1_UP_TIM16_IRQHandler(void){
  88.  
  89. if((TIM1->SR & 0x0001)) {
  90. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_SET);
  91. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
  92. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
  93. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET);
  94. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
  95. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET);
  96. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
  97.  
  98. }
  99.  
  100. TIM1->SR ^= 0x0001;
  101. }
  102.  
  103. void TIM1_CC_IRQHandler(void) {
  104.  
  105. if(TIM1->SR & 0x0002){ // CCR1
  106. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_RESET);
  107. TIM1->SR ^= 0x0002;
  108. }
  109. if(TIM1->SR & 0x0004){ // CCR2
  110. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
  111. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
  112. TIM1->SR ^= 0x0004;
  113. }
  114. if(TIM1->SR & 0x0008){ // CCR3
  115. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET);
  116. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
  117. TIM1->SR ^= 0x0008;
  118. }
  119. if(TIM1->SR & 0x0010){ // CCR4
  120. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET);
  121. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_RESET);
  122. TIM1->SR ^= 0x0010;
  123. }
  124. }
  125.  
  126. void initTimer(void) {
  127.  
  128. RCC->APB2ENR |= 0x00000800; // APB2 TIM1 48MHzクロック供給
  129.  
  130. TIM1->PSC = 480 - 1; // プリスケーラー = 480
  131. TIM1->ARR = 1000; // オートリロード = 1000 で100ミリ秒の設定
  132.  
  133. TIM1->CCR1 = 900; // 90%
  134. TIM1->CCR2 = 250; // 25%
  135. TIM1->CCR3 = 50; // 5%
  136. TIM1->CCR4 = 10; // 1%
  137.  
  138. TIM1->CR1 |= 0x0001; // カウンタ許可
  139.  
  140. TIM1->DIER |= 0x001F; // アップデート/コンペア割り込み許可
  141.  
  142. // NVIC割り込み設定
  143. NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
  144. NVIC_SetPriority(TIM1_UP_TIM16_IRQn,10);
  145. NVIC_EnableIRQ(TIM1_CC_IRQn);
  146. NVIC_SetPriority(TIM1_CC_IRQn,10);
  147. }
  148.  
  149. /* USER CODE END 0 */
  150.  
  151. /**
  152. * @brief The application entry point.
  153. * @retval int
  154. */
  155. int main(void)
  156. {
  157. /* USER CODE BEGIN 1 */
  158.  
  159. /* USER CODE END 1 */
  160.  
  161. /* MCU Configuration--------------------------------------------------------*/
  162.  
  163. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  164. HAL_Init();
  165.  
  166. /* USER CODE BEGIN Init */
  167.  
  168. /* USER CODE END Init */
  169.  
  170. /* Configure the system clock */
  171. SystemClock_Config();
  172.  
  173. /* USER CODE BEGIN SysInit */
  174.  
  175. /* USER CODE END SysInit */
  176.  
  177. /* Initialize all configured peripherals */
  178. MX_GPIO_Init();
  179. MX_I2C1_Init();
  180. MX_SPI1_Init();
  181. MX_USB_PCD_Init();
  182.  
  183. /* USER CODE BEGIN 2 */
  184. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9 ,GPIO_PIN_SET);
  185.  
  186. initTimer();
  187.  
  188. /* USER CODE END 2 */
  189.  
  190. /* Infinite loop */
  191. /* USER CODE BEGIN WHILE */
  192. while (1)
  193. {
  194. /* USER CODE END WHILE */
  195. HAL_Delay(100);
  196. /* USER CODE BEGIN 3 */
  197. }
  198. /* USER CODE END 3 */
  199. }
  200.  
  201. /**
  202. * @brief System Clock Configuration
  203. * @retval None
  204. */
  205. void SystemClock_Config(void)
  206. {
  207. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  208. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  209. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  210.  
  211. /**Initializes the CPU, AHB and APB busses clocks
  212. */
  213. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
  214. RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  215. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  216. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  217. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  218. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  219. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  220. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  221. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  222. {
  223. Error_Handler();
  224. }
  225. /**Initializes the CPU, AHB and APB busses clocks
  226. */
  227. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  228. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  229. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  230. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  231. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  232. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  233.  
  234. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  235. {
  236. Error_Handler();
  237. }
  238. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB|RCC_PERIPHCLK_I2C1;
  239. PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  240. PeriphClkInit.USBClockSelection = RCC_USBCLKSOURCE_PLL;
  241. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  242. {
  243. Error_Handler();
  244. }
  245. }
  246.  
  247. /**
  248. * @brief I2C1 Initialization Function
  249. * @param None
  250. * @retval None
  251. */
  252. static void MX_I2C1_Init(void)
  253. {
  254.  
  255. /* USER CODE BEGIN I2C1_Init 0 */
  256.  
  257. /* USER CODE END I2C1_Init 0 */
  258.  
  259. /* USER CODE BEGIN I2C1_Init 1 */
  260.  
  261. /* USER CODE END I2C1_Init 1 */
  262. hi2c1.Instance = I2C1;
  263. hi2c1.Init.Timing = 0x2000090E;
  264. hi2c1.Init.OwnAddress1 = 0;
  265. hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  266. hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  267. hi2c1.Init.OwnAddress2 = 0;
  268. hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  269. hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  270. hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  271. if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  272. {
  273. Error_Handler();
  274. }
  275. /**Configure Analogue filter
  276. */
  277. if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  278. {
  279. Error_Handler();
  280. }
  281. /**Configure Digital filter
  282. */
  283. if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  284. {
  285. Error_Handler();
  286. }
  287. /* USER CODE BEGIN I2C1_Init 2 */
  288.  
  289. /* USER CODE END I2C1_Init 2 */
  290.  
  291. }
  292.  
  293. /**
  294. * @brief SPI1 Initialization Function
  295. * @param None
  296. * @retval None
  297. */
  298. static void MX_SPI1_Init(void)
  299. {
  300.  
  301. /* USER CODE BEGIN SPI1_Init 0 */
  302.  
  303. /* USER CODE END SPI1_Init 0 */
  304.  
  305. /* USER CODE BEGIN SPI1_Init 1 */
  306.  
  307. /* USER CODE END SPI1_Init 1 */
  308. /* SPI1 parameter configuration*/
  309. hspi1.Instance = SPI1;
  310. hspi1.Init.Mode = SPI_MODE_MASTER;
  311. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  312. hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
  313. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  314. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  315. hspi1.Init.NSS = SPI_NSS_SOFT;
  316. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  317. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  318. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  319. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  320. hspi1.Init.CRCPolynomial = 7;
  321. hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  322. hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  323. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  324. {
  325. Error_Handler();
  326. }
  327. /* USER CODE BEGIN SPI1_Init 2 */
  328.  
  329. /* USER CODE END SPI1_Init 2 */
  330.  
  331. }
  332.  
  333. /**
  334. * @brief USB Initialization Function
  335. * @param None
  336. * @retval None
  337. */
  338. static void MX_USB_PCD_Init(void)
  339. {
  340.  
  341. /* USER CODE BEGIN USB_Init 0 */
  342.  
  343. /* USER CODE END USB_Init 0 */
  344.  
  345. /* USER CODE BEGIN USB_Init 1 */
  346.  
  347. /* USER CODE END USB_Init 1 */
  348. hpcd_USB_FS.Instance = USB;
  349. hpcd_USB_FS.Init.dev_endpoints = 8;
  350. hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
  351. hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_64;
  352. hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
  353. hpcd_USB_FS.Init.low_power_enable = DISABLE;
  354. hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
  355. if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
  356. {
  357. Error_Handler();
  358. }
  359. /* USER CODE BEGIN USB_Init 2 */
  360.  
  361. /* USER CODE END USB_Init 2 */
  362.  
  363. }
  364.  
  365. /**
  366. * @brief GPIO Initialization Function
  367. * @param None
  368. * @retval None
  369. */
  370. static void MX_GPIO_Init(void)
  371. {
  372. GPIO_InitTypeDef GPIO_InitStruct = {0};
  373.  
  374. /* GPIO Ports Clock Enable */
  375. __HAL_RCC_GPIOE_CLK_ENABLE();
  376. __HAL_RCC_GPIOC_CLK_ENABLE();
  377. __HAL_RCC_GPIOF_CLK_ENABLE();
  378. __HAL_RCC_GPIOA_CLK_ENABLE();
  379. __HAL_RCC_GPIOB_CLK_ENABLE();
  380.  
  381. /*Configure GPIO pin Output Level */
  382. HAL_GPIO_WritePin(GPIOE, CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  383. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  384. |LD6_Pin, GPIO_PIN_RESET);
  385.  
  386. /*Configure GPIO pins : DRDY_Pin MEMS_INT3_Pin MEMS_INT4_Pin MEMS_INT1_Pin
  387. MEMS_INT2_Pin */
  388. GPIO_InitStruct.Pin = DRDY_Pin|MEMS_INT3_Pin|MEMS_INT4_Pin|MEMS_INT1_Pin
  389. |MEMS_INT2_Pin;
  390. GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  391. GPIO_InitStruct.Pull = GPIO_NOPULL;
  392. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  393.  
  394. /*Configure GPIO pins : CS_I2C_SPI_Pin LD4_Pin LD3_Pin LD5_Pin
  395. LD7_Pin LD9_Pin LD10_Pin LD8_Pin
  396. LD6_Pin */
  397. GPIO_InitStruct.Pin = CS_I2C_SPI_Pin|LD4_Pin|LD3_Pin|LD5_Pin
  398. |LD7_Pin|LD9_Pin|LD10_Pin|LD8_Pin
  399. |LD6_Pin;
  400. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  401. GPIO_InitStruct.Pull = GPIO_NOPULL;
  402. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  403. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  404.  
  405. /*Configure GPIO pin : B1_Pin */
  406. GPIO_InitStruct.Pin = B1_Pin;
  407. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  408. GPIO_InitStruct.Pull = GPIO_NOPULL;
  409. HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
  410.  
  411. }
  412.  
  413. /* USER CODE BEGIN 4 */
  414.  
  415. /* USER CODE END 4 */
  416.  
  417. /**
  418. * @brief This function is executed in case of error occurrence.
  419. * @retval None
  420. */
  421. void Error_Handler(void)
  422. {
  423. /* USER CODE BEGIN Error_Handler_Debug */
  424. /* User can add his own implementation to report the HAL error return state */
  425.  
  426. /* USER CODE END Error_Handler_Debug */
  427. }
  428.  
  429. #ifdef USE_FULL_ASSERT
  430. /**
  431. * @brief Reports the name of the source file and the source line number
  432. * where the assert_param error has occurred.
  433. * @param file: pointer to the source file name
  434. * @param line: assert_param error line source number
  435. * @retval None
  436. */
  437. void assert_failed(char *file, uint32_t line)
  438. {
  439. /* USER CODE BEGIN 6 */
  440. /* User can add his own implementation to report the file name and line number,
  441. tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  442. /* USER CODE END 6 */
  443. }
  444. #endif /* USE_FULL_ASSERT */
  445.  
  446. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

initTimer()でのCCR設定は下記のようになります。

  1. TIM1->CCR1 = 900; // 90%
  2. TIM1->CCR2 = 250; // 25%
  3. TIM1->CCR3 = 50; // 5%
  4. TIM1->CCR4 = 10; // 1%

Updateは”その2”同様に100ミリ秒です。
CCR1を90%に、CCR2を25%に、CCR3を5%、CCR4を1%に設定します。

  1. TIM1->DIER |= 0x001F; // アップデート/コンペア割り込み許可

割り込みについては”その2”ではUIEとCC1IEをONに設定していましたが、CC2IE、CC3IE、CC4IEも同様にONとして割り込みを許可にします。

アップデートの割り込みでは、全てのLEDをONとするだけの処理とします。

コンペア割り込みについては、CC1IE~CC4IEまで同じ割り込みハンドラで処理することになるので、ハンドラ内で割り込み要因を判定して処理を行う必要があります。

  1. void TIM1_CC_IRQHandler(void) {
  2.  
  3. if(TIM1->SR & 0x0002){ // CCR1
  4. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_RESET);
  5. TIM1->SR ^= 0x0002;
  6. }
  7. if(TIM1->SR & 0x0004){ // CCR2
  8. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
  9. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
  10. TIM1->SR ^= 0x0004;
  11. }
  12. if(TIM1->SR & 0x0008){ // CCR3
  13. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET);
  14. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
  15. TIM1->SR ^= 0x0008;
  16. }
  17. if(TIM1->SR & 0x0010){ // CCR4
  18. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET);
  19. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_RESET);
  20. TIM1->SR ^= 0x0010;
  21. }
  22. }

それぞれの割り込みに対するLEDをOFFし、ステータスレジスタの割り込みフラグをOFFします。

タイマーや割り込みは使い方がわかってしまえば簡単です。
今回のサンプルコードは、LEDをPWMで制御でしたが、これを応用してモーターを制御するなどが可能です。

タイマー制御や割り込みは、マイコン使いにとってはキホンですが奥が深い世界です。
IoTの時代になってもマイコン使いは必要です。
マイコンの使い方もマスターして、食いっぱぐれないエンジニアを目指そう!





Have a Happy Hucking!!

Lightning Brains

コメント

このブログの人気の投稿

Linuxシステムコール、メッセージキューの使い方

Linuxシステムコール、共有メモリの使い方

Linuxシステムコール、セマフォの使い方