From 79bb2e8f9852d7771142229f45ea06ce3cef8d28 Mon Sep 17 00:00:00 2001 From: nhuvaoanh123 Date: Mon, 1 Jun 2026 18:15:29 +0200 Subject: [PATCH 1/4] Add STM32 device headers via RIM Import the STM32F4 and STM32G4 CMSIS device headers from STMicroelectronics' dedicated RIM-tracked repositories. Keep only the F413 and G474 headers needed by the STM32 MCU foundation and record the unused upstream headers as RIM ignores. --- NOTICE.md | 1 + .../bsp/bspMcu/include/3rdparty/st/LICENSE | 202 + .../include/3rdparty/st/stm32f4/.riminfo | 15 + .../include/3rdparty/st/stm32f4/stm32f413xx.h | 15466 +++++++++++++ .../include/3rdparty/st/stm32f4/stm32f4xx.h | 301 + .../3rdparty/st/stm32f4/system_stm32f4xx.h | 104 + .../include/3rdparty/st/stm32g4/.riminfo | 15 + .../include/3rdparty/st/stm32g4/stm32g474xx.h | 18129 ++++++++++++++++ .../include/3rdparty/st/stm32g4/stm32g4xx.h | 269 + .../3rdparty/st/stm32g4/system_stm32g4xx.h | 104 + 10 files changed, 34606 insertions(+) create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/.riminfo create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/stm32f413xx.h create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/stm32f4xx.h create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/system_stm32f4xx.h create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32g4/.riminfo create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32g4/stm32g474xx.h create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32g4/stm32g4xx.h create mode 100644 platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32g4/system_stm32g4xx.h diff --git a/NOTICE.md b/NOTICE.md index ca162642261..9be29d742b7 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -47,6 +47,7 @@ We recommend to read their licenses, as their terms may differ from the terms de | ThreadX Linux Port | 6.4.3 | MIT | ``platforms/posix/3rdparty/threadx/LICENSE.md`` | | CMSIS | 6.1.0 | Apache v2 | ``libs/3rdparty/cmsis/LICENSE`` | | NXP S32K148 Headers | 1.1a | BSD-3 | ``platforms/s32k1xx/bsp/bspMcu/include/3rdparty/nxp/*.h`` | +| ST STM32 Device Headers | 2.6.11 / 1.2.6 | Apache v2 | ``platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE`` | | CodeCoverage | | BSD-3 | ``cmake/modules/CodeCoverage.cmake`` | ## MISRA diff --git a/platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE new file mode 100644 index 00000000000..7a4a3ea2424 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/.riminfo b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/.riminfo new file mode 100644 index 00000000000..25fdf37d82b --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/.riminfo @@ -0,0 +1,15 @@ +efaecd478788406b1d98ba8e37809c6ff9957ebe + +RIM Info file. You're welcome to read but don't write it. +Instead, use RIM commands to do the things you want to do. +BEWARE: Any manual modification will invalidate the file! + +remote_url : https://github.com/STMicroelectronics/cmsis_device_f4.git +revision_sha1 : b364e5ad14523994ebb30f9e854a7c28537b0c28 +target_revision: v2.6.11 +ignores : stm32f401xc.h,stm32f401xe.h,stm32f405xx.h,stm32f407xx.h,stm32f410cx.h,stm32f410rx.h,stm32f410tx.h,stm32f411xe.h,stm32f412cx.h,stm32f412rx.h,stm32f412vx.h,stm32f412zx.h,stm32f415xx.h,stm32f417xx.h,stm32f423xx.h,stm32f427xx.h,stm32f429xx.h,stm32f437xx.h,stm32f439xx.h,stm32f446xx.h,stm32f469xx.h,stm32f479xx.h +checksum : d95d4934b47fee01f36cd076c1bb8af7ce8a228e +subdir : Include + +committer_date : 2025-05-20 15:35:16 +0100 + diff --git a/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/stm32f413xx.h b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/stm32f413xx.h new file mode 100644 index 00000000000..7a5ed4e7cef --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/include/3rdparty/st/stm32f4/stm32f413xx.h @@ -0,0 +1,15466 @@ +/** + ****************************************************************************** + * @file stm32f413xx.h + * @author MCD Application Team + * @brief CMSIS STM32F413xx Device Peripheral Access Layer Header File. + * + * This file contains: + * - Data structures and the address mapping for all peripherals + * - peripherals registers declarations and bits definition + * - Macros to access peripheral's registers hardware + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS_Device + * @{ + */ + +/** @addtogroup stm32f413xx + * @{ + */ + +#ifndef __STM32F413xx_H +#define __STM32F413xx_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @addtogroup Configuration_section_for_CMSIS + * @{ + */ + +/** + * @brief Configuration of the Cortex-M4 Processor and Core Peripherals + */ +#define __CM4_REV 0x0001U /*!< Core revision r0p1 */ +#define __MPU_PRESENT 1U /*!< STM32F4XX provides an MPU */ +#define __NVIC_PRIO_BITS 4U /*!< STM32F4XX uses 4 Bits for the Priority Levels */ +#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */ +#define __FPU_PRESENT 1U /*!< FPU present */ + +/** + * @} + */ + +/** @addtogroup Peripheral_interrupt_number_definition + * @{ + */ + +/** + * @brief STM32F4XX Interrupt Number Definition, according to the selected device + * in @ref Library_configuration_section + */ +typedef enum +{ + /****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */ + /****** STM32 specific Interrupt Numbers **********************************************************************/ + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ + TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ + DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ + DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ + DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ + DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ + DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ + DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ + ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts */ + CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupt */ + CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupt */ + CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM9_IRQn = 24, /*!< TIM1 Break interrupt and TIM9 global interrupt */ + TIM1_UP_TIM10_IRQn = 25, /*!< TIM1 Update Interrupt and TIM10 global interrupt */ + TIM1_TRG_COM_TIM11_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */ + TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ + TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ + TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare global interrupt */ + DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ + SDIO_IRQn = 49, /*!< SDIO global Interrupt */ + TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global interrupt */ + DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ + DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ + DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ + DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ + DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ + DFSDM1_FLT0_IRQn = 61, /*!< DFSDM1 Filter 0 global Interrupt */ + DFSDM1_FLT1_IRQn = 62, /*!< DFSDM1 Filter 1 global Interrupt */ + CAN2_TX_IRQn = 63, /*!< CAN2 TX Interrupt */ + CAN2_RX0_IRQn = 64, /*!< CAN2 RX0 Interrupt */ + CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */ + CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */ + OTG_FS_IRQn = 67, /*!< USB OTG FS global Interrupt */ + DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ + DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ + DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ + USART6_IRQn = 71, /*!< USART6 global interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ + CAN3_TX_IRQn = 74, /*!< CAN3 TX Interrupt */ + CAN3_RX0_IRQn = 75, /*!< CAN3 RX0 Interrupt */ + CAN3_RX1_IRQn = 76, /*!< CAN3 RX1 Interrupt */ + CAN3_SCE_IRQn = 77, /*!< CAN3 SCE Interrupt */ + RNG_IRQn = 80, /*!< RNG global Interrupt */ + FPU_IRQn = 81, /*!< FPU global interrupt */ + UART7_IRQn = 82, /*!< UART7 global interrupt */ + UART8_IRQn = 83, /*!< UART8 global interrupt */ + SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ + SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ + SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ + UART9_IRQn = 88, /*!< UART9 global Interrupt */ + UART10_IRQn = 89, /*!< UART10 global Interrupt */ + QUADSPI_IRQn = 92, /*!< QuadSPI global Interrupt */ + FMPI2C1_EV_IRQn = 95, /*!< FMPI2C1 Event Interrupt */ + FMPI2C1_ER_IRQn = 96, /*!< FMPI2C1 Error Interrupt */ + LPTIM1_IRQn = 97, /*!< LP TIM1 interrupt */ + DFSDM2_FLT0_IRQn = 98, /*!< DFSDM2 Filter 0 global Interrupt */ + DFSDM2_FLT1_IRQn = 99, /*!< DFSDM2 Filter 1 global Interrupt */ + DFSDM2_FLT2_IRQn = 100, /*!< DFSDM2 Filter 2 global Interrupt */ + DFSDM2_FLT3_IRQn = 101 /*!< DFSDM2 Filter 3 global Interrupt */ +} IRQn_Type; + +/** + * @} + */ + +#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */ +#include "system_stm32f4xx.h" +#include + +/** @addtogroup Peripheral_registers_structures + * @{ + */ + +/** + * @brief Analog to Digital Converter + */ + +typedef struct +{ + __IO uint32_t SR; /*!< ADC status register, Address offset: 0x00 */ + __IO uint32_t CR1; /*!< ADC control register 1, Address offset: 0x04 */ + __IO uint32_t CR2; /*!< ADC control register 2, Address offset: 0x08 */ + __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x0C */ + __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x10 */ + __IO uint32_t JOFR1; /*!< ADC injected channel data offset register 1, Address offset: 0x14 */ + __IO uint32_t JOFR2; /*!< ADC injected channel data offset register 2, Address offset: 0x18 */ + __IO uint32_t JOFR3; /*!< ADC injected channel data offset register 3, Address offset: 0x1C */ + __IO uint32_t JOFR4; /*!< ADC injected channel data offset register 4, Address offset: 0x20 */ + __IO uint32_t HTR; /*!< ADC watchdog higher threshold register, Address offset: 0x24 */ + __IO uint32_t LTR; /*!< ADC watchdog lower threshold register, Address offset: 0x28 */ + __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x2C */ + __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x30 */ + __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x34 */ + __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x38*/ + __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x3C */ + __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x40 */ + __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x44 */ + __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x48 */ + __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x4C */ +} ADC_TypeDef; + +typedef struct +{ + __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ + __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ + __IO uint32_t CDR; /*!< ADC common regular data register for dual + AND triple modes, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; + + +/** + * @brief Controller Area Network TxMailBox + */ + +typedef struct +{ + __IO uint32_t TIR; /*!< CAN TX mailbox identifier register */ + __IO uint32_t TDTR; /*!< CAN mailbox data length control and time stamp register */ + __IO uint32_t TDLR; /*!< CAN mailbox data low register */ + __IO uint32_t TDHR; /*!< CAN mailbox data high register */ +} CAN_TxMailBox_TypeDef; + +/** + * @brief Controller Area Network FIFOMailBox + */ + +typedef struct +{ + __IO uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ + __IO uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ + __IO uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ + __IO uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ +} CAN_FIFOMailBox_TypeDef; + +/** + * @brief Controller Area Network FilterRegister + */ + +typedef struct +{ + __IO uint32_t FR1; /*!< CAN Filter bank register 1 */ + __IO uint32_t FR2; /*!< CAN Filter bank register 1 */ +} CAN_FilterRegister_TypeDef; + +/** + * @brief Controller Area Network + */ + +typedef struct +{ + __IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */ + __IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */ + __IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */ + __IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */ + __IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */ + __IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */ + __IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */ + __IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */ + uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */ + CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */ + CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */ + uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */ + __IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */ + __IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */ + uint32_t RESERVED2; /*!< Reserved, 0x208 */ + __IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */ + uint32_t RESERVED3; /*!< Reserved, 0x210 */ + __IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */ + uint32_t RESERVED4; /*!< Reserved, 0x218 */ + __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */ + uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */ + CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */ +} CAN_TypeDef; + +/** + * @brief CRC calculation unit + */ + +typedef struct +{ + __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ + __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ + uint8_t RESERVED0; /*!< Reserved, 0x05 */ + uint16_t RESERVED1; /*!< Reserved, 0x06 */ + __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ +} CRC_TypeDef; + +/** + * @brief DFSDM module registers + */ +typedef struct +{ + __IO uint32_t FLTCR1; /*!< DFSDM control register1, Address offset: 0x100 */ + __IO uint32_t FLTCR2; /*!< DFSDM control register2, Address offset: 0x104 */ + __IO uint32_t FLTISR; /*!< DFSDM interrupt and status register, Address offset: 0x108 */ + __IO uint32_t FLTICR; /*!< DFSDM interrupt flag clear register, Address offset: 0x10C */ + __IO uint32_t FLTJCHGR; /*!< DFSDM injected channel group selection register, Address offset: 0x110 */ + __IO uint32_t FLTFCR; /*!< DFSDM filter control register, Address offset: 0x114 */ + __IO uint32_t FLTJDATAR; /*!< DFSDM data register for injected group, Address offset: 0x118 */ + __IO uint32_t FLTRDATAR; /*!< DFSDM data register for regular group, Address offset: 0x11C */ + __IO uint32_t FLTAWHTR; /*!< DFSDM analog watchdog high threshold register, Address offset: 0x120 */ + __IO uint32_t FLTAWLTR; /*!< DFSDM analog watchdog low threshold register, Address offset: 0x124 */ + __IO uint32_t FLTAWSR; /*!< DFSDM analog watchdog status register Address offset: 0x128 */ + __IO uint32_t FLTAWCFR; /*!< DFSDM analog watchdog clear flag register Address offset: 0x12C */ + __IO uint32_t FLTEXMAX; /*!< DFSDM extreme detector maximum register, Address offset: 0x130 */ + __IO uint32_t FLTEXMIN; /*!< DFSDM extreme detector minimum register Address offset: 0x134 */ + __IO uint32_t FLTCNVTIMR; /*!< DFSDM conversion timer, Address offset: 0x138 */ +} DFSDM_Filter_TypeDef; + +/** + * @brief DFSDM channel configuration registers + */ +typedef struct +{ + __IO uint32_t CHCFGR1; /*!< DFSDM channel configuration register1, Address offset: 0x00 */ + __IO uint32_t CHCFGR2; /*!< DFSDM channel configuration register2, Address offset: 0x04 */ + __IO uint32_t CHAWSCDR; /*!< DFSDM channel analog watchdog and + short circuit detector register, Address offset: 0x08 */ + __IO uint32_t CHWDATAR; /*!< DFSDM channel watchdog filter data register, Address offset: 0x0C */ + __IO uint32_t CHDATINR; /*!< DFSDM channel data input register, Address offset: 0x10 */ +} DFSDM_Channel_TypeDef; + +/** + * @brief Digital to Analog Converter + */ + +typedef struct +{ + __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */ + __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */ + __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */ + __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */ + __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */ + __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */ + __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */ + __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */ + __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */ + __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */ + __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */ + __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */ + __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */ + __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */ +} DAC_TypeDef; + +/** + * @brief Debug MCU + */ + +typedef struct +{ + __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ + __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ + __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ + __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ +} DBGMCU_TypeDef; + + +/** + * @brief DMA Controller + */ + +typedef struct +{ + __IO uint32_t CR; /*!< DMA stream x configuration register */ + __IO uint32_t NDTR; /*!< DMA stream x number of data register */ + __IO uint32_t PAR; /*!< DMA stream x peripheral address register */ + __IO uint32_t M0AR; /*!< DMA stream x memory 0 address register */ + __IO uint32_t M1AR; /*!< DMA stream x memory 1 address register */ + __IO uint32_t FCR; /*!< DMA stream x FIFO control register */ +} DMA_Stream_TypeDef; + +typedef struct +{ + __IO uint32_t LISR; /*!< DMA low interrupt status register, Address offset: 0x00 */ + __IO uint32_t HISR; /*!< DMA high interrupt status register, Address offset: 0x04 */ + __IO uint32_t LIFCR; /*!< DMA low interrupt flag clear register, Address offset: 0x08 */ + __IO uint32_t HIFCR; /*!< DMA high interrupt flag clear register, Address offset: 0x0C */ +} DMA_TypeDef; + +/** + * @brief External Interrupt/Event Controller + */ + +typedef struct +{ + __IO uint32_t IMR; /*!< EXTI Interrupt mask register, Address offset: 0x00 */ + __IO uint32_t EMR; /*!< EXTI Event mask register, Address offset: 0x04 */ + __IO uint32_t RTSR; /*!< EXTI Rising trigger selection register, Address offset: 0x08 */ + __IO uint32_t FTSR; /*!< EXTI Falling trigger selection register, Address offset: 0x0C */ + __IO uint32_t SWIER; /*!< EXTI Software interrupt event register, Address offset: 0x10 */ + __IO uint32_t PR; /*!< EXTI Pending register, Address offset: 0x14 */ +} EXTI_TypeDef; + +/** + * @brief FLASH Registers + */ + +typedef struct +{ + __IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */ + __IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x04 */ + __IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ + __IO uint32_t SR; /*!< FLASH status register, Address offset: 0x0C */ + __IO uint32_t CR; /*!< FLASH control register, Address offset: 0x10 */ + __IO uint32_t OPTCR; /*!< FLASH option control register , Address offset: 0x14 */ + __IO uint32_t OPTCR1; /*!< FLASH option control register 1, Address offset: 0x18 */ +} FLASH_TypeDef; + + + +/** + * @brief Flexible Static Memory Controller + */ + +typedef struct +{ + __IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR), Address offset: 0x00-1C */ +} FSMC_Bank1_TypeDef; + +/** + * @brief Flexible Static Memory Controller Bank1E + */ + +typedef struct +{ + __IO uint32_t BWTR[7]; /*!< NOR/PSRAM write timing registers, Address offset: 0x104-0x11C */ +} FSMC_Bank1E_TypeDef; +/** + * @brief General Purpose I/O + */ + +typedef struct +{ + __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */ + __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ + __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ + __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ + __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */ + __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */ + __IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */ + __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ + __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */ +} GPIO_TypeDef; + +/** + * @brief System configuration controller + */ + +typedef struct +{ + __IO uint32_t MEMRMP; /*!< SYSCFG memory remap register, Address offset: 0x00 */ + __IO uint32_t PMC; /*!< SYSCFG peripheral mode configuration register, Address offset: 0x04 */ + __IO uint32_t EXTICR[4]; /*!< SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */ + uint32_t RESERVED; /*!< Reserved, 0x18 */ + __IO uint32_t CFGR2; /*!< SYSCFG Configuration register2, Address offset: 0x1C */ + __IO uint32_t CMPCR; /*!< SYSCFG Compensation cell control register, Address offset: 0x20 */ + uint32_t RESERVED1[2]; /*!< Reserved, 0x24-0x28 */ + __IO uint32_t CFGR; /*!< SYSCFG Configuration register, Address offset: 0x2C */ + __IO uint32_t MCHDLYCR; /*!< SYSCFG multi-channel delay register, Address offset: 0x30 */ +} SYSCFG_TypeDef; + +/** + * @brief Inter-integrated Circuit Interface + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< I2C Control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< I2C Control register 2, Address offset: 0x04 */ + __IO uint32_t OAR1; /*!< I2C Own address register 1, Address offset: 0x08 */ + __IO uint32_t OAR2; /*!< I2C Own address register 2, Address offset: 0x0C */ + __IO uint32_t DR; /*!< I2C Data register, Address offset: 0x10 */ + __IO uint32_t SR1; /*!< I2C Status register 1, Address offset: 0x14 */ + __IO uint32_t SR2; /*!< I2C Status register 2, Address offset: 0x18 */ + __IO uint32_t CCR; /*!< I2C Clock control register, Address offset: 0x1C */ + __IO uint32_t TRISE; /*!< I2C TRISE register, Address offset: 0x20 */ + __IO uint32_t FLTR; /*!< I2C FLTR register, Address offset: 0x24 */ +} I2C_TypeDef; + +/** + * @brief Inter-integrated Circuit Interface + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< FMPI2C Control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< FMPI2C Control register 2, Address offset: 0x04 */ + __IO uint32_t OAR1; /*!< FMPI2C Own address 1 register, Address offset: 0x08 */ + __IO uint32_t OAR2; /*!< FMPI2C Own address 2 register, Address offset: 0x0C */ + __IO uint32_t TIMINGR; /*!< FMPI2C Timing register, Address offset: 0x10 */ + __IO uint32_t TIMEOUTR; /*!< FMPI2C Timeout register, Address offset: 0x14 */ + __IO uint32_t ISR; /*!< FMPI2C Interrupt and status register, Address offset: 0x18 */ + __IO uint32_t ICR; /*!< FMPI2C Interrupt clear register, Address offset: 0x1C */ + __IO uint32_t PECR; /*!< FMPI2C PEC register, Address offset: 0x20 */ + __IO uint32_t RXDR; /*!< FMPI2C Receive data register, Address offset: 0x24 */ + __IO uint32_t TXDR; /*!< FMPI2C Transmit data register, Address offset: 0x28 */ +} FMPI2C_TypeDef; + +/** + * @brief Independent WATCHDOG + */ + +typedef struct +{ + __IO uint32_t KR; /*!< IWDG Key register, Address offset: 0x00 */ + __IO uint32_t PR; /*!< IWDG Prescaler register, Address offset: 0x04 */ + __IO uint32_t RLR; /*!< IWDG Reload register, Address offset: 0x08 */ + __IO uint32_t SR; /*!< IWDG Status register, Address offset: 0x0C */ +} IWDG_TypeDef; + + +/** + * @brief Power Control + */ + +typedef struct +{ + __IO uint32_t CR; /*!< PWR power control register, Address offset: 0x00 */ + __IO uint32_t CSR; /*!< PWR power control/status register, Address offset: 0x04 */ +} PWR_TypeDef; + +/** + * @brief Reset and Clock Control + */ + +typedef struct +{ + __IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */ + __IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ + __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ + __IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ + __IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ + __IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ + __IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ + uint32_t RESERVED0; /*!< Reserved, 0x1C */ + __IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ + __IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ + uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ + __IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ + __IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ + __IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ + uint32_t RESERVED2; /*!< Reserved, 0x3C */ + __IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ + __IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ + uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ + __IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ + __IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ + __IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ + uint32_t RESERVED4; /*!< Reserved, 0x5C */ + __IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ + __IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ + uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ + __IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ + __IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ + uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ + __IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ + __IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ + uint32_t RESERVED7; /*!< Reserved, 0x84 */ + __IO uint32_t DCKCFGR; /*!< RCC Dedicated Clocks configuration register, Address offset: 0x8C */ + __IO uint32_t CKGATENR; /*!< RCC Clocks Gated ENable Register, Address offset: 0x90 */ + __IO uint32_t DCKCFGR2; /*!< RCC Dedicated Clocks configuration register 2, Address offset: 0x94 */ +} RCC_TypeDef; + +/** + * @brief Real-Time Clock + */ + +typedef struct +{ + __IO uint32_t TR; /*!< RTC time register, Address offset: 0x00 */ + __IO uint32_t DR; /*!< RTC date register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< RTC control register, Address offset: 0x08 */ + __IO uint32_t ISR; /*!< RTC initialization and status register, Address offset: 0x0C */ + __IO uint32_t PRER; /*!< RTC prescaler register, Address offset: 0x10 */ + __IO uint32_t WUTR; /*!< RTC wakeup timer register, Address offset: 0x14 */ + __IO uint32_t CALIBR; /*!< RTC calibration register, Address offset: 0x18 */ + __IO uint32_t ALRMAR; /*!< RTC alarm A register, Address offset: 0x1C */ + __IO uint32_t ALRMBR; /*!< RTC alarm B register, Address offset: 0x20 */ + __IO uint32_t WPR; /*!< RTC write protection register, Address offset: 0x24 */ + __IO uint32_t SSR; /*!< RTC sub second register, Address offset: 0x28 */ + __IO uint32_t SHIFTR; /*!< RTC shift control register, Address offset: 0x2C */ + __IO uint32_t TSTR; /*!< RTC time stamp time register, Address offset: 0x30 */ + __IO uint32_t TSDR; /*!< RTC time stamp date register, Address offset: 0x34 */ + __IO uint32_t TSSSR; /*!< RTC time-stamp sub second register, Address offset: 0x38 */ + __IO uint32_t CALR; /*!< RTC calibration register, Address offset: 0x3C */ + __IO uint32_t TAFCR; /*!< RTC tamper and alternate function configuration register, Address offset: 0x40 */ + __IO uint32_t ALRMASSR;/*!< RTC alarm A sub second register, Address offset: 0x44 */ + __IO uint32_t ALRMBSSR;/*!< RTC alarm B sub second register, Address offset: 0x48 */ + uint32_t RESERVED7; /*!< Reserved, 0x4C */ + __IO uint32_t BKP0R; /*!< RTC backup register 1, Address offset: 0x50 */ + __IO uint32_t BKP1R; /*!< RTC backup register 1, Address offset: 0x54 */ + __IO uint32_t BKP2R; /*!< RTC backup register 2, Address offset: 0x58 */ + __IO uint32_t BKP3R; /*!< RTC backup register 3, Address offset: 0x5C */ + __IO uint32_t BKP4R; /*!< RTC backup register 4, Address offset: 0x60 */ + __IO uint32_t BKP5R; /*!< RTC backup register 5, Address offset: 0x64 */ + __IO uint32_t BKP6R; /*!< RTC backup register 6, Address offset: 0x68 */ + __IO uint32_t BKP7R; /*!< RTC backup register 7, Address offset: 0x6C */ + __IO uint32_t BKP8R; /*!< RTC backup register 8, Address offset: 0x70 */ + __IO uint32_t BKP9R; /*!< RTC backup register 9, Address offset: 0x74 */ + __IO uint32_t BKP10R; /*!< RTC backup register 10, Address offset: 0x78 */ + __IO uint32_t BKP11R; /*!< RTC backup register 11, Address offset: 0x7C */ + __IO uint32_t BKP12R; /*!< RTC backup register 12, Address offset: 0x80 */ + __IO uint32_t BKP13R; /*!< RTC backup register 13, Address offset: 0x84 */ + __IO uint32_t BKP14R; /*!< RTC backup register 14, Address offset: 0x88 */ + __IO uint32_t BKP15R; /*!< RTC backup register 15, Address offset: 0x8C */ + __IO uint32_t BKP16R; /*!< RTC backup register 16, Address offset: 0x90 */ + __IO uint32_t BKP17R; /*!< RTC backup register 17, Address offset: 0x94 */ + __IO uint32_t BKP18R; /*!< RTC backup register 18, Address offset: 0x98 */ + __IO uint32_t BKP19R; /*!< RTC backup register 19, Address offset: 0x9C */ +} RTC_TypeDef; + +/** + * @brief Serial Audio Interface + */ + +typedef struct +{ + __IO uint32_t GCR; /*!< SAI global configuration register, Address offset: 0x00 */ +} SAI_TypeDef; + +typedef struct +{ + __IO uint32_t CR1; /*!< SAI block x configuration register 1, Address offset: 0x04 */ + __IO uint32_t CR2; /*!< SAI block x configuration register 2, Address offset: 0x08 */ + __IO uint32_t FRCR; /*!< SAI block x frame configuration register, Address offset: 0x0C */ + __IO uint32_t SLOTR; /*!< SAI block x slot register, Address offset: 0x10 */ + __IO uint32_t IMR; /*!< SAI block x interrupt mask register, Address offset: 0x14 */ + __IO uint32_t SR; /*!< SAI block x status register, Address offset: 0x18 */ + __IO uint32_t CLRFR; /*!< SAI block x clear flag register, Address offset: 0x1C */ + __IO uint32_t DR; /*!< SAI block x data register, Address offset: 0x20 */ +} SAI_Block_TypeDef; + +/** + * @brief SD host Interface + */ + +typedef struct +{ + __IO uint32_t POWER; /*!< SDIO power control register, Address offset: 0x00 */ + __IO uint32_t CLKCR; /*!< SDI clock control register, Address offset: 0x04 */ + __IO uint32_t ARG; /*!< SDIO argument register, Address offset: 0x08 */ + __IO uint32_t CMD; /*!< SDIO command register, Address offset: 0x0C */ + __IO const uint32_t RESPCMD; /*!< SDIO command response register, Address offset: 0x10 */ + __IO const uint32_t RESP1; /*!< SDIO response 1 register, Address offset: 0x14 */ + __IO const uint32_t RESP2; /*!< SDIO response 2 register, Address offset: 0x18 */ + __IO const uint32_t RESP3; /*!< SDIO response 3 register, Address offset: 0x1C */ + __IO const uint32_t RESP4; /*!< SDIO response 4 register, Address offset: 0x20 */ + __IO uint32_t DTIMER; /*!< SDIO data timer register, Address offset: 0x24 */ + __IO uint32_t DLEN; /*!< SDIO data length register, Address offset: 0x28 */ + __IO uint32_t DCTRL; /*!< SDIO data control register, Address offset: 0x2C */ + __IO const uint32_t DCOUNT; /*!< SDIO data counter register, Address offset: 0x30 */ + __IO const uint32_t STA; /*!< SDIO status register, Address offset: 0x34 */ + __IO uint32_t ICR; /*!< SDIO interrupt clear register, Address offset: 0x38 */ + __IO uint32_t MASK; /*!< SDIO mask register, Address offset: 0x3C */ + uint32_t RESERVED0[2]; /*!< Reserved, 0x40-0x44 */ + __IO const uint32_t FIFOCNT; /*!< SDIO FIFO counter register, Address offset: 0x48 */ + uint32_t RESERVED1[13]; /*!< Reserved, 0x4C-0x7C */ + __IO uint32_t FIFO; /*!< SDIO data FIFO register, Address offset: 0x80 */ +} SDIO_TypeDef; + +/** + * @brief Serial Peripheral Interface + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< SPI control register 1 (not used in I2S mode), Address offset: 0x00 */ + __IO uint32_t CR2; /*!< SPI control register 2, Address offset: 0x04 */ + __IO uint32_t SR; /*!< SPI status register, Address offset: 0x08 */ + __IO uint32_t DR; /*!< SPI data register, Address offset: 0x0C */ + __IO uint32_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */ + __IO uint32_t RXCRCR; /*!< SPI RX CRC register (not used in I2S mode), Address offset: 0x14 */ + __IO uint32_t TXCRCR; /*!< SPI TX CRC register (not used in I2S mode), Address offset: 0x18 */ + __IO uint32_t I2SCFGR; /*!< SPI_I2S configuration register, Address offset: 0x1C */ + __IO uint32_t I2SPR; /*!< SPI_I2S prescaler register, Address offset: 0x20 */ +} SPI_TypeDef; + +/** + * @brief QUAD Serial Peripheral Interface + */ + +typedef struct +{ + __IO uint32_t CR; /*!< QUADSPI Control register, Address offset: 0x00 */ + __IO uint32_t DCR; /*!< QUADSPI Device Configuration register, Address offset: 0x04 */ + __IO uint32_t SR; /*!< QUADSPI Status register, Address offset: 0x08 */ + __IO uint32_t FCR; /*!< QUADSPI Flag Clear register, Address offset: 0x0C */ + __IO uint32_t DLR; /*!< QUADSPI Data Length register, Address offset: 0x10 */ + __IO uint32_t CCR; /*!< QUADSPI Communication Configuration register, Address offset: 0x14 */ + __IO uint32_t AR; /*!< QUADSPI Address register, Address offset: 0x18 */ + __IO uint32_t ABR; /*!< QUADSPI Alternate Bytes register, Address offset: 0x1C */ + __IO uint32_t DR; /*!< QUADSPI Data register, Address offset: 0x20 */ + __IO uint32_t PSMKR; /*!< QUADSPI Polling Status Mask register, Address offset: 0x24 */ + __IO uint32_t PSMAR; /*!< QUADSPI Polling Status Match register, Address offset: 0x28 */ + __IO uint32_t PIR; /*!< QUADSPI Polling Interval register, Address offset: 0x2C */ + __IO uint32_t LPTR; /*!< QUADSPI Low Power Timeout register, Address offset: 0x30 */ +} QUADSPI_TypeDef; + +/** + * @brief TIM + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ + __IO uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + __IO uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + __IO uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ + __IO uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ + __IO uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + __IO uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + __IO uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + __IO uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ + __IO uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ + __IO uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + __IO uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + __IO uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + __IO uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + __IO uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + __IO uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + __IO uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + __IO uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + __IO uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + __IO uint32_t OR; /*!< TIM option register, Address offset: 0x50 */ +} TIM_TypeDef; + +/** + * @brief Universal Synchronous Asynchronous Receiver Transmitter + */ + +typedef struct +{ + __IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */ + __IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */ + __IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */ + __IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */ + __IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */ + __IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */ + __IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */ +} USART_TypeDef; + +/** + * @brief Window WATCHDOG + */ + +typedef struct +{ + __IO uint32_t CR; /*!< WWDG Control register, Address offset: 0x00 */ + __IO uint32_t CFR; /*!< WWDG Configuration register, Address offset: 0x04 */ + __IO uint32_t SR; /*!< WWDG Status register, Address offset: 0x08 */ +} WWDG_TypeDef; + +/** + * @brief RNG + */ + +typedef struct +{ + __IO uint32_t CR; /*!< RNG control register, Address offset: 0x00 */ + __IO uint32_t SR; /*!< RNG status register, Address offset: 0x04 */ + __IO uint32_t DR; /*!< RNG data register, Address offset: 0x08 */ +} RNG_TypeDef; + +/** + * @brief USB_OTG_Core_Registers + */ +typedef struct +{ + __IO uint32_t GOTGCTL; /*!< USB_OTG Control and Status Register 000h */ + __IO uint32_t GOTGINT; /*!< USB_OTG Interrupt Register 004h */ + __IO uint32_t GAHBCFG; /*!< Core AHB Configuration Register 008h */ + __IO uint32_t GUSBCFG; /*!< Core USB Configuration Register 00Ch */ + __IO uint32_t GRSTCTL; /*!< Core Reset Register 010h */ + __IO uint32_t GINTSTS; /*!< Core Interrupt Register 014h */ + __IO uint32_t GINTMSK; /*!< Core Interrupt Mask Register 018h */ + __IO uint32_t GRXSTSR; /*!< Receive Sts Q Read Register 01Ch */ + __IO uint32_t GRXSTSP; /*!< Receive Sts Q Read & POP Register 020h */ + __IO uint32_t GRXFSIZ; /*!< Receive FIFO Size Register 024h */ + __IO uint32_t DIEPTXF0_HNPTXFSIZ; /*!< EP0 / Non Periodic Tx FIFO Size Register 028h */ + __IO uint32_t HNPTXSTS; /*!< Non Periodic Tx FIFO/Queue Sts reg 02Ch */ + uint32_t Reserved30[2]; /*!< Reserved 030h */ + __IO uint32_t GCCFG; /*!< General Purpose IO Register 038h */ + __IO uint32_t CID; /*!< User ID Register 03Ch */ + uint32_t Reserved5[3]; /*!< Reserved 040h-048h */ + __IO uint32_t GHWCFG3; /*!< User HW config3 04Ch */ + uint32_t Reserved6; /*!< Reserved 050h */ + __IO uint32_t GLPMCFG; /*!< LPM Register 054h */ + uint32_t Reserved; /*!< Reserved 058h */ + __IO uint32_t GDFIFOCFG; /*!< DFIFO Software Config Register 05Ch */ + uint32_t Reserved43[40]; /*!< Reserved 058h-0FFh */ + __IO uint32_t HPTXFSIZ; /*!< Host Periodic Tx FIFO Size Reg 100h */ + __IO uint32_t DIEPTXF[0x0F]; /*!< dev Periodic Transmit FIFO */ +} USB_OTG_GlobalTypeDef; + +/** + * @brief USB_OTG_device_Registers + */ +typedef struct +{ + __IO uint32_t DCFG; /*!< dev Configuration Register 800h */ + __IO uint32_t DCTL; /*!< dev Control Register 804h */ + __IO uint32_t DSTS; /*!< dev Status Register (RO) 808h */ + uint32_t Reserved0C; /*!< Reserved 80Ch */ + __IO uint32_t DIEPMSK; /*!< dev IN Endpoint Mask 810h */ + __IO uint32_t DOEPMSK; /*!< dev OUT Endpoint Mask 814h */ + __IO uint32_t DAINT; /*!< dev All Endpoints Itr Reg 818h */ + __IO uint32_t DAINTMSK; /*!< dev All Endpoints Itr Mask 81Ch */ + uint32_t Reserved20; /*!< Reserved 820h */ + uint32_t Reserved9; /*!< Reserved 824h */ + __IO uint32_t DVBUSDIS; /*!< dev VBUS discharge Register 828h */ + __IO uint32_t DVBUSPULSE; /*!< dev VBUS Pulse Register 82Ch */ + __IO uint32_t DTHRCTL; /*!< dev threshold 830h */ + __IO uint32_t DIEPEMPMSK; /*!< dev empty msk 834h */ + __IO uint32_t DEACHINT; /*!< dedicated EP interrupt 838h */ + __IO uint32_t DEACHMSK; /*!< dedicated EP msk 83Ch */ + uint32_t Reserved40; /*!< dedicated EP mask 840h */ + __IO uint32_t DINEP1MSK; /*!< dedicated EP mask 844h */ + uint32_t Reserved44[15]; /*!< Reserved 844-87Ch */ + __IO uint32_t DOUTEP1MSK; /*!< dedicated EP msk 884h */ +} USB_OTG_DeviceTypeDef; + +/** + * @brief USB_OTG_IN_Endpoint-Specific_Register + */ +typedef struct +{ + __IO uint32_t DIEPCTL; /*!< dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h */ + uint32_t Reserved04; /*!< Reserved 900h + (ep_num * 20h) + 04h */ + __IO uint32_t DIEPINT; /*!< dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h */ + uint32_t Reserved0C; /*!< Reserved 900h + (ep_num * 20h) + 0Ch */ + __IO uint32_t DIEPTSIZ; /*!< IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h */ + __IO uint32_t DIEPDMA; /*!< IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h */ + __IO uint32_t DTXFSTS; /*!< IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h */ + uint32_t Reserved18; /*!< Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch */ +} USB_OTG_INEndpointTypeDef; + +/** + * @brief USB_OTG_OUT_Endpoint-Specific_Registers + */ +typedef struct +{ + __IO uint32_t DOEPCTL; /*!< dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h */ + uint32_t Reserved04; /*!< Reserved B00h + (ep_num * 20h) + 04h */ + __IO uint32_t DOEPINT; /*!< dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h */ + uint32_t Reserved0C; /*!< Reserved B00h + (ep_num * 20h) + 0Ch */ + __IO uint32_t DOEPTSIZ; /*!< dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h */ + __IO uint32_t DOEPDMA; /*!< dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h */ + uint32_t Reserved18[2]; /*!< Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch */ +} USB_OTG_OUTEndpointTypeDef; + +/** + * @brief USB_OTG_Host_Mode_Register_Structures + */ +typedef struct +{ + __IO uint32_t HCFG; /*!< Host Configuration Register 400h */ + __IO uint32_t HFIR; /*!< Host Frame Interval Register 404h */ + __IO uint32_t HFNUM; /*!< Host Frame Nbr/Frame Remaining 408h */ + uint32_t Reserved40C; /*!< Reserved 40Ch */ + __IO uint32_t HPTXSTS; /*!< Host Periodic Tx FIFO/ Queue Status 410h */ + __IO uint32_t HAINT; /*!< Host All Channels Interrupt Register 414h */ + __IO uint32_t HAINTMSK; /*!< Host All Channels Interrupt Mask 418h */ +} USB_OTG_HostTypeDef; + +/** + * @brief USB_OTG_Host_Channel_Specific_Registers + */ +typedef struct +{ + __IO uint32_t HCCHAR; /*!< Host Channel Characteristics Register 500h */ + __IO uint32_t HCSPLT; /*!< Host Channel Split Control Register 504h */ + __IO uint32_t HCINT; /*!< Host Channel Interrupt Register 508h */ + __IO uint32_t HCINTMSK; /*!< Host Channel Interrupt Mask Register 50Ch */ + __IO uint32_t HCTSIZ; /*!< Host Channel Transfer Size Register 510h */ + __IO uint32_t HCDMA; /*!< Host Channel DMA Address Register 514h */ + uint32_t Reserved[2]; /*!< Reserved */ +} USB_OTG_HostChannelTypeDef; + +/** + * @brief LPTIMER + */ +typedef struct +{ + __IO uint32_t ISR; /*!< LPTIM Interrupt and Status register, Address offset: 0x00 */ + __IO uint32_t ICR; /*!< LPTIM Interrupt Clear register, Address offset: 0x04 */ + __IO uint32_t IER; /*!< LPTIM Interrupt Enable register, Address offset: 0x08 */ + __IO uint32_t CFGR; /*!< LPTIM Configuration register, Address offset: 0x0C */ + __IO uint32_t CR; /*!< LPTIM Control register, Address offset: 0x10 */ + __IO uint32_t CMP; /*!< LPTIM Compare register, Address offset: 0x14 */ + __IO uint32_t ARR; /*!< LPTIM Autoreload register, Address offset: 0x18 */ + __IO uint32_t CNT; /*!< LPTIM Counter register, Address offset: 0x1C */ + __IO uint32_t OR; /*!< LPTIM Option register, Address offset: 0x20 */ +} LPTIM_TypeDef; + +/** + * @} + */ + +/** @addtogroup Peripheral_memory_map + * @{ + */ +#define FLASH_BASE 0x08000000UL /*!< FLASH (up to 1.5 MB) base address in the alias region */ +#define SRAM1_BASE 0x20000000UL /*!< SRAM1(256 KB) base address in the alias region */ +#define SRAM2_BASE 0x20040000UL /*!< SRAM2(64 KB) base address in the alias region */ +#define PERIPH_BASE 0x40000000UL /*!< Peripheral base address in the alias region */ +#define FSMC_R_BASE 0xA0000000UL /*!< FSMC registers base address */ +#define QSPI_R_BASE 0xA0001000UL /*!< QuadSPI registers base address */ +#define SRAM1_BB_BASE 0x22000000UL /*!< SRAM1(256 KB) base address in the bit-band region */ +#define SRAM2_BB_BASE 0x22800000UL /*!< SRAM2(64 KB) base address in the bit-band region */ +#define PERIPH_BB_BASE 0x42000000UL /*!< Peripheral base address in the bit-band region */ +#define FLASH_END 0x0817FFFFUL /*!< FLASH end address */ +#define FLASH_OTP_BASE 0x1FFF7800UL /*!< Base address of : (up to 528 Bytes) embedded FLASH OTP Area */ +#define FLASH_OTP_END 0x1FFF7A0FUL /*!< End address of : (up to 528 Bytes) embedded FLASH OTP Area */ + +/* Legacy defines */ +#define SRAM_BASE SRAM1_BASE +#define SRAM_BB_BASE SRAM1_BB_BASE + +/*!< Peripheral memory map */ +#define APB1PERIPH_BASE PERIPH_BASE +#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000UL) +#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000UL) +#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000UL) + +/*!< APB1 peripherals */ +#define TIM2_BASE (APB1PERIPH_BASE + 0x0000UL) +#define TIM3_BASE (APB1PERIPH_BASE + 0x0400UL) +#define TIM4_BASE (APB1PERIPH_BASE + 0x0800UL) +#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00UL) +#define TIM6_BASE (APB1PERIPH_BASE + 0x1000UL) +#define TIM7_BASE (APB1PERIPH_BASE + 0x1400UL) +#define TIM12_BASE (APB1PERIPH_BASE + 0x1800UL) +#define TIM13_BASE (APB1PERIPH_BASE + 0x1C00UL) +#define TIM14_BASE (APB1PERIPH_BASE + 0x2000UL) +#define LPTIM1_BASE (APB1PERIPH_BASE + 0x2400UL) +#define RTC_BASE (APB1PERIPH_BASE + 0x2800UL) +#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00UL) +#define IWDG_BASE (APB1PERIPH_BASE + 0x3000UL) +#define I2S2ext_BASE (APB1PERIPH_BASE + 0x3400UL) +#define SPI2_BASE (APB1PERIPH_BASE + 0x3800UL) +#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00UL) +#define I2S3ext_BASE (APB1PERIPH_BASE + 0x4000UL) +#define USART2_BASE (APB1PERIPH_BASE + 0x4400UL) +#define USART3_BASE (APB1PERIPH_BASE + 0x4800UL) +#define UART4_BASE (APB1PERIPH_BASE + 0x4C00UL) +#define UART5_BASE (APB1PERIPH_BASE + 0x5000UL) +#define I2C1_BASE (APB1PERIPH_BASE + 0x5400UL) +#define I2C2_BASE (APB1PERIPH_BASE + 0x5800UL) +#define I2C3_BASE (APB1PERIPH_BASE + 0x5C00UL) +#define FMPI2C1_BASE (APB1PERIPH_BASE + 0x6000UL) +#define CAN1_BASE (APB1PERIPH_BASE + 0x6400UL) +#define CAN2_BASE (APB1PERIPH_BASE + 0x6800UL) +#define CAN3_BASE (APB1PERIPH_BASE + 0x6C00UL) +#define PWR_BASE (APB1PERIPH_BASE + 0x7000UL) +#define DAC_BASE (APB1PERIPH_BASE + 0x7400UL) +#define UART7_BASE (APB1PERIPH_BASE + 0x7800UL) +#define UART8_BASE (APB1PERIPH_BASE + 0x7C00UL) + +/*!< APB2 peripherals */ +#define TIM1_BASE (APB2PERIPH_BASE + 0x0000UL) +#define TIM8_BASE (APB2PERIPH_BASE + 0x0400UL) +#define USART1_BASE (APB2PERIPH_BASE + 0x1000UL) +#define USART6_BASE (APB2PERIPH_BASE + 0x1400UL) +#define UART9_BASE (APB2PERIPH_BASE + 0x1800UL) +#define UART10_BASE (APB2PERIPH_BASE + 0x1C00UL) +#define ADC1_BASE (APB2PERIPH_BASE + 0x2000UL) +#define ADC1_COMMON_BASE (APB2PERIPH_BASE + 0x2300UL) +/* Legacy define */ +#define ADC_BASE ADC1_COMMON_BASE +#define SDIO_BASE (APB2PERIPH_BASE + 0x2C00UL) +#define SPI1_BASE (APB2PERIPH_BASE + 0x3000UL) +#define SPI4_BASE (APB2PERIPH_BASE + 0x3400UL) +#define SYSCFG_BASE (APB2PERIPH_BASE + 0x3800UL) +#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00UL) +#define TIM9_BASE (APB2PERIPH_BASE + 0x4000UL) +#define TIM10_BASE (APB2PERIPH_BASE + 0x4400UL) +#define TIM11_BASE (APB2PERIPH_BASE + 0x4800UL) +#define SPI5_BASE (APB2PERIPH_BASE + 0x5000UL) +#define DFSDM1_BASE (APB2PERIPH_BASE + 0x6000UL) +#define DFSDM2_BASE (APB2PERIPH_BASE + 0x6400UL) +#define DFSDM1_Channel0_BASE (DFSDM1_BASE + 0x00UL) +#define DFSDM1_Channel1_BASE (DFSDM1_BASE + 0x20UL) +#define DFSDM1_Channel2_BASE (DFSDM1_BASE + 0x40UL) +#define DFSDM1_Channel3_BASE (DFSDM1_BASE + 0x60UL) +#define DFSDM1_Filter0_BASE (DFSDM1_BASE + 0x100UL) +#define DFSDM1_Filter1_BASE (DFSDM1_BASE + 0x180UL) +#define DFSDM2_Channel0_BASE (DFSDM2_BASE + 0x00UL) +#define DFSDM2_Channel1_BASE (DFSDM2_BASE + 0x20UL) +#define DFSDM2_Channel2_BASE (DFSDM2_BASE + 0x40UL) +#define DFSDM2_Channel3_BASE (DFSDM2_BASE + 0x60UL) +#define DFSDM2_Channel4_BASE (DFSDM2_BASE + 0x80UL) +#define DFSDM2_Channel5_BASE (DFSDM2_BASE + 0xA0UL) +#define DFSDM2_Channel6_BASE (DFSDM2_BASE + 0xC0UL) +#define DFSDM2_Channel7_BASE (DFSDM2_BASE + 0xE0UL) +#define DFSDM2_Filter0_BASE (DFSDM2_BASE + 0x100UL) +#define DFSDM2_Filter1_BASE (DFSDM2_BASE + 0x180UL) +#define DFSDM2_Filter2_BASE (DFSDM2_BASE + 0x200UL) +#define DFSDM2_Filter3_BASE (DFSDM2_BASE + 0x280UL) +#define SAI1_BASE (APB2PERIPH_BASE + 0x5800UL) +#define SAI1_Block_A_BASE (SAI1_BASE + 0x004UL) +#define SAI1_Block_B_BASE (SAI1_BASE + 0x024UL) + +/*!< AHB1 peripherals */ +#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000UL) +#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400UL) +#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800UL) +#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00UL) +#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000UL) +#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400UL) +#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800UL) +#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00UL) +#define CRC_BASE (AHB1PERIPH_BASE + 0x3000UL) +#define RCC_BASE (AHB1PERIPH_BASE + 0x3800UL) +#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x3C00UL) +#define DMA1_BASE (AHB1PERIPH_BASE + 0x6000UL) +#define DMA1_Stream0_BASE (DMA1_BASE + 0x010UL) +#define DMA1_Stream1_BASE (DMA1_BASE + 0x028UL) +#define DMA1_Stream2_BASE (DMA1_BASE + 0x040UL) +#define DMA1_Stream3_BASE (DMA1_BASE + 0x058UL) +#define DMA1_Stream4_BASE (DMA1_BASE + 0x070UL) +#define DMA1_Stream5_BASE (DMA1_BASE + 0x088UL) +#define DMA1_Stream6_BASE (DMA1_BASE + 0x0A0UL) +#define DMA1_Stream7_BASE (DMA1_BASE + 0x0B8UL) +#define DMA2_BASE (AHB1PERIPH_BASE + 0x6400UL) +#define DMA2_Stream0_BASE (DMA2_BASE + 0x010UL) +#define DMA2_Stream1_BASE (DMA2_BASE + 0x028UL) +#define DMA2_Stream2_BASE (DMA2_BASE + 0x040UL) +#define DMA2_Stream3_BASE (DMA2_BASE + 0x058UL) +#define DMA2_Stream4_BASE (DMA2_BASE + 0x070UL) +#define DMA2_Stream5_BASE (DMA2_BASE + 0x088UL) +#define DMA2_Stream6_BASE (DMA2_BASE + 0x0A0UL) +#define DMA2_Stream7_BASE (DMA2_BASE + 0x0B8UL) + +/*!< AHB2 peripherals */ +#define RNG_BASE (AHB2PERIPH_BASE + 0x60800UL) + + +/*!< FSMC Bankx registers base address */ +#define FSMC_Bank1_R_BASE (FSMC_R_BASE + 0x0000UL) +#define FSMC_Bank1E_R_BASE (FSMC_R_BASE + 0x0104UL) + +/*!< Debug MCU registers base address */ +#define DBGMCU_BASE 0xE0042000UL +/*!< USB registers base address */ +#define USB_OTG_FS_PERIPH_BASE 0x50000000UL + +#define USB_OTG_GLOBAL_BASE 0x000UL +#define USB_OTG_DEVICE_BASE 0x800UL +#define USB_OTG_IN_ENDPOINT_BASE 0x900UL +#define USB_OTG_OUT_ENDPOINT_BASE 0xB00UL +#define USB_OTG_EP_REG_SIZE 0x20UL +#define USB_OTG_HOST_BASE 0x400UL +#define USB_OTG_HOST_PORT_BASE 0x440UL +#define USB_OTG_HOST_CHANNEL_BASE 0x500UL +#define USB_OTG_HOST_CHANNEL_SIZE 0x20UL +#define USB_OTG_PCGCCTL_BASE 0xE00UL +#define USB_OTG_FIFO_BASE 0x1000UL +#define USB_OTG_FIFO_SIZE 0x1000UL + +#define UID_BASE 0x1FFF7A10UL /*!< Unique device ID register base address */ +#define FLASHSIZE_BASE 0x1FFF7A22UL /*!< FLASH Size register base address */ +#define PACKAGE_BASE 0x1FFF7BF0UL /*!< Package size register base address */ +/** + * @} + */ + +/** @addtogroup Peripheral_declaration + * @{ + */ +#define TIM2 ((TIM_TypeDef *) TIM2_BASE) +#define TIM3 ((TIM_TypeDef *) TIM3_BASE) +#define TIM4 ((TIM_TypeDef *) TIM4_BASE) +#define TIM5 ((TIM_TypeDef *) TIM5_BASE) +#define TIM6 ((TIM_TypeDef *) TIM6_BASE) +#define TIM7 ((TIM_TypeDef *) TIM7_BASE) +#define TIM12 ((TIM_TypeDef *) TIM12_BASE) +#define TIM13 ((TIM_TypeDef *) TIM13_BASE) +#define TIM14 ((TIM_TypeDef *) TIM14_BASE) +#define LPTIM1 ((LPTIM_TypeDef *) LPTIM1_BASE) +#define RTC ((RTC_TypeDef *) RTC_BASE) +#define WWDG ((WWDG_TypeDef *) WWDG_BASE) +#define IWDG ((IWDG_TypeDef *) IWDG_BASE) +#define I2S2ext ((SPI_TypeDef *) I2S2ext_BASE) +#define SPI2 ((SPI_TypeDef *) SPI2_BASE) +#define SPI3 ((SPI_TypeDef *) SPI3_BASE) +#define I2S3ext ((SPI_TypeDef *) I2S3ext_BASE) +#define USART2 ((USART_TypeDef *) USART2_BASE) +#define USART3 ((USART_TypeDef *) USART3_BASE) +#define UART4 ((USART_TypeDef *) UART4_BASE) +#define UART5 ((USART_TypeDef *) UART5_BASE) +#define I2C1 ((I2C_TypeDef *) I2C1_BASE) +#define I2C2 ((I2C_TypeDef *) I2C2_BASE) +#define I2C3 ((I2C_TypeDef *) I2C3_BASE) +#define FMPI2C1 ((FMPI2C_TypeDef *) FMPI2C1_BASE) +#define CAN1 ((CAN_TypeDef *) CAN1_BASE) +#define CAN2 ((CAN_TypeDef *) CAN2_BASE) +#define CAN3 ((CAN_TypeDef *) CAN3_BASE) +#define PWR ((PWR_TypeDef *) PWR_BASE) +#define DAC1 ((DAC_TypeDef *) DAC_BASE) +#define DAC ((DAC_TypeDef *) DAC_BASE) /* Kept for legacy purpose */ +#define UART7 ((USART_TypeDef *) UART7_BASE) +#define UART8 ((USART_TypeDef *) UART8_BASE) +#define TIM1 ((TIM_TypeDef *) TIM1_BASE) +#define TIM8 ((TIM_TypeDef *) TIM8_BASE) +#define USART1 ((USART_TypeDef *) USART1_BASE) +#define USART6 ((USART_TypeDef *) USART6_BASE) +#define UART9 ((USART_TypeDef *) UART9_BASE) +#define UART10 ((USART_TypeDef *) UART10_BASE) +#define ADC1 ((ADC_TypeDef *) ADC1_BASE) +#define ADC1_COMMON ((ADC_Common_TypeDef *) ADC1_COMMON_BASE) +/* Legacy define */ +#define ADC ADC1_COMMON +#define SDIO ((SDIO_TypeDef *) SDIO_BASE) +#define SPI1 ((SPI_TypeDef *) SPI1_BASE) +#define SPI4 ((SPI_TypeDef *) SPI4_BASE) +#define SYSCFG ((SYSCFG_TypeDef *) SYSCFG_BASE) +#define EXTI ((EXTI_TypeDef *) EXTI_BASE) +#define TIM9 ((TIM_TypeDef *) TIM9_BASE) +#define TIM10 ((TIM_TypeDef *) TIM10_BASE) +#define TIM11 ((TIM_TypeDef *) TIM11_BASE) +#define SPI5 ((SPI_TypeDef *) SPI5_BASE) +#define DFSDM1_Channel0 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel0_BASE) +#define DFSDM1_Channel1 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel1_BASE) +#define DFSDM1_Channel2 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel2_BASE) +#define DFSDM1_Channel3 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel3_BASE) +#define DFSDM1_Filter0 ((DFSDM_Filter_TypeDef *) DFSDM1_Filter0_BASE) +#define DFSDM1_Filter1 ((DFSDM_Filter_TypeDef *) DFSDM1_Filter1_BASE) +#define DFSDM2_Channel0 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel0_BASE) +#define DFSDM2_Channel1 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel1_BASE) +#define DFSDM2_Channel2 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel2_BASE) +#define DFSDM2_Channel3 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel3_BASE) +#define DFSDM2_Channel4 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel4_BASE) +#define DFSDM2_Channel5 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel5_BASE) +#define DFSDM2_Channel6 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel6_BASE) +#define DFSDM2_Channel7 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel7_BASE) +#define DFSDM2_Filter0 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter0_BASE) +#define DFSDM2_Filter1 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter1_BASE) +#define DFSDM2_Filter2 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter2_BASE) +#define DFSDM2_Filter3 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter3_BASE) +#define SAI1 ((SAI_TypeDef *) SAI1_BASE) +#define SAI1_Block_A ((SAI_Block_TypeDef *)SAI1_Block_A_BASE) +#define SAI1_Block_B ((SAI_Block_TypeDef *)SAI1_Block_B_BASE) +#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) +#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) +#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) +#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) +#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) +#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) +#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) +#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) +#define CRC ((CRC_TypeDef *) CRC_BASE) +#define RCC ((RCC_TypeDef *) RCC_BASE) +#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) +#define DMA1 ((DMA_TypeDef *) DMA1_BASE) +#define DMA1_Stream0 ((DMA_Stream_TypeDef *) DMA1_Stream0_BASE) +#define DMA1_Stream1 ((DMA_Stream_TypeDef *) DMA1_Stream1_BASE) +#define DMA1_Stream2 ((DMA_Stream_TypeDef *) DMA1_Stream2_BASE) +#define DMA1_Stream3 ((DMA_Stream_TypeDef *) DMA1_Stream3_BASE) +#define DMA1_Stream4 ((DMA_Stream_TypeDef *) DMA1_Stream4_BASE) +#define DMA1_Stream5 ((DMA_Stream_TypeDef *) DMA1_Stream5_BASE) +#define DMA1_Stream6 ((DMA_Stream_TypeDef *) DMA1_Stream6_BASE) +#define DMA1_Stream7 ((DMA_Stream_TypeDef *) DMA1_Stream7_BASE) +#define DMA2 ((DMA_TypeDef *) DMA2_BASE) +#define DMA2_Stream0 ((DMA_Stream_TypeDef *) DMA2_Stream0_BASE) +#define DMA2_Stream1 ((DMA_Stream_TypeDef *) DMA2_Stream1_BASE) +#define DMA2_Stream2 ((DMA_Stream_TypeDef *) DMA2_Stream2_BASE) +#define DMA2_Stream3 ((DMA_Stream_TypeDef *) DMA2_Stream3_BASE) +#define DMA2_Stream4 ((DMA_Stream_TypeDef *) DMA2_Stream4_BASE) +#define DMA2_Stream5 ((DMA_Stream_TypeDef *) DMA2_Stream5_BASE) +#define DMA2_Stream6 ((DMA_Stream_TypeDef *) DMA2_Stream6_BASE) +#define DMA2_Stream7 ((DMA_Stream_TypeDef *) DMA2_Stream7_BASE) +#define RNG ((RNG_TypeDef *) RNG_BASE) +#define FSMC_Bank1 ((FSMC_Bank1_TypeDef *) FSMC_Bank1_R_BASE) +#define FSMC_Bank1E ((FSMC_Bank1E_TypeDef *) FSMC_Bank1E_R_BASE) +#define QUADSPI ((QUADSPI_TypeDef *) QSPI_R_BASE) +#define DBGMCU ((DBGMCU_TypeDef *) DBGMCU_BASE) +#define USB_OTG_FS ((USB_OTG_GlobalTypeDef *) USB_OTG_FS_PERIPH_BASE) + +/** + * @} + */ + +/** @addtogroup Exported_constants + * @{ + */ + +/** @addtogroup Hardware_Constant_Definition + * @{ + */ +#define LSI_STARTUP_TIME 40U /*!< LSI Maximum startup time in us */ +/** + * @} + */ + +/** @addtogroup Peripheral_Registers_Bits_Definition +* @{ +*/ + +/******************************************************************************/ +/* Peripheral Registers_Bits_Definition */ +/******************************************************************************/ + +/******************************************************************************/ +/* */ +/* Analog to Digital Converter */ +/* */ +/******************************************************************************/ + +/******************** Bit definition for ADC_SR register ********************/ +#define ADC_SR_AWD_Pos (0U) +#define ADC_SR_AWD_Msk (0x1UL << ADC_SR_AWD_Pos) /*!< 0x00000001 */ +#define ADC_SR_AWD ADC_SR_AWD_Msk /*! + +/** @addtogroup Peripheral_registers_structures + * @{ + */ + +/** + * @brief Analog to Digital Converter + */ + +typedef struct +{ + __IO uint32_t ISR; /*!< ADC interrupt and status register, Address offset: 0x00 */ + __IO uint32_t IER; /*!< ADC interrupt enable register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */ + __IO uint32_t CFGR; /*!< ADC configuration register 1, Address offset: 0x0C */ + __IO uint32_t CFGR2; /*!< ADC configuration register 2, Address offset: 0x10 */ + __IO uint32_t SMPR1; /*!< ADC sampling time register 1, Address offset: 0x14 */ + __IO uint32_t SMPR2; /*!< ADC sampling time register 2, Address offset: 0x18 */ + uint32_t RESERVED1; /*!< Reserved, 0x1C */ + __IO uint32_t TR1; /*!< ADC analog watchdog 1 threshold register, Address offset: 0x20 */ + __IO uint32_t TR2; /*!< ADC analog watchdog 2 threshold register, Address offset: 0x24 */ + __IO uint32_t TR3; /*!< ADC analog watchdog 3 threshold register, Address offset: 0x28 */ + uint32_t RESERVED2; /*!< Reserved, 0x2C */ + __IO uint32_t SQR1; /*!< ADC group regular sequencer register 1, Address offset: 0x30 */ + __IO uint32_t SQR2; /*!< ADC group regular sequencer register 2, Address offset: 0x34 */ + __IO uint32_t SQR3; /*!< ADC group regular sequencer register 3, Address offset: 0x38 */ + __IO uint32_t SQR4; /*!< ADC group regular sequencer register 4, Address offset: 0x3C */ + __IO uint32_t DR; /*!< ADC group regular data register, Address offset: 0x40 */ + uint32_t RESERVED3; /*!< Reserved, 0x44 */ + uint32_t RESERVED4; /*!< Reserved, 0x48 */ + __IO uint32_t JSQR; /*!< ADC group injected sequencer register, Address offset: 0x4C */ + uint32_t RESERVED5[4]; /*!< Reserved, 0x50 - 0x5C */ + __IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */ + __IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */ + __IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */ + __IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */ + uint32_t RESERVED6[4]; /*!< Reserved, 0x70 - 0x7C */ + __IO uint32_t JDR1; /*!< ADC group injected rank 1 data register, Address offset: 0x80 */ + __IO uint32_t JDR2; /*!< ADC group injected rank 2 data register, Address offset: 0x84 */ + __IO uint32_t JDR3; /*!< ADC group injected rank 3 data register, Address offset: 0x88 */ + __IO uint32_t JDR4; /*!< ADC group injected rank 4 data register, Address offset: 0x8C */ + uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */ + __IO uint32_t AWD2CR; /*!< ADC analog watchdog 2 configuration register, Address offset: 0xA0 */ + __IO uint32_t AWD3CR; /*!< ADC analog watchdog 3 Configuration Register, Address offset: 0xA4 */ + uint32_t RESERVED8; /*!< Reserved, 0x0A8 */ + uint32_t RESERVED9; /*!< Reserved, 0x0AC */ + __IO uint32_t DIFSEL; /*!< ADC differential mode selection register, Address offset: 0xB0 */ + __IO uint32_t CALFACT; /*!< ADC calibration factors, Address offset: 0xB4 */ + uint32_t RESERVED10[2];/*!< Reserved, 0x0B8 - 0x0BC */ + __IO uint32_t GCOMP; /*!< ADC calibration factors, Address offset: 0xC0 */ +} ADC_TypeDef; + +typedef struct +{ + __IO uint32_t CSR; /*!< ADC common status register, Address offset: 0x300 + 0x00 */ + uint32_t RESERVED1; /*!< Reserved, Address offset: 0x300 + 0x04 */ + __IO uint32_t CCR; /*!< ADC common configuration register, Address offset: 0x300 + 0x08 */ + __IO uint32_t CDR; /*!< ADC common group regular data register Address offset: 0x300 + 0x0C */ +} ADC_Common_TypeDef; + +/** + * @brief FD Controller Area Network + */ + +typedef struct +{ + __IO uint32_t CREL; /*!< FDCAN Core Release register, Address offset: 0x000 */ + __IO uint32_t ENDN; /*!< FDCAN Endian register, Address offset: 0x004 */ + uint32_t RESERVED1; /*!< Reserved, 0x008 */ + __IO uint32_t DBTP; /*!< FDCAN Data Bit Timing & Prescaler register, Address offset: 0x00C */ + __IO uint32_t TEST; /*!< FDCAN Test register, Address offset: 0x010 */ + __IO uint32_t RWD; /*!< FDCAN RAM Watchdog register, Address offset: 0x014 */ + __IO uint32_t CCCR; /*!< FDCAN CC Control register, Address offset: 0x018 */ + __IO uint32_t NBTP; /*!< FDCAN Nominal Bit Timing & Prescaler register, Address offset: 0x01C */ + __IO uint32_t TSCC; /*!< FDCAN Timestamp Counter Configuration register, Address offset: 0x020 */ + __IO uint32_t TSCV; /*!< FDCAN Timestamp Counter Value register, Address offset: 0x024 */ + __IO uint32_t TOCC; /*!< FDCAN Timeout Counter Configuration register, Address offset: 0x028 */ + __IO uint32_t TOCV; /*!< FDCAN Timeout Counter Value register, Address offset: 0x02C */ + uint32_t RESERVED2[4]; /*!< Reserved, 0x030 - 0x03C */ + __IO uint32_t ECR; /*!< FDCAN Error Counter register, Address offset: 0x040 */ + __IO uint32_t PSR; /*!< FDCAN Protocol Status register, Address offset: 0x044 */ + __IO uint32_t TDCR; /*!< FDCAN Transmitter Delay Compensation register, Address offset: 0x048 */ + uint32_t RESERVED3; /*!< Reserved, 0x04C */ + __IO uint32_t IR; /*!< FDCAN Interrupt register, Address offset: 0x050 */ + __IO uint32_t IE; /*!< FDCAN Interrupt Enable register, Address offset: 0x054 */ + __IO uint32_t ILS; /*!< FDCAN Interrupt Line Select register, Address offset: 0x058 */ + __IO uint32_t ILE; /*!< FDCAN Interrupt Line Enable register, Address offset: 0x05C */ + uint32_t RESERVED4[8]; /*!< Reserved, 0x060 - 0x07C */ + __IO uint32_t RXGFC; /*!< FDCAN Global Filter Configuration register, Address offset: 0x080 */ + __IO uint32_t XIDAM; /*!< FDCAN Extended ID AND Mask register, Address offset: 0x084 */ + __IO uint32_t HPMS; /*!< FDCAN High Priority Message Status register, Address offset: 0x088 */ + uint32_t RESERVED5; /*!< Reserved, 0x08C */ + __IO uint32_t RXF0S; /*!< FDCAN Rx FIFO 0 Status register, Address offset: 0x090 */ + __IO uint32_t RXF0A; /*!< FDCAN Rx FIFO 0 Acknowledge register, Address offset: 0x094 */ + __IO uint32_t RXF1S; /*!< FDCAN Rx FIFO 1 Status register, Address offset: 0x098 */ + __IO uint32_t RXF1A; /*!< FDCAN Rx FIFO 1 Acknowledge register, Address offset: 0x09C */ + uint32_t RESERVED6[8]; /*!< Reserved, 0x0A0 - 0x0BC */ + __IO uint32_t TXBC; /*!< FDCAN Tx Buffer Configuration register, Address offset: 0x0C0 */ + __IO uint32_t TXFQS; /*!< FDCAN Tx FIFO/Queue Status register, Address offset: 0x0C4 */ + __IO uint32_t TXBRP; /*!< FDCAN Tx Buffer Request Pending register, Address offset: 0x0C8 */ + __IO uint32_t TXBAR; /*!< FDCAN Tx Buffer Add Request register, Address offset: 0x0CC */ + __IO uint32_t TXBCR; /*!< FDCAN Tx Buffer Cancellation Request register, Address offset: 0x0D0 */ + __IO uint32_t TXBTO; /*!< FDCAN Tx Buffer Transmission Occurred register, Address offset: 0x0D4 */ + __IO uint32_t TXBCF; /*!< FDCAN Tx Buffer Cancellation Finished register, Address offset: 0x0D8 */ + __IO uint32_t TXBTIE; /*!< FDCAN Tx Buffer Transmission Interrupt Enable register, Address offset: 0x0DC */ + __IO uint32_t TXBCIE; /*!< FDCAN Tx Buffer Cancellation Finished Interrupt Enable register, Address offset: 0x0E0 */ + __IO uint32_t TXEFS; /*!< FDCAN Tx Event FIFO Status register, Address offset: 0x0E4 */ + __IO uint32_t TXEFA; /*!< FDCAN Tx Event FIFO Acknowledge register, Address offset: 0x0E8 */ +} FDCAN_GlobalTypeDef; + +/** + * @brief FD Controller Area Network Configuration + */ + +typedef struct +{ + __IO uint32_t CKDIV; /*!< FDCAN clock divider register, Address offset: 0x100 + 0x000 */ +} FDCAN_Config_TypeDef; + +/** + * @brief Comparator + */ + +typedef struct +{ + __IO uint32_t CSR; /*!< COMP control and status register, Address offset: 0x00 */ +} COMP_TypeDef; + +/** + * @brief CRC calculation unit + */ + +typedef struct +{ + __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ + __IO uint32_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ + uint32_t RESERVED0; /*!< Reserved, 0x0C */ + __IO uint32_t INIT; /*!< Initial CRC value register, Address offset: 0x10 */ + __IO uint32_t POL; /*!< CRC polynomial register, Address offset: 0x14 */ +} CRC_TypeDef; + +/** + * @brief Clock Recovery System + */ +typedef struct +{ + __IO uint32_t CR; /*!< CRS ccontrol register, Address offset: 0x00 */ + __IO uint32_t CFGR; /*!< CRS configuration register, Address offset: 0x04 */ + __IO uint32_t ISR; /*!< CRS interrupt and status register, Address offset: 0x08 */ + __IO uint32_t ICR; /*!< CRS interrupt flag clear register, Address offset: 0x0C */ +} CRS_TypeDef; + +/** + * @brief Digital to Analog Converter + */ + +typedef struct +{ + __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */ + __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */ + __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */ + __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */ + __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */ + __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */ + __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */ + __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */ + __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */ + __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */ + __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */ + __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */ + __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */ + __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */ + __IO uint32_t CCR; /*!< DAC calibration control register, Address offset: 0x38 */ + __IO uint32_t MCR; /*!< DAC mode control register, Address offset: 0x3C */ + __IO uint32_t SHSR1; /*!< DAC Sample and Hold sample time register 1, Address offset: 0x40 */ + __IO uint32_t SHSR2; /*!< DAC Sample and Hold sample time register 2, Address offset: 0x44 */ + __IO uint32_t SHHR; /*!< DAC Sample and Hold hold time register, Address offset: 0x48 */ + __IO uint32_t SHRR; /*!< DAC Sample and Hold refresh time register, Address offset: 0x4C */ + __IO uint32_t RESERVED[2]; + __IO uint32_t STR1; /*!< DAC Sawtooth register, Address offset: 0x58 */ + __IO uint32_t STR2; /*!< DAC Sawtooth register, Address offset: 0x5C */ + __IO uint32_t STMODR; /*!< DAC Sawtooth Mode register, Address offset: 0x60 */ +} DAC_TypeDef; + +/** + * @brief Debug MCU + */ + +typedef struct +{ + __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ + __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ + __IO uint32_t APB1FZR1; /*!< Debug MCU APB1 freeze register 1, Address offset: 0x08 */ + __IO uint32_t APB1FZR2; /*!< Debug MCU APB1 freeze register 2, Address offset: 0x0C */ + __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x10 */ +} DBGMCU_TypeDef; + +/** + * @brief DMA Controller + */ + +typedef struct +{ + __IO uint32_t CCR; /*!< DMA channel x configuration register */ + __IO uint32_t CNDTR; /*!< DMA channel x number of data register */ + __IO uint32_t CPAR; /*!< DMA channel x peripheral address register */ + __IO uint32_t CMAR; /*!< DMA channel x memory address register */ +} DMA_Channel_TypeDef; + +typedef struct +{ + __IO uint32_t ISR; /*!< DMA interrupt status register, Address offset: 0x00 */ + __IO uint32_t IFCR; /*!< DMA interrupt flag clear register, Address offset: 0x04 */ +} DMA_TypeDef; + +/** + * @brief DMA Multiplexer + */ + +typedef struct +{ + __IO uint32_t CCR; /*!< DMA Multiplexer Channel x Control Register Address offset: 0x0004 * (channel x) */ +}DMAMUX_Channel_TypeDef; + +typedef struct +{ + __IO uint32_t CSR; /*!< DMA Channel Status Register Address offset: 0x0080 */ + __IO uint32_t CFR; /*!< DMA Channel Clear Flag Register Address offset: 0x0084 */ +}DMAMUX_ChannelStatus_TypeDef; + +typedef struct +{ + __IO uint32_t RGCR; /*!< DMA Request Generator x Control Register Address offset: 0x0100 + 0x0004 * (Req Gen x) */ +}DMAMUX_RequestGen_TypeDef; + +typedef struct +{ + __IO uint32_t RGSR; /*!< DMA Request Generator Status Register Address offset: 0x0140 */ + __IO uint32_t RGCFR; /*!< DMA Request Generator Clear Flag Register Address offset: 0x0144 */ +}DMAMUX_RequestGenStatus_TypeDef; + +/** + * @brief External Interrupt/Event Controller + */ + +typedef struct +{ + __IO uint32_t IMR1; /*!< EXTI Interrupt mask register 1, Address offset: 0x00 */ + __IO uint32_t EMR1; /*!< EXTI Event mask register 1, Address offset: 0x04 */ + __IO uint32_t RTSR1; /*!< EXTI Rising trigger selection register 1, Address offset: 0x08 */ + __IO uint32_t FTSR1; /*!< EXTI Falling trigger selection register 1, Address offset: 0x0C */ + __IO uint32_t SWIER1; /*!< EXTI Software interrupt event register 1, Address offset: 0x10 */ + __IO uint32_t PR1; /*!< EXTI Pending register 1, Address offset: 0x14 */ + uint32_t RESERVED1; /*!< Reserved, 0x18 */ + uint32_t RESERVED2; /*!< Reserved, 0x1C */ + __IO uint32_t IMR2; /*!< EXTI Interrupt mask register 2, Address offset: 0x20 */ + __IO uint32_t EMR2; /*!< EXTI Event mask register 2, Address offset: 0x24 */ + __IO uint32_t RTSR2; /*!< EXTI Rising trigger selection register 2, Address offset: 0x28 */ + __IO uint32_t FTSR2; /*!< EXTI Falling trigger selection register 2, Address offset: 0x2C */ + __IO uint32_t SWIER2; /*!< EXTI Software interrupt event register 2, Address offset: 0x30 */ + __IO uint32_t PR2; /*!< EXTI Pending register 2, Address offset: 0x34 */ +} EXTI_TypeDef; + +/** + * @brief FLASH Registers + */ + +typedef struct +{ + __IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */ + __IO uint32_t PDKEYR; /*!< FLASH power down key register, Address offset: 0x04 */ + __IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x08 */ + __IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x0C */ + __IO uint32_t SR; /*!< FLASH status register, Address offset: 0x10 */ + __IO uint32_t CR; /*!< FLASH control register, Address offset: 0x14 */ + __IO uint32_t ECCR; /*!< FLASH ECC register, Address offset: 0x18 */ + uint32_t RESERVED1; /*!< Reserved1, Address offset: 0x1C */ + __IO uint32_t OPTR; /*!< FLASH option register, Address offset: 0x20 */ + __IO uint32_t PCROP1SR; /*!< FLASH bank1 PCROP start address register, Address offset: 0x24 */ + __IO uint32_t PCROP1ER; /*!< FLASH bank1 PCROP end address register, Address offset: 0x28 */ + __IO uint32_t WRP1AR; /*!< FLASH bank1 WRP area A address register, Address offset: 0x2C */ + __IO uint32_t WRP1BR; /*!< FLASH bank1 WRP area B address register, Address offset: 0x30 */ + uint32_t RESERVED2[4]; /*!< Reserved2, Address offset: 0x34 */ + __IO uint32_t PCROP2SR; /*!< FLASH bank2 PCROP start address register, Address offset: 0x44 */ + __IO uint32_t PCROP2ER; /*!< FLASH bank2 PCROP end address register, Address offset: 0x48 */ + __IO uint32_t WRP2AR; /*!< FLASH bank2 WRP area A address register, Address offset: 0x4C */ + __IO uint32_t WRP2BR; /*!< FLASH bank2 WRP area B address register, Address offset: 0x50 */ + uint32_t RESERVED3[7]; /*!< Reserved3, Address offset: 0x54 */ + __IO uint32_t SEC1R; /*!< FLASH Securable memory register bank1, Address offset: 0x70 */ + __IO uint32_t SEC2R; /*!< FLASH Securable memory register bank2, Address offset: 0x74 */ +} FLASH_TypeDef; + +/** + * @brief FMAC + */ +typedef struct +{ + __IO uint32_t X1BUFCFG; /*!< FMAC X1 Buffer Configuration register, Address offset: 0x00 */ + __IO uint32_t X2BUFCFG; /*!< FMAC X2 Buffer Configuration register, Address offset: 0x04 */ + __IO uint32_t YBUFCFG; /*!< FMAC Y Buffer Configuration register, Address offset: 0x08 */ + __IO uint32_t PARAM; /*!< FMAC Parameter register, Address offset: 0x0C */ + __IO uint32_t CR; /*!< FMAC Control register, Address offset: 0x10 */ + __IO uint32_t SR; /*!< FMAC Status register, Address offset: 0x14 */ + __IO uint32_t WDATA; /*!< FMAC Write Data register, Address offset: 0x18 */ + __IO uint32_t RDATA; /*!< FMAC Read Data register, Address offset: 0x1C */ +} FMAC_TypeDef; + +/** + * @brief Flexible Memory Controller + */ + +typedef struct +{ + __IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR), Address offset: 0x00-1C */ + __IO uint32_t PCSCNTR; /*!< PSRAM chip-select counter register, Address offset: 0x20 */ +} FMC_Bank1_TypeDef; + +/** + * @brief Flexible Memory Controller Bank1E + */ + +typedef struct +{ + __IO uint32_t BWTR[7]; /*!< NOR/PSRAM write timing registers, Address offset: 0x104-0x11C */ +} FMC_Bank1E_TypeDef; + +/** + * @brief Flexible Memory Controller Bank3 + */ + +typedef struct +{ + __IO uint32_t PCR; /*!< NAND Flash control register, Address offset: 0x80 */ + __IO uint32_t SR; /*!< NAND Flash FIFO status and interrupt register, Address offset: 0x84 */ + __IO uint32_t PMEM; /*!< NAND Flash Common memory space timing register, Address offset: 0x88 */ + __IO uint32_t PATT; /*!< NAND Flash Attribute memory space timing register, Address offset: 0x8C */ + uint32_t RESERVED0; /*!< Reserved, 0x90 */ + __IO uint32_t ECCR; /*!< NAND Flash ECC result registers, Address offset: 0x94 */ +} FMC_Bank3_TypeDef; + +/** + * @brief General Purpose I/O + */ + +typedef struct +{ + __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */ + __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ + __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ + __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ + __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */ + __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */ + __IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */ + __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ + __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */ + __IO uint32_t BRR; /*!< GPIO Bit Reset register, Address offset: 0x28 */ +} GPIO_TypeDef; + +/** + * @brief Inter-integrated Circuit Interface + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< I2C Control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< I2C Control register 2, Address offset: 0x04 */ + __IO uint32_t OAR1; /*!< I2C Own address 1 register, Address offset: 0x08 */ + __IO uint32_t OAR2; /*!< I2C Own address 2 register, Address offset: 0x0C */ + __IO uint32_t TIMINGR; /*!< I2C Timing register, Address offset: 0x10 */ + __IO uint32_t TIMEOUTR; /*!< I2C Timeout register, Address offset: 0x14 */ + __IO uint32_t ISR; /*!< I2C Interrupt and status register, Address offset: 0x18 */ + __IO uint32_t ICR; /*!< I2C Interrupt clear register, Address offset: 0x1C */ + __IO uint32_t PECR; /*!< I2C PEC register, Address offset: 0x20 */ + __IO uint32_t RXDR; /*!< I2C Receive data register, Address offset: 0x24 */ + __IO uint32_t TXDR; /*!< I2C Transmit data register, Address offset: 0x28 */ +} I2C_TypeDef; + +/** + * @brief Independent WATCHDOG + */ + +typedef struct +{ + __IO uint32_t KR; /*!< IWDG Key register, Address offset: 0x00 */ + __IO uint32_t PR; /*!< IWDG Prescaler register, Address offset: 0x04 */ + __IO uint32_t RLR; /*!< IWDG Reload register, Address offset: 0x08 */ + __IO uint32_t SR; /*!< IWDG Status register, Address offset: 0x0C */ + __IO uint32_t WINR; /*!< IWDG Window register, Address offset: 0x10 */ +} IWDG_TypeDef; + +/** + * @brief LPTIMER + */ + +typedef struct +{ + __IO uint32_t ISR; /*!< LPTIM Interrupt and Status register, Address offset: 0x00 */ + __IO uint32_t ICR; /*!< LPTIM Interrupt Clear register, Address offset: 0x04 */ + __IO uint32_t IER; /*!< LPTIM Interrupt Enable register, Address offset: 0x08 */ + __IO uint32_t CFGR; /*!< LPTIM Configuration register, Address offset: 0x0C */ + __IO uint32_t CR; /*!< LPTIM Control register, Address offset: 0x10 */ + __IO uint32_t CMP; /*!< LPTIM Compare register, Address offset: 0x14 */ + __IO uint32_t ARR; /*!< LPTIM Autoreload register, Address offset: 0x18 */ + __IO uint32_t CNT; /*!< LPTIM Counter register, Address offset: 0x1C */ + __IO uint32_t OR; /*!< LPTIM Option register, Address offset: 0x20 */ +} LPTIM_TypeDef; + +/** + * @brief Operational Amplifier (OPAMP) + */ + +typedef struct +{ + __IO uint32_t CSR; /*!< OPAMP control/status register, Address offset: 0x00 */ + __IO uint32_t RESERVED[5]; /*!< OPAMP offset trimming register for normal mode, Address offset: 0x04 */ + __IO uint32_t TCMR; /*!< OPAMP timer controlled mux mode register, Address offset: 0x18 */ +} OPAMP_TypeDef; + +/** + * @brief Power Control + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< PWR power control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< PWR power control register 2, Address offset: 0x04 */ + __IO uint32_t CR3; /*!< PWR power control register 3, Address offset: 0x08 */ + __IO uint32_t CR4; /*!< PWR power control register 4, Address offset: 0x0C */ + __IO uint32_t SR1; /*!< PWR power status register 1, Address offset: 0x10 */ + __IO uint32_t SR2; /*!< PWR power status register 2, Address offset: 0x14 */ + __IO uint32_t SCR; /*!< PWR power status reset register, Address offset: 0x18 */ + uint32_t RESERVED; /*!< Reserved, Address offset: 0x1C */ + __IO uint32_t PUCRA; /*!< Pull_up control register of portA, Address offset: 0x20 */ + __IO uint32_t PDCRA; /*!< Pull_Down control register of portA, Address offset: 0x24 */ + __IO uint32_t PUCRB; /*!< Pull_up control register of portB, Address offset: 0x28 */ + __IO uint32_t PDCRB; /*!< Pull_Down control register of portB, Address offset: 0x2C */ + __IO uint32_t PUCRC; /*!< Pull_up control register of portC, Address offset: 0x30 */ + __IO uint32_t PDCRC; /*!< Pull_Down control register of portC, Address offset: 0x34 */ + __IO uint32_t PUCRD; /*!< Pull_up control register of portD, Address offset: 0x38 */ + __IO uint32_t PDCRD; /*!< Pull_Down control register of portD, Address offset: 0x3C */ + __IO uint32_t PUCRE; /*!< Pull_up control register of portE, Address offset: 0x40 */ + __IO uint32_t PDCRE; /*!< Pull_Down control register of portE, Address offset: 0x44 */ + __IO uint32_t PUCRF; /*!< Pull_up control register of portF, Address offset: 0x48 */ + __IO uint32_t PDCRF; /*!< Pull_Down control register of portF, Address offset: 0x4C */ + __IO uint32_t PUCRG; /*!< Pull_up control register of portG, Address offset: 0x50 */ + __IO uint32_t PDCRG; /*!< Pull_Down control register of portG, Address offset: 0x54 */ + uint32_t RESERVED1[10]; /*!< Reserved Address offset: 0x58 - 0x7C */ + __IO uint32_t CR5; /*!< PWR power control register 5, Address offset: 0x80 */ +} PWR_TypeDef; + +/** + * @brief QUAD Serial Peripheral Interface + */ + +typedef struct +{ + __IO uint32_t CR; /*!< QUADSPI Control register, Address offset: 0x00 */ + __IO uint32_t DCR; /*!< QUADSPI Device Configuration register, Address offset: 0x04 */ + __IO uint32_t SR; /*!< QUADSPI Status register, Address offset: 0x08 */ + __IO uint32_t FCR; /*!< QUADSPI Flag Clear register, Address offset: 0x0C */ + __IO uint32_t DLR; /*!< QUADSPI Data Length register, Address offset: 0x10 */ + __IO uint32_t CCR; /*!< QUADSPI Communication Configuration register, Address offset: 0x14 */ + __IO uint32_t AR; /*!< QUADSPI Address register, Address offset: 0x18 */ + __IO uint32_t ABR; /*!< QUADSPI Alternate Bytes register, Address offset: 0x1C */ + __IO uint32_t DR; /*!< QUADSPI Data register, Address offset: 0x20 */ + __IO uint32_t PSMKR; /*!< QUADSPI Polling Status Mask register, Address offset: 0x24 */ + __IO uint32_t PSMAR; /*!< QUADSPI Polling Status Match register, Address offset: 0x28 */ + __IO uint32_t PIR; /*!< QUADSPI Polling Interval register, Address offset: 0x2C */ + __IO uint32_t LPTR; /*!< QUADSPI Low Power Timeout register, Address offset: 0x30 */ +} QUADSPI_TypeDef; + +/** + * @brief Reset and Clock Control + */ + +typedef struct +{ + __IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */ + __IO uint32_t ICSCR; /*!< RCC internal clock sources calibration register, Address offset: 0x04 */ + __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ + __IO uint32_t PLLCFGR; /*!< RCC system PLL configuration register, Address offset: 0x0C */ + uint32_t RESERVED0; /*!< Reserved, Address offset: 0x10 */ + uint32_t RESERVED1; /*!< Reserved, Address offset: 0x14 */ + __IO uint32_t CIER; /*!< RCC clock interrupt enable register, Address offset: 0x18 */ + __IO uint32_t CIFR; /*!< RCC clock interrupt flag register, Address offset: 0x1C */ + __IO uint32_t CICR; /*!< RCC clock interrupt clear register, Address offset: 0x20 */ + uint32_t RESERVED2; /*!< Reserved, Address offset: 0x24 */ + __IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x28 */ + __IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x2C */ + __IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x30 */ + uint32_t RESERVED3; /*!< Reserved, Address offset: 0x34 */ + __IO uint32_t APB1RSTR1; /*!< RCC APB1 peripheral reset register 1, Address offset: 0x38 */ + __IO uint32_t APB1RSTR2; /*!< RCC APB1 peripheral reset register 2, Address offset: 0x3C */ + __IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x40 */ + uint32_t RESERVED4; /*!< Reserved, Address offset: 0x44 */ + __IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clocks enable register, Address offset: 0x48 */ + __IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clocks enable register, Address offset: 0x4C */ + __IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clocks enable register, Address offset: 0x50 */ + uint32_t RESERVED5; /*!< Reserved, Address offset: 0x54 */ + __IO uint32_t APB1ENR1; /*!< RCC APB1 peripheral clocks enable register 1, Address offset: 0x58 */ + __IO uint32_t APB1ENR2; /*!< RCC APB1 peripheral clocks enable register 2, Address offset: 0x5C */ + __IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clocks enable register, Address offset: 0x60 */ + uint32_t RESERVED6; /*!< Reserved, Address offset: 0x64 */ + __IO uint32_t AHB1SMENR; /*!< RCC AHB1 peripheral clocks enable in sleep and stop modes register, Address offset: 0x68 */ + __IO uint32_t AHB2SMENR; /*!< RCC AHB2 peripheral clocks enable in sleep and stop modes register, Address offset: 0x6C */ + __IO uint32_t AHB3SMENR; /*!< RCC AHB3 peripheral clocks enable in sleep and stop modes register, Address offset: 0x70 */ + uint32_t RESERVED7; /*!< Reserved, Address offset: 0x74 */ + __IO uint32_t APB1SMENR1; /*!< RCC APB1 peripheral clocks enable in sleep mode and stop modes register 1, Address offset: 0x78 */ + __IO uint32_t APB1SMENR2; /*!< RCC APB1 peripheral clocks enable in sleep mode and stop modes register 2, Address offset: 0x7C */ + __IO uint32_t APB2SMENR; /*!< RCC APB2 peripheral clocks enable in sleep mode and stop modes register, Address offset: 0x80 */ + uint32_t RESERVED8; /*!< Reserved, Address offset: 0x84 */ + __IO uint32_t CCIPR; /*!< RCC peripherals independent clock configuration register, Address offset: 0x88 */ + uint32_t RESERVED9; /*!< Reserved, Address offset: 0x8C */ + __IO uint32_t BDCR; /*!< RCC backup domain control register, Address offset: 0x90 */ + __IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x94 */ + __IO uint32_t CRRCR; /*!< RCC clock recovery RC register, Address offset: 0x98 */ + __IO uint32_t CCIPR2; /*!< RCC peripherals independent clock configuration register 2, Address offset: 0x9C */ +} RCC_TypeDef; + +/** + * @brief Real-Time Clock + */ +/* +* @brief Specific device feature definitions +*/ +#define RTC_TAMP_INT_6_SUPPORT +#define RTC_TAMP_INT_NB 4u + +#define RTC_TAMP_NB 3u +#define RTC_BACKUP_NB 32u + + +typedef struct +{ + __IO uint32_t TR; /*!< RTC time register, Address offset: 0x00 */ + __IO uint32_t DR; /*!< RTC date register, Address offset: 0x04 */ + __IO uint32_t SSR; /*!< RTC sub second register, Address offset: 0x08 */ + __IO uint32_t ICSR; /*!< RTC initialization control and status register, Address offset: 0x0C */ + __IO uint32_t PRER; /*!< RTC prescaler register, Address offset: 0x10 */ + __IO uint32_t WUTR; /*!< RTC wakeup timer register, Address offset: 0x14 */ + __IO uint32_t CR; /*!< RTC control register, Address offset: 0x18 */ + uint32_t RESERVED0; /*!< Reserved Address offset: 0x1C */ + uint32_t RESERVED1; /*!< Reserved Address offset: 0x20 */ + __IO uint32_t WPR; /*!< RTC write protection register, Address offset: 0x24 */ + __IO uint32_t CALR; /*!< RTC calibration register, Address offset: 0x28 */ + __IO uint32_t SHIFTR; /*!< RTC shift control register, Address offset: 0x2C */ + __IO uint32_t TSTR; /*!< RTC time stamp time register, Address offset: 0x30 */ + __IO uint32_t TSDR; /*!< RTC time stamp date register, Address offset: 0x34 */ + __IO uint32_t TSSSR; /*!< RTC time-stamp sub second register, Address offset: 0x38 */ + uint32_t RESERVED2; /*!< Reserved Address offset: 0x3C */ + __IO uint32_t ALRMAR; /*!< RTC alarm A register, Address offset: 0x40 */ + __IO uint32_t ALRMASSR; /*!< RTC alarm A sub second register, Address offset: 0x44 */ + __IO uint32_t ALRMBR; /*!< RTC alarm B register, Address offset: 0x48 */ + __IO uint32_t ALRMBSSR; /*!< RTC alarm B sub second register, Address offset: 0x4C */ + __IO uint32_t SR; /*!< RTC Status register, Address offset: 0x50 */ + __IO uint32_t MISR; /*!< RTC Masked Interrupt Status register, Address offset: 0x54 */ + uint32_t RESERVED3; /*!< Reserved Address offset: 0x58 */ + __IO uint32_t SCR; /*!< RTC Status Clear register, Address offset: 0x5C */ +} RTC_TypeDef; + +/** + * @brief Tamper and backup registers + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< TAMP configuration register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< TAMP configuration register 2, Address offset: 0x04 */ + uint32_t RESERVED0; /*!< no configuration register 3, Address offset: 0x08 */ + __IO uint32_t FLTCR; /*!< TAMP filter control register, Address offset: 0x0C */ + uint32_t RESERVED1[6]; /*!< Reserved Address offset: 0x10 - 0x24 */ + uint32_t RESERVED2; /*!< Reserved Address offset: 0x28 */ + __IO uint32_t IER; /*!< TAMP Interrupt enable register, Address offset: 0x2C */ + __IO uint32_t SR; /*!< TAMP Status register, Address offset: 0x30 */ + __IO uint32_t MISR; /*!< TAMP Masked Interrupt Status register Address offset: 0x34 */ + uint32_t RESERVED3; /*!< Reserved Address offset: 0x38 */ + __IO uint32_t SCR; /*!< TAMP Status clear register, Address offset: 0x3C */ + uint32_t RESERVED4[48]; /*!< Reserved Address offset: 0x040 - 0xFC */ + __IO uint32_t BKP0R; /*!< TAMP backup register 0, Address offset: 0x100 */ + __IO uint32_t BKP1R; /*!< TAMP backup register 1, Address offset: 0x104 */ + __IO uint32_t BKP2R; /*!< TAMP backup register 2, Address offset: 0x108 */ + __IO uint32_t BKP3R; /*!< TAMP backup register 3, Address offset: 0x10C */ + __IO uint32_t BKP4R; /*!< TAMP backup register 4, Address offset: 0x110 */ + __IO uint32_t BKP5R; /*!< TAMP backup register 5, Address offset: 0x114 */ + __IO uint32_t BKP6R; /*!< TAMP backup register 6, Address offset: 0x118 */ + __IO uint32_t BKP7R; /*!< TAMP backup register 7, Address offset: 0x11C */ + __IO uint32_t BKP8R; /*!< TAMP backup register 8, Address offset: 0x120 */ + __IO uint32_t BKP9R; /*!< TAMP backup register 9, Address offset: 0x124 */ + __IO uint32_t BKP10R; /*!< TAMP backup register 10, Address offset: 0x128 */ + __IO uint32_t BKP11R; /*!< TAMP backup register 11, Address offset: 0x12C */ + __IO uint32_t BKP12R; /*!< TAMP backup register 12, Address offset: 0x130 */ + __IO uint32_t BKP13R; /*!< TAMP backup register 13, Address offset: 0x134 */ + __IO uint32_t BKP14R; /*!< TAMP backup register 14, Address offset: 0x138 */ + __IO uint32_t BKP15R; /*!< TAMP backup register 15, Address offset: 0x13C */ + __IO uint32_t BKP16R; /*!< TAMP backup register 16, Address offset: 0x140 */ + __IO uint32_t BKP17R; /*!< TAMP backup register 17, Address offset: 0x144 */ + __IO uint32_t BKP18R; /*!< TAMP backup register 18, Address offset: 0x148 */ + __IO uint32_t BKP19R; /*!< TAMP backup register 19, Address offset: 0x14C */ + __IO uint32_t BKP20R; /*!< TAMP backup register 20, Address offset: 0x150 */ + __IO uint32_t BKP21R; /*!< TAMP backup register 21, Address offset: 0x154 */ + __IO uint32_t BKP22R; /*!< TAMP backup register 22, Address offset: 0x158 */ + __IO uint32_t BKP23R; /*!< TAMP backup register 23, Address offset: 0x15C */ + __IO uint32_t BKP24R; /*!< TAMP backup register 24, Address offset: 0x160 */ + __IO uint32_t BKP25R; /*!< TAMP backup register 25, Address offset: 0x164 */ + __IO uint32_t BKP26R; /*!< TAMP backup register 26, Address offset: 0x168 */ + __IO uint32_t BKP27R; /*!< TAMP backup register 27, Address offset: 0x16C */ + __IO uint32_t BKP28R; /*!< TAMP backup register 28, Address offset: 0x170 */ + __IO uint32_t BKP29R; /*!< TAMP backup register 29, Address offset: 0x174 */ + __IO uint32_t BKP30R; /*!< TAMP backup register 30, Address offset: 0x178 */ + __IO uint32_t BKP31R; /*!< TAMP backup register 31, Address offset: 0x17C */ +} TAMP_TypeDef; + +/** + * @brief Serial Audio Interface + */ + +typedef struct +{ + uint32_t RESERVED[17]; /*!< Reserved, Address offset: 0x00 to 0x40 */ + __IO uint32_t PDMCR; /*!< SAI PDM control register, Address offset: 0x44 */ + __IO uint32_t PDMDLY; /*!< SAI PDM delay register, Address offset: 0x48 */ +} SAI_TypeDef; + +typedef struct +{ + __IO uint32_t CR1; /*!< SAI block x configuration register 1, Address offset: 0x04 */ + __IO uint32_t CR2; /*!< SAI block x configuration register 2, Address offset: 0x08 */ + __IO uint32_t FRCR; /*!< SAI block x frame configuration register, Address offset: 0x0C */ + __IO uint32_t SLOTR; /*!< SAI block x slot register, Address offset: 0x10 */ + __IO uint32_t IMR; /*!< SAI block x interrupt mask register, Address offset: 0x14 */ + __IO uint32_t SR; /*!< SAI block x status register, Address offset: 0x18 */ + __IO uint32_t CLRFR; /*!< SAI block x clear flag register, Address offset: 0x1C */ + __IO uint32_t DR; /*!< SAI block x data register, Address offset: 0x20 */ +} SAI_Block_TypeDef; + +/** + * @brief Serial Peripheral Interface + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< SPI Control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< SPI Control register 2, Address offset: 0x04 */ + __IO uint32_t SR; /*!< SPI Status register, Address offset: 0x08 */ + __IO uint32_t DR; /*!< SPI data register, Address offset: 0x0C */ + __IO uint32_t CRCPR; /*!< SPI CRC polynomial register, Address offset: 0x10 */ + __IO uint32_t RXCRCR; /*!< SPI Rx CRC register, Address offset: 0x14 */ + __IO uint32_t TXCRCR; /*!< SPI Tx CRC register, Address offset: 0x18 */ + __IO uint32_t I2SCFGR; /*!< SPI_I2S configuration register, Address offset: 0x1C */ + __IO uint32_t I2SPR; /*!< SPI_I2S prescaler register, Address offset: 0x20 */ +} SPI_TypeDef; + +/** + * @brief System configuration controller + */ + +typedef struct +{ + __IO uint32_t MEMRMP; /*!< SYSCFG memory remap register, Address offset: 0x00 */ + __IO uint32_t CFGR1; /*!< SYSCFG configuration register 1, Address offset: 0x04 */ + __IO uint32_t EXTICR[4]; /*!< SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */ + __IO uint32_t SCSR; /*!< SYSCFG CCMSRAM control and status register, Address offset: 0x18 */ + __IO uint32_t CFGR2; /*!< SYSCFG configuration register 2, Address offset: 0x1C */ + __IO uint32_t SWPR; /*!< SYSCFG CCMSRAM write protection register, Address offset: 0x20 */ + __IO uint32_t SKR; /*!< SYSCFG CCMSRAM Key Register, Address offset: 0x24 */ +} SYSCFG_TypeDef; + +/** + * @brief TIM + */ + +typedef struct +{ + __IO uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ + __IO uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + __IO uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + __IO uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ + __IO uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ + __IO uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + __IO uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + __IO uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + __IO uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ + __IO uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ + __IO uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + __IO uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + __IO uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + __IO uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + __IO uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + __IO uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + __IO uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + __IO uint32_t CCR5; /*!< TIM capture/compare register 5, Address offset: 0x48 */ + __IO uint32_t CCR6; /*!< TIM capture/compare register 6, Address offset: 0x4C */ + __IO uint32_t CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x50 */ + __IO uint32_t DTR2; /*!< TIM deadtime register 2, Address offset: 0x54 */ + __IO uint32_t ECR; /*!< TIM encoder control register, Address offset: 0x58 */ + __IO uint32_t TISEL; /*!< TIM Input Selection register, Address offset: 0x5C */ + __IO uint32_t AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + __IO uint32_t AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + __IO uint32_t OR ; /*!< TIM option register, Address offset: 0x68 */ + uint32_t RESERVED0[220];/*!< Reserved, Address offset: 0x6C */ + __IO uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x3DC */ + __IO uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x3E0 */ +} TIM_TypeDef; + +/** + * @brief Universal Synchronous Asynchronous Receiver Transmitter + */ +typedef struct +{ + __IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x04 */ + __IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x08 */ + __IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x0C */ + __IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x10 */ + __IO uint32_t RTOR; /*!< USART Receiver Timeout register, Address offset: 0x14 */ + __IO uint32_t RQR; /*!< USART Request register, Address offset: 0x18 */ + __IO uint32_t ISR; /*!< USART Interrupt and status register, Address offset: 0x1C */ + __IO uint32_t ICR; /*!< USART Interrupt flag Clear register, Address offset: 0x20 */ + __IO uint32_t RDR; /*!< USART Receive Data register, Address offset: 0x24 */ + __IO uint32_t TDR; /*!< USART Transmit Data register, Address offset: 0x28 */ + __IO uint32_t PRESC; /*!< USART Prescaler register, Address offset: 0x2C */ +} USART_TypeDef; + +/** + * @brief Universal Serial Bus Full Speed Device + */ + +typedef struct +{ + __IO uint16_t EP0R; /*!< USB Endpoint 0 register, Address offset: 0x00 */ + __IO uint16_t RESERVED0; /*!< Reserved */ + __IO uint16_t EP1R; /*!< USB Endpoint 1 register, Address offset: 0x04 */ + __IO uint16_t RESERVED1; /*!< Reserved */ + __IO uint16_t EP2R; /*!< USB Endpoint 2 register, Address offset: 0x08 */ + __IO uint16_t RESERVED2; /*!< Reserved */ + __IO uint16_t EP3R; /*!< USB Endpoint 3 register, Address offset: 0x0C */ + __IO uint16_t RESERVED3; /*!< Reserved */ + __IO uint16_t EP4R; /*!< USB Endpoint 4 register, Address offset: 0x10 */ + __IO uint16_t RESERVED4; /*!< Reserved */ + __IO uint16_t EP5R; /*!< USB Endpoint 5 register, Address offset: 0x14 */ + __IO uint16_t RESERVED5; /*!< Reserved */ + __IO uint16_t EP6R; /*!< USB Endpoint 6 register, Address offset: 0x18 */ + __IO uint16_t RESERVED6; /*!< Reserved */ + __IO uint16_t EP7R; /*!< USB Endpoint 7 register, Address offset: 0x1C */ + __IO uint16_t RESERVED7[17]; /*!< Reserved */ + __IO uint16_t CNTR; /*!< Control register, Address offset: 0x40 */ + __IO uint16_t RESERVED8; /*!< Reserved */ + __IO uint16_t ISTR; /*!< Interrupt status register, Address offset: 0x44 */ + __IO uint16_t RESERVED9; /*!< Reserved */ + __IO uint16_t FNR; /*!< Frame number register, Address offset: 0x48 */ + __IO uint16_t RESERVEDA; /*!< Reserved */ + __IO uint16_t DADDR; /*!< Device address register, Address offset: 0x4C */ + __IO uint16_t RESERVEDB; /*!< Reserved */ + __IO uint16_t BTABLE; /*!< Buffer Table address register, Address offset: 0x50 */ + __IO uint16_t RESERVEDC; /*!< Reserved */ + __IO uint16_t LPMCSR; /*!< LPM Control and Status register, Address offset: 0x54 */ + __IO uint16_t RESERVEDD; /*!< Reserved */ + __IO uint16_t BCDR; /*!< Battery Charging detector register, Address offset: 0x58 */ + __IO uint16_t RESERVEDE; /*!< Reserved */ +} USB_TypeDef; + +/** + * @brief VREFBUF + */ + +typedef struct +{ + __IO uint32_t CSR; /*!< VREFBUF control and status register, Address offset: 0x00 */ + __IO uint32_t CCR; /*!< VREFBUF calibration and control register, Address offset: 0x04 */ +} VREFBUF_TypeDef; + +/** + * @brief Window WATCHDOG + */ + +typedef struct +{ + __IO uint32_t CR; /*!< WWDG Control register, Address offset: 0x00 */ + __IO uint32_t CFR; /*!< WWDG Configuration register, Address offset: 0x04 */ + __IO uint32_t SR; /*!< WWDG Status register, Address offset: 0x08 */ +} WWDG_TypeDef; + + +/** + * @brief RNG + */ +typedef struct +{ + __IO uint32_t CR; /*!< RNG control register, Address offset: 0x00 */ + __IO uint32_t SR; /*!< RNG status register, Address offset: 0x04 */ + __IO uint32_t DR; /*!< RNG data register, Address offset: 0x08 */ +} RNG_TypeDef; + +/** + * @brief CORDIC + */ + +typedef struct +{ + __IO uint32_t CSR; /*!< CORDIC control and status register, Address offset: 0x00 */ + __IO uint32_t WDATA; /*!< CORDIC argument register, Address offset: 0x04 */ + __IO uint32_t RDATA; /*!< CORDIC result register, Address offset: 0x08 */ +} CORDIC_TypeDef; + +/** + * @brief UCPD + */ + +typedef struct +{ + __IO uint32_t CFG1; /*!< UCPD configuration register 1, Address offset: 0x00 */ + __IO uint32_t CFG2; /*!< UCPD configuration register 2, Address offset: 0x04 */ + __IO uint32_t RESERVED0; /*!< UCPD reserved register, Address offset: 0x08 */ + __IO uint32_t CR; /*!< UCPD control register, Address offset: 0x0C */ + __IO uint32_t IMR; /*!< UCPD interrupt mask register, Address offset: 0x10 */ + __IO uint32_t SR; /*!< UCPD status register, Address offset: 0x14 */ + __IO uint32_t ICR; /*!< UCPD interrupt flag clear register Address offset: 0x18 */ + __IO uint32_t TX_ORDSET; /*!< UCPD Tx ordered set type register, Address offset: 0x1C */ + __IO uint32_t TX_PAYSZ; /*!< UCPD Tx payload size register, Address offset: 0x20 */ + __IO uint32_t TXDR; /*!< UCPD Tx data register, Address offset: 0x24 */ + __IO uint32_t RX_ORDSET; /*!< UCPD Rx ordered set type register, Address offset: 0x28 */ + __IO uint32_t RX_PAYSZ; /*!< UCPD Rx payload size register, Address offset: 0x2C */ + __IO uint32_t RXDR; /*!< UCPD Rx data register, Address offset: 0x30 */ + __IO uint32_t RX_ORDEXT1; /*!< UCPD Rx ordered set extension 1 register, Address offset: 0x34 */ + __IO uint32_t RX_ORDEXT2; /*!< UCPD Rx ordered set extension 2 register, Address offset: 0x38 */ +} UCPD_TypeDef; + +/** + * @brief High resolution Timer (HRTIM) + */ + +#define c7amba_hrtim1_v2_0 + +/* HRTIM master registers definition */ +typedef struct +{ + __IO uint32_t MCR; /*!< HRTIM Master Timer control register, Address offset: 0x00 */ + __IO uint32_t MISR; /*!< HRTIM Master Timer interrupt status register, Address offset: 0x04 */ + __IO uint32_t MICR; /*!< HRTIM Master Timer interrupt clear register, Address offset: 0x08 */ + __IO uint32_t MDIER; /*!< HRTIM Master Timer DMA/interrupt enable register Address offset: 0x0C */ + __IO uint32_t MCNTR; /*!< HRTIM Master Timer counter register, Address offset: 0x10 */ + __IO uint32_t MPER; /*!< HRTIM Master Timer period register, Address offset: 0x14 */ + __IO uint32_t MREP; /*!< HRTIM Master Timer repetition register, Address offset: 0x18 */ + __IO uint32_t MCMP1R; /*!< HRTIM Master Timer compare 1 register, Address offset: 0x1C */ + uint32_t RESERVED0; /*!< Reserved, 0x20 */ + __IO uint32_t MCMP2R; /*!< HRTIM Master Timer compare 2 register, Address offset: 0x24 */ + __IO uint32_t MCMP3R; /*!< HRTIM Master Timer compare 3 register, Address offset: 0x28 */ + __IO uint32_t MCMP4R; /*!< HRTIM Master Timer compare 4 register, Address offset: 0x2C */ + uint32_t RESERVED1[20]; /*!< Reserved, 0x30..0x7C */ +}HRTIM_Master_TypeDef; + +/* HRTIM Timer A to F registers definition */ +typedef struct +{ + __IO uint32_t TIMxCR; /*!< HRTIM Timerx control register, Address offset: 0x00 */ + __IO uint32_t TIMxISR; /*!< HRTIM Timerx interrupt status register, Address offset: 0x04 */ + __IO uint32_t TIMxICR; /*!< HRTIM Timerx interrupt clear register, Address offset: 0x08 */ + __IO uint32_t TIMxDIER; /*!< HRTIM Timerx DMA/interrupt enable register, Address offset: 0x0C */ + __IO uint32_t CNTxR; /*!< HRTIM Timerx counter register, Address offset: 0x10 */ + __IO uint32_t PERxR; /*!< HRTIM Timerx period register, Address offset: 0x14 */ + __IO uint32_t REPxR; /*!< HRTIM Timerx repetition register, Address offset: 0x18 */ + __IO uint32_t CMP1xR; /*!< HRTIM Timerx compare 1 register, Address offset: 0x1C */ + __IO uint32_t CMP1CxR; /*!< HRTIM Timerx compare 1 compound register, Address offset: 0x20 */ + __IO uint32_t CMP2xR; /*!< HRTIM Timerx compare 2 register, Address offset: 0x24 */ + __IO uint32_t CMP3xR; /*!< HRTIM Timerx compare 3 register, Address offset: 0x28 */ + __IO uint32_t CMP4xR; /*!< HRTIM Timerx compare 4 register, Address offset: 0x2C */ + __IO uint32_t CPT1xR; /*!< HRTIM Timerx capture 1 register, Address offset: 0x30 */ + __IO uint32_t CPT2xR; /*!< HRTIM Timerx capture 2 register, Address offset: 0x34 */ + __IO uint32_t DTxR; /*!< HRTIM Timerx dead time register, Address offset: 0x38 */ + __IO uint32_t SETx1R; /*!< HRTIM Timerx output 1 set register, Address offset: 0x3C */ + __IO uint32_t RSTx1R; /*!< HRTIM Timerx output 1 reset register, Address offset: 0x40 */ + __IO uint32_t SETx2R; /*!< HRTIM Timerx output 2 set register, Address offset: 0x44 */ + __IO uint32_t RSTx2R; /*!< HRTIM Timerx output 2 reset register, Address offset: 0x48 */ + __IO uint32_t EEFxR1; /*!< HRTIM Timerx external event filtering 1 register, Address offset: 0x4C */ + __IO uint32_t EEFxR2; /*!< HRTIM Timerx external event filtering 2 register, Address offset: 0x50 */ + __IO uint32_t RSTxR; /*!< HRTIM Timerx Reset register, Address offset: 0x54 */ + __IO uint32_t CHPxR; /*!< HRTIM Timerx Chopper register, Address offset: 0x58 */ + __IO uint32_t CPT1xCR; /*!< HRTIM Timerx Capture 1 register, Address offset: 0x5C */ + __IO uint32_t CPT2xCR; /*!< HRTIM Timerx Capture 2 register, Address offset: 0x60 */ + __IO uint32_t OUTxR; /*!< HRTIM Timerx Output register, Address offset: 0x64 */ + __IO uint32_t FLTxR; /*!< HRTIM Timerx Fault register, Address offset: 0x68 */ + __IO uint32_t TIMxCR2; /*!< HRTIM Timerx Control register 2, Address offset: 0x6C */ + __IO uint32_t EEFxR3; /*!< HRTIM Timerx external event filtering 3 register, Address offset: 0x70 */ + uint32_t RESERVED0[3]; /*!< Reserved, 0x74..0x7C */ +}HRTIM_Timerx_TypeDef; + +/* HRTIM common register definition */ +typedef struct +{ + __IO uint32_t CR1; /*!< HRTIM control register1, Address offset: 0x00 */ + __IO uint32_t CR2; /*!< HRTIM control register2, Address offset: 0x04 */ + __IO uint32_t ISR; /*!< HRTIM interrupt status register, Address offset: 0x08 */ + __IO uint32_t ICR; /*!< HRTIM interrupt clear register, Address offset: 0x0C */ + __IO uint32_t IER; /*!< HRTIM interrupt enable register, Address offset: 0x10 */ + __IO uint32_t OENR; /*!< HRTIM Output enable register, Address offset: 0x14 */ + __IO uint32_t ODISR; /*!< HRTIM Output disable register, Address offset: 0x18 */ + __IO uint32_t ODSR; /*!< HRTIM Output disable status register, Address offset: 0x1C */ + __IO uint32_t BMCR; /*!< HRTIM Burst mode control register, Address offset: 0x20 */ + __IO uint32_t BMTRGR; /*!< HRTIM Busrt mode trigger register, Address offset: 0x24 */ + __IO uint32_t BMCMPR; /*!< HRTIM Burst mode compare register, Address offset: 0x28 */ + __IO uint32_t BMPER; /*!< HRTIM Burst mode period register, Address offset: 0x2C */ + __IO uint32_t EECR1; /*!< HRTIM Timer external event control register1, Address offset: 0x30 */ + __IO uint32_t EECR2; /*!< HRTIM Timer external event control register2, Address offset: 0x34 */ + __IO uint32_t EECR3; /*!< HRTIM Timer external event control register3, Address offset: 0x38 */ + __IO uint32_t ADC1R; /*!< HRTIM ADC Trigger 1 register, Address offset: 0x3C */ + __IO uint32_t ADC2R; /*!< HRTIM ADC Trigger 2 register, Address offset: 0x40 */ + __IO uint32_t ADC3R; /*!< HRTIM ADC Trigger 3 register, Address offset: 0x44 */ + __IO uint32_t ADC4R; /*!< HRTIM ADC Trigger 4 register, Address offset: 0x48 */ + __IO uint32_t DLLCR; /*!< HRTIM DLL control register, Address offset: 0x4C */ + __IO uint32_t FLTINR1; /*!< HRTIM Fault input register1, Address offset: 0x50 */ + __IO uint32_t FLTINR2; /*!< HRTIM Fault input register2, Address offset: 0x54 */ + __IO uint32_t BDMUPR; /*!< HRTIM Burst DMA Master Timer update register, Address offset: 0x58 */ + __IO uint32_t BDTAUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x5C */ + __IO uint32_t BDTBUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x60 */ + __IO uint32_t BDTCUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x64 */ + __IO uint32_t BDTDUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x68 */ + __IO uint32_t BDTEUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x6C */ + __IO uint32_t BDMADR; /*!< HRTIM Burst DMA Master Data register, Address offset: 0x70 */ + __IO uint32_t BDTFUPR; /*!< HRTIM Burst DMA Timerx update register, Address offset: 0x74 */ + __IO uint32_t ADCER; /*!< HRTIM ADC Extended Trigger register, Address offset: 0x78 */ + __IO uint32_t ADCUR; /*!< HRTIM ADC Trigger Update register, Address offset: 0x7C */ + __IO uint32_t ADCPS1; /*!< HRTIM ADC Post Scaler Register 1, Address offset: 0x80 */ + __IO uint32_t ADCPS2; /*!< HRTIM ADC Post Scaler Register 2, Address offset: 0x84 */ + __IO uint32_t FLTINR3; /*!< HRTIM Fault input register3, Address offset: 0x88 */ + __IO uint32_t FLTINR4; /*!< HRTIM Fault input register4, Address offset: 0x8C */ +}HRTIM_Common_TypeDef; + +/* HRTIM register definition */ +typedef struct { + HRTIM_Master_TypeDef sMasterRegs; + HRTIM_Timerx_TypeDef sTimerxRegs[6]; + HRTIM_Common_TypeDef sCommonRegs; +}HRTIM_TypeDef; + +/** + * @} + */ + +/** @addtogroup Peripheral_memory_map + * @{ + */ + +#define FLASH_BASE (0x08000000UL) /*!< FLASH (up to 512 kB) base address */ +#define SRAM1_BASE (0x20000000UL) /*!< SRAM1(up to 80 KB) base address */ +#define SRAM2_BASE (0x20014000UL) /*!< SRAM2(16 KB) base address */ +#define CCMSRAM_BASE (0x10000000UL) /*!< CCMSRAM(32 KB) base address */ +#define PERIPH_BASE (0x40000000UL) /*!< Peripheral base address */ +#define FMC_BASE (0x60000000UL) /*!< FMC base address */ +#define QSPI_BASE (0x90000000UL) /*!< QUADSPI memories accessible over AHB base address */ + +#define FMC_R_BASE (0xA0000000UL) /*!< FMC control registers base address */ +#define QSPI_R_BASE (0xA0001000UL) /*!< QUADSPI control registers base address */ +#define SRAM1_BB_BASE (0x22000000UL) /*!< SRAM1(80 KB) base address in the bit-band region */ +#define SRAM2_BB_BASE (0x22280000UL) /*!< SRAM2(16 KB) base address in the bit-band region */ +#define CCMSRAM_BB_BASE (0x22300000UL) /*!< CCMSRAM(32 KB) base address in the bit-band region */ +#define PERIPH_BB_BASE (0x42000000UL) /*!< Peripheral base address in the bit-band region */ +/* Legacy defines */ +#define SRAM_BASE SRAM1_BASE +#define SRAM_BB_BASE SRAM1_BB_BASE + +#define SRAM1_SIZE_MAX (0x00014000UL) /*!< maximum SRAM1 size (up to 80 KBytes) */ +#define SRAM2_SIZE (0x00004000UL) /*!< SRAM2 size (16 KBytes) */ +#define CCMSRAM_SIZE (0x00008000UL) /*!< CCMSRAM size (32 KBytes) */ + +/*!< Peripheral memory map */ +#define APB1PERIPH_BASE PERIPH_BASE +#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000UL) +#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000UL) +#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000UL) + +#define FMC_BANK1 FMC_BASE +#define FMC_BANK1_1 FMC_BANK1 +#define FMC_BANK1_2 (FMC_BANK1 + 0x04000000UL) +#define FMC_BANK1_3 (FMC_BANK1 + 0x08000000UL) +#define FMC_BANK1_4 (FMC_BANK1 + 0x0C000000UL) +#define FMC_BANK3 (FMC_BASE + 0x20000000UL) + +/*!< APB1 peripherals */ +#define TIM2_BASE (APB1PERIPH_BASE + 0x0000UL) +#define TIM3_BASE (APB1PERIPH_BASE + 0x0400UL) +#define TIM4_BASE (APB1PERIPH_BASE + 0x0800UL) +#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00UL) +#define TIM6_BASE (APB1PERIPH_BASE + 0x1000UL) +#define TIM7_BASE (APB1PERIPH_BASE + 0x1400UL) +#define CRS_BASE (APB1PERIPH_BASE + 0x2000UL) +#define TAMP_BASE (APB1PERIPH_BASE + 0x2400UL) +#define RTC_BASE (APB1PERIPH_BASE + 0x2800UL) +#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00UL) +#define IWDG_BASE (APB1PERIPH_BASE + 0x3000UL) +#define SPI2_BASE (APB1PERIPH_BASE + 0x3800UL) +#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00UL) +#define USART2_BASE (APB1PERIPH_BASE + 0x4400UL) +#define USART3_BASE (APB1PERIPH_BASE + 0x4800UL) +#define UART4_BASE (APB1PERIPH_BASE + 0x4C00UL) +#define UART5_BASE (APB1PERIPH_BASE + 0x5000UL) +#define I2C1_BASE (APB1PERIPH_BASE + 0x5400UL) +#define I2C2_BASE (APB1PERIPH_BASE + 0x5800UL) +#define USB_BASE (APB1PERIPH_BASE + 0x5C00UL) /*!< USB_IP Peripheral Registers base address */ +#define USB_PMAADDR (APB1PERIPH_BASE + 0x6000UL) /*!< USB_IP Packet Memory Area base address */ +#define FDCAN1_BASE (APB1PERIPH_BASE + 0x6400UL) +#define FDCAN_CONFIG_BASE (APB1PERIPH_BASE + 0x6500UL) /*!< FDCAN configuration registers base address */ +#define FDCAN2_BASE (APB1PERIPH_BASE + 0x6800UL) +#define FDCAN3_BASE (APB1PERIPH_BASE + 0x6C00UL) +#define PWR_BASE (APB1PERIPH_BASE + 0x7000UL) +#define I2C3_BASE (APB1PERIPH_BASE + 0x7800UL) +#define LPTIM1_BASE (APB1PERIPH_BASE + 0x7C00UL) +#define LPUART1_BASE (APB1PERIPH_BASE + 0x8000UL) +#define I2C4_BASE (APB1PERIPH_BASE + 0x8400UL) +#define UCPD1_BASE (APB1PERIPH_BASE + 0xA000UL) +#define SRAMCAN_BASE (APB1PERIPH_BASE + 0xA400UL) + +/*!< APB2 peripherals */ +#define SYSCFG_BASE (APB2PERIPH_BASE + 0x0000UL) +#define VREFBUF_BASE (APB2PERIPH_BASE + 0x0030UL) +#define COMP1_BASE (APB2PERIPH_BASE + 0x0200UL) +#define COMP2_BASE (APB2PERIPH_BASE + 0x0204UL) +#define COMP3_BASE (APB2PERIPH_BASE + 0x0208UL) +#define COMP4_BASE (APB2PERIPH_BASE + 0x020CUL) +#define COMP5_BASE (APB2PERIPH_BASE + 0x0210UL) +#define COMP6_BASE (APB2PERIPH_BASE + 0x0214UL) +#define COMP7_BASE (APB2PERIPH_BASE + 0x0218UL) +#define OPAMP_BASE (APB2PERIPH_BASE + 0x0300UL) +#define OPAMP1_BASE (APB2PERIPH_BASE + 0x0300UL) +#define OPAMP2_BASE (APB2PERIPH_BASE + 0x0304UL) +#define OPAMP3_BASE (APB2PERIPH_BASE + 0x0308UL) +#define OPAMP4_BASE (APB2PERIPH_BASE + 0x030CUL) +#define OPAMP5_BASE (APB2PERIPH_BASE + 0x0310UL) +#define OPAMP6_BASE (APB2PERIPH_BASE + 0x0314UL) + +#define EXTI_BASE (APB2PERIPH_BASE + 0x0400UL) +#define TIM1_BASE (APB2PERIPH_BASE + 0x2C00UL) +#define SPI1_BASE (APB2PERIPH_BASE + 0x3000UL) +#define TIM8_BASE (APB2PERIPH_BASE + 0x3400UL) +#define USART1_BASE (APB2PERIPH_BASE + 0x3800UL) +#define SPI4_BASE (APB2PERIPH_BASE + 0x3C00UL) +#define TIM15_BASE (APB2PERIPH_BASE + 0x4000UL) +#define TIM16_BASE (APB2PERIPH_BASE + 0x4400UL) +#define TIM17_BASE (APB2PERIPH_BASE + 0x4800UL) +#define TIM20_BASE (APB2PERIPH_BASE + 0x5000UL) +#define SAI1_BASE (APB2PERIPH_BASE + 0x5400UL) +#define SAI1_Block_A_BASE (SAI1_BASE + 0x0004UL) +#define SAI1_Block_B_BASE (SAI1_BASE + 0x0024UL) +#define HRTIM1_BASE (APB2PERIPH_BASE + 0x6800UL) +#define HRTIM1_TIMA_BASE (HRTIM1_BASE + 0x0080UL) +#define HRTIM1_TIMB_BASE (HRTIM1_BASE + 0x0100UL) +#define HRTIM1_TIMC_BASE (HRTIM1_BASE + 0x0180UL) +#define HRTIM1_TIMD_BASE (HRTIM1_BASE + 0x0200UL) +#define HRTIM1_TIME_BASE (HRTIM1_BASE + 0x0280UL) +#define HRTIM1_TIMF_BASE (HRTIM1_BASE + 0x0300UL) +#define HRTIM1_COMMON_BASE (HRTIM1_BASE + 0x0380UL) + +/*!< AHB1 peripherals */ +#define DMA1_BASE (AHB1PERIPH_BASE) +#define DMA2_BASE (AHB1PERIPH_BASE + 0x0400UL) +#define DMAMUX1_BASE (AHB1PERIPH_BASE + 0x0800UL) +#define CORDIC_BASE (AHB1PERIPH_BASE + 0x0C00UL) +#define RCC_BASE (AHB1PERIPH_BASE + 0x1000UL) +#define FMAC_BASE (AHB1PERIPH_BASE + 0x1400UL) +#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x2000UL) +#define CRC_BASE (AHB1PERIPH_BASE + 0x3000UL) + +#define DMA1_Channel1_BASE (DMA1_BASE + 0x0008UL) +#define DMA1_Channel2_BASE (DMA1_BASE + 0x001CUL) +#define DMA1_Channel3_BASE (DMA1_BASE + 0x0030UL) +#define DMA1_Channel4_BASE (DMA1_BASE + 0x0044UL) +#define DMA1_Channel5_BASE (DMA1_BASE + 0x0058UL) +#define DMA1_Channel6_BASE (DMA1_BASE + 0x006CUL) +#define DMA1_Channel7_BASE (DMA1_BASE + 0x0080UL) +#define DMA1_Channel8_BASE (DMA1_BASE + 0x0094UL) + +#define DMA2_Channel1_BASE (DMA2_BASE + 0x0008UL) +#define DMA2_Channel2_BASE (DMA2_BASE + 0x001CUL) +#define DMA2_Channel3_BASE (DMA2_BASE + 0x0030UL) +#define DMA2_Channel4_BASE (DMA2_BASE + 0x0044UL) +#define DMA2_Channel5_BASE (DMA2_BASE + 0x0058UL) +#define DMA2_Channel6_BASE (DMA2_BASE + 0x006CUL) +#define DMA2_Channel7_BASE (DMA2_BASE + 0x0080UL) +#define DMA2_Channel8_BASE (DMA2_BASE + 0x0094UL) + +#define DMAMUX1_Channel0_BASE (DMAMUX1_BASE) +#define DMAMUX1_Channel1_BASE (DMAMUX1_BASE + 0x0004UL) +#define DMAMUX1_Channel2_BASE (DMAMUX1_BASE + 0x0008UL) +#define DMAMUX1_Channel3_BASE (DMAMUX1_BASE + 0x000CUL) +#define DMAMUX1_Channel4_BASE (DMAMUX1_BASE + 0x0010UL) +#define DMAMUX1_Channel5_BASE (DMAMUX1_BASE + 0x0014UL) +#define DMAMUX1_Channel6_BASE (DMAMUX1_BASE + 0x0018UL) +#define DMAMUX1_Channel7_BASE (DMAMUX1_BASE + 0x001CUL) +#define DMAMUX1_Channel8_BASE (DMAMUX1_BASE + 0x0020UL) +#define DMAMUX1_Channel9_BASE (DMAMUX1_BASE + 0x0024UL) +#define DMAMUX1_Channel10_BASE (DMAMUX1_BASE + 0x0028UL) +#define DMAMUX1_Channel11_BASE (DMAMUX1_BASE + 0x002CUL) +#define DMAMUX1_Channel12_BASE (DMAMUX1_BASE + 0x0030UL) +#define DMAMUX1_Channel13_BASE (DMAMUX1_BASE + 0x0034UL) +#define DMAMUX1_Channel14_BASE (DMAMUX1_BASE + 0x0038UL) +#define DMAMUX1_Channel15_BASE (DMAMUX1_BASE + 0x003CUL) +#define DMAMUX1_RequestGenerator0_BASE (DMAMUX1_BASE + 0x0100UL) +#define DMAMUX1_RequestGenerator1_BASE (DMAMUX1_BASE + 0x0104UL) +#define DMAMUX1_RequestGenerator2_BASE (DMAMUX1_BASE + 0x0108UL) +#define DMAMUX1_RequestGenerator3_BASE (DMAMUX1_BASE + 0x010CUL) + +#define DMAMUX1_ChannelStatus_BASE (DMAMUX1_BASE + 0x0080UL) +#define DMAMUX1_RequestGenStatus_BASE (DMAMUX1_BASE + 0x0140UL) + +/*!< AHB2 peripherals */ +#define GPIOA_BASE (AHB2PERIPH_BASE + 0x0000UL) +#define GPIOB_BASE (AHB2PERIPH_BASE + 0x0400UL) +#define GPIOC_BASE (AHB2PERIPH_BASE + 0x0800UL) +#define GPIOD_BASE (AHB2PERIPH_BASE + 0x0C00UL) +#define GPIOE_BASE (AHB2PERIPH_BASE + 0x1000UL) +#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400UL) +#define GPIOG_BASE (AHB2PERIPH_BASE + 0x1800UL) + +#define ADC1_BASE (AHB2PERIPH_BASE + 0x08000000UL) +#define ADC2_BASE (AHB2PERIPH_BASE + 0x08000100UL) +#define ADC12_COMMON_BASE (AHB2PERIPH_BASE + 0x08000300UL) +#define ADC3_BASE (AHB2PERIPH_BASE + 0x08000400UL) +#define ADC4_BASE (AHB2PERIPH_BASE + 0x08000500UL) +#define ADC5_BASE (AHB2PERIPH_BASE + 0x08000600UL) +#define ADC345_COMMON_BASE (AHB2PERIPH_BASE + 0x08000700UL) + +#define DAC_BASE (AHB2PERIPH_BASE + 0x08000800UL) +#define DAC1_BASE (AHB2PERIPH_BASE + 0x08000800UL) +#define DAC2_BASE (AHB2PERIPH_BASE + 0x08000C00UL) +#define DAC3_BASE (AHB2PERIPH_BASE + 0x08001000UL) +#define DAC4_BASE (AHB2PERIPH_BASE + 0x08001400UL) + +/*!< FMC Banks registers base address */ +#define FMC_Bank1_R_BASE (FMC_R_BASE + 0x0000UL) +#define FMC_Bank1E_R_BASE (FMC_R_BASE + 0x0104UL) +#define FMC_Bank3_R_BASE (FMC_R_BASE + 0x0080UL) +#define RNG_BASE (AHB2PERIPH_BASE + 0x08060800UL) +/* Debug MCU registers base address */ +#define DBGMCU_BASE (0xE0042000UL) + +#define PACKAGE_BASE (0x1FFF7500UL) /*!< Package data register base address */ +#define UID_BASE (0x1FFF7590UL) /*!< Unique device ID register base address */ +#define FLASHSIZE_BASE (0x1FFF75E0UL) /*!< Flash size data register base address */ +/** + * @} + */ + +/** @addtogroup Peripheral_declaration + * @{ + */ +#define TIM2 ((TIM_TypeDef *) TIM2_BASE) +#define TIM3 ((TIM_TypeDef *) TIM3_BASE) +#define TIM4 ((TIM_TypeDef *) TIM4_BASE) +#define TIM5 ((TIM_TypeDef *) TIM5_BASE) +#define TIM6 ((TIM_TypeDef *) TIM6_BASE) +#define TIM7 ((TIM_TypeDef *) TIM7_BASE) +#define CRS ((CRS_TypeDef *) CRS_BASE) +#define TAMP ((TAMP_TypeDef *) TAMP_BASE) +#define RTC ((RTC_TypeDef *) RTC_BASE) +#define WWDG ((WWDG_TypeDef *) WWDG_BASE) +#define IWDG ((IWDG_TypeDef *) IWDG_BASE) +#define SPI2 ((SPI_TypeDef *) SPI2_BASE) +#define SPI3 ((SPI_TypeDef *) SPI3_BASE) +#define USART2 ((USART_TypeDef *) USART2_BASE) +#define USART3 ((USART_TypeDef *) USART3_BASE) +#define UART4 ((USART_TypeDef *) UART4_BASE) +#define UART5 ((USART_TypeDef *) UART5_BASE) +#define I2C1 ((I2C_TypeDef *) I2C1_BASE) +#define I2C2 ((I2C_TypeDef *) I2C2_BASE) +#define USB ((USB_TypeDef *) USB_BASE) +#define FDCAN1 ((FDCAN_GlobalTypeDef *) FDCAN1_BASE) +#define FDCAN_CONFIG ((FDCAN_Config_TypeDef *) FDCAN_CONFIG_BASE) +#define FDCAN2 ((FDCAN_GlobalTypeDef *) FDCAN2_BASE) +#define FDCAN3 ((FDCAN_GlobalTypeDef *) FDCAN3_BASE) +#define PWR ((PWR_TypeDef *) PWR_BASE) +#define I2C3 ((I2C_TypeDef *) I2C3_BASE) +#define LPTIM1 ((LPTIM_TypeDef *) LPTIM1_BASE) +#define LPUART1 ((USART_TypeDef *) LPUART1_BASE) +#define I2C4 ((I2C_TypeDef *) I2C4_BASE) +#define UCPD1 ((UCPD_TypeDef *) UCPD1_BASE) + +#define SYSCFG ((SYSCFG_TypeDef *) SYSCFG_BASE) +#define VREFBUF ((VREFBUF_TypeDef *) VREFBUF_BASE) +#define COMP1 ((COMP_TypeDef *) COMP1_BASE) +#define COMP2 ((COMP_TypeDef *) COMP2_BASE) +#define COMP3 ((COMP_TypeDef *) COMP3_BASE) +#define COMP4 ((COMP_TypeDef *) COMP4_BASE) +#define COMP5 ((COMP_TypeDef *) COMP5_BASE) +#define COMP6 ((COMP_TypeDef *) COMP6_BASE) +#define COMP7 ((COMP_TypeDef *) COMP7_BASE) + +#define OPAMP ((OPAMP_TypeDef *) OPAMP_BASE) +#define OPAMP1 ((OPAMP_TypeDef *) OPAMP1_BASE) +#define OPAMP2 ((OPAMP_TypeDef *) OPAMP2_BASE) +#define OPAMP3 ((OPAMP_TypeDef *) OPAMP3_BASE) +#define OPAMP4 ((OPAMP_TypeDef *) OPAMP4_BASE) +#define OPAMP5 ((OPAMP_TypeDef *) OPAMP5_BASE) +#define OPAMP6 ((OPAMP_TypeDef *) OPAMP6_BASE) + +#define EXTI ((EXTI_TypeDef *) EXTI_BASE) +#define TIM1 ((TIM_TypeDef *) TIM1_BASE) +#define SPI1 ((SPI_TypeDef *) SPI1_BASE) +#define TIM8 ((TIM_TypeDef *) TIM8_BASE) +#define USART1 ((USART_TypeDef *) USART1_BASE) +#define SPI4 ((SPI_TypeDef *) SPI4_BASE) +#define TIM15 ((TIM_TypeDef *) TIM15_BASE) +#define TIM16 ((TIM_TypeDef *) TIM16_BASE) +#define TIM17 ((TIM_TypeDef *) TIM17_BASE) +#define TIM20 ((TIM_TypeDef *) TIM20_BASE) +#define SAI1 ((SAI_TypeDef *) SAI1_BASE) +#define SAI1_Block_A ((SAI_Block_TypeDef *)SAI1_Block_A_BASE) +#define SAI1_Block_B ((SAI_Block_TypeDef *)SAI1_Block_B_BASE) +#define HRTIM1 ((HRTIM_TypeDef *) HRTIM1_BASE) +#define HRTIM1_TIMA ((HRTIM_Timerx_TypeDef *) HRTIM1_TIMA_BASE) +#define HRTIM1_TIMB ((HRTIM_Timerx_TypeDef *) HRTIM1_TIMB_BASE) +#define HRTIM1_TIMC ((HRTIM_Timerx_TypeDef *) HRTIM1_TIMC_BASE) +#define HRTIM1_TIMD ((HRTIM_Timerx_TypeDef *) HRTIM1_TIMD_BASE) +#define HRTIM1_TIME ((HRTIM_Timerx_TypeDef *) HRTIM1_TIME_BASE) +#define HRTIM1_TIMF ((HRTIM_Timerx_TypeDef *) HRTIM1_TIMF_BASE) +#define HRTIM1_COMMON ((HRTIM_Common_TypeDef *) HRTIM1_COMMON_BASE) +#define DMA1 ((DMA_TypeDef *) DMA1_BASE) +#define DMA2 ((DMA_TypeDef *) DMA2_BASE) +#define DMAMUX1 ((DMAMUX_Channel_TypeDef *) DMAMUX1_BASE) +#define CORDIC ((CORDIC_TypeDef *) CORDIC_BASE) +#define RCC ((RCC_TypeDef *) RCC_BASE) +#define FMAC ((FMAC_TypeDef *) FMAC_BASE) +#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) +#define CRC ((CRC_TypeDef *) CRC_BASE) + +#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) +#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) +#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) +#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) +#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) +#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) +#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) +#define ADC1 ((ADC_TypeDef *) ADC1_BASE) +#define ADC2 ((ADC_TypeDef *) ADC2_BASE) +#define ADC12_COMMON ((ADC_Common_TypeDef *) ADC12_COMMON_BASE) +#define ADC3 ((ADC_TypeDef *) ADC3_BASE) +#define ADC4 ((ADC_TypeDef *) ADC4_BASE) +#define ADC5 ((ADC_TypeDef *) ADC5_BASE) +#define ADC345_COMMON ((ADC_Common_TypeDef *) ADC345_COMMON_BASE) +#define DAC ((DAC_TypeDef *) DAC_BASE) +#define DAC1 ((DAC_TypeDef *) DAC1_BASE) +#define DAC2 ((DAC_TypeDef *) DAC2_BASE) +#define DAC3 ((DAC_TypeDef *) DAC3_BASE) +#define DAC4 ((DAC_TypeDef *) DAC4_BASE) +#define RNG ((RNG_TypeDef *) RNG_BASE) + +#define DMA1_Channel1 ((DMA_Channel_TypeDef *) DMA1_Channel1_BASE) +#define DMA1_Channel2 ((DMA_Channel_TypeDef *) DMA1_Channel2_BASE) +#define DMA1_Channel3 ((DMA_Channel_TypeDef *) DMA1_Channel3_BASE) +#define DMA1_Channel4 ((DMA_Channel_TypeDef *) DMA1_Channel4_BASE) +#define DMA1_Channel5 ((DMA_Channel_TypeDef *) DMA1_Channel5_BASE) +#define DMA1_Channel6 ((DMA_Channel_TypeDef *) DMA1_Channel6_BASE) +#define DMA1_Channel7 ((DMA_Channel_TypeDef *) DMA1_Channel7_BASE) +#define DMA1_Channel8 ((DMA_Channel_TypeDef *) DMA1_Channel8_BASE) + +#define DMA2_Channel1 ((DMA_Channel_TypeDef *) DMA2_Channel1_BASE) +#define DMA2_Channel2 ((DMA_Channel_TypeDef *) DMA2_Channel2_BASE) +#define DMA2_Channel3 ((DMA_Channel_TypeDef *) DMA2_Channel3_BASE) +#define DMA2_Channel4 ((DMA_Channel_TypeDef *) DMA2_Channel4_BASE) +#define DMA2_Channel5 ((DMA_Channel_TypeDef *) DMA2_Channel5_BASE) +#define DMA2_Channel6 ((DMA_Channel_TypeDef *) DMA2_Channel6_BASE) +#define DMA2_Channel7 ((DMA_Channel_TypeDef *) DMA2_Channel7_BASE) +#define DMA2_Channel8 ((DMA_Channel_TypeDef *) DMA2_Channel8_BASE) + +#define DMAMUX1_Channel0 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel0_BASE) +#define DMAMUX1_Channel1 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel1_BASE) +#define DMAMUX1_Channel2 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel2_BASE) +#define DMAMUX1_Channel3 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel3_BASE) +#define DMAMUX1_Channel4 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel4_BASE) +#define DMAMUX1_Channel5 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel5_BASE) +#define DMAMUX1_Channel6 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel6_BASE) +#define DMAMUX1_Channel7 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel7_BASE) +#define DMAMUX1_Channel8 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel8_BASE) +#define DMAMUX1_Channel9 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel9_BASE) +#define DMAMUX1_Channel10 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel10_BASE) +#define DMAMUX1_Channel11 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel11_BASE) +#define DMAMUX1_Channel12 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel12_BASE) +#define DMAMUX1_Channel13 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel13_BASE) +#define DMAMUX1_Channel14 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel14_BASE) +#define DMAMUX1_Channel15 ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel15_BASE) + +#define DMAMUX1_RequestGenerator0 ((DMAMUX_RequestGen_TypeDef *) DMAMUX1_RequestGenerator0_BASE) +#define DMAMUX1_RequestGenerator1 ((DMAMUX_RequestGen_TypeDef *) DMAMUX1_RequestGenerator1_BASE) +#define DMAMUX1_RequestGenerator2 ((DMAMUX_RequestGen_TypeDef *) DMAMUX1_RequestGenerator2_BASE) +#define DMAMUX1_RequestGenerator3 ((DMAMUX_RequestGen_TypeDef *) DMAMUX1_RequestGenerator3_BASE) + +#define DMAMUX1_ChannelStatus ((DMAMUX_ChannelStatus_TypeDef *) DMAMUX1_ChannelStatus_BASE) +#define DMAMUX1_RequestGenStatus ((DMAMUX_RequestGenStatus_TypeDef *) DMAMUX1_RequestGenStatus_BASE) + +#define FMC_Bank1_R ((FMC_Bank1_TypeDef *) FMC_Bank1_R_BASE) +#define FMC_Bank1E_R ((FMC_Bank1E_TypeDef *) FMC_Bank1E_R_BASE) +#define FMC_Bank3_R ((FMC_Bank3_TypeDef *) FMC_Bank3_R_BASE) + +#define QUADSPI ((QUADSPI_TypeDef *) QSPI_R_BASE) + +#define DBGMCU ((DBGMCU_TypeDef *) DBGMCU_BASE) + +/** + * @} + */ + +/** @addtogroup Exported_constants + * @{ + */ + + /** @addtogroup Hardware_Constant_Definition + * @{ + */ +#define LSI_STARTUP_TIME 130U /*!< LSI Maximum startup time in us */ + + /** + * @} + */ + +/** @addtogroup Peripheral_Registers_Bits_Definition + * @{ + */ + +/******************************************************************************/ +/* Peripheral Registers_Bits_Definition */ +/******************************************************************************/ + +/******************************************************************************/ +/* */ +/* Analog to Digital Converter */ +/* */ +/******************************************************************************/ + +/* + * @brief Specific device feature definitions (not present on all devices in the STM32G4 series) + */ +#define ADC_MULTIMODE_SUPPORT /*!< ADC feature available only on specific devices: multimode available on devices with several ADC instances */ + +/******************** Bit definition for ADC_ISR register *******************/ +#define ADC_ISR_ADRDY_Pos (0U) +#define ADC_ISR_ADRDY_Msk (0x1UL << ADC_ISR_ADRDY_Pos) /*!< 0x00000001 */ +#define ADC_ISR_ADRDY ADC_ISR_ADRDY_Msk /*!< ADC ready flag */ +#define ADC_ISR_EOSMP_Pos (1U) +#define ADC_ISR_EOSMP_Msk (0x1UL << ADC_ISR_EOSMP_Pos) /*!< 0x00000002 */ +#define ADC_ISR_EOSMP ADC_ISR_EOSMP_Msk /*!< ADC group regular end of sampling flag */ +#define ADC_ISR_EOC_Pos (2U) +#define ADC_ISR_EOC_Msk (0x1UL << ADC_ISR_EOC_Pos) /*!< 0x00000004 */ +#define ADC_ISR_EOC ADC_ISR_EOC_Msk /*!< ADC group regular end of unitary conversion flag */ +#define ADC_ISR_EOS_Pos (3U) +#define ADC_ISR_EOS_Msk (0x1UL << ADC_ISR_EOS_Pos) /*!< 0x00000008 */ +#define ADC_ISR_EOS ADC_ISR_EOS_Msk /*!< ADC group regular end of sequence conversions flag */ +#define ADC_ISR_OVR_Pos (4U) +#define ADC_ISR_OVR_Msk (0x1UL << ADC_ISR_OVR_Pos) /*!< 0x00000010 */ +#define ADC_ISR_OVR ADC_ISR_OVR_Msk /*!< ADC group regular overrun flag */ +#define ADC_ISR_JEOC_Pos (5U) +#define ADC_ISR_JEOC_Msk (0x1UL << ADC_ISR_JEOC_Pos) /*!< 0x00000020 */ +#define ADC_ISR_JEOC ADC_ISR_JEOC_Msk /*!< ADC group injected end of unitary conversion flag */ +#define ADC_ISR_JEOS_Pos (6U) +#define ADC_ISR_JEOS_Msk (0x1UL << ADC_ISR_JEOS_Pos) /*!< 0x00000040 */ +#define ADC_ISR_JEOS ADC_ISR_JEOS_Msk /*!< ADC group injected end of sequence conversions flag */ +#define ADC_ISR_AWD1_Pos (7U) +#define ADC_ISR_AWD1_Msk (0x1UL << ADC_ISR_AWD1_Pos) /*!< 0x00000080 */ +#define ADC_ISR_AWD1 ADC_ISR_AWD1_Msk /*!< ADC analog watchdog 1 flag */ +#define ADC_ISR_AWD2_Pos (8U) +#define ADC_ISR_AWD2_Msk (0x1UL << ADC_ISR_AWD2_Pos) /*!< 0x00000100 */ +#define ADC_ISR_AWD2 ADC_ISR_AWD2_Msk /*!< ADC analog watchdog 2 flag */ +#define ADC_ISR_AWD3_Pos (9U) +#define ADC_ISR_AWD3_Msk (0x1UL << ADC_ISR_AWD3_Pos) /*!< 0x00000200 */ +#define ADC_ISR_AWD3 ADC_ISR_AWD3_Msk /*!< ADC analog watchdog 3 flag */ +#define ADC_ISR_JQOVF_Pos (10U) +#define ADC_ISR_JQOVF_Msk (0x1UL << ADC_ISR_JQOVF_Pos) /*!< 0x00000400 */ +#define ADC_ISR_JQOVF ADC_ISR_JQOVF_Msk /*!< ADC group injected contexts queue overflow flag */ + +/******************** Bit definition for ADC_IER register *******************/ +#define ADC_IER_ADRDYIE_Pos (0U) +#define ADC_IER_ADRDYIE_Msk (0x1UL << ADC_IER_ADRDYIE_Pos) /*!< 0x00000001 */ +#define ADC_IER_ADRDYIE ADC_IER_ADRDYIE_Msk /*!< ADC ready interrupt */ +#define ADC_IER_EOSMPIE_Pos (1U) +#define ADC_IER_EOSMPIE_Msk (0x1UL << ADC_IER_EOSMPIE_Pos) /*!< 0x00000002 */ +#define ADC_IER_EOSMPIE ADC_IER_EOSMPIE_Msk /*!< ADC group regular end of sampling interrupt */ +#define ADC_IER_EOCIE_Pos (2U) +#define ADC_IER_EOCIE_Msk (0x1UL << ADC_IER_EOCIE_Pos) /*!< 0x00000004 */ +#define ADC_IER_EOCIE ADC_IER_EOCIE_Msk /*!< ADC group regular end of unitary conversion interrupt */ +#define ADC_IER_EOSIE_Pos (3U) +#define ADC_IER_EOSIE_Msk (0x1UL << ADC_IER_EOSIE_Pos) /*!< 0x00000008 */ +#define ADC_IER_EOSIE ADC_IER_EOSIE_Msk /*!< ADC group regular end of sequence conversions interrupt */ +#define ADC_IER_OVRIE_Pos (4U) +#define ADC_IER_OVRIE_Msk (0x1UL << ADC_IER_OVRIE_Pos) /*!< 0x00000010 */ +#define ADC_IER_OVRIE ADC_IER_OVRIE_Msk /*!< ADC group regular overrun interrupt */ +#define ADC_IER_JEOCIE_Pos (5U) +#define ADC_IER_JEOCIE_Msk (0x1UL << ADC_IER_JEOCIE_Pos) /*!< 0x00000020 */ +#define ADC_IER_JEOCIE ADC_IER_JEOCIE_Msk /*!< ADC group injected end of unitary conversion interrupt */ +#define ADC_IER_JEOSIE_Pos (6U) +#define ADC_IER_JEOSIE_Msk (0x1UL << ADC_IER_JEOSIE_Pos) /*!< 0x00000040 */ +#define ADC_IER_JEOSIE ADC_IER_JEOSIE_Msk /*!< ADC group injected end of sequence conversions interrupt */ +#define ADC_IER_AWD1IE_Pos (7U) +#define ADC_IER_AWD1IE_Msk (0x1UL << ADC_IER_AWD1IE_Pos) /*!< 0x00000080 */ +#define ADC_IER_AWD1IE ADC_IER_AWD1IE_Msk /*!< ADC analog watchdog 1 interrupt */ +#define ADC_IER_AWD2IE_Pos (8U) +#define ADC_IER_AWD2IE_Msk (0x1UL << ADC_IER_AWD2IE_Pos) /*!< 0x00000100 */ +#define ADC_IER_AWD2IE ADC_IER_AWD2IE_Msk /*!< ADC analog watchdog 2 interrupt */ +#define ADC_IER_AWD3IE_Pos (9U) +#define ADC_IER_AWD3IE_Msk (0x1UL << ADC_IER_AWD3IE_Pos) /*!< 0x00000200 */ +#define ADC_IER_AWD3IE ADC_IER_AWD3IE_Msk /*!< ADC analog watchdog 3 interrupt */ +#define ADC_IER_JQOVFIE_Pos (10U) +#define ADC_IER_JQOVFIE_Msk (0x1UL << ADC_IER_JQOVFIE_Pos) /*!< 0x00000400 */ +#define ADC_IER_JQOVFIE ADC_IER_JQOVFIE_Msk /*!< ADC group injected contexts queue overflow interrupt */ + +/******************** Bit definition for ADC_CR register ********************/ +#define ADC_CR_ADEN_Pos (0U) +#define ADC_CR_ADEN_Msk (0x1UL << ADC_CR_ADEN_Pos) /*!< 0x00000001 */ +#define ADC_CR_ADEN ADC_CR_ADEN_Msk /*!< ADC enable */ +#define ADC_CR_ADDIS_Pos (1U) +#define ADC_CR_ADDIS_Msk (0x1UL << ADC_CR_ADDIS_Pos) /*!< 0x00000002 */ +#define ADC_CR_ADDIS ADC_CR_ADDIS_Msk /*!< ADC disable */ +#define ADC_CR_ADSTART_Pos (2U) +#define ADC_CR_ADSTART_Msk (0x1UL << ADC_CR_ADSTART_Pos) /*!< 0x00000004 */ +#define ADC_CR_ADSTART ADC_CR_ADSTART_Msk /*!< ADC group regular conversion start */ +#define ADC_CR_JADSTART_Pos (3U) +#define ADC_CR_JADSTART_Msk (0x1UL << ADC_CR_JADSTART_Pos) /*!< 0x00000008 */ +#define ADC_CR_JADSTART ADC_CR_JADSTART_Msk /*!< ADC group injected conversion start */ +#define ADC_CR_ADSTP_Pos (4U) +#define ADC_CR_ADSTP_Msk (0x1UL << ADC_CR_ADSTP_Pos) /*!< 0x00000010 */ +#define ADC_CR_ADSTP ADC_CR_ADSTP_Msk /*!< ADC group regular conversion stop */ +#define ADC_CR_JADSTP_Pos (5U) +#define ADC_CR_JADSTP_Msk (0x1UL << ADC_CR_JADSTP_Pos) /*!< 0x00000020 */ +#define ADC_CR_JADSTP ADC_CR_JADSTP_Msk /*!< ADC group injected conversion stop */ +#define ADC_CR_ADVREGEN_Pos (28U) +#define ADC_CR_ADVREGEN_Msk (0x1UL << ADC_CR_ADVREGEN_Pos) /*!< 0x10000000 */ +#define ADC_CR_ADVREGEN ADC_CR_ADVREGEN_Msk /*!< ADC voltage regulator enable */ +#define ADC_CR_DEEPPWD_Pos (29U) +#define ADC_CR_DEEPPWD_Msk (0x1UL << ADC_CR_DEEPPWD_Pos) /*!< 0x20000000 */ +#define ADC_CR_DEEPPWD ADC_CR_DEEPPWD_Msk /*!< ADC deep power down enable */ +#define ADC_CR_ADCALDIF_Pos (30U) +#define ADC_CR_ADCALDIF_Msk (0x1UL << ADC_CR_ADCALDIF_Pos) /*!< 0x40000000 */ +#define ADC_CR_ADCALDIF ADC_CR_ADCALDIF_Msk /*!< ADC differential mode for calibration */ +#define ADC_CR_ADCAL_Pos (31U) +#define ADC_CR_ADCAL_Msk (0x1UL << ADC_CR_ADCAL_Pos) /*!< 0x80000000 */ +#define ADC_CR_ADCAL ADC_CR_ADCAL_Msk /*!< ADC calibration */ + +/******************** Bit definition for ADC_CFGR register ******************/ +#define ADC_CFGR_DMAEN_Pos (0U) +#define ADC_CFGR_DMAEN_Msk (0x1UL << ADC_CFGR_DMAEN_Pos) /*!< 0x00000001 */ +#define ADC_CFGR_DMAEN ADC_CFGR_DMAEN_Msk /*!< ADC DMA transfer enable */ +#define ADC_CFGR_DMACFG_Pos (1U) +#define ADC_CFGR_DMACFG_Msk (0x1UL << ADC_CFGR_DMACFG_Pos) /*!< 0x00000002 */ +#define ADC_CFGR_DMACFG ADC_CFGR_DMACFG_Msk /*!< ADC DMA transfer configuration */ + +#define ADC_CFGR_RES_Pos (3U) +#define ADC_CFGR_RES_Msk (0x3UL << ADC_CFGR_RES_Pos) /*!< 0x00000018 */ +#define ADC_CFGR_RES ADC_CFGR_RES_Msk /*!< ADC data resolution */ +#define ADC_CFGR_RES_0 (0x1UL << ADC_CFGR_RES_Pos) /*!< 0x00000008 */ +#define ADC_CFGR_RES_1 (0x2UL << ADC_CFGR_RES_Pos) /*!< 0x00000010 */ + +#define ADC_CFGR_EXTSEL_Pos (5U) +#define ADC_CFGR_EXTSEL_Msk (0x1FUL << ADC_CFGR_EXTSEL_Pos) /*!< 0x000003E0 */ +#define ADC_CFGR_EXTSEL ADC_CFGR_EXTSEL_Msk /*!< ADC group regular external trigger source */ +#define ADC_CFGR_EXTSEL_0 (0x1UL << ADC_CFGR_EXTSEL_Pos) /*!< 0x00000020 */ +#define ADC_CFGR_EXTSEL_1 (0x2UL << ADC_CFGR_EXTSEL_Pos) /*!< 0x00000040 */ +#define ADC_CFGR_EXTSEL_2 (0x4UL << ADC_CFGR_EXTSEL_Pos) /*!< 0x00000080 */ +#define ADC_CFGR_EXTSEL_3 (0x8UL << ADC_CFGR_EXTSEL_Pos) /*!< 0x00000100 */ +#define ADC_CFGR_EXTSEL_4 (0x10UL << ADC_CFGR_EXTSEL_Pos) /*!< 0x00000200 */ + +#define ADC_CFGR_EXTEN_Pos (10U) +#define ADC_CFGR_EXTEN_Msk (0x3UL << ADC_CFGR_EXTEN_Pos) /*!< 0x00000C00 */ +#define ADC_CFGR_EXTEN ADC_CFGR_EXTEN_Msk /*!< ADC group regular external trigger polarity */ +#define ADC_CFGR_EXTEN_0 (0x1UL << ADC_CFGR_EXTEN_Pos) /*!< 0x00000400 */ +#define ADC_CFGR_EXTEN_1 (0x2UL << ADC_CFGR_EXTEN_Pos) /*!< 0x00000800 */ + +#define ADC_CFGR_OVRMOD_Pos (12U) +#define ADC_CFGR_OVRMOD_Msk (0x1UL << ADC_CFGR_OVRMOD_Pos) /*!< 0x00001000 */ +#define ADC_CFGR_OVRMOD ADC_CFGR_OVRMOD_Msk /*!< ADC group regular overrun configuration */ +#define ADC_CFGR_CONT_Pos (13U) +#define ADC_CFGR_CONT_Msk (0x1UL << ADC_CFGR_CONT_Pos) /*!< 0x00002000 */ +#define ADC_CFGR_CONT ADC_CFGR_CONT_Msk /*!< ADC group regular continuous conversion mode */ +#define ADC_CFGR_AUTDLY_Pos (14U) +#define ADC_CFGR_AUTDLY_Msk (0x1UL << ADC_CFGR_AUTDLY_Pos) /*!< 0x00004000 */ +#define ADC_CFGR_AUTDLY ADC_CFGR_AUTDLY_Msk /*!< ADC low power auto wait */ +#define ADC_CFGR_ALIGN_Pos (15U) +#define ADC_CFGR_ALIGN_Msk (0x1UL << ADC_CFGR_ALIGN_Pos) /*!< 0x00008000 */ +#define ADC_CFGR_ALIGN ADC_CFGR_ALIGN_Msk /*!< ADC data alignment */ +#define ADC_CFGR_DISCEN_Pos (16U) +#define ADC_CFGR_DISCEN_Msk (0x1UL << ADC_CFGR_DISCEN_Pos) /*!< 0x00010000 */ +#define ADC_CFGR_DISCEN ADC_CFGR_DISCEN_Msk /*!< ADC group regular sequencer discontinuous mode */ + +#define ADC_CFGR_DISCNUM_Pos (17U) +#define ADC_CFGR_DISCNUM_Msk (0x7UL << ADC_CFGR_DISCNUM_Pos) /*!< 0x000E0000 */ +#define ADC_CFGR_DISCNUM ADC_CFGR_DISCNUM_Msk /*!< ADC group regular sequencer discontinuous number of ranks */ +#define ADC_CFGR_DISCNUM_0 (0x1UL << ADC_CFGR_DISCNUM_Pos) /*!< 0x00020000 */ +#define ADC_CFGR_DISCNUM_1 (0x2UL << ADC_CFGR_DISCNUM_Pos) /*!< 0x00040000 */ +#define ADC_CFGR_DISCNUM_2 (0x4UL << ADC_CFGR_DISCNUM_Pos) /*!< 0x00080000 */ + +#define ADC_CFGR_JDISCEN_Pos (20U) +#define ADC_CFGR_JDISCEN_Msk (0x1UL << ADC_CFGR_JDISCEN_Pos) /*!< 0x00100000 */ +#define ADC_CFGR_JDISCEN ADC_CFGR_JDISCEN_Msk /*!< ADC group injected sequencer discontinuous mode */ +#define ADC_CFGR_JQM_Pos (21U) +#define ADC_CFGR_JQM_Msk (0x1UL << ADC_CFGR_JQM_Pos) /*!< 0x00200000 */ +#define ADC_CFGR_JQM ADC_CFGR_JQM_Msk /*!< ADC group injected contexts queue mode */ +#define ADC_CFGR_AWD1SGL_Pos (22U) +#define ADC_CFGR_AWD1SGL_Msk (0x1UL << ADC_CFGR_AWD1SGL_Pos) /*!< 0x00400000 */ +#define ADC_CFGR_AWD1SGL ADC_CFGR_AWD1SGL_Msk /*!< ADC analog watchdog 1 monitoring a single channel or all channels */ +#define ADC_CFGR_AWD1EN_Pos (23U) +#define ADC_CFGR_AWD1EN_Msk (0x1UL << ADC_CFGR_AWD1EN_Pos) /*!< 0x00800000 */ +#define ADC_CFGR_AWD1EN ADC_CFGR_AWD1EN_Msk /*!< ADC analog watchdog 1 enable on scope ADC group regular */ +#define ADC_CFGR_JAWD1EN_Pos (24U) +#define ADC_CFGR_JAWD1EN_Msk (0x1UL << ADC_CFGR_JAWD1EN_Pos) /*!< 0x01000000 */ +#define ADC_CFGR_JAWD1EN ADC_CFGR_JAWD1EN_Msk /*!< ADC analog watchdog 1 enable on scope ADC group injected */ +#define ADC_CFGR_JAUTO_Pos (25U) +#define ADC_CFGR_JAUTO_Msk (0x1UL << ADC_CFGR_JAUTO_Pos) /*!< 0x02000000 */ +#define ADC_CFGR_JAUTO ADC_CFGR_JAUTO_Msk /*!< ADC group injected automatic trigger mode */ + +#define ADC_CFGR_AWD1CH_Pos (26U) +#define ADC_CFGR_AWD1CH_Msk (0x1FUL << ADC_CFGR_AWD1CH_Pos) /*!< 0x7C000000 */ +#define ADC_CFGR_AWD1CH ADC_CFGR_AWD1CH_Msk /*!< ADC analog watchdog 1 monitored channel selection */ +#define ADC_CFGR_AWD1CH_0 (0x01UL << ADC_CFGR_AWD1CH_Pos) /*!< 0x04000000 */ +#define ADC_CFGR_AWD1CH_1 (0x02UL << ADC_CFGR_AWD1CH_Pos) /*!< 0x08000000 */ +#define ADC_CFGR_AWD1CH_2 (0x04UL << ADC_CFGR_AWD1CH_Pos) /*!< 0x10000000 */ +#define ADC_CFGR_AWD1CH_3 (0x08UL << ADC_CFGR_AWD1CH_Pos) /*!< 0x20000000 */ +#define ADC_CFGR_AWD1CH_4 (0x10UL << ADC_CFGR_AWD1CH_Pos) /*!< 0x40000000 */ + +#define ADC_CFGR_JQDIS_Pos (31U) +#define ADC_CFGR_JQDIS_Msk (0x1UL << ADC_CFGR_JQDIS_Pos) /*!< 0x80000000 */ +#define ADC_CFGR_JQDIS ADC_CFGR_JQDIS_Msk /*!< ADC group injected contexts queue disable */ + +/******************** Bit definition for ADC_CFGR2 register *****************/ +#define ADC_CFGR2_ROVSE_Pos (0U) +#define ADC_CFGR2_ROVSE_Msk (0x1UL << ADC_CFGR2_ROVSE_Pos) /*!< 0x00000001 */ +#define ADC_CFGR2_ROVSE ADC_CFGR2_ROVSE_Msk /*!< ADC oversampler enable on scope ADC group regular */ +#define ADC_CFGR2_JOVSE_Pos (1U) +#define ADC_CFGR2_JOVSE_Msk (0x1UL << ADC_CFGR2_JOVSE_Pos) /*!< 0x00000002 */ +#define ADC_CFGR2_JOVSE ADC_CFGR2_JOVSE_Msk /*!< ADC oversampler enable on scope ADC group injected */ + +#define ADC_CFGR2_OVSR_Pos (2U) +#define ADC_CFGR2_OVSR_Msk (0x7UL << ADC_CFGR2_OVSR_Pos) /*!< 0x0000001C */ +#define ADC_CFGR2_OVSR ADC_CFGR2_OVSR_Msk /*!< ADC oversampling ratio */ +#define ADC_CFGR2_OVSR_0 (0x1UL << ADC_CFGR2_OVSR_Pos) /*!< 0x00000004 */ +#define ADC_CFGR2_OVSR_1 (0x2UL << ADC_CFGR2_OVSR_Pos) /*!< 0x00000008 */ +#define ADC_CFGR2_OVSR_2 (0x4UL << ADC_CFGR2_OVSR_Pos) /*!< 0x00000010 */ + +#define ADC_CFGR2_OVSS_Pos (5U) +#define ADC_CFGR2_OVSS_Msk (0xFUL << ADC_CFGR2_OVSS_Pos) /*!< 0x000001E0 */ +#define ADC_CFGR2_OVSS ADC_CFGR2_OVSS_Msk /*!< ADC oversampling shift */ +#define ADC_CFGR2_OVSS_0 (0x1UL << ADC_CFGR2_OVSS_Pos) /*!< 0x00000020 */ +#define ADC_CFGR2_OVSS_1 (0x2UL << ADC_CFGR2_OVSS_Pos) /*!< 0x00000040 */ +#define ADC_CFGR2_OVSS_2 (0x4UL << ADC_CFGR2_OVSS_Pos) /*!< 0x00000080 */ +#define ADC_CFGR2_OVSS_3 (0x8UL << ADC_CFGR2_OVSS_Pos) /*!< 0x00000100 */ + +#define ADC_CFGR2_TROVS_Pos (9U) +#define ADC_CFGR2_TROVS_Msk (0x1UL << ADC_CFGR2_TROVS_Pos) /*!< 0x00000200 */ +#define ADC_CFGR2_TROVS ADC_CFGR2_TROVS_Msk /*!< ADC oversampling discontinuous mode (triggered mode) for ADC group regular */ +#define ADC_CFGR2_ROVSM_Pos (10U) +#define ADC_CFGR2_ROVSM_Msk (0x1UL << ADC_CFGR2_ROVSM_Pos) /*!< 0x00000400 */ +#define ADC_CFGR2_ROVSM ADC_CFGR2_ROVSM_Msk /*!< ADC oversampling mode managing interlaced conversions of ADC group regular and group injected */ + +#define ADC_CFGR2_GCOMP_Pos (16U) +#define ADC_CFGR2_GCOMP_Msk (0x1UL << ADC_CFGR2_GCOMP_Pos) /*!< 0x00010000 */ +#define ADC_CFGR2_GCOMP ADC_CFGR2_GCOMP_Msk /*!< ADC Gain Compensation mode */ + +#define ADC_CFGR2_SWTRIG_Pos (25U) +#define ADC_CFGR2_SWTRIG_Msk (0x1UL << ADC_CFGR2_SWTRIG_Pos) /*!< 0x02000000 */ +#define ADC_CFGR2_SWTRIG ADC_CFGR2_SWTRIG_Msk /*!< ADC Software Trigger Bit for Sample time control trigger mode */ +#define ADC_CFGR2_BULB_Pos (26U) +#define ADC_CFGR2_BULB_Msk (0x1UL << ADC_CFGR2_BULB_Pos) /*!< 0x04000000 */ +#define ADC_CFGR2_BULB ADC_CFGR2_BULB_Msk /*!< ADC Bulb sampling mode */ +#define ADC_CFGR2_SMPTRIG_Pos (27U) +#define ADC_CFGR2_SMPTRIG_Msk (0x1UL << ADC_CFGR2_SMPTRIG_Pos) /*!< 0x08000000 */ +#define ADC_CFGR2_SMPTRIG ADC_CFGR2_SMPTRIG_Msk /*!< ADC Sample Time Control Trigger mode */ + +/******************** Bit definition for ADC_SMPR1 register *****************/ +#define ADC_SMPR1_SMP0_Pos (0U) +#define ADC_SMPR1_SMP0_Msk (0x7UL << ADC_SMPR1_SMP0_Pos) /*!< 0x00000007 */ +#define ADC_SMPR1_SMP0 ADC_SMPR1_SMP0_Msk /*!< ADC channel 0 sampling time selection */ +#define ADC_SMPR1_SMP0_0 (0x1UL << ADC_SMPR1_SMP0_Pos) /*!< 0x00000001 */ +#define ADC_SMPR1_SMP0_1 (0x2UL << ADC_SMPR1_SMP0_Pos) /*!< 0x00000002 */ +#define ADC_SMPR1_SMP0_2 (0x4UL << ADC_SMPR1_SMP0_Pos) /*!< 0x00000004 */ + +#define ADC_SMPR1_SMP1_Pos (3U) +#define ADC_SMPR1_SMP1_Msk (0x7UL << ADC_SMPR1_SMP1_Pos) /*!< 0x00000038 */ +#define ADC_SMPR1_SMP1 ADC_SMPR1_SMP1_Msk /*!< ADC channel 1 sampling time selection */ +#define ADC_SMPR1_SMP1_0 (0x1UL << ADC_SMPR1_SMP1_Pos) /*!< 0x00000008 */ +#define ADC_SMPR1_SMP1_1 (0x2UL << ADC_SMPR1_SMP1_Pos) /*!< 0x00000010 */ +#define ADC_SMPR1_SMP1_2 (0x4UL << ADC_SMPR1_SMP1_Pos) /*!< 0x00000020 */ + +#define ADC_SMPR1_SMP2_Pos (6U) +#define ADC_SMPR1_SMP2_Msk (0x7UL << ADC_SMPR1_SMP2_Pos) /*!< 0x000001C0 */ +#define ADC_SMPR1_SMP2 ADC_SMPR1_SMP2_Msk /*!< ADC channel 2 sampling time selection */ +#define ADC_SMPR1_SMP2_0 (0x1UL << ADC_SMPR1_SMP2_Pos) /*!< 0x00000040 */ +#define ADC_SMPR1_SMP2_1 (0x2UL << ADC_SMPR1_SMP2_Pos) /*!< 0x00000080 */ +#define ADC_SMPR1_SMP2_2 (0x4UL << ADC_SMPR1_SMP2_Pos) /*!< 0x00000100 */ + +#define ADC_SMPR1_SMP3_Pos (9U) +#define ADC_SMPR1_SMP3_Msk (0x7UL << ADC_SMPR1_SMP3_Pos) /*!< 0x00000E00 */ +#define ADC_SMPR1_SMP3 ADC_SMPR1_SMP3_Msk /*!< ADC channel 3 sampling time selection */ +#define ADC_SMPR1_SMP3_0 (0x1UL << ADC_SMPR1_SMP3_Pos) /*!< 0x00000200 */ +#define ADC_SMPR1_SMP3_1 (0x2UL << ADC_SMPR1_SMP3_Pos) /*!< 0x00000400 */ +#define ADC_SMPR1_SMP3_2 (0x4UL << ADC_SMPR1_SMP3_Pos) /*!< 0x00000800 */ + +#define ADC_SMPR1_SMP4_Pos (12U) +#define ADC_SMPR1_SMP4_Msk (0x7UL << ADC_SMPR1_SMP4_Pos) /*!< 0x00007000 */ +#define ADC_SMPR1_SMP4 ADC_SMPR1_SMP4_Msk /*!< ADC channel 4 sampling time selection */ +#define ADC_SMPR1_SMP4_0 (0x1UL << ADC_SMPR1_SMP4_Pos) /*!< 0x00001000 */ +#define ADC_SMPR1_SMP4_1 (0x2UL << ADC_SMPR1_SMP4_Pos) /*!< 0x00002000 */ +#define ADC_SMPR1_SMP4_2 (0x4UL << ADC_SMPR1_SMP4_Pos) /*!< 0x00004000 */ + +#define ADC_SMPR1_SMP5_Pos (15U) +#define ADC_SMPR1_SMP5_Msk (0x7UL << ADC_SMPR1_SMP5_Pos) /*!< 0x00038000 */ +#define ADC_SMPR1_SMP5 ADC_SMPR1_SMP5_Msk /*!< ADC channel 5 sampling time selection */ +#define ADC_SMPR1_SMP5_0 (0x1UL << ADC_SMPR1_SMP5_Pos) /*!< 0x00008000 */ +#define ADC_SMPR1_SMP5_1 (0x2UL << ADC_SMPR1_SMP5_Pos) /*!< 0x00010000 */ +#define ADC_SMPR1_SMP5_2 (0x4UL << ADC_SMPR1_SMP5_Pos) /*!< 0x00020000 */ + +#define ADC_SMPR1_SMP6_Pos (18U) +#define ADC_SMPR1_SMP6_Msk (0x7UL << ADC_SMPR1_SMP6_Pos) /*!< 0x001C0000 */ +#define ADC_SMPR1_SMP6 ADC_SMPR1_SMP6_Msk /*!< ADC channel 6 sampling time selection */ +#define ADC_SMPR1_SMP6_0 (0x1UL << ADC_SMPR1_SMP6_Pos) /*!< 0x00040000 */ +#define ADC_SMPR1_SMP6_1 (0x2UL << ADC_SMPR1_SMP6_Pos) /*!< 0x00080000 */ +#define ADC_SMPR1_SMP6_2 (0x4UL << ADC_SMPR1_SMP6_Pos) /*!< 0x00100000 */ + +#define ADC_SMPR1_SMP7_Pos (21U) +#define ADC_SMPR1_SMP7_Msk (0x7UL << ADC_SMPR1_SMP7_Pos) /*!< 0x00E00000 */ +#define ADC_SMPR1_SMP7 ADC_SMPR1_SMP7_Msk /*!< ADC channel 7 sampling time selection */ +#define ADC_SMPR1_SMP7_0 (0x1UL << ADC_SMPR1_SMP7_Pos) /*!< 0x00200000 */ +#define ADC_SMPR1_SMP7_1 (0x2UL << ADC_SMPR1_SMP7_Pos) /*!< 0x00400000 */ +#define ADC_SMPR1_SMP7_2 (0x4UL << ADC_SMPR1_SMP7_Pos) /*!< 0x00800000 */ + +#define ADC_SMPR1_SMP8_Pos (24U) +#define ADC_SMPR1_SMP8_Msk (0x7UL << ADC_SMPR1_SMP8_Pos) /*!< 0x07000000 */ +#define ADC_SMPR1_SMP8 ADC_SMPR1_SMP8_Msk /*!< ADC channel 8 sampling time selection */ +#define ADC_SMPR1_SMP8_0 (0x1UL << ADC_SMPR1_SMP8_Pos) /*!< 0x01000000 */ +#define ADC_SMPR1_SMP8_1 (0x2UL << ADC_SMPR1_SMP8_Pos) /*!< 0x02000000 */ +#define ADC_SMPR1_SMP8_2 (0x4UL << ADC_SMPR1_SMP8_Pos) /*!< 0x04000000 */ + +#define ADC_SMPR1_SMP9_Pos (27U) +#define ADC_SMPR1_SMP9_Msk (0x7UL << ADC_SMPR1_SMP9_Pos) /*!< 0x38000000 */ +#define ADC_SMPR1_SMP9 ADC_SMPR1_SMP9_Msk /*!< ADC channel 9 sampling time selection */ +#define ADC_SMPR1_SMP9_0 (0x1UL << ADC_SMPR1_SMP9_Pos) /*!< 0x08000000 */ +#define ADC_SMPR1_SMP9_1 (0x2UL << ADC_SMPR1_SMP9_Pos) /*!< 0x10000000 */ +#define ADC_SMPR1_SMP9_2 (0x4UL << ADC_SMPR1_SMP9_Pos) /*!< 0x20000000 */ + +#define ADC_SMPR1_SMPPLUS_Pos (31U) +#define ADC_SMPR1_SMPPLUS_Msk (0x1UL << ADC_SMPR1_SMPPLUS_Pos) /*!< 0x80000000 */ +#define ADC_SMPR1_SMPPLUS ADC_SMPR1_SMPPLUS_Msk /*!< ADC channels sampling time additional setting */ + +/******************** Bit definition for ADC_SMPR2 register *****************/ +#define ADC_SMPR2_SMP10_Pos (0U) +#define ADC_SMPR2_SMP10_Msk (0x7UL << ADC_SMPR2_SMP10_Pos) /*!< 0x00000007 */ +#define ADC_SMPR2_SMP10 ADC_SMPR2_SMP10_Msk /*!< ADC channel 10 sampling time selection */ +#define ADC_SMPR2_SMP10_0 (0x1UL << ADC_SMPR2_SMP10_Pos) /*!< 0x00000001 */ +#define ADC_SMPR2_SMP10_1 (0x2UL << ADC_SMPR2_SMP10_Pos) /*!< 0x00000002 */ +#define ADC_SMPR2_SMP10_2 (0x4UL << ADC_SMPR2_SMP10_Pos) /*!< 0x00000004 */ + +#define ADC_SMPR2_SMP11_Pos (3U) +#define ADC_SMPR2_SMP11_Msk (0x7UL << ADC_SMPR2_SMP11_Pos) /*!< 0x00000038 */ +#define ADC_SMPR2_SMP11 ADC_SMPR2_SMP11_Msk /*!< ADC channel 11 sampling time selection */ +#define ADC_SMPR2_SMP11_0 (0x1UL << ADC_SMPR2_SMP11_Pos) /*!< 0x00000008 */ +#define ADC_SMPR2_SMP11_1 (0x2UL << ADC_SMPR2_SMP11_Pos) /*!< 0x00000010 */ +#define ADC_SMPR2_SMP11_2 (0x4UL << ADC_SMPR2_SMP11_Pos) /*!< 0x00000020 */ + +#define ADC_SMPR2_SMP12_Pos (6U) +#define ADC_SMPR2_SMP12_Msk (0x7UL << ADC_SMPR2_SMP12_Pos) /*!< 0x000001C0 */ +#define ADC_SMPR2_SMP12 ADC_SMPR2_SMP12_Msk /*!< ADC channel 12 sampling time selection */ +#define ADC_SMPR2_SMP12_0 (0x1UL << ADC_SMPR2_SMP12_Pos) /*!< 0x00000040 */ +#define ADC_SMPR2_SMP12_1 (0x2UL << ADC_SMPR2_SMP12_Pos) /*!< 0x00000080 */ +#define ADC_SMPR2_SMP12_2 (0x4UL << ADC_SMPR2_SMP12_Pos) /*!< 0x00000100 */ + +#define ADC_SMPR2_SMP13_Pos (9U) +#define ADC_SMPR2_SMP13_Msk (0x7UL << ADC_SMPR2_SMP13_Pos) /*!< 0x00000E00 */ +#define ADC_SMPR2_SMP13 ADC_SMPR2_SMP13_Msk /*!< ADC channel 13 sampling time selection */ +#define ADC_SMPR2_SMP13_0 (0x1UL << ADC_SMPR2_SMP13_Pos) /*!< 0x00000200 */ +#define ADC_SMPR2_SMP13_1 (0x2UL << ADC_SMPR2_SMP13_Pos) /*!< 0x00000400 */ +#define ADC_SMPR2_SMP13_2 (0x4UL << ADC_SMPR2_SMP13_Pos) /*!< 0x00000800 */ + +#define ADC_SMPR2_SMP14_Pos (12U) +#define ADC_SMPR2_SMP14_Msk (0x7UL << ADC_SMPR2_SMP14_Pos) /*!< 0x00007000 */ +#define ADC_SMPR2_SMP14 ADC_SMPR2_SMP14_Msk /*!< ADC channel 14 sampling time selection */ +#define ADC_SMPR2_SMP14_0 (0x1UL << ADC_SMPR2_SMP14_Pos) /*!< 0x00001000 */ +#define ADC_SMPR2_SMP14_1 (0x2UL << ADC_SMPR2_SMP14_Pos) /*!< 0x00002000 */ +#define ADC_SMPR2_SMP14_2 (0x4UL << ADC_SMPR2_SMP14_Pos) /*!< 0x00004000 */ + +#define ADC_SMPR2_SMP15_Pos (15U) +#define ADC_SMPR2_SMP15_Msk (0x7UL << ADC_SMPR2_SMP15_Pos) /*!< 0x00038000 */ +#define ADC_SMPR2_SMP15 ADC_SMPR2_SMP15_Msk /*!< ADC channel 15 sampling time selection */ +#define ADC_SMPR2_SMP15_0 (0x1UL << ADC_SMPR2_SMP15_Pos) /*!< 0x00008000 */ +#define ADC_SMPR2_SMP15_1 (0x2UL << ADC_SMPR2_SMP15_Pos) /*!< 0x00010000 */ +#define ADC_SMPR2_SMP15_2 (0x4UL << ADC_SMPR2_SMP15_Pos) /*!< 0x00020000 */ + +#define ADC_SMPR2_SMP16_Pos (18U) +#define ADC_SMPR2_SMP16_Msk (0x7UL << ADC_SMPR2_SMP16_Pos) /*!< 0x001C0000 */ +#define ADC_SMPR2_SMP16 ADC_SMPR2_SMP16_Msk /*!< ADC channel 16 sampling time selection */ +#define ADC_SMPR2_SMP16_0 (0x1UL << ADC_SMPR2_SMP16_Pos) /*!< 0x00040000 */ +#define ADC_SMPR2_SMP16_1 (0x2UL << ADC_SMPR2_SMP16_Pos) /*!< 0x00080000 */ +#define ADC_SMPR2_SMP16_2 (0x4UL << ADC_SMPR2_SMP16_Pos) /*!< 0x00100000 */ + +#define ADC_SMPR2_SMP17_Pos (21U) +#define ADC_SMPR2_SMP17_Msk (0x7UL << ADC_SMPR2_SMP17_Pos) /*!< 0x00E00000 */ +#define ADC_SMPR2_SMP17 ADC_SMPR2_SMP17_Msk /*!< ADC channel 17 sampling time selection */ +#define ADC_SMPR2_SMP17_0 (0x1UL << ADC_SMPR2_SMP17_Pos) /*!< 0x00200000 */ +#define ADC_SMPR2_SMP17_1 (0x2UL << ADC_SMPR2_SMP17_Pos) /*!< 0x00400000 */ +#define ADC_SMPR2_SMP17_2 (0x4UL << ADC_SMPR2_SMP17_Pos) /*!< 0x00800000 */ + +#define ADC_SMPR2_SMP18_Pos (24U) +#define ADC_SMPR2_SMP18_Msk (0x7UL << ADC_SMPR2_SMP18_Pos) /*!< 0x07000000 */ +#define ADC_SMPR2_SMP18 ADC_SMPR2_SMP18_Msk /*!< ADC channel 18 sampling time selection */ +#define ADC_SMPR2_SMP18_0 (0x1UL << ADC_SMPR2_SMP18_Pos) /*!< 0x01000000 */ +#define ADC_SMPR2_SMP18_1 (0x2UL << ADC_SMPR2_SMP18_Pos) /*!< 0x02000000 */ +#define ADC_SMPR2_SMP18_2 (0x4UL << ADC_SMPR2_SMP18_Pos) /*!< 0x04000000 */ + +/******************** Bit definition for ADC_TR1 register *******************/ +#define ADC_TR1_LT1_Pos (0U) +#define ADC_TR1_LT1_Msk (0xFFFUL << ADC_TR1_LT1_Pos) /*!< 0x00000FFF */ +#define ADC_TR1_LT1 ADC_TR1_LT1_Msk /*!< ADC analog watchdog 1 threshold low */ + +#define ADC_TR1_AWDFILT_Pos (12U) +#define ADC_TR1_AWDFILT_Msk (0x7UL << ADC_TR1_AWDFILT_Pos) /*!< 0x00007000 */ +#define ADC_TR1_AWDFILT ADC_TR1_AWDFILT_Msk /*!< ADC analog watchdog filtering parameter */ +#define ADC_TR1_AWDFILT_0 (0x1UL << ADC_TR1_AWDFILT_Pos) /*!< 0x00001000 */ +#define ADC_TR1_AWDFILT_1 (0x2UL << ADC_TR1_AWDFILT_Pos) /*!< 0x00002000 */ +#define ADC_TR1_AWDFILT_2 (0x4UL << ADC_TR1_AWDFILT_Pos) /*!< 0x00004000 */ + +#define ADC_TR1_HT1_Pos (16U) +#define ADC_TR1_HT1_Msk (0xFFFUL << ADC_TR1_HT1_Pos) /*!< 0x0FFF0000 */ +#define ADC_TR1_HT1 ADC_TR1_HT1_Msk /*!< ADC analog watchdog 1 threshold high */ + +/******************** Bit definition for ADC_TR2 register *******************/ +#define ADC_TR2_LT2_Pos (0U) +#define ADC_TR2_LT2_Msk (0xFFUL << ADC_TR2_LT2_Pos) /*!< 0x000000FF */ +#define ADC_TR2_LT2 ADC_TR2_LT2_Msk /*!< ADC analog watchdog 2 threshold low */ + +#define ADC_TR2_HT2_Pos (16U) +#define ADC_TR2_HT2_Msk (0xFFUL << ADC_TR2_HT2_Pos) /*!< 0x00FF0000 */ +#define ADC_TR2_HT2 ADC_TR2_HT2_Msk /*!< ADC analog watchdog 2 threshold high */ + +/******************** Bit definition for ADC_TR3 register *******************/ +#define ADC_TR3_LT3_Pos (0U) +#define ADC_TR3_LT3_Msk (0xFFUL << ADC_TR3_LT3_Pos) /*!< 0x000000FF */ +#define ADC_TR3_LT3 ADC_TR3_LT3_Msk /*!< ADC analog watchdog 3 threshold low */ + +#define ADC_TR3_HT3_Pos (16U) +#define ADC_TR3_HT3_Msk (0xFFUL << ADC_TR3_HT3_Pos) /*!< 0x00FF0000 */ +#define ADC_TR3_HT3 ADC_TR3_HT3_Msk /*!< ADC analog watchdog 3 threshold high */ + +/******************** Bit definition for ADC_SQR1 register ******************/ +#define ADC_SQR1_L_Pos (0U) +#define ADC_SQR1_L_Msk (0xFUL << ADC_SQR1_L_Pos) /*!< 0x0000000F */ +#define ADC_SQR1_L ADC_SQR1_L_Msk /*!< ADC group regular sequencer scan length */ +#define ADC_SQR1_L_0 (0x1UL << ADC_SQR1_L_Pos) /*!< 0x00000001 */ +#define ADC_SQR1_L_1 (0x2UL << ADC_SQR1_L_Pos) /*!< 0x00000002 */ +#define ADC_SQR1_L_2 (0x4UL << ADC_SQR1_L_Pos) /*!< 0x00000004 */ +#define ADC_SQR1_L_3 (0x8UL << ADC_SQR1_L_Pos) /*!< 0x00000008 */ + +#define ADC_SQR1_SQ1_Pos (6U) +#define ADC_SQR1_SQ1_Msk (0x1FUL << ADC_SQR1_SQ1_Pos) /*!< 0x000007C0 */ +#define ADC_SQR1_SQ1 ADC_SQR1_SQ1_Msk /*!< ADC group regular sequencer rank 1 */ +#define ADC_SQR1_SQ1_0 (0x01UL << ADC_SQR1_SQ1_Pos) /*!< 0x00000040 */ +#define ADC_SQR1_SQ1_1 (0x02UL << ADC_SQR1_SQ1_Pos) /*!< 0x00000080 */ +#define ADC_SQR1_SQ1_2 (0x04UL << ADC_SQR1_SQ1_Pos) /*!< 0x00000100 */ +#define ADC_SQR1_SQ1_3 (0x08UL << ADC_SQR1_SQ1_Pos) /*!< 0x00000200 */ +#define ADC_SQR1_SQ1_4 (0x10UL << ADC_SQR1_SQ1_Pos) /*!< 0x00000400 */ + +#define ADC_SQR1_SQ2_Pos (12U) +#define ADC_SQR1_SQ2_Msk (0x1FUL << ADC_SQR1_SQ2_Pos) /*!< 0x0001F000 */ +#define ADC_SQR1_SQ2 ADC_SQR1_SQ2_Msk /*!< ADC group regular sequencer rank 2 */ +#define ADC_SQR1_SQ2_0 (0x01UL << ADC_SQR1_SQ2_Pos) /*!< 0x00001000 */ +#define ADC_SQR1_SQ2_1 (0x02UL << ADC_SQR1_SQ2_Pos) /*!< 0x00002000 */ +#define ADC_SQR1_SQ2_2 (0x04UL << ADC_SQR1_SQ2_Pos) /*!< 0x00004000 */ +#define ADC_SQR1_SQ2_3 (0x08UL << ADC_SQR1_SQ2_Pos) /*!< 0x00008000 */ +#define ADC_SQR1_SQ2_4 (0x10UL << ADC_SQR1_SQ2_Pos) /*!< 0x00010000 */ + +#define ADC_SQR1_SQ3_Pos (18U) +#define ADC_SQR1_SQ3_Msk (0x1FUL << ADC_SQR1_SQ3_Pos) /*!< 0x007C0000 */ +#define ADC_SQR1_SQ3 ADC_SQR1_SQ3_Msk /*!< ADC group regular sequencer rank 3 */ +#define ADC_SQR1_SQ3_0 (0x01UL << ADC_SQR1_SQ3_Pos) /*!< 0x00040000 */ +#define ADC_SQR1_SQ3_1 (0x02UL << ADC_SQR1_SQ3_Pos) /*!< 0x00080000 */ +#define ADC_SQR1_SQ3_2 (0x04UL << ADC_SQR1_SQ3_Pos) /*!< 0x00100000 */ +#define ADC_SQR1_SQ3_3 (0x08UL << ADC_SQR1_SQ3_Pos) /*!< 0x00200000 */ +#define ADC_SQR1_SQ3_4 (0x10UL<< ADC_SQR1_SQ3_Pos) /*!< 0x00400000 */ + +#define ADC_SQR1_SQ4_Pos (24U) +#define ADC_SQR1_SQ4_Msk (0x1FUL << ADC_SQR1_SQ4_Pos) /*!< 0x1F000000 */ +#define ADC_SQR1_SQ4 ADC_SQR1_SQ4_Msk /*!< ADC group regular sequencer rank 4 */ +#define ADC_SQR1_SQ4_0 (0x01UL << ADC_SQR1_SQ4_Pos) /*!< 0x01000000 */ +#define ADC_SQR1_SQ4_1 (0x02UL << ADC_SQR1_SQ4_Pos) /*!< 0x02000000 */ +#define ADC_SQR1_SQ4_2 (0x04UL << ADC_SQR1_SQ4_Pos) /*!< 0x04000000 */ +#define ADC_SQR1_SQ4_3 (0x08UL << ADC_SQR1_SQ4_Pos) /*!< 0x08000000 */ +#define ADC_SQR1_SQ4_4 (0x10UL << ADC_SQR1_SQ4_Pos) /*!< 0x10000000 */ + +/******************** Bit definition for ADC_SQR2 register ******************/ +#define ADC_SQR2_SQ5_Pos (0U) +#define ADC_SQR2_SQ5_Msk (0x1FUL << ADC_SQR2_SQ5_Pos) /*!< 0x0000001F */ +#define ADC_SQR2_SQ5 ADC_SQR2_SQ5_Msk /*!< ADC group regular sequencer rank 5 */ +#define ADC_SQR2_SQ5_0 (0x01UL << ADC_SQR2_SQ5_Pos) /*!< 0x00000001 */ +#define ADC_SQR2_SQ5_1 (0x02UL << ADC_SQR2_SQ5_Pos) /*!< 0x00000002 */ +#define ADC_SQR2_SQ5_2 (0x04UL << ADC_SQR2_SQ5_Pos) /*!< 0x00000004 */ +#define ADC_SQR2_SQ5_3 (0x08UL << ADC_SQR2_SQ5_Pos) /*!< 0x00000008 */ +#define ADC_SQR2_SQ5_4 (0x10UL << ADC_SQR2_SQ5_Pos) /*!< 0x00000010 */ + +#define ADC_SQR2_SQ6_Pos (6U) +#define ADC_SQR2_SQ6_Msk (0x1FUL << ADC_SQR2_SQ6_Pos) /*!< 0x000007C0 */ +#define ADC_SQR2_SQ6 ADC_SQR2_SQ6_Msk /*!< ADC group regular sequencer rank 6 */ +#define ADC_SQR2_SQ6_0 (0x01UL << ADC_SQR2_SQ6_Pos) /*!< 0x00000040 */ +#define ADC_SQR2_SQ6_1 (0x02UL << ADC_SQR2_SQ6_Pos) /*!< 0x00000080 */ +#define ADC_SQR2_SQ6_2 (0x04UL << ADC_SQR2_SQ6_Pos) /*!< 0x00000100 */ +#define ADC_SQR2_SQ6_3 (0x08UL << ADC_SQR2_SQ6_Pos) /*!< 0x00000200 */ +#define ADC_SQR2_SQ6_4 (0x10UL << ADC_SQR2_SQ6_Pos) /*!< 0x00000400 */ + +#define ADC_SQR2_SQ7_Pos (12U) +#define ADC_SQR2_SQ7_Msk (0x1FUL << ADC_SQR2_SQ7_Pos) /*!< 0x0001F000 */ +#define ADC_SQR2_SQ7 ADC_SQR2_SQ7_Msk /*!< ADC group regular sequencer rank 7 */ +#define ADC_SQR2_SQ7_0 (0x01UL << ADC_SQR2_SQ7_Pos) /*!< 0x00001000 */ +#define ADC_SQR2_SQ7_1 (0x02UL << ADC_SQR2_SQ7_Pos) /*!< 0x00002000 */ +#define ADC_SQR2_SQ7_2 (0x04UL << ADC_SQR2_SQ7_Pos) /*!< 0x00004000 */ +#define ADC_SQR2_SQ7_3 (0x08UL << ADC_SQR2_SQ7_Pos) /*!< 0x00008000 */ +#define ADC_SQR2_SQ7_4 (0x10UL << ADC_SQR2_SQ7_Pos) /*!< 0x00010000 */ + +#define ADC_SQR2_SQ8_Pos (18U) +#define ADC_SQR2_SQ8_Msk (0x1FUL << ADC_SQR2_SQ8_Pos) /*!< 0x007C0000 */ +#define ADC_SQR2_SQ8 ADC_SQR2_SQ8_Msk /*!< ADC group regular sequencer rank 8 */ +#define ADC_SQR2_SQ8_0 (0x01UL << ADC_SQR2_SQ8_Pos) /*!< 0x00040000 */ +#define ADC_SQR2_SQ8_1 (0x02UL << ADC_SQR2_SQ8_Pos) /*!< 0x00080000 */ +#define ADC_SQR2_SQ8_2 (0x04UL << ADC_SQR2_SQ8_Pos) /*!< 0x00100000 */ +#define ADC_SQR2_SQ8_3 (0x08UL << ADC_SQR2_SQ8_Pos) /*!< 0x00200000 */ +#define ADC_SQR2_SQ8_4 (0x10UL << ADC_SQR2_SQ8_Pos) /*!< 0x00400000 */ + +#define ADC_SQR2_SQ9_Pos (24U) +#define ADC_SQR2_SQ9_Msk (0x1FUL << ADC_SQR2_SQ9_Pos) /*!< 0x1F000000 */ +#define ADC_SQR2_SQ9 ADC_SQR2_SQ9_Msk /*!< ADC group regular sequencer rank 9 */ +#define ADC_SQR2_SQ9_0 (0x01UL << ADC_SQR2_SQ9_Pos) /*!< 0x01000000 */ +#define ADC_SQR2_SQ9_1 (0x02UL << ADC_SQR2_SQ9_Pos) /*!< 0x02000000 */ +#define ADC_SQR2_SQ9_2 (0x04UL << ADC_SQR2_SQ9_Pos) /*!< 0x04000000 */ +#define ADC_SQR2_SQ9_3 (0x08UL << ADC_SQR2_SQ9_Pos) /*!< 0x08000000 */ +#define ADC_SQR2_SQ9_4 (0x10UL << ADC_SQR2_SQ9_Pos) /*!< 0x10000000 */ + +/******************** Bit definition for ADC_SQR3 register ******************/ +#define ADC_SQR3_SQ10_Pos (0U) +#define ADC_SQR3_SQ10_Msk (0x1FUL << ADC_SQR3_SQ10_Pos) /*!< 0x0000001F */ +#define ADC_SQR3_SQ10 ADC_SQR3_SQ10_Msk /*!< ADC group regular sequencer rank 10 */ +#define ADC_SQR3_SQ10_0 (0x01UL << ADC_SQR3_SQ10_Pos) /*!< 0x00000001 */ +#define ADC_SQR3_SQ10_1 (0x02UL << ADC_SQR3_SQ10_Pos) /*!< 0x00000002 */ +#define ADC_SQR3_SQ10_2 (0x04UL << ADC_SQR3_SQ10_Pos) /*!< 0x00000004 */ +#define ADC_SQR3_SQ10_3 (0x08UL << ADC_SQR3_SQ10_Pos) /*!< 0x00000008 */ +#define ADC_SQR3_SQ10_4 (0x10UL << ADC_SQR3_SQ10_Pos) /*!< 0x00000010 */ + +#define ADC_SQR3_SQ11_Pos (6U) +#define ADC_SQR3_SQ11_Msk (0x1FUL << ADC_SQR3_SQ11_Pos) /*!< 0x000007C0 */ +#define ADC_SQR3_SQ11 ADC_SQR3_SQ11_Msk /*!< ADC group regular sequencer rank 11 */ +#define ADC_SQR3_SQ11_0 (0x01UL << ADC_SQR3_SQ11_Pos) /*!< 0x00000040 */ +#define ADC_SQR3_SQ11_1 (0x02UL << ADC_SQR3_SQ11_Pos) /*!< 0x00000080 */ +#define ADC_SQR3_SQ11_2 (0x04UL << ADC_SQR3_SQ11_Pos) /*!< 0x00000100 */ +#define ADC_SQR3_SQ11_3 (0x08UL << ADC_SQR3_SQ11_Pos) /*!< 0x00000200 */ +#define ADC_SQR3_SQ11_4 (0x10UL << ADC_SQR3_SQ11_Pos) /*!< 0x00000400 */ + +#define ADC_SQR3_SQ12_Pos (12U) +#define ADC_SQR3_SQ12_Msk (0x1FUL << ADC_SQR3_SQ12_Pos) /*!< 0x0001F000 */ +#define ADC_SQR3_SQ12 ADC_SQR3_SQ12_Msk /*!< ADC group regular sequencer rank 12 */ +#define ADC_SQR3_SQ12_0 (0x01UL << ADC_SQR3_SQ12_Pos) /*!< 0x00001000 */ +#define ADC_SQR3_SQ12_1 (0x02UL << ADC_SQR3_SQ12_Pos) /*!< 0x00002000 */ +#define ADC_SQR3_SQ12_2 (0x04UL << ADC_SQR3_SQ12_Pos) /*!< 0x00004000 */ +#define ADC_SQR3_SQ12_3 (0x08UL << ADC_SQR3_SQ12_Pos) /*!< 0x00008000 */ +#define ADC_SQR3_SQ12_4 (0x10UL << ADC_SQR3_SQ12_Pos) /*!< 0x00010000 */ + +#define ADC_SQR3_SQ13_Pos (18U) +#define ADC_SQR3_SQ13_Msk (0x1FUL << ADC_SQR3_SQ13_Pos) /*!< 0x007C0000 */ +#define ADC_SQR3_SQ13 ADC_SQR3_SQ13_Msk /*!< ADC group regular sequencer rank 13 */ +#define ADC_SQR3_SQ13_0 (0x01UL << ADC_SQR3_SQ13_Pos) /*!< 0x00040000 */ +#define ADC_SQR3_SQ13_1 (0x02UL << ADC_SQR3_SQ13_Pos) /*!< 0x00080000 */ +#define ADC_SQR3_SQ13_2 (0x04UL << ADC_SQR3_SQ13_Pos) /*!< 0x00100000 */ +#define ADC_SQR3_SQ13_3 (0x08UL << ADC_SQR3_SQ13_Pos) /*!< 0x00200000 */ +#define ADC_SQR3_SQ13_4 (0x10UL << ADC_SQR3_SQ13_Pos) /*!< 0x00400000 */ + +#define ADC_SQR3_SQ14_Pos (24U) +#define ADC_SQR3_SQ14_Msk (0x1FUL << ADC_SQR3_SQ14_Pos) /*!< 0x1F000000 */ +#define ADC_SQR3_SQ14 ADC_SQR3_SQ14_Msk /*!< ADC group regular sequencer rank 14 */ +#define ADC_SQR3_SQ14_0 (0x01UL << ADC_SQR3_SQ14_Pos) /*!< 0x01000000 */ +#define ADC_SQR3_SQ14_1 (0x02UL << ADC_SQR3_SQ14_Pos) /*!< 0x02000000 */ +#define ADC_SQR3_SQ14_2 (0x04UL << ADC_SQR3_SQ14_Pos) /*!< 0x04000000 */ +#define ADC_SQR3_SQ14_3 (0x08UL << ADC_SQR3_SQ14_Pos) /*!< 0x08000000 */ +#define ADC_SQR3_SQ14_4 (0x10UL << ADC_SQR3_SQ14_Pos) /*!< 0x10000000 */ + +/******************** Bit definition for ADC_SQR4 register ******************/ +#define ADC_SQR4_SQ15_Pos (0U) +#define ADC_SQR4_SQ15_Msk (0x1FUL << ADC_SQR4_SQ15_Pos) /*!< 0x0000001F */ +#define ADC_SQR4_SQ15 ADC_SQR4_SQ15_Msk /*!< ADC group regular sequencer rank 15 */ +#define ADC_SQR4_SQ15_0 (0x01UL << ADC_SQR4_SQ15_Pos) /*!< 0x00000001 */ +#define ADC_SQR4_SQ15_1 (0x02UL << ADC_SQR4_SQ15_Pos) /*!< 0x00000002 */ +#define ADC_SQR4_SQ15_2 (0x04UL << ADC_SQR4_SQ15_Pos) /*!< 0x00000004 */ +#define ADC_SQR4_SQ15_3 (0x08UL << ADC_SQR4_SQ15_Pos) /*!< 0x00000008 */ +#define ADC_SQR4_SQ15_4 (0x10UL << ADC_SQR4_SQ15_Pos) /*!< 0x00000010 */ + +#define ADC_SQR4_SQ16_Pos (6U) +#define ADC_SQR4_SQ16_Msk (0x1FUL << ADC_SQR4_SQ16_Pos) /*!< 0x000007C0 */ +#define ADC_SQR4_SQ16 ADC_SQR4_SQ16_Msk /*!< ADC group regular sequencer rank 16 */ +#define ADC_SQR4_SQ16_0 (0x01UL << ADC_SQR4_SQ16_Pos) /*!< 0x00000040 */ +#define ADC_SQR4_SQ16_1 (0x02UL << ADC_SQR4_SQ16_Pos) /*!< 0x00000080 */ +#define ADC_SQR4_SQ16_2 (0x04UL << ADC_SQR4_SQ16_Pos) /*!< 0x00000100 */ +#define ADC_SQR4_SQ16_3 (0x08UL << ADC_SQR4_SQ16_Pos) /*!< 0x00000200 */ +#define ADC_SQR4_SQ16_4 (0x10UL << ADC_SQR4_SQ16_Pos) /*!< 0x00000400 */ + +/******************** Bit definition for ADC_DR register ********************/ +#define ADC_DR_RDATA_Pos (0U) +#define ADC_DR_RDATA_Msk (0xFFFFUL << ADC_DR_RDATA_Pos) /*!< 0x0000FFFF */ +#define ADC_DR_RDATA ADC_DR_RDATA_Msk /*!< ADC group regular conversion data */ + +/******************** Bit definition for ADC_JSQR register ******************/ +#define ADC_JSQR_JL_Pos (0U) +#define ADC_JSQR_JL_Msk (0x3UL << ADC_JSQR_JL_Pos) /*!< 0x00000003 */ +#define ADC_JSQR_JL ADC_JSQR_JL_Msk /*!< ADC group injected sequencer scan length */ +#define ADC_JSQR_JL_0 (0x1UL << ADC_JSQR_JL_Pos) /*!< 0x00000001 */ +#define ADC_JSQR_JL_1 (0x2UL << ADC_JSQR_JL_Pos) /*!< 0x00000002 */ + +#define ADC_JSQR_JEXTSEL_Pos (2U) +#define ADC_JSQR_JEXTSEL_Msk (0x1FUL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x0000007C */ +#define ADC_JSQR_JEXTSEL ADC_JSQR_JEXTSEL_Msk /*!< ADC group injected external trigger source */ +#define ADC_JSQR_JEXTSEL_0 (0x1UL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x00000004 */ +#define ADC_JSQR_JEXTSEL_1 (0x2UL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x00000008 */ +#define ADC_JSQR_JEXTSEL_2 (0x4UL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x00000010 */ +#define ADC_JSQR_JEXTSEL_3 (0x8UL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x00000020 */ +#define ADC_JSQR_JEXTSEL_4 (0x10UL << ADC_JSQR_JEXTSEL_Pos) /*!< 0x00000040 */ + +#define ADC_JSQR_JEXTEN_Pos (7U) +#define ADC_JSQR_JEXTEN_Msk (0x3UL << ADC_JSQR_JEXTEN_Pos) /*!< 0x00000180 */ +#define ADC_JSQR_JEXTEN ADC_JSQR_JEXTEN_Msk /*!< ADC group injected external trigger polarity */ +#define ADC_JSQR_JEXTEN_0 (0x1UL << ADC_JSQR_JEXTEN_Pos) /*!< 0x00000080 */ +#define ADC_JSQR_JEXTEN_1 (0x2UL << ADC_JSQR_JEXTEN_Pos) /*!< 0x00000100 */ + +#define ADC_JSQR_JSQ1_Pos (9U) +#define ADC_JSQR_JSQ1_Msk (0x1FUL << ADC_JSQR_JSQ1_Pos) /*!< 0x00003E00 */ +#define ADC_JSQR_JSQ1 ADC_JSQR_JSQ1_Msk /*!< ADC group injected sequencer rank 1 */ +#define ADC_JSQR_JSQ1_0 (0x01UL << ADC_JSQR_JSQ1_Pos) /*!< 0x00000200 */ +#define ADC_JSQR_JSQ1_1 (0x02UL << ADC_JSQR_JSQ1_Pos) /*!< 0x00000400 */ +#define ADC_JSQR_JSQ1_2 (0x04UL << ADC_JSQR_JSQ1_Pos) /*!< 0x00000800 */ +#define ADC_JSQR_JSQ1_3 (0x08UL << ADC_JSQR_JSQ1_Pos) /*!< 0x00001000 */ +#define ADC_JSQR_JSQ1_4 (0x10UL << ADC_JSQR_JSQ1_Pos) /*!< 0x00002000 */ + +#define ADC_JSQR_JSQ2_Pos (15U) +#define ADC_JSQR_JSQ2_Msk (0x1FUL << ADC_JSQR_JSQ2_Pos) /*!< 0x0007C000 */ +#define ADC_JSQR_JSQ2 ADC_JSQR_JSQ2_Msk /*!< ADC group injected sequencer rank 2 */ +#define ADC_JSQR_JSQ2_0 (0x01UL << ADC_JSQR_JSQ2_Pos) /*!< 0x00004000 */ +#define ADC_JSQR_JSQ2_1 (0x02UL << ADC_JSQR_JSQ2_Pos) /*!< 0x00008000 */ +#define ADC_JSQR_JSQ2_2 (0x04UL << ADC_JSQR_JSQ2_Pos) /*!< 0x00010000 */ +#define ADC_JSQR_JSQ2_3 (0x08UL << ADC_JSQR_JSQ2_Pos) /*!< 0x00020000 */ +#define ADC_JSQR_JSQ2_4 (0x10UL << ADC_JSQR_JSQ2_Pos) /*!< 0x00040000 */ + +#define ADC_JSQR_JSQ3_Pos (21U) +#define ADC_JSQR_JSQ3_Msk (0x1FUL << ADC_JSQR_JSQ3_Pos) /*!< 0x03E00000 */ +#define ADC_JSQR_JSQ3 ADC_JSQR_JSQ3_Msk /*!< ADC group injected sequencer rank 3 */ +#define ADC_JSQR_JSQ3_0 (0x01UL << ADC_JSQR_JSQ3_Pos) /*!< 0x00200000 */ +#define ADC_JSQR_JSQ3_1 (0x02UL << ADC_JSQR_JSQ3_Pos) /*!< 0x00400000 */ +#define ADC_JSQR_JSQ3_2 (0x04UL << ADC_JSQR_JSQ3_Pos) /*!< 0x00800000 */ +#define ADC_JSQR_JSQ3_3 (0x08UL << ADC_JSQR_JSQ3_Pos) /*!< 0x01000000 */ +#define ADC_JSQR_JSQ3_4 (0x10UL << ADC_JSQR_JSQ3_Pos) /*!< 0x02000000 */ + +#define ADC_JSQR_JSQ4_Pos (27U) +#define ADC_JSQR_JSQ4_Msk (0x1FUL << ADC_JSQR_JSQ4_Pos) /*!< 0xF8000000 */ +#define ADC_JSQR_JSQ4 ADC_JSQR_JSQ4_Msk /*!< ADC group injected sequencer rank 4 */ +#define ADC_JSQR_JSQ4_0 (0x01UL << ADC_JSQR_JSQ4_Pos) /*!< 0x08000000 */ +#define ADC_JSQR_JSQ4_1 (0x02UL << ADC_JSQR_JSQ4_Pos) /*!< 0x10000000 */ +#define ADC_JSQR_JSQ4_2 (0x04UL << ADC_JSQR_JSQ4_Pos) /*!< 0x20000000 */ +#define ADC_JSQR_JSQ4_3 (0x08UL << ADC_JSQR_JSQ4_Pos) /*!< 0x40000000 */ +#define ADC_JSQR_JSQ4_4 (0x10UL << ADC_JSQR_JSQ4_Pos) /*!< 0x80000000 */ + +/******************** Bit definition for ADC_OFR1 register ******************/ +#define ADC_OFR1_OFFSET1_Pos (0U) +#define ADC_OFR1_OFFSET1_Msk (0xFFFUL << ADC_OFR1_OFFSET1_Pos) /*!< 0x00000FFF */ +#define ADC_OFR1_OFFSET1 ADC_OFR1_OFFSET1_Msk /*!< ADC offset number 1 offset level */ + +#define ADC_OFR1_OFFSETPOS_Pos (24U) +#define ADC_OFR1_OFFSETPOS_Msk (0x1UL << ADC_OFR1_OFFSETPOS_Pos) /*!< 0x01000000 */ +#define ADC_OFR1_OFFSETPOS ADC_OFR1_OFFSETPOS_Msk /*!< ADC offset number 1 positive */ +#define ADC_OFR1_SATEN_Pos (25U) +#define ADC_OFR1_SATEN_Msk (0x1UL << ADC_OFR1_SATEN_Pos) /*!< 0x02000000 */ +#define ADC_OFR1_SATEN ADC_OFR1_SATEN_Msk /*!< ADC offset number 1 saturation enable */ + +#define ADC_OFR1_OFFSET1_CH_Pos (26U) +#define ADC_OFR1_OFFSET1_CH_Msk (0x1FUL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x7C000000 */ +#define ADC_OFR1_OFFSET1_CH ADC_OFR1_OFFSET1_CH_Msk /*!< ADC offset number 1 channel selection */ +#define ADC_OFR1_OFFSET1_CH_0 (0x01UL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x04000000 */ +#define ADC_OFR1_OFFSET1_CH_1 (0x02UL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x08000000 */ +#define ADC_OFR1_OFFSET1_CH_2 (0x04UL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x10000000 */ +#define ADC_OFR1_OFFSET1_CH_3 (0x08UL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x20000000 */ +#define ADC_OFR1_OFFSET1_CH_4 (0x10UL << ADC_OFR1_OFFSET1_CH_Pos) /*!< 0x40000000 */ + +#define ADC_OFR1_OFFSET1_EN_Pos (31U) +#define ADC_OFR1_OFFSET1_EN_Msk (0x1UL << ADC_OFR1_OFFSET1_EN_Pos) /*!< 0x80000000 */ +#define ADC_OFR1_OFFSET1_EN ADC_OFR1_OFFSET1_EN_Msk /*!< ADC offset number 1 enable */ + +/******************** Bit definition for ADC_OFR2 register ******************/ +#define ADC_OFR2_OFFSET2_Pos (0U) +#define ADC_OFR2_OFFSET2_Msk (0xFFFUL << ADC_OFR2_OFFSET2_Pos) /*!< 0x00000FFF */ +#define ADC_OFR2_OFFSET2 ADC_OFR2_OFFSET2_Msk /*!< ADC offset number 2 offset level */ + +#define ADC_OFR2_OFFSETPOS_Pos (24U) +#define ADC_OFR2_OFFSETPOS_Msk (0x1UL << ADC_OFR2_OFFSETPOS_Pos) /*!< 0x01000000 */ +#define ADC_OFR2_OFFSETPOS ADC_OFR2_OFFSETPOS_Msk /*!< ADC offset number 2 positive */ +#define ADC_OFR2_SATEN_Pos (25U) +#define ADC_OFR2_SATEN_Msk (0x1UL << ADC_OFR2_SATEN_Pos) /*!< 0x02000000 */ +#define ADC_OFR2_SATEN ADC_OFR2_SATEN_Msk /*!< ADC offset number 2 saturation enable */ + +#define ADC_OFR2_OFFSET2_CH_Pos (26U) +#define ADC_OFR2_OFFSET2_CH_Msk (0x1FUL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x7C000000 */ +#define ADC_OFR2_OFFSET2_CH ADC_OFR2_OFFSET2_CH_Msk /*!< ADC offset number 2 channel selection */ +#define ADC_OFR2_OFFSET2_CH_0 (0x01UL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x04000000 */ +#define ADC_OFR2_OFFSET2_CH_1 (0x02UL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x08000000 */ +#define ADC_OFR2_OFFSET2_CH_2 (0x04UL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x10000000 */ +#define ADC_OFR2_OFFSET2_CH_3 (0x08UL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x20000000 */ +#define ADC_OFR2_OFFSET2_CH_4 (0x10UL << ADC_OFR2_OFFSET2_CH_Pos) /*!< 0x40000000 */ + +#define ADC_OFR2_OFFSET2_EN_Pos (31U) +#define ADC_OFR2_OFFSET2_EN_Msk (0x1UL << ADC_OFR2_OFFSET2_EN_Pos) /*!< 0x80000000 */ +#define ADC_OFR2_OFFSET2_EN ADC_OFR2_OFFSET2_EN_Msk /*!< ADC offset number 2 enable */ + +/******************** Bit definition for ADC_OFR3 register ******************/ +#define ADC_OFR3_OFFSET3_Pos (0U) +#define ADC_OFR3_OFFSET3_Msk (0xFFFUL << ADC_OFR3_OFFSET3_Pos) /*!< 0x00000FFF */ +#define ADC_OFR3_OFFSET3 ADC_OFR3_OFFSET3_Msk /*!< ADC offset number 3 offset level */ + +#define ADC_OFR3_OFFSETPOS_Pos (24U) +#define ADC_OFR3_OFFSETPOS_Msk (0x1UL << ADC_OFR3_OFFSETPOS_Pos) /*!< 0x01000000 */ +#define ADC_OFR3_OFFSETPOS ADC_OFR3_OFFSETPOS_Msk /*!< ADC offset number 3 positive */ +#define ADC_OFR3_SATEN_Pos (25U) +#define ADC_OFR3_SATEN_Msk (0x1UL << ADC_OFR3_SATEN_Pos) /*!< 0x02000000 */ +#define ADC_OFR3_SATEN ADC_OFR3_SATEN_Msk /*!< ADC offset number 3 saturation enable */ + +#define ADC_OFR3_OFFSET3_CH_Pos (26U) +#define ADC_OFR3_OFFSET3_CH_Msk (0x1FUL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x7C000000 */ +#define ADC_OFR3_OFFSET3_CH ADC_OFR3_OFFSET3_CH_Msk /*!< ADC offset number 3 channel selection */ +#define ADC_OFR3_OFFSET3_CH_0 (0x01UL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x04000000 */ +#define ADC_OFR3_OFFSET3_CH_1 (0x02UL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x08000000 */ +#define ADC_OFR3_OFFSET3_CH_2 (0x04UL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x10000000 */ +#define ADC_OFR3_OFFSET3_CH_3 (0x08UL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x20000000 */ +#define ADC_OFR3_OFFSET3_CH_4 (0x10UL << ADC_OFR3_OFFSET3_CH_Pos) /*!< 0x40000000 */ + +#define ADC_OFR3_OFFSET3_EN_Pos (31U) +#define ADC_OFR3_OFFSET3_EN_Msk (0x1UL << ADC_OFR3_OFFSET3_EN_Pos) /*!< 0x80000000 */ +#define ADC_OFR3_OFFSET3_EN ADC_OFR3_OFFSET3_EN_Msk /*!< ADC offset number 3 enable */ + +/******************** Bit definition for ADC_OFR4 register ******************/ +#define ADC_OFR4_OFFSET4_Pos (0U) +#define ADC_OFR4_OFFSET4_Msk (0xFFFUL << ADC_OFR4_OFFSET4_Pos) /*!< 0x00000FFF */ +#define ADC_OFR4_OFFSET4 ADC_OFR4_OFFSET4_Msk /*!< ADC offset number 4 offset level */ + +#define ADC_OFR4_OFFSETPOS_Pos (24U) +#define ADC_OFR4_OFFSETPOS_Msk (0x1UL << ADC_OFR4_OFFSETPOS_Pos) /*!< 0x01000000 */ +#define ADC_OFR4_OFFSETPOS ADC_OFR4_OFFSETPOS_Msk /*!< ADC offset number 4 positive */ +#define ADC_OFR4_SATEN_Pos (25U) +#define ADC_OFR4_SATEN_Msk (0x1UL << ADC_OFR4_SATEN_Pos) /*!< 0x02000000 */ +#define ADC_OFR4_SATEN ADC_OFR4_SATEN_Msk /*!< ADC offset number 4 saturation enable */ + +#define ADC_OFR4_OFFSET4_CH_Pos (26U) +#define ADC_OFR4_OFFSET4_CH_Msk (0x1FUL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x7C000000 */ +#define ADC_OFR4_OFFSET4_CH ADC_OFR4_OFFSET4_CH_Msk /*!< ADC offset number 4 channel selection */ +#define ADC_OFR4_OFFSET4_CH_0 (0x01UL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x04000000 */ +#define ADC_OFR4_OFFSET4_CH_1 (0x02UL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x08000000 */ +#define ADC_OFR4_OFFSET4_CH_2 (0x04UL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x10000000 */ +#define ADC_OFR4_OFFSET4_CH_3 (0x08UL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x20000000 */ +#define ADC_OFR4_OFFSET4_CH_4 (0x10UL << ADC_OFR4_OFFSET4_CH_Pos) /*!< 0x40000000 */ + +#define ADC_OFR4_OFFSET4_EN_Pos (31U) +#define ADC_OFR4_OFFSET4_EN_Msk (0x1UL << ADC_OFR4_OFFSET4_EN_Pos) /*!< 0x80000000 */ +#define ADC_OFR4_OFFSET4_EN ADC_OFR4_OFFSET4_EN_Msk /*!< ADC offset number 4 enable */ + +/******************** Bit definition for ADC_JDR1 register ******************/ +#define ADC_JDR1_JDATA_Pos (0U) +#define ADC_JDR1_JDATA_Msk (0xFFFFUL << ADC_JDR1_JDATA_Pos) /*!< 0x0000FFFF */ +#define ADC_JDR1_JDATA ADC_JDR1_JDATA_Msk /*!< ADC group injected sequencer rank 1 conversion data */ + +/******************** Bit definition for ADC_JDR2 register ******************/ +#define ADC_JDR2_JDATA_Pos (0U) +#define ADC_JDR2_JDATA_Msk (0xFFFFUL << ADC_JDR2_JDATA_Pos) /*!< 0x0000FFFF */ +#define ADC_JDR2_JDATA ADC_JDR2_JDATA_Msk /*!< ADC group injected sequencer rank 2 conversion data */ + +/******************** Bit definition for ADC_JDR3 register ******************/ +#define ADC_JDR3_JDATA_Pos (0U) +#define ADC_JDR3_JDATA_Msk (0xFFFFUL << ADC_JDR3_JDATA_Pos) /*!< 0x0000FFFF */ +#define ADC_JDR3_JDATA ADC_JDR3_JDATA_Msk /*!< ADC group injected sequencer rank 3 conversion data */ + +/******************** Bit definition for ADC_JDR4 register ******************/ +#define ADC_JDR4_JDATA_Pos (0U) +#define ADC_JDR4_JDATA_Msk (0xFFFFUL << ADC_JDR4_JDATA_Pos) /*!< 0x0000FFFF */ +#define ADC_JDR4_JDATA ADC_JDR4_JDATA_Msk /*!< ADC group injected sequencer rank 4 conversion data */ + +/******************** Bit definition for ADC_AWD2CR register ****************/ +#define ADC_AWD2CR_AWD2CH_Pos (0U) +#define ADC_AWD2CR_AWD2CH_Msk (0x7FFFFUL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x0007FFFF */ +#define ADC_AWD2CR_AWD2CH ADC_AWD2CR_AWD2CH_Msk /*!< ADC analog watchdog 2 monitored channel selection */ +#define ADC_AWD2CR_AWD2CH_0 (0x00001UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000001 */ +#define ADC_AWD2CR_AWD2CH_1 (0x00002UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000002 */ +#define ADC_AWD2CR_AWD2CH_2 (0x00004UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000004 */ +#define ADC_AWD2CR_AWD2CH_3 (0x00008UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000008 */ +#define ADC_AWD2CR_AWD2CH_4 (0x00010UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000010 */ +#define ADC_AWD2CR_AWD2CH_5 (0x00020UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000020 */ +#define ADC_AWD2CR_AWD2CH_6 (0x00040UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000040 */ +#define ADC_AWD2CR_AWD2CH_7 (0x00080UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000080 */ +#define ADC_AWD2CR_AWD2CH_8 (0x00100UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000100 */ +#define ADC_AWD2CR_AWD2CH_9 (0x00200UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000200 */ +#define ADC_AWD2CR_AWD2CH_10 (0x00400UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000400 */ +#define ADC_AWD2CR_AWD2CH_11 (0x00800UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00000800 */ +#define ADC_AWD2CR_AWD2CH_12 (0x01000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00001000 */ +#define ADC_AWD2CR_AWD2CH_13 (0x02000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00002000 */ +#define ADC_AWD2CR_AWD2CH_14 (0x04000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00004000 */ +#define ADC_AWD2CR_AWD2CH_15 (0x08000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00008000 */ +#define ADC_AWD2CR_AWD2CH_16 (0x10000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00010000 */ +#define ADC_AWD2CR_AWD2CH_17 (0x20000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00020000 */ +#define ADC_AWD2CR_AWD2CH_18 (0x40000UL << ADC_AWD2CR_AWD2CH_Pos) /*!< 0x00040000 */ + +/******************** Bit definition for ADC_AWD3CR register ****************/ +#define ADC_AWD3CR_AWD3CH_Pos (0U) +#define ADC_AWD3CR_AWD3CH_Msk (0x7FFFFUL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x0007FFFF */ +#define ADC_AWD3CR_AWD3CH ADC_AWD3CR_AWD3CH_Msk /*!< ADC analog watchdog 3 monitored channel selection */ +#define ADC_AWD3CR_AWD3CH_0 (0x00001UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000001 */ +#define ADC_AWD3CR_AWD3CH_1 (0x00002UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000002 */ +#define ADC_AWD3CR_AWD3CH_2 (0x00004UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000004 */ +#define ADC_AWD3CR_AWD3CH_3 (0x00008UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000008 */ +#define ADC_AWD3CR_AWD3CH_4 (0x00010UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000010 */ +#define ADC_AWD3CR_AWD3CH_5 (0x00020UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000020 */ +#define ADC_AWD3CR_AWD3CH_6 (0x00040UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000040 */ +#define ADC_AWD3CR_AWD3CH_7 (0x00080UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000080 */ +#define ADC_AWD3CR_AWD3CH_8 (0x00100UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000100 */ +#define ADC_AWD3CR_AWD3CH_9 (0x00200UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000200 */ +#define ADC_AWD3CR_AWD3CH_10 (0x00400UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000400 */ +#define ADC_AWD3CR_AWD3CH_11 (0x00800UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00000800 */ +#define ADC_AWD3CR_AWD3CH_12 (0x01000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00001000 */ +#define ADC_AWD3CR_AWD3CH_13 (0x02000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00002000 */ +#define ADC_AWD3CR_AWD3CH_14 (0x04000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00004000 */ +#define ADC_AWD3CR_AWD3CH_15 (0x08000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00008000 */ +#define ADC_AWD3CR_AWD3CH_16 (0x10000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00010000 */ +#define ADC_AWD3CR_AWD3CH_17 (0x20000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00020000 */ +#define ADC_AWD3CR_AWD3CH_18 (0x40000UL << ADC_AWD3CR_AWD3CH_Pos) /*!< 0x00040000 */ + +/******************** Bit definition for ADC_DIFSEL register ****************/ +#define ADC_DIFSEL_DIFSEL_Pos (0U) +#define ADC_DIFSEL_DIFSEL_Msk (0x7FFFFUL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x0007FFFF */ +#define ADC_DIFSEL_DIFSEL ADC_DIFSEL_DIFSEL_Msk /*!< ADC channel differential or single-ended mode */ +#define ADC_DIFSEL_DIFSEL_0 (0x00001UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000001 */ +#define ADC_DIFSEL_DIFSEL_1 (0x00002UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000002 */ +#define ADC_DIFSEL_DIFSEL_2 (0x00004UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000004 */ +#define ADC_DIFSEL_DIFSEL_3 (0x00008UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000008 */ +#define ADC_DIFSEL_DIFSEL_4 (0x00010UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000010 */ +#define ADC_DIFSEL_DIFSEL_5 (0x00020UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000020 */ +#define ADC_DIFSEL_DIFSEL_6 (0x00040UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000040 */ +#define ADC_DIFSEL_DIFSEL_7 (0x00080UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000080 */ +#define ADC_DIFSEL_DIFSEL_8 (0x00100UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000100 */ +#define ADC_DIFSEL_DIFSEL_9 (0x00200UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000200 */ +#define ADC_DIFSEL_DIFSEL_10 (0x00400UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000400 */ +#define ADC_DIFSEL_DIFSEL_11 (0x00800UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00000800 */ +#define ADC_DIFSEL_DIFSEL_12 (0x01000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00001000 */ +#define ADC_DIFSEL_DIFSEL_13 (0x02000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00002000 */ +#define ADC_DIFSEL_DIFSEL_14 (0x04000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00004000 */ +#define ADC_DIFSEL_DIFSEL_15 (0x08000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00008000 */ +#define ADC_DIFSEL_DIFSEL_16 (0x10000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00010000 */ +#define ADC_DIFSEL_DIFSEL_17 (0x20000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00020000 */ +#define ADC_DIFSEL_DIFSEL_18 (0x40000UL << ADC_DIFSEL_DIFSEL_Pos) /*!< 0x00040000 */ + +/******************** Bit definition for ADC_CALFACT register ***************/ +#define ADC_CALFACT_CALFACT_S_Pos (0U) +#define ADC_CALFACT_CALFACT_S_Msk (0x7FUL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x0000007F */ +#define ADC_CALFACT_CALFACT_S ADC_CALFACT_CALFACT_S_Msk /*!< ADC calibration factor in single-ended mode */ +#define ADC_CALFACT_CALFACT_S_0 (0x01UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000001 */ +#define ADC_CALFACT_CALFACT_S_1 (0x02UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000002 */ +#define ADC_CALFACT_CALFACT_S_2 (0x04UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000004 */ +#define ADC_CALFACT_CALFACT_S_3 (0x08UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000008 */ +#define ADC_CALFACT_CALFACT_S_4 (0x10UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000010 */ +#define ADC_CALFACT_CALFACT_S_5 (0x20UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000020 */ +#define ADC_CALFACT_CALFACT_S_6 (0x40UL << ADC_CALFACT_CALFACT_S_Pos) /*!< 0x00000030 */ + +#define ADC_CALFACT_CALFACT_D_Pos (16U) +#define ADC_CALFACT_CALFACT_D_Msk (0x7FUL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x007F0000 */ +#define ADC_CALFACT_CALFACT_D ADC_CALFACT_CALFACT_D_Msk /*!< ADC calibration factor in differential mode */ +#define ADC_CALFACT_CALFACT_D_0 (0x01UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00010000 */ +#define ADC_CALFACT_CALFACT_D_1 (0x02UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00020000 */ +#define ADC_CALFACT_CALFACT_D_2 (0x04UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00040000 */ +#define ADC_CALFACT_CALFACT_D_3 (0x08UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00080000 */ +#define ADC_CALFACT_CALFACT_D_4 (0x10UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00100000 */ +#define ADC_CALFACT_CALFACT_D_5 (0x20UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00200000 */ +#define ADC_CALFACT_CALFACT_D_6 (0x40UL << ADC_CALFACT_CALFACT_D_Pos) /*!< 0x00300000 */ + +/******************** Bit definition for ADC_GCOMP register *****************/ +#define ADC_GCOMP_GCOMPCOEFF_Pos (0U) +#define ADC_GCOMP_GCOMPCOEFF_Msk (0x3FFFUL << ADC_GCOMP_GCOMPCOEFF_Pos) /*!< 0x00003FFF */ +#define ADC_GCOMP_GCOMPCOEFF ADC_GCOMP_GCOMPCOEFF_Msk /*!< ADC Gain Compensation Coefficient */ + +/************************* ADC Common registers *****************************/ +/******************** Bit definition for ADC_CSR register *******************/ +#define ADC_CSR_ADRDY_MST_Pos (0U) +#define ADC_CSR_ADRDY_MST_Msk (0x1UL << ADC_CSR_ADRDY_MST_Pos) /*!< 0x00000001 */ +#define ADC_CSR_ADRDY_MST ADC_CSR_ADRDY_MST_Msk /*!< ADC multimode master ready flag */ +#define ADC_CSR_EOSMP_MST_Pos (1U) +#define ADC_CSR_EOSMP_MST_Msk (0x1UL << ADC_CSR_EOSMP_MST_Pos) /*!< 0x00000002 */ +#define ADC_CSR_EOSMP_MST ADC_CSR_EOSMP_MST_Msk /*!< ADC multimode master group regular end of sampling flag */ +#define ADC_CSR_EOC_MST_Pos (2U) +#define ADC_CSR_EOC_MST_Msk (0x1UL << ADC_CSR_EOC_MST_Pos) /*!< 0x00000004 */ +#define ADC_CSR_EOC_MST ADC_CSR_EOC_MST_Msk /*!< ADC multimode master group regular end of unitary conversion flag */ +#define ADC_CSR_EOS_MST_Pos (3U) +#define ADC_CSR_EOS_MST_Msk (0x1UL << ADC_CSR_EOS_MST_Pos) /*!< 0x00000008 */ +#define ADC_CSR_EOS_MST ADC_CSR_EOS_MST_Msk /*!< ADC multimode master group regular end of sequence conversions flag */ +#define ADC_CSR_OVR_MST_Pos (4U) +#define ADC_CSR_OVR_MST_Msk (0x1UL << ADC_CSR_OVR_MST_Pos) /*!< 0x00000010 */ +#define ADC_CSR_OVR_MST ADC_CSR_OVR_MST_Msk /*!< ADC multimode master group regular overrun flag */ +#define ADC_CSR_JEOC_MST_Pos (5U) +#define ADC_CSR_JEOC_MST_Msk (0x1UL << ADC_CSR_JEOC_MST_Pos) /*!< 0x00000020 */ +#define ADC_CSR_JEOC_MST ADC_CSR_JEOC_MST_Msk /*!< ADC multimode master group injected end of unitary conversion flag */ +#define ADC_CSR_JEOS_MST_Pos (6U) +#define ADC_CSR_JEOS_MST_Msk (0x1UL << ADC_CSR_JEOS_MST_Pos) /*!< 0x00000040 */ +#define ADC_CSR_JEOS_MST ADC_CSR_JEOS_MST_Msk /*!< ADC multimode master group injected end of sequence conversions flag */ +#define ADC_CSR_AWD1_MST_Pos (7U) +#define ADC_CSR_AWD1_MST_Msk (0x1UL << ADC_CSR_AWD1_MST_Pos) /*!< 0x00000080 */ +#define ADC_CSR_AWD1_MST ADC_CSR_AWD1_MST_Msk /*!< ADC multimode master analog watchdog 1 flag */ +#define ADC_CSR_AWD2_MST_Pos (8U) +#define ADC_CSR_AWD2_MST_Msk (0x1UL << ADC_CSR_AWD2_MST_Pos) /*!< 0x00000100 */ +#define ADC_CSR_AWD2_MST ADC_CSR_AWD2_MST_Msk /*!< ADC multimode master analog watchdog 2 flag */ +#define ADC_CSR_AWD3_MST_Pos (9U) +#define ADC_CSR_AWD3_MST_Msk (0x1UL << ADC_CSR_AWD3_MST_Pos) /*!< 0x00000200 */ +#define ADC_CSR_AWD3_MST ADC_CSR_AWD3_MST_Msk /*!< ADC multimode master analog watchdog 3 flag */ +#define ADC_CSR_JQOVF_MST_Pos (10U) +#define ADC_CSR_JQOVF_MST_Msk (0x1UL << ADC_CSR_JQOVF_MST_Pos) /*!< 0x00000400 */ +#define ADC_CSR_JQOVF_MST ADC_CSR_JQOVF_MST_Msk /*!< ADC multimode master group injected contexts queue overflow flag */ + +#define ADC_CSR_ADRDY_SLV_Pos (16U) +#define ADC_CSR_ADRDY_SLV_Msk (0x1UL << ADC_CSR_ADRDY_SLV_Pos) /*!< 0x00010000 */ +#define ADC_CSR_ADRDY_SLV ADC_CSR_ADRDY_SLV_Msk /*!< ADC multimode slave ready flag */ +#define ADC_CSR_EOSMP_SLV_Pos (17U) +#define ADC_CSR_EOSMP_SLV_Msk (0x1UL << ADC_CSR_EOSMP_SLV_Pos) /*!< 0x00020000 */ +#define ADC_CSR_EOSMP_SLV ADC_CSR_EOSMP_SLV_Msk /*!< ADC multimode slave group regular end of sampling flag */ +#define ADC_CSR_EOC_SLV_Pos (18U) +#define ADC_CSR_EOC_SLV_Msk (0x1UL << ADC_CSR_EOC_SLV_Pos) /*!< 0x00040000 */ +#define ADC_CSR_EOC_SLV ADC_CSR_EOC_SLV_Msk /*!< ADC multimode slave group regular end of unitary conversion flag */ +#define ADC_CSR_EOS_SLV_Pos (19U) +#define ADC_CSR_EOS_SLV_Msk (0x1UL << ADC_CSR_EOS_SLV_Pos) /*!< 0x00080000 */ +#define ADC_CSR_EOS_SLV ADC_CSR_EOS_SLV_Msk /*!< ADC multimode slave group regular end of sequence conversions flag */ +#define ADC_CSR_OVR_SLV_Pos (20U) +#define ADC_CSR_OVR_SLV_Msk (0x1UL << ADC_CSR_OVR_SLV_Pos) /*!< 0x00100000 */ +#define ADC_CSR_OVR_SLV ADC_CSR_OVR_SLV_Msk /*!< ADC multimode slave group regular overrun flag */ +#define ADC_CSR_JEOC_SLV_Pos (21U) +#define ADC_CSR_JEOC_SLV_Msk (0x1UL << ADC_CSR_JEOC_SLV_Pos) /*!< 0x00200000 */ +#define ADC_CSR_JEOC_SLV ADC_CSR_JEOC_SLV_Msk /*!< ADC multimode slave group injected end of unitary conversion flag */ +#define ADC_CSR_JEOS_SLV_Pos (22U) +#define ADC_CSR_JEOS_SLV_Msk (0x1UL << ADC_CSR_JEOS_SLV_Pos) /*!< 0x00400000 */ +#define ADC_CSR_JEOS_SLV ADC_CSR_JEOS_SLV_Msk /*!< ADC multimode slave group injected end of sequence conversions flag */ +#define ADC_CSR_AWD1_SLV_Pos (23U) +#define ADC_CSR_AWD1_SLV_Msk (0x1UL << ADC_CSR_AWD1_SLV_Pos) /*!< 0x00800000 */ +#define ADC_CSR_AWD1_SLV ADC_CSR_AWD1_SLV_Msk /*!< ADC multimode slave analog watchdog 1 flag */ +#define ADC_CSR_AWD2_SLV_Pos (24U) +#define ADC_CSR_AWD2_SLV_Msk (0x1UL << ADC_CSR_AWD2_SLV_Pos) /*!< 0x01000000 */ +#define ADC_CSR_AWD2_SLV ADC_CSR_AWD2_SLV_Msk /*!< ADC multimode slave analog watchdog 2 flag */ +#define ADC_CSR_AWD3_SLV_Pos (25U) +#define ADC_CSR_AWD3_SLV_Msk (0x1UL << ADC_CSR_AWD3_SLV_Pos) /*!< 0x02000000 */ +#define ADC_CSR_AWD3_SLV ADC_CSR_AWD3_SLV_Msk /*!< ADC multimode slave analog watchdog 3 flag */ +#define ADC_CSR_JQOVF_SLV_Pos (26U) +#define ADC_CSR_JQOVF_SLV_Msk (0x1UL << ADC_CSR_JQOVF_SLV_Pos) /*!< 0x04000000 */ +#define ADC_CSR_JQOVF_SLV ADC_CSR_JQOVF_SLV_Msk /*!< ADC multimode slave group injected contexts queue overflow flag */ + +/******************** Bit definition for ADC_CCR register *******************/ +#define ADC_CCR_DUAL_Pos (0U) +#define ADC_CCR_DUAL_Msk (0x1FUL << ADC_CCR_DUAL_Pos) /*!< 0x0000001F */ +#define ADC_CCR_DUAL ADC_CCR_DUAL_Msk /*!< ADC multimode mode selection */ +#define ADC_CCR_DUAL_0 (0x01UL << ADC_CCR_DUAL_Pos) /*!< 0x00000001 */ +#define ADC_CCR_DUAL_1 (0x02UL << ADC_CCR_DUAL_Pos) /*!< 0x00000002 */ +#define ADC_CCR_DUAL_2 (0x04UL << ADC_CCR_DUAL_Pos) /*!< 0x00000004 */ +#define ADC_CCR_DUAL_3 (0x08UL << ADC_CCR_DUAL_Pos) /*!< 0x00000008 */ +#define ADC_CCR_DUAL_4 (0x10UL << ADC_CCR_DUAL_Pos) /*!< 0x00000010 */ + +#define ADC_CCR_DELAY_Pos (8U) +#define ADC_CCR_DELAY_Msk (0xFUL << ADC_CCR_DELAY_Pos) /*!< 0x00000F00 */ +#define ADC_CCR_DELAY ADC_CCR_DELAY_Msk /*!< ADC multimode delay between 2 sampling phases */ +#define ADC_CCR_DELAY_0 (0x1UL << ADC_CCR_DELAY_Pos) /*!< 0x00000100 */ +#define ADC_CCR_DELAY_1 (0x2UL << ADC_CCR_DELAY_Pos) /*!< 0x00000200 */ +#define ADC_CCR_DELAY_2 (0x4UL << ADC_CCR_DELAY_Pos) /*!< 0x00000400 */ +#define ADC_CCR_DELAY_3 (0x8UL << ADC_CCR_DELAY_Pos) /*!< 0x00000800 */ + +#define ADC_CCR_DMACFG_Pos (13U) +#define ADC_CCR_DMACFG_Msk (0x1UL << ADC_CCR_DMACFG_Pos) /*!< 0x00002000 */ +#define ADC_CCR_DMACFG ADC_CCR_DMACFG_Msk /*!< ADC multimode DMA transfer configuration */ + +#define ADC_CCR_MDMA_Pos (14U) +#define ADC_CCR_MDMA_Msk (0x3UL << ADC_CCR_MDMA_Pos) /*!< 0x0000C000 */ +#define ADC_CCR_MDMA ADC_CCR_MDMA_Msk /*!< ADC multimode DMA transfer enable */ +#define ADC_CCR_MDMA_0 (0x1UL << ADC_CCR_MDMA_Pos) /*!< 0x00004000 */ +#define ADC_CCR_MDMA_1 (0x2UL << ADC_CCR_MDMA_Pos) /*!< 0x00008000 */ + +#define ADC_CCR_CKMODE_Pos (16U) +#define ADC_CCR_CKMODE_Msk (0x3UL << ADC_CCR_CKMODE_Pos) /*!< 0x00030000 */ +#define ADC_CCR_CKMODE ADC_CCR_CKMODE_Msk /*!< ADC common clock source and prescaler (prescaler only for clock source synchronous) */ +#define ADC_CCR_CKMODE_0 (0x1UL << ADC_CCR_CKMODE_Pos) /*!< 0x00010000 */ +#define ADC_CCR_CKMODE_1 (0x2UL << ADC_CCR_CKMODE_Pos) /*!< 0x00020000 */ + +#define ADC_CCR_PRESC_Pos (18U) +#define ADC_CCR_PRESC_Msk (0xFUL << ADC_CCR_PRESC_Pos) /*!< 0x003C0000 */ +#define ADC_CCR_PRESC ADC_CCR_PRESC_Msk /*!< ADC common clock prescaler, only for clock source asynchronous */ +#define ADC_CCR_PRESC_0 (0x1UL << ADC_CCR_PRESC_Pos) /*!< 0x00040000 */ +#define ADC_CCR_PRESC_1 (0x2UL << ADC_CCR_PRESC_Pos) /*!< 0x00080000 */ +#define ADC_CCR_PRESC_2 (0x4UL << ADC_CCR_PRESC_Pos) /*!< 0x00100000 */ +#define ADC_CCR_PRESC_3 (0x8UL << ADC_CCR_PRESC_Pos) /*!< 0x00200000 */ + +#define ADC_CCR_VREFEN_Pos (22U) +#define ADC_CCR_VREFEN_Msk (0x1UL << ADC_CCR_VREFEN_Pos) /*!< 0x00400000 */ +#define ADC_CCR_VREFEN ADC_CCR_VREFEN_Msk /*!< ADC internal path to VrefInt enable */ +#define ADC_CCR_VSENSESEL_Pos (23U) +#define ADC_CCR_VSENSESEL_Msk (0x1UL << ADC_CCR_VSENSESEL_Pos) /*!< 0x00800000 */ +#define ADC_CCR_VSENSESEL ADC_CCR_VSENSESEL_Msk /*!< ADC internal path to temperature sensor enable */ +#define ADC_CCR_VBATSEL_Pos (24U) +#define ADC_CCR_VBATSEL_Msk (0x1UL << ADC_CCR_VBATSEL_Pos) /*!< 0x01000000 */ +#define ADC_CCR_VBATSEL ADC_CCR_VBATSEL_Msk /*!< ADC internal path to battery voltage enable */ + +/******************** Bit definition for ADC_CDR register *******************/ +#define ADC_CDR_RDATA_MST_Pos (0U) +#define ADC_CDR_RDATA_MST_Msk (0xFFFFUL << ADC_CDR_RDATA_MST_Pos) /*!< 0x0000FFFF */ +#define ADC_CDR_RDATA_MST ADC_CDR_RDATA_MST_Msk /*!< ADC multimode master group regular conversion data */ + +#define ADC_CDR_RDATA_SLV_Pos (16U) +#define ADC_CDR_RDATA_SLV_Msk (0xFFFFUL << ADC_CDR_RDATA_SLV_Pos) /*!< 0xFFFF0000 */ +#define ADC_CDR_RDATA_SLV ADC_CDR_RDATA_SLV_Msk /*!< ADC multimode slave group regular conversion data */ + + +/******************************************************************************/ +/* */ +/* Analog Comparators (COMP) */ +/* */ +/******************************************************************************/ +/********************** Bit definition for COMP_CSR register ****************/ +#define COMP_CSR_EN_Pos (0U) +#define COMP_CSR_EN_Msk (0x1UL << COMP_CSR_EN_Pos) /*!< 0x00000001 */ +#define COMP_CSR_EN COMP_CSR_EN_Msk /*!< Comparator enable */ + +#define COMP_CSR_INMSEL_Pos (4U) +#define COMP_CSR_INMSEL_Msk (0xFUL << COMP_CSR_INMSEL_Pos) /*!< 0x00000070 */ +#define COMP_CSR_INMSEL COMP_CSR_INMSEL_Msk /*!< Comparator input minus selection */ +#define COMP_CSR_INMSEL_0 (0x1UL << COMP_CSR_INMSEL_Pos) /*!< 0x00000010 */ +#define COMP_CSR_INMSEL_1 (0x2UL << COMP_CSR_INMSEL_Pos) /*!< 0x00000020 */ +#define COMP_CSR_INMSEL_2 (0x4UL << COMP_CSR_INMSEL_Pos) /*!< 0x00000040 */ +#define COMP_CSR_INMSEL_3 (0x8UL << COMP_CSR_INMSEL_Pos) /*!< 0x00000080 */ + +#define COMP_CSR_INPSEL_Pos (8U) +#define COMP_CSR_INPSEL_Msk (0x1UL << COMP_CSR_INPSEL_Pos) /*!< 0x00000100 */ +#define COMP_CSR_INPSEL COMP_CSR_INPSEL_Msk /*!< Comparator input plus selection */ + +#define COMP_CSR_POLARITY_Pos (15U) +#define COMP_CSR_POLARITY_Msk (0x1UL << COMP_CSR_POLARITY_Pos) /*!< 0x00008000 */ +#define COMP_CSR_POLARITY COMP_CSR_POLARITY_Msk /*!< Comparator output polarity */ + +#define COMP_CSR_HYST_Pos (16U) +#define COMP_CSR_HYST_Msk (0x7UL << COMP_CSR_HYST_Pos) /*!< 0x00070000 */ +#define COMP_CSR_HYST COMP_CSR_HYST_Msk /*!< Comparator hysteresis */ +#define COMP_CSR_HYST_0 (0x1UL << COMP_CSR_HYST_Pos) /*!< 0x00010000 */ +#define COMP_CSR_HYST_1 (0x2UL << COMP_CSR_HYST_Pos) /*!< 0x00020000 */ +#define COMP_CSR_HYST_2 (0x4UL << COMP_CSR_HYST_Pos) /*!< 0x00040000 */ + +#define COMP_CSR_BLANKING_Pos (19U) +#define COMP_CSR_BLANKING_Msk (0x7UL << COMP_CSR_BLANKING_Pos) /*!< 0x00380000 */ +#define COMP_CSR_BLANKING COMP_CSR_BLANKING_Msk /*!< Comparator blanking source */ +#define COMP_CSR_BLANKING_0 (0x1UL << COMP_CSR_BLANKING_Pos) /*!< 0x00080000 */ +#define COMP_CSR_BLANKING_1 (0x2UL << COMP_CSR_BLANKING_Pos) /*!< 0x00100000 */ +#define COMP_CSR_BLANKING_2 (0x4UL << COMP_CSR_BLANKING_Pos) /*!< 0x00200000 */ + +#define COMP_CSR_BRGEN_Pos (22U) +#define COMP_CSR_BRGEN_Msk (0x1UL << COMP_CSR_BRGEN_Pos) /*!< 0x00400000 */ +#define COMP_CSR_BRGEN COMP_CSR_BRGEN_Msk /*!< Comparator scaler bridge enable */ + +#define COMP_CSR_SCALEN_Pos (23U) +#define COMP_CSR_SCALEN_Msk (0x1UL << COMP_CSR_SCALEN_Pos) /*!< 0x00800000 */ +#define COMP_CSR_SCALEN COMP_CSR_SCALEN_Msk /*!< Comparator voltage scaler enable */ + +#define COMP_CSR_VALUE_Pos (30U) +#define COMP_CSR_VALUE_Msk (0x1UL << COMP_CSR_VALUE_Pos) /*!< 0x40000000 */ +#define COMP_CSR_VALUE COMP_CSR_VALUE_Msk /*!< Comparator output level */ + +#define COMP_CSR_LOCK_Pos (31U) +#define COMP_CSR_LOCK_Msk (0x1UL << COMP_CSR_LOCK_Pos) /*!< 0x80000000 */ +#define COMP_CSR_LOCK COMP_CSR_LOCK_Msk /*!< Comparator lock */ + +/******************************************************************************/ +/* */ +/* CORDIC calculation unit */ +/* */ +/******************************************************************************/ +/******************* Bit definition for CORDIC_CSR register *****************/ +#define CORDIC_CSR_FUNC_Pos (0U) +#define CORDIC_CSR_FUNC_Msk (0xFUL << CORDIC_CSR_FUNC_Pos) /*!< 0x0000000F */ +#define CORDIC_CSR_FUNC CORDIC_CSR_FUNC_Msk /*!< Function */ +#define CORDIC_CSR_FUNC_0 (0x1UL << CORDIC_CSR_FUNC_Pos) /*!< 0x00000001 */ +#define CORDIC_CSR_FUNC_1 (0x2UL << CORDIC_CSR_FUNC_Pos) /*!< 0x00000002 */ +#define CORDIC_CSR_FUNC_2 (0x4UL << CORDIC_CSR_FUNC_Pos) /*!< 0x00000004 */ +#define CORDIC_CSR_FUNC_3 (0x8UL << CORDIC_CSR_FUNC_Pos) /*!< 0x00000008 */ +#define CORDIC_CSR_PRECISION_Pos (4U) +#define CORDIC_CSR_PRECISION_Msk (0xFUL << CORDIC_CSR_PRECISION_Pos) /*!< 0x000000F0 */ +#define CORDIC_CSR_PRECISION CORDIC_CSR_PRECISION_Msk /*!< Precision */ +#define CORDIC_CSR_PRECISION_0 (0x1UL << CORDIC_CSR_PRECISION_Pos) /*!< 0x00000010 */ +#define CORDIC_CSR_PRECISION_1 (0x2UL << CORDIC_CSR_PRECISION_Pos) /*!< 0x00000020 */ +#define CORDIC_CSR_PRECISION_2 (0x4UL << CORDIC_CSR_PRECISION_Pos) /*!< 0x00000040 */ +#define CORDIC_CSR_PRECISION_3 (0x8UL << CORDIC_CSR_PRECISION_Pos) /*!< 0x00000080 */ +#define CORDIC_CSR_SCALE_Pos (8U) +#define CORDIC_CSR_SCALE_Msk (0x7UL << CORDIC_CSR_SCALE_Pos) /*!< 0x00000700 */ +#define CORDIC_CSR_SCALE CORDIC_CSR_SCALE_Msk /*!< Scaling factor */ +#define CORDIC_CSR_SCALE_0 (0x1UL << CORDIC_CSR_SCALE_Pos) /*!< 0x00000100 */ +#define CORDIC_CSR_SCALE_1 (0x2UL << CORDIC_CSR_SCALE_Pos) /*!< 0x00000200 */ +#define CORDIC_CSR_SCALE_2 (0x4UL << CORDIC_CSR_SCALE_Pos) /*!< 0x00000400 */ +#define CORDIC_CSR_IEN_Pos (16U) +#define CORDIC_CSR_IEN_Msk (0x1UL << CORDIC_CSR_IEN_Pos) /*!< 0x00010000 */ +#define CORDIC_CSR_IEN CORDIC_CSR_IEN_Msk /*!< Interrupt Enable */ +#define CORDIC_CSR_DMAREN_Pos (17U) +#define CORDIC_CSR_DMAREN_Msk (0x1UL << CORDIC_CSR_DMAREN_Pos) /*!< 0x00020000 */ +#define CORDIC_CSR_DMAREN CORDIC_CSR_DMAREN_Msk /*!< DMA Read channel Enable */ +#define CORDIC_CSR_DMAWEN_Pos (18U) +#define CORDIC_CSR_DMAWEN_Msk (0x1UL << CORDIC_CSR_DMAWEN_Pos) /*!< 0x00040000 */ +#define CORDIC_CSR_DMAWEN CORDIC_CSR_DMAWEN_Msk /*!< DMA Write channel Enable */ +#define CORDIC_CSR_NRES_Pos (19U) +#define CORDIC_CSR_NRES_Msk (0x1UL << CORDIC_CSR_NRES_Pos) /*!< 0x00080000 */ +#define CORDIC_CSR_NRES CORDIC_CSR_NRES_Msk /*!< Number of results in WDATA register */ +#define CORDIC_CSR_NARGS_Pos (20U) +#define CORDIC_CSR_NARGS_Msk (0x1UL << CORDIC_CSR_NARGS_Pos) /*!< 0x00100000 */ +#define CORDIC_CSR_NARGS CORDIC_CSR_NARGS_Msk /*!< Number of arguments in RDATA register */ +#define CORDIC_CSR_RESSIZE_Pos (21U) +#define CORDIC_CSR_RESSIZE_Msk (0x1UL << CORDIC_CSR_RESSIZE_Pos) /*!< 0x00200000 */ +#define CORDIC_CSR_RESSIZE CORDIC_CSR_RESSIZE_Msk /*!< Width of output data */ +#define CORDIC_CSR_ARGSIZE_Pos (22U) +#define CORDIC_CSR_ARGSIZE_Msk (0x1UL << CORDIC_CSR_ARGSIZE_Pos) /*!< 0x00400000 */ +#define CORDIC_CSR_ARGSIZE CORDIC_CSR_ARGSIZE_Msk /*!< Width of input data */ +#define CORDIC_CSR_RRDY_Pos (31U) +#define CORDIC_CSR_RRDY_Msk (0x1UL << CORDIC_CSR_RRDY_Pos) /*!< 0x80000000 */ +#define CORDIC_CSR_RRDY CORDIC_CSR_RRDY_Msk /*!< Result Ready Flag */ + +/******************* Bit definition for CORDIC_WDATA register ***************/ +#define CORDIC_WDATA_ARG_Pos (0U) +#define CORDIC_WDATA_ARG_Msk (0xFFFFFFFFUL << CORDIC_WDATA_ARG_Pos) /*!< 0xFFFFFFFF */ +#define CORDIC_WDATA_ARG CORDIC_WDATA_ARG_Msk /*!< Input Argument */ + +/******************* Bit definition for CORDIC_RDATA register ***************/ +#define CORDIC_RDATA_RES_Pos (0U) +#define CORDIC_RDATA_RES_Msk (0xFFFFFFFFUL << CORDIC_RDATA_RES_Pos) /*!< 0xFFFFFFFF */ +#define CORDIC_RDATA_RES CORDIC_RDATA_RES_Msk /*!< Output Result */ + +/******************************************************************************/ +/* */ +/* CRC calculation unit */ +/* */ +/******************************************************************************/ +/******************* Bit definition for CRC_DR register *********************/ +#define CRC_DR_DR_Pos (0U) +#define CRC_DR_DR_Msk (0xFFFFFFFFUL << CRC_DR_DR_Pos) /*!< 0xFFFFFFFF */ +#define CRC_DR_DR CRC_DR_DR_Msk /*!< Data register bits */ + +/******************* Bit definition for CRC_IDR register ********************/ +#define CRC_IDR_IDR_Pos (0U) +#define CRC_IDR_IDR_Msk (0xFFFFFFFFUL << CRC_IDR_IDR_Pos) /*!< 0xFFFFFFFF */ +#define CRC_IDR_IDR CRC_IDR_IDR_Msk /*!< General-purpose 32-bit data register bits */ + +/******************** Bit definition for CRC_CR register ********************/ +#define CRC_CR_RESET_Pos (0U) +#define CRC_CR_RESET_Msk (0x1UL << CRC_CR_RESET_Pos) /*!< 0x00000001 */ +#define CRC_CR_RESET CRC_CR_RESET_Msk /*!< RESET the CRC computation unit bit */ +#define CRC_CR_POLYSIZE_Pos (3U) +#define CRC_CR_POLYSIZE_Msk (0x3UL << CRC_CR_POLYSIZE_Pos) /*!< 0x00000018 */ +#define CRC_CR_POLYSIZE CRC_CR_POLYSIZE_Msk /*!< Polynomial size bits */ +#define CRC_CR_POLYSIZE_0 (0x1UL << CRC_CR_POLYSIZE_Pos) /*!< 0x00000008 */ +#define CRC_CR_POLYSIZE_1 (0x2UL << CRC_CR_POLYSIZE_Pos) /*!< 0x00000010 */ +#define CRC_CR_REV_IN_Pos (5U) +#define CRC_CR_REV_IN_Msk (0x3UL << CRC_CR_REV_IN_Pos) /*!< 0x00000060 */ +#define CRC_CR_REV_IN CRC_CR_REV_IN_Msk /*!< REV_IN Reverse Input Data bits */ +#define CRC_CR_REV_IN_0 (0x1UL << CRC_CR_REV_IN_Pos) /*!< 0x00000020 */ +#define CRC_CR_REV_IN_1 (0x2UL << CRC_CR_REV_IN_Pos) /*!< 0x00000040 */ +#define CRC_CR_REV_OUT_Pos (7U) +#define CRC_CR_REV_OUT_Msk (0x1UL << CRC_CR_REV_OUT_Pos) /*!< 0x00000080 */ +#define CRC_CR_REV_OUT CRC_CR_REV_OUT_Msk /*!< REV_OUT Reverse Output Data bits */ + +/******************* Bit definition for CRC_INIT register *******************/ +#define CRC_INIT_INIT_Pos (0U) +#define CRC_INIT_INIT_Msk (0xFFFFFFFFUL << CRC_INIT_INIT_Pos) /*!< 0xFFFFFFFF */ +#define CRC_INIT_INIT CRC_INIT_INIT_Msk /*!< Initial CRC value bits */ + +/******************* Bit definition for CRC_POL register ********************/ +#define CRC_POL_POL_Pos (0U) +#define CRC_POL_POL_Msk (0xFFFFFFFFUL << CRC_POL_POL_Pos) /*!< 0xFFFFFFFF */ +#define CRC_POL_POL CRC_POL_POL_Msk /*!< Coefficients of the polynomial */ + +/******************************************************************************/ +/* */ +/* CRS Clock Recovery System */ +/******************************************************************************/ + +/******************* Bit definition for CRS_CR register *********************/ +#define CRS_CR_SYNCOKIE_Pos (0U) +#define CRS_CR_SYNCOKIE_Msk (0x1UL << CRS_CR_SYNCOKIE_Pos) /*!< 0x00000001 */ +#define CRS_CR_SYNCOKIE CRS_CR_SYNCOKIE_Msk /*!< SYNC event OK interrupt enable */ +#define CRS_CR_SYNCWARNIE_Pos (1U) +#define CRS_CR_SYNCWARNIE_Msk (0x1UL << CRS_CR_SYNCWARNIE_Pos) /*!< 0x00000002 */ +#define CRS_CR_SYNCWARNIE CRS_CR_SYNCWARNIE_Msk /*!< SYNC warning interrupt enable */ +#define CRS_CR_ERRIE_Pos (2U) +#define CRS_CR_ERRIE_Msk (0x1UL << CRS_CR_ERRIE_Pos) /*!< 0x00000004 */ +#define CRS_CR_ERRIE CRS_CR_ERRIE_Msk /*!< SYNC error or trimming error interrupt enable */ +#define CRS_CR_ESYNCIE_Pos (3U) +#define CRS_CR_ESYNCIE_Msk (0x1UL << CRS_CR_ESYNCIE_Pos) /*!< 0x00000008 */ +#define CRS_CR_ESYNCIE CRS_CR_ESYNCIE_Msk /*!< Expected SYNC interrupt enable */ +#define CRS_CR_CEN_Pos (5U) +#define CRS_CR_CEN_Msk (0x1UL << CRS_CR_CEN_Pos) /*!< 0x00000020 */ +#define CRS_CR_CEN CRS_CR_CEN_Msk /*!< Frequency error counter enable */ +#define CRS_CR_AUTOTRIMEN_Pos (6U) +#define CRS_CR_AUTOTRIMEN_Msk (0x1UL << CRS_CR_AUTOTRIMEN_Pos) /*!< 0x00000040 */ +#define CRS_CR_AUTOTRIMEN CRS_CR_AUTOTRIMEN_Msk /*!< Automatic trimming enable */ +#define CRS_CR_SWSYNC_Pos (7U) +#define CRS_CR_SWSYNC_Msk (0x1UL << CRS_CR_SWSYNC_Pos) /*!< 0x00000080 */ +#define CRS_CR_SWSYNC CRS_CR_SWSYNC_Msk /*!< Generate software SYNC event */ +#define CRS_CR_TRIM_Pos (8U) +#define CRS_CR_TRIM_Msk (0x7FUL << CRS_CR_TRIM_Pos) /*!< 0x00007F00 */ +#define CRS_CR_TRIM CRS_CR_TRIM_Msk /*!< HSI48 oscillator smooth trimming */ + +/******************* Bit definition for CRS_CFGR register *********************/ +#define CRS_CFGR_RELOAD_Pos (0U) +#define CRS_CFGR_RELOAD_Msk (0xFFFFUL << CRS_CFGR_RELOAD_Pos) /*!< 0x0000FFFF */ +#define CRS_CFGR_RELOAD CRS_CFGR_RELOAD_Msk /*!< Counter reload value */ +#define CRS_CFGR_FELIM_Pos (16U) +#define CRS_CFGR_FELIM_Msk (0xFFUL << CRS_CFGR_FELIM_Pos) /*!< 0x00FF0000 */ +#define CRS_CFGR_FELIM CRS_CFGR_FELIM_Msk /*!< Frequency error limit */ + +#define CRS_CFGR_SYNCDIV_Pos (24U) +#define CRS_CFGR_SYNCDIV_Msk (0x7UL << CRS_CFGR_SYNCDIV_Pos) /*!< 0x07000000 */ +#define CRS_CFGR_SYNCDIV CRS_CFGR_SYNCDIV_Msk /*!< SYNC divider */ +#define CRS_CFGR_SYNCDIV_0 (0x1UL << CRS_CFGR_SYNCDIV_Pos) /*!< 0x01000000 */ +#define CRS_CFGR_SYNCDIV_1 (0x2UL << CRS_CFGR_SYNCDIV_Pos) /*!< 0x02000000 */ +#define CRS_CFGR_SYNCDIV_2 (0x4UL << CRS_CFGR_SYNCDIV_Pos) /*!< 0x04000000 */ + +#define CRS_CFGR_SYNCSRC_Pos (28U) +#define CRS_CFGR_SYNCSRC_Msk (0x3UL << CRS_CFGR_SYNCSRC_Pos) /*!< 0x30000000 */ +#define CRS_CFGR_SYNCSRC CRS_CFGR_SYNCSRC_Msk /*!< SYNC signal source selection */ +#define CRS_CFGR_SYNCSRC_0 (0x1UL << CRS_CFGR_SYNCSRC_Pos) /*!< 0x10000000 */ +#define CRS_CFGR_SYNCSRC_1 (0x2UL << CRS_CFGR_SYNCSRC_Pos) /*!< 0x20000000 */ + +#define CRS_CFGR_SYNCPOL_Pos (31U) +#define CRS_CFGR_SYNCPOL_Msk (0x1UL << CRS_CFGR_SYNCPOL_Pos) /*!< 0x80000000 */ +#define CRS_CFGR_SYNCPOL CRS_CFGR_SYNCPOL_Msk /*!< SYNC polarity selection */ + +/******************* Bit definition for CRS_ISR register *********************/ +#define CRS_ISR_SYNCOKF_Pos (0U) +#define CRS_ISR_SYNCOKF_Msk (0x1UL << CRS_ISR_SYNCOKF_Pos) /*!< 0x00000001 */ +#define CRS_ISR_SYNCOKF CRS_ISR_SYNCOKF_Msk /*!< SYNC event OK flag */ +#define CRS_ISR_SYNCWARNF_Pos (1U) +#define CRS_ISR_SYNCWARNF_Msk (0x1UL << CRS_ISR_SYNCWARNF_Pos) /*!< 0x00000002 */ +#define CRS_ISR_SYNCWARNF CRS_ISR_SYNCWARNF_Msk /*!< SYNC warning flag */ +#define CRS_ISR_ERRF_Pos (2U) +#define CRS_ISR_ERRF_Msk (0x1UL << CRS_ISR_ERRF_Pos) /*!< 0x00000004 */ +#define CRS_ISR_ERRF CRS_ISR_ERRF_Msk /*!< Error flag */ +#define CRS_ISR_ESYNCF_Pos (3U) +#define CRS_ISR_ESYNCF_Msk (0x1UL << CRS_ISR_ESYNCF_Pos) /*!< 0x00000008 */ +#define CRS_ISR_ESYNCF CRS_ISR_ESYNCF_Msk /*!< Expected SYNC flag */ +#define CRS_ISR_SYNCERR_Pos (8U) +#define CRS_ISR_SYNCERR_Msk (0x1UL << CRS_ISR_SYNCERR_Pos) /*!< 0x00000100 */ +#define CRS_ISR_SYNCERR CRS_ISR_SYNCERR_Msk /*!< SYNC error */ +#define CRS_ISR_SYNCMISS_Pos (9U) +#define CRS_ISR_SYNCMISS_Msk (0x1UL << CRS_ISR_SYNCMISS_Pos) /*!< 0x00000200 */ +#define CRS_ISR_SYNCMISS CRS_ISR_SYNCMISS_Msk /*!< SYNC missed */ +#define CRS_ISR_TRIMOVF_Pos (10U) +#define CRS_ISR_TRIMOVF_Msk (0x1UL << CRS_ISR_TRIMOVF_Pos) /*!< 0x00000400 */ +#define CRS_ISR_TRIMOVF CRS_ISR_TRIMOVF_Msk /*!< Trimming overflow or underflow */ +#define CRS_ISR_FEDIR_Pos (15U) +#define CRS_ISR_FEDIR_Msk (0x1UL << CRS_ISR_FEDIR_Pos) /*!< 0x00008000 */ +#define CRS_ISR_FEDIR CRS_ISR_FEDIR_Msk /*!< Frequency error direction */ +#define CRS_ISR_FECAP_Pos (16U) +#define CRS_ISR_FECAP_Msk (0xFFFFUL << CRS_ISR_FECAP_Pos) /*!< 0xFFFF0000 */ +#define CRS_ISR_FECAP CRS_ISR_FECAP_Msk /*!< Frequency error capture */ + +/******************* Bit definition for CRS_ICR register *********************/ +#define CRS_ICR_SYNCOKC_Pos (0U) +#define CRS_ICR_SYNCOKC_Msk (0x1UL << CRS_ICR_SYNCOKC_Pos) /*!< 0x00000001 */ +#define CRS_ICR_SYNCOKC CRS_ICR_SYNCOKC_Msk /*!< SYNC event OK clear flag */ +#define CRS_ICR_SYNCWARNC_Pos (1U) +#define CRS_ICR_SYNCWARNC_Msk (0x1UL << CRS_ICR_SYNCWARNC_Pos) /*!< 0x00000002 */ +#define CRS_ICR_SYNCWARNC CRS_ICR_SYNCWARNC_Msk /*!< SYNC warning clear flag */ +#define CRS_ICR_ERRC_Pos (2U) +#define CRS_ICR_ERRC_Msk (0x1UL << CRS_ICR_ERRC_Pos) /*!< 0x00000004 */ +#define CRS_ICR_ERRC CRS_ICR_ERRC_Msk /*!< Error clear flag */ +#define CRS_ICR_ESYNCC_Pos (3U) +#define CRS_ICR_ESYNCC_Msk (0x1UL << CRS_ICR_ESYNCC_Pos) /*!< 0x00000008 */ +#define CRS_ICR_ESYNCC CRS_ICR_ESYNCC_Msk /*!< Expected SYNC clear flag */ + +/******************************************************************************/ +/* */ +/* Digital to Analog Converter */ +/* */ +/******************************************************************************/ +/* + * @brief Specific device feature definitions (not present on all devices in the STM32G4 series) + */ +#define DAC_CHANNEL2_SUPPORT /*!< DAC feature available only on specific devices: DAC channel 2 available */ + +/******************** Bit definition for DAC_CR register ********************/ +#define DAC_CR_EN1_Pos (0U) +#define DAC_CR_EN1_Msk (0x1UL << DAC_CR_EN1_Pos) /*!< 0x00000001 */ +#define DAC_CR_EN1 DAC_CR_EN1_Msk /*!*/ +#define DAC_CR_CEN1_Pos (14U) +#define DAC_CR_CEN1_Msk (0x1UL << DAC_CR_CEN1_Pos) /*!< 0x00004000 */ +#define DAC_CR_CEN1 DAC_CR_CEN1_Msk /*!*/ + +#define DAC_CR_HFSEL_Pos (15U) +#define DAC_CR_HFSEL_Msk (0x1UL << DAC_CR_HFSEL_Pos) /*!< 0x00008000 */ +#define DAC_CR_HFSEL DAC_CR_HFSEL_Msk /*!*/ + +#define DAC_CR_EN2_Pos (16U) +#define DAC_CR_EN2_Msk (0x1UL << DAC_CR_EN2_Pos) /*!< 0x00010000 */ +#define DAC_CR_EN2 DAC_CR_EN2_Msk /*!*/ +#define DAC_CR_CEN2_Pos (30U) +#define DAC_CR_CEN2_Msk (0x1UL << DAC_CR_CEN2_Pos) /*!< 0x40000000 */ +#define DAC_CR_CEN2 DAC_CR_CEN2_Msk /*!*/ + +/***************** Bit definition for DAC_SWTRIGR register ******************/ +#define DAC_SWTRIGR_SWTRIG1_Pos (0U) +#define DAC_SWTRIGR_SWTRIG1_Msk (0x1UL << DAC_SWTRIGR_SWTRIG1_Pos) /*!< 0x00000001 */ +#define DAC_SWTRIGR_SWTRIG1 DAC_SWTRIGR_SWTRIG1_Msk /*! */ + +/******************* Bit definition for HRTIM_CPT2R register ****************/ +#define HRTIM_CPT2R_CPT2R_Pos (0U) +#define HRTIM_CPT2R_CPT2R_Msk (0x0000FFFFUL << HRTIM_CPT2R_CPT2R_Pos) /*!< 0x0000FFFF */ +#define HRTIM_CPT2R_CPT2R HRTIM_CPT2R_CPT2R_Msk /*!< Capture 2 Value */ +#define HRTIM_CPT2R_DIR_Pos (16U) +#define HRTIM_CPT2R_DIR_Msk (0x1UL << HRTIM_CPT2R_DIR_Pos) /*!< 0x00010000 */ +#define HRTIM_CPT2R_DIR HRTIM_CPT2R_DIR_Msk /*!< Capture 2 direction */ + +/******************** Bit definition for Slave Deadtime register **************/ +#define HRTIM_DTR_DTR_Pos (0U) +#define HRTIM_DTR_DTR_Msk (0x1FFUL << HRTIM_DTR_DTR_Pos) /*!< 0x000001FF */ +#define HRTIM_DTR_DTR HRTIM_DTR_DTR_Msk /*!< Dead time rising value */ +#define HRTIM_DTR_DTR_0 (0x001UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000001 */ +#define HRTIM_DTR_DTR_1 (0x002UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000002 */ +#define HRTIM_DTR_DTR_2 (0x004UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000004 */ +#define HRTIM_DTR_DTR_3 (0x008UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000008 */ +#define HRTIM_DTR_DTR_4 (0x010UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000010 */ +#define HRTIM_DTR_DTR_5 (0x020UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000020 */ +#define HRTIM_DTR_DTR_6 (0x040UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000040 */ +#define HRTIM_DTR_DTR_7 (0x080UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000080 */ +#define HRTIM_DTR_DTR_8 (0x100UL << HRTIM_DTR_DTR_Pos) /*!< 0x00000100 */ +#define HRTIM_DTR_SDTR_Pos (9U) +#define HRTIM_DTR_SDTR_Msk (0x1UL << HRTIM_DTR_SDTR_Pos) /*!< 0x00000200 */ +#define HRTIM_DTR_SDTR HRTIM_DTR_SDTR_Msk /*!< Sign dead time rising value */ +#define HRTIM_DTR_DTPRSC_Pos (10U) +#define HRTIM_DTR_DTPRSC_Msk (0x7UL << HRTIM_DTR_DTPRSC_Pos) /*!< 0x00001C00 */ +#define HRTIM_DTR_DTPRSC HRTIM_DTR_DTPRSC_Msk /*!< Dead time prescaler */ +#define HRTIM_DTR_DTPRSC_0 (0x1UL << HRTIM_DTR_DTPRSC_Pos) /*!< 0x00000400 */ +#define HRTIM_DTR_DTPRSC_1 (0x2UL << HRTIM_DTR_DTPRSC_Pos) /*!< 0x00000800 */ +#define HRTIM_DTR_DTPRSC_2 (0x4UL << HRTIM_DTR_DTPRSC_Pos) /*!< 0x00001000 */ +#define HRTIM_DTR_DTRSLK_Pos (14U) +#define HRTIM_DTR_DTRSLK_Msk (0x1UL << HRTIM_DTR_DTRSLK_Pos) /*!< 0x00004000 */ +#define HRTIM_DTR_DTRSLK HRTIM_DTR_DTRSLK_Msk /*!< Dead time rising sign lock */ +#define HRTIM_DTR_DTRLK_Pos (15U) +#define HRTIM_DTR_DTRLK_Msk (0x1UL << HRTIM_DTR_DTRLK_Pos) /*!< 0x00008000 */ +#define HRTIM_DTR_DTRLK HRTIM_DTR_DTRLK_Msk /*!< Dead time rising lock */ +#define HRTIM_DTR_DTF_Pos (16U) +#define HRTIM_DTR_DTF_Msk (0x1FFUL << HRTIM_DTR_DTF_Pos) /*!< 0x01FF0000 */ +#define HRTIM_DTR_DTF HRTIM_DTR_DTF_Msk /*!< Dead time falling value */ +#define HRTIM_DTR_DTF_0 (0x001UL << HRTIM_DTR_DTF_Pos) /*!< 0x00010000 */ +#define HRTIM_DTR_DTF_1 (0x002UL << HRTIM_DTR_DTF_Pos) /*!< 0x00020000 */ +#define HRTIM_DTR_DTF_2 (0x004UL << HRTIM_DTR_DTF_Pos) /*!< 0x00040000 */ +#define HRTIM_DTR_DTF_3 (0x008UL << HRTIM_DTR_DTF_Pos) /*!< 0x00080000 */ +#define HRTIM_DTR_DTF_4 (0x010UL << HRTIM_DTR_DTF_Pos) /*!< 0x00100000 */ +#define HRTIM_DTR_DTF_5 (0x020UL << HRTIM_DTR_DTF_Pos) /*!< 0x00200000 */ +#define HRTIM_DTR_DTF_6 (0x040UL << HRTIM_DTR_DTF_Pos) /*!< 0x00400000 */ +#define HRTIM_DTR_DTF_7 (0x080UL << HRTIM_DTR_DTF_Pos) /*!< 0x00800000 */ +#define HRTIM_DTR_DTF_8 (0x100UL << HRTIM_DTR_DTF_Pos) /*!< 0x01000000 */ +#define HRTIM_DTR_SDTF_Pos (25U) +#define HRTIM_DTR_SDTF_Msk (0x1UL << HRTIM_DTR_SDTF_Pos) /*!< 0x02000000 */ +#define HRTIM_DTR_SDTF HRTIM_DTR_SDTF_Msk /*!< Sign dead time falling value */ +#define HRTIM_DTR_DTFSLK_Pos (30U) +#define HRTIM_DTR_DTFSLK_Msk (0x1UL << HRTIM_DTR_DTFSLK_Pos) /*!< 0x40000000 */ +#define HRTIM_DTR_DTFSLK HRTIM_DTR_DTFSLK_Msk /*!< Dead time falling sign lock */ +#define HRTIM_DTR_DTFLK_Pos (31U) +#define HRTIM_DTR_DTFLK_Msk (0x1UL << HRTIM_DTR_DTFLK_Pos) /*!< 0x80000000 */ +#define HRTIM_DTR_DTFLK HRTIM_DTR_DTFLK_Msk /*!< Dead time falling lock */ + +/**** Bit definition for Slave Output 1 set register **************************/ +#define HRTIM_SET1R_SST_Pos (0U) +#define HRTIM_SET1R_SST_Msk (0x1UL << HRTIM_SET1R_SST_Pos) /*!< 0x00000001 */ +#define HRTIM_SET1R_SST HRTIM_SET1R_SST_Msk /*!< software set trigger */ +#define HRTIM_SET1R_RESYNC_Pos (1U) +#define HRTIM_SET1R_RESYNC_Msk (0x1UL << HRTIM_SET1R_RESYNC_Pos) /*!< 0x00000002 */ +#define HRTIM_SET1R_RESYNC HRTIM_SET1R_RESYNC_Msk /*!< Timer A resynchronization */ +#define HRTIM_SET1R_PER_Pos (2U) +#define HRTIM_SET1R_PER_Msk (0x1UL << HRTIM_SET1R_PER_Pos) /*!< 0x00000004 */ +#define HRTIM_SET1R_PER HRTIM_SET1R_PER_Msk /*!< Timer A period */ +#define HRTIM_SET1R_CMP1_Pos (3U) +#define HRTIM_SET1R_CMP1_Msk (0x1UL << HRTIM_SET1R_CMP1_Pos) /*!< 0x00000008 */ +#define HRTIM_SET1R_CMP1 HRTIM_SET1R_CMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_SET1R_CMP2_Pos (4U) +#define HRTIM_SET1R_CMP2_Msk (0x1UL << HRTIM_SET1R_CMP2_Pos) /*!< 0x00000010 */ +#define HRTIM_SET1R_CMP2 HRTIM_SET1R_CMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_SET1R_CMP3_Pos (5U) +#define HRTIM_SET1R_CMP3_Msk (0x1UL << HRTIM_SET1R_CMP3_Pos) /*!< 0x00000020 */ +#define HRTIM_SET1R_CMP3 HRTIM_SET1R_CMP3_Msk /*!< Timer A compare 3 */ +#define HRTIM_SET1R_CMP4_Pos (6U) +#define HRTIM_SET1R_CMP4_Msk (0x1UL << HRTIM_SET1R_CMP4_Pos) /*!< 0x00000040 */ +#define HRTIM_SET1R_CMP4 HRTIM_SET1R_CMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_SET1R_MSTPER_Pos (7U) +#define HRTIM_SET1R_MSTPER_Msk (0x1UL << HRTIM_SET1R_MSTPER_Pos) /*!< 0x00000080 */ +#define HRTIM_SET1R_MSTPER HRTIM_SET1R_MSTPER_Msk /*!< Master period */ +#define HRTIM_SET1R_MSTCMP1_Pos (8U) +#define HRTIM_SET1R_MSTCMP1_Msk (0x1UL << HRTIM_SET1R_MSTCMP1_Pos) /*!< 0x00000100 */ +#define HRTIM_SET1R_MSTCMP1 HRTIM_SET1R_MSTCMP1_Msk /*!< Master compare 1 */ +#define HRTIM_SET1R_MSTCMP2_Pos (9U) +#define HRTIM_SET1R_MSTCMP2_Msk (0x1UL << HRTIM_SET1R_MSTCMP2_Pos) /*!< 0x00000200 */ +#define HRTIM_SET1R_MSTCMP2 HRTIM_SET1R_MSTCMP2_Msk /*!< Master compare 2 */ +#define HRTIM_SET1R_MSTCMP3_Pos (10U) +#define HRTIM_SET1R_MSTCMP3_Msk (0x1UL << HRTIM_SET1R_MSTCMP3_Pos) /*!< 0x00000400 */ +#define HRTIM_SET1R_MSTCMP3 HRTIM_SET1R_MSTCMP3_Msk /*!< Master compare 3 */ +#define HRTIM_SET1R_MSTCMP4_Pos (11U) +#define HRTIM_SET1R_MSTCMP4_Msk (0x1UL << HRTIM_SET1R_MSTCMP4_Pos) /*!< 0x00000800 */ +#define HRTIM_SET1R_MSTCMP4 HRTIM_SET1R_MSTCMP4_Msk /*!< Master compare 4 */ + +#define HRTIM_SET1R_TIMEVNT1_Pos (12U) +#define HRTIM_SET1R_TIMEVNT1_Msk (0x1UL << HRTIM_SET1R_TIMEVNT1_Pos) /*!< 0x00001000 */ +#define HRTIM_SET1R_TIMEVNT1 HRTIM_SET1R_TIMEVNT1_Msk /*!< Timer event 1 */ +#define HRTIM_SET1R_TIMEVNT2_Pos (13U) +#define HRTIM_SET1R_TIMEVNT2_Msk (0x1UL << HRTIM_SET1R_TIMEVNT2_Pos) /*!< 0x00002000 */ +#define HRTIM_SET1R_TIMEVNT2 HRTIM_SET1R_TIMEVNT2_Msk /*!< Timer event 2 */ +#define HRTIM_SET1R_TIMEVNT3_Pos (14U) +#define HRTIM_SET1R_TIMEVNT3_Msk (0x1UL << HRTIM_SET1R_TIMEVNT3_Pos) /*!< 0x00004000 */ +#define HRTIM_SET1R_TIMEVNT3 HRTIM_SET1R_TIMEVNT3_Msk /*!< Timer event 3 */ +#define HRTIM_SET1R_TIMEVNT4_Pos (15U) +#define HRTIM_SET1R_TIMEVNT4_Msk (0x1UL << HRTIM_SET1R_TIMEVNT4_Pos) /*!< 0x00008000 */ +#define HRTIM_SET1R_TIMEVNT4 HRTIM_SET1R_TIMEVNT4_Msk /*!< Timer event 4 */ +#define HRTIM_SET1R_TIMEVNT5_Pos (16U) +#define HRTIM_SET1R_TIMEVNT5_Msk (0x1UL << HRTIM_SET1R_TIMEVNT5_Pos) /*!< 0x00010000 */ +#define HRTIM_SET1R_TIMEVNT5 HRTIM_SET1R_TIMEVNT5_Msk /*!< Timer event 5 */ +#define HRTIM_SET1R_TIMEVNT6_Pos (17U) +#define HRTIM_SET1R_TIMEVNT6_Msk (0x1UL << HRTIM_SET1R_TIMEVNT6_Pos) /*!< 0x00020000 */ +#define HRTIM_SET1R_TIMEVNT6 HRTIM_SET1R_TIMEVNT6_Msk /*!< Timer event 6 */ +#define HRTIM_SET1R_TIMEVNT7_Pos (18U) +#define HRTIM_SET1R_TIMEVNT7_Msk (0x1UL << HRTIM_SET1R_TIMEVNT7_Pos) /*!< 0x00040000 */ +#define HRTIM_SET1R_TIMEVNT7 HRTIM_SET1R_TIMEVNT7_Msk /*!< Timer event 7 */ +#define HRTIM_SET1R_TIMEVNT8_Pos (19U) +#define HRTIM_SET1R_TIMEVNT8_Msk (0x1UL << HRTIM_SET1R_TIMEVNT8_Pos) /*!< 0x00080000 */ +#define HRTIM_SET1R_TIMEVNT8 HRTIM_SET1R_TIMEVNT8_Msk /*!< Timer event 8 */ +#define HRTIM_SET1R_TIMEVNT9_Pos (20U) +#define HRTIM_SET1R_TIMEVNT9_Msk (0x1UL << HRTIM_SET1R_TIMEVNT9_Pos) /*!< 0x00100000 */ +#define HRTIM_SET1R_TIMEVNT9 HRTIM_SET1R_TIMEVNT9_Msk /*!< Timer event 9 */ + +#define HRTIM_SET1R_EXTVNT1_Pos (21U) +#define HRTIM_SET1R_EXTVNT1_Msk (0x1UL << HRTIM_SET1R_EXTVNT1_Pos) /*!< 0x00200000 */ +#define HRTIM_SET1R_EXTVNT1 HRTIM_SET1R_EXTVNT1_Msk /*!< External event 1 */ +#define HRTIM_SET1R_EXTVNT2_Pos (22U) +#define HRTIM_SET1R_EXTVNT2_Msk (0x1UL << HRTIM_SET1R_EXTVNT2_Pos) /*!< 0x00400000 */ +#define HRTIM_SET1R_EXTVNT2 HRTIM_SET1R_EXTVNT2_Msk /*!< External event 2 */ +#define HRTIM_SET1R_EXTVNT3_Pos (23U) +#define HRTIM_SET1R_EXTVNT3_Msk (0x1UL << HRTIM_SET1R_EXTVNT3_Pos) /*!< 0x00800000 */ +#define HRTIM_SET1R_EXTVNT3 HRTIM_SET1R_EXTVNT3_Msk /*!< External event 3 */ +#define HRTIM_SET1R_EXTVNT4_Pos (24U) +#define HRTIM_SET1R_EXTVNT4_Msk (0x1UL << HRTIM_SET1R_EXTVNT4_Pos) /*!< 0x01000000 */ +#define HRTIM_SET1R_EXTVNT4 HRTIM_SET1R_EXTVNT4_Msk /*!< External event 4 */ +#define HRTIM_SET1R_EXTVNT5_Pos (25U) +#define HRTIM_SET1R_EXTVNT5_Msk (0x1UL << HRTIM_SET1R_EXTVNT5_Pos) /*!< 0x02000000 */ +#define HRTIM_SET1R_EXTVNT5 HRTIM_SET1R_EXTVNT5_Msk /*!< External event 5 */ +#define HRTIM_SET1R_EXTVNT6_Pos (26U) +#define HRTIM_SET1R_EXTVNT6_Msk (0x1UL << HRTIM_SET1R_EXTVNT6_Pos) /*!< 0x04000000 */ +#define HRTIM_SET1R_EXTVNT6 HRTIM_SET1R_EXTVNT6_Msk /*!< External event 6 */ +#define HRTIM_SET1R_EXTVNT7_Pos (27U) +#define HRTIM_SET1R_EXTVNT7_Msk (0x1UL << HRTIM_SET1R_EXTVNT7_Pos) /*!< 0x08000000 */ +#define HRTIM_SET1R_EXTVNT7 HRTIM_SET1R_EXTVNT7_Msk /*!< External event 7 */ +#define HRTIM_SET1R_EXTVNT8_Pos (28U) +#define HRTIM_SET1R_EXTVNT8_Msk (0x1UL << HRTIM_SET1R_EXTVNT8_Pos) /*!< 0x10000000 */ +#define HRTIM_SET1R_EXTVNT8 HRTIM_SET1R_EXTVNT8_Msk /*!< External event 8 */ +#define HRTIM_SET1R_EXTVNT9_Pos (29U) +#define HRTIM_SET1R_EXTVNT9_Msk (0x1UL << HRTIM_SET1R_EXTVNT9_Pos) /*!< 0x20000000 */ +#define HRTIM_SET1R_EXTVNT9 HRTIM_SET1R_EXTVNT9_Msk /*!< External event 9 */ +#define HRTIM_SET1R_EXTVNT10_Pos (30U) +#define HRTIM_SET1R_EXTVNT10_Msk (0x1UL << HRTIM_SET1R_EXTVNT10_Pos) /*!< 0x40000000 */ +#define HRTIM_SET1R_EXTVNT10 HRTIM_SET1R_EXTVNT10_Msk /*!< External event 10 */ + +#define HRTIM_SET1R_UPDATE_Pos (31U) +#define HRTIM_SET1R_UPDATE_Msk (0x1UL << HRTIM_SET1R_UPDATE_Pos) /*!< 0x80000000 */ +#define HRTIM_SET1R_UPDATE HRTIM_SET1R_UPDATE_Msk /*!< Register update (transfer preload to active) */ + +/**** Bit definition for Slave Output 1 reset register ************************/ +#define HRTIM_RST1R_SRT_Pos (0U) +#define HRTIM_RST1R_SRT_Msk (0x1UL << HRTIM_RST1R_SRT_Pos) /*!< 0x00000001 */ +#define HRTIM_RST1R_SRT HRTIM_RST1R_SRT_Msk /*!< software reset trigger */ +#define HRTIM_RST1R_RESYNC_Pos (1U) +#define HRTIM_RST1R_RESYNC_Msk (0x1UL << HRTIM_RST1R_RESYNC_Pos) /*!< 0x00000002 */ +#define HRTIM_RST1R_RESYNC HRTIM_RST1R_RESYNC_Msk /*!< Timer A resynchronization */ +#define HRTIM_RST1R_PER_Pos (2U) +#define HRTIM_RST1R_PER_Msk (0x1UL << HRTIM_RST1R_PER_Pos) /*!< 0x00000004 */ +#define HRTIM_RST1R_PER HRTIM_RST1R_PER_Msk /*!< Timer A period */ +#define HRTIM_RST1R_CMP1_Pos (3U) +#define HRTIM_RST1R_CMP1_Msk (0x1UL << HRTIM_RST1R_CMP1_Pos) /*!< 0x00000008 */ +#define HRTIM_RST1R_CMP1 HRTIM_RST1R_CMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RST1R_CMP2_Pos (4U) +#define HRTIM_RST1R_CMP2_Msk (0x1UL << HRTIM_RST1R_CMP2_Pos) /*!< 0x00000010 */ +#define HRTIM_RST1R_CMP2 HRTIM_RST1R_CMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RST1R_CMP3_Pos (5U) +#define HRTIM_RST1R_CMP3_Msk (0x1UL << HRTIM_RST1R_CMP3_Pos) /*!< 0x00000020 */ +#define HRTIM_RST1R_CMP3 HRTIM_RST1R_CMP3_Msk /*!< Timer A compare 3 */ +#define HRTIM_RST1R_CMP4_Pos (6U) +#define HRTIM_RST1R_CMP4_Msk (0x1UL << HRTIM_RST1R_CMP4_Pos) /*!< 0x00000040 */ +#define HRTIM_RST1R_CMP4 HRTIM_RST1R_CMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RST1R_MSTPER_Pos (7U) +#define HRTIM_RST1R_MSTPER_Msk (0x1UL << HRTIM_RST1R_MSTPER_Pos) /*!< 0x00000080 */ +#define HRTIM_RST1R_MSTPER HRTIM_RST1R_MSTPER_Msk /*!< Master period */ +#define HRTIM_RST1R_MSTCMP1_Pos (8U) +#define HRTIM_RST1R_MSTCMP1_Msk (0x1UL << HRTIM_RST1R_MSTCMP1_Pos) /*!< 0x00000100 */ +#define HRTIM_RST1R_MSTCMP1 HRTIM_RST1R_MSTCMP1_Msk /*!< Master compare 1 */ +#define HRTIM_RST1R_MSTCMP2_Pos (9U) +#define HRTIM_RST1R_MSTCMP2_Msk (0x1UL << HRTIM_RST1R_MSTCMP2_Pos) /*!< 0x00000200 */ +#define HRTIM_RST1R_MSTCMP2 HRTIM_RST1R_MSTCMP2_Msk /*!< Master compare 2 */ +#define HRTIM_RST1R_MSTCMP3_Pos (10U) +#define HRTIM_RST1R_MSTCMP3_Msk (0x1UL << HRTIM_RST1R_MSTCMP3_Pos) /*!< 0x00000400 */ +#define HRTIM_RST1R_MSTCMP3 HRTIM_RST1R_MSTCMP3_Msk /*!< Master compare 3 */ +#define HRTIM_RST1R_MSTCMP4_Pos (11U) +#define HRTIM_RST1R_MSTCMP4_Msk (0x1UL << HRTIM_RST1R_MSTCMP4_Pos) /*!< 0x00000800 */ +#define HRTIM_RST1R_MSTCMP4 HRTIM_RST1R_MSTCMP4_Msk /*!< Master compare 4 */ + +#define HRTIM_RST1R_TIMEVNT1_Pos (12U) +#define HRTIM_RST1R_TIMEVNT1_Msk (0x1UL << HRTIM_RST1R_TIMEVNT1_Pos) /*!< 0x00001000 */ +#define HRTIM_RST1R_TIMEVNT1 HRTIM_RST1R_TIMEVNT1_Msk /*!< Timer event 1 */ +#define HRTIM_RST1R_TIMEVNT2_Pos (13U) +#define HRTIM_RST1R_TIMEVNT2_Msk (0x1UL << HRTIM_RST1R_TIMEVNT2_Pos) /*!< 0x00002000 */ +#define HRTIM_RST1R_TIMEVNT2 HRTIM_RST1R_TIMEVNT2_Msk /*!< Timer event 2 */ +#define HRTIM_RST1R_TIMEVNT3_Pos (14U) +#define HRTIM_RST1R_TIMEVNT3_Msk (0x1UL << HRTIM_RST1R_TIMEVNT3_Pos) /*!< 0x00004000 */ +#define HRTIM_RST1R_TIMEVNT3 HRTIM_RST1R_TIMEVNT3_Msk /*!< Timer event 3 */ +#define HRTIM_RST1R_TIMEVNT4_Pos (15U) +#define HRTIM_RST1R_TIMEVNT4_Msk (0x1UL << HRTIM_RST1R_TIMEVNT4_Pos) /*!< 0x00008000 */ +#define HRTIM_RST1R_TIMEVNT4 HRTIM_RST1R_TIMEVNT4_Msk /*!< Timer event 4 */ +#define HRTIM_RST1R_TIMEVNT5_Pos (16U) +#define HRTIM_RST1R_TIMEVNT5_Msk (0x1UL << HRTIM_RST1R_TIMEVNT5_Pos) /*!< 0x00010000 */ +#define HRTIM_RST1R_TIMEVNT5 HRTIM_RST1R_TIMEVNT5_Msk /*!< Timer event 5 */ +#define HRTIM_RST1R_TIMEVNT6_Pos (17U) +#define HRTIM_RST1R_TIMEVNT6_Msk (0x1UL << HRTIM_RST1R_TIMEVNT6_Pos) /*!< 0x00020000 */ +#define HRTIM_RST1R_TIMEVNT6 HRTIM_RST1R_TIMEVNT6_Msk /*!< Timer event 6 */ +#define HRTIM_RST1R_TIMEVNT7_Pos (18U) +#define HRTIM_RST1R_TIMEVNT7_Msk (0x1UL << HRTIM_RST1R_TIMEVNT7_Pos) /*!< 0x00040000 */ +#define HRTIM_RST1R_TIMEVNT7 HRTIM_RST1R_TIMEVNT7_Msk /*!< Timer event 7 */ +#define HRTIM_RST1R_TIMEVNT8_Pos (19U) +#define HRTIM_RST1R_TIMEVNT8_Msk (0x1UL << HRTIM_RST1R_TIMEVNT8_Pos) /*!< 0x00080000 */ +#define HRTIM_RST1R_TIMEVNT8 HRTIM_RST1R_TIMEVNT8_Msk /*!< Timer event 8 */ +#define HRTIM_RST1R_TIMEVNT9_Pos (20U) +#define HRTIM_RST1R_TIMEVNT9_Msk (0x1UL << HRTIM_RST1R_TIMEVNT9_Pos) /*!< 0x00100000 */ +#define HRTIM_RST1R_TIMEVNT9 HRTIM_RST1R_TIMEVNT9_Msk /*!< Timer event 9 */ + +#define HRTIM_RST1R_EXTVNT1_Pos (21U) +#define HRTIM_RST1R_EXTVNT1_Msk (0x1UL << HRTIM_RST1R_EXTVNT1_Pos) /*!< 0x00200000 */ +#define HRTIM_RST1R_EXTVNT1 HRTIM_RST1R_EXTVNT1_Msk /*!< External event 1 */ +#define HRTIM_RST1R_EXTVNT2_Pos (22U) +#define HRTIM_RST1R_EXTVNT2_Msk (0x1UL << HRTIM_RST1R_EXTVNT2_Pos) /*!< 0x00400000 */ +#define HRTIM_RST1R_EXTVNT2 HRTIM_RST1R_EXTVNT2_Msk /*!< External event 2 */ +#define HRTIM_RST1R_EXTVNT3_Pos (23U) +#define HRTIM_RST1R_EXTVNT3_Msk (0x1UL << HRTIM_RST1R_EXTVNT3_Pos) /*!< 0x00800000 */ +#define HRTIM_RST1R_EXTVNT3 HRTIM_RST1R_EXTVNT3_Msk /*!< External event 3 */ +#define HRTIM_RST1R_EXTVNT4_Pos (24U) +#define HRTIM_RST1R_EXTVNT4_Msk (0x1UL << HRTIM_RST1R_EXTVNT4_Pos) /*!< 0x01000000 */ +#define HRTIM_RST1R_EXTVNT4 HRTIM_RST1R_EXTVNT4_Msk /*!< External event 4 */ +#define HRTIM_RST1R_EXTVNT5_Pos (25U) +#define HRTIM_RST1R_EXTVNT5_Msk (0x1UL << HRTIM_RST1R_EXTVNT5_Pos) /*!< 0x02000000 */ +#define HRTIM_RST1R_EXTVNT5 HRTIM_RST1R_EXTVNT5_Msk /*!< External event 5 */ +#define HRTIM_RST1R_EXTVNT6_Pos (26U) +#define HRTIM_RST1R_EXTVNT6_Msk (0x1UL << HRTIM_RST1R_EXTVNT6_Pos) /*!< 0x04000000 */ +#define HRTIM_RST1R_EXTVNT6 HRTIM_RST1R_EXTVNT6_Msk /*!< External event 6 */ +#define HRTIM_RST1R_EXTVNT7_Pos (27U) +#define HRTIM_RST1R_EXTVNT7_Msk (0x1UL << HRTIM_RST1R_EXTVNT7_Pos) /*!< 0x08000000 */ +#define HRTIM_RST1R_EXTVNT7 HRTIM_RST1R_EXTVNT7_Msk /*!< External event 7 */ +#define HRTIM_RST1R_EXTVNT8_Pos (28U) +#define HRTIM_RST1R_EXTVNT8_Msk (0x1UL << HRTIM_RST1R_EXTVNT8_Pos) /*!< 0x10000000 */ +#define HRTIM_RST1R_EXTVNT8 HRTIM_RST1R_EXTVNT8_Msk /*!< External event 8 */ +#define HRTIM_RST1R_EXTVNT9_Pos (29U) +#define HRTIM_RST1R_EXTVNT9_Msk (0x1UL << HRTIM_RST1R_EXTVNT9_Pos) /*!< 0x20000000 */ +#define HRTIM_RST1R_EXTVNT9 HRTIM_RST1R_EXTVNT9_Msk /*!< External event 9 */ +#define HRTIM_RST1R_EXTVNT10_Pos (30U) +#define HRTIM_RST1R_EXTVNT10_Msk (0x1UL << HRTIM_RST1R_EXTVNT10_Pos) /*!< 0x40000000 */ +#define HRTIM_RST1R_EXTVNT10 HRTIM_RST1R_EXTVNT10_Msk /*!< External event 10 */ +#define HRTIM_RST1R_UPDATE_Pos (31U) +#define HRTIM_RST1R_UPDATE_Msk (0x1UL << HRTIM_RST1R_UPDATE_Pos) /*!< 0x80000000 */ +#define HRTIM_RST1R_UPDATE HRTIM_RST1R_UPDATE_Msk /*!< Register update (transfer preload to active) */ + +/**** Bit definition for Slave Output 2 set register **************************/ +#define HRTIM_SET2R_SST_Pos (0U) +#define HRTIM_SET2R_SST_Msk (0x1UL << HRTIM_SET2R_SST_Pos) /*!< 0x00000001 */ +#define HRTIM_SET2R_SST HRTIM_SET2R_SST_Msk /*!< software set trigger */ +#define HRTIM_SET2R_RESYNC_Pos (1U) +#define HRTIM_SET2R_RESYNC_Msk (0x1UL << HRTIM_SET2R_RESYNC_Pos) /*!< 0x00000002 */ +#define HRTIM_SET2R_RESYNC HRTIM_SET2R_RESYNC_Msk /*!< Timer A resynchronization */ +#define HRTIM_SET2R_PER_Pos (2U) +#define HRTIM_SET2R_PER_Msk (0x1UL << HRTIM_SET2R_PER_Pos) /*!< 0x00000004 */ +#define HRTIM_SET2R_PER HRTIM_SET2R_PER_Msk /*!< Timer A period */ +#define HRTIM_SET2R_CMP1_Pos (3U) +#define HRTIM_SET2R_CMP1_Msk (0x1UL << HRTIM_SET2R_CMP1_Pos) /*!< 0x00000008 */ +#define HRTIM_SET2R_CMP1 HRTIM_SET2R_CMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_SET2R_CMP2_Pos (4U) +#define HRTIM_SET2R_CMP2_Msk (0x1UL << HRTIM_SET2R_CMP2_Pos) /*!< 0x00000010 */ +#define HRTIM_SET2R_CMP2 HRTIM_SET2R_CMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_SET2R_CMP3_Pos (5U) +#define HRTIM_SET2R_CMP3_Msk (0x1UL << HRTIM_SET2R_CMP3_Pos) /*!< 0x00000020 */ +#define HRTIM_SET2R_CMP3 HRTIM_SET2R_CMP3_Msk /*!< Timer A compare 3 */ +#define HRTIM_SET2R_CMP4_Pos (6U) +#define HRTIM_SET2R_CMP4_Msk (0x1UL << HRTIM_SET2R_CMP4_Pos) /*!< 0x00000040 */ +#define HRTIM_SET2R_CMP4 HRTIM_SET2R_CMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_SET2R_MSTPER_Pos (7U) +#define HRTIM_SET2R_MSTPER_Msk (0x1UL << HRTIM_SET2R_MSTPER_Pos) /*!< 0x00000080 */ +#define HRTIM_SET2R_MSTPER HRTIM_SET2R_MSTPER_Msk /*!< Master period */ +#define HRTIM_SET2R_MSTCMP1_Pos (8U) +#define HRTIM_SET2R_MSTCMP1_Msk (0x1UL << HRTIM_SET2R_MSTCMP1_Pos) /*!< 0x00000100 */ +#define HRTIM_SET2R_MSTCMP1 HRTIM_SET2R_MSTCMP1_Msk /*!< Master compare 1 */ +#define HRTIM_SET2R_MSTCMP2_Pos (9U) +#define HRTIM_SET2R_MSTCMP2_Msk (0x1UL << HRTIM_SET2R_MSTCMP2_Pos) /*!< 0x00000200 */ +#define HRTIM_SET2R_MSTCMP2 HRTIM_SET2R_MSTCMP2_Msk /*!< Master compare 2 */ +#define HRTIM_SET2R_MSTCMP3_Pos (10U) +#define HRTIM_SET2R_MSTCMP3_Msk (0x1UL << HRTIM_SET2R_MSTCMP3_Pos) /*!< 0x00000400 */ +#define HRTIM_SET2R_MSTCMP3 HRTIM_SET2R_MSTCMP3_Msk /*!< Master compare 3 */ +#define HRTIM_SET2R_MSTCMP4_Pos (11U) +#define HRTIM_SET2R_MSTCMP4_Msk (0x1UL << HRTIM_SET2R_MSTCMP4_Pos) /*!< 0x00000800 */ +#define HRTIM_SET2R_MSTCMP4 HRTIM_SET2R_MSTCMP4_Msk /*!< Master compare 4 */ + +#define HRTIM_SET2R_TIMEVNT1_Pos (12U) +#define HRTIM_SET2R_TIMEVNT1_Msk (0x1UL << HRTIM_SET2R_TIMEVNT1_Pos) /*!< 0x00001000 */ +#define HRTIM_SET2R_TIMEVNT1 HRTIM_SET2R_TIMEVNT1_Msk /*!< Timer event 1 */ +#define HRTIM_SET2R_TIMEVNT2_Pos (13U) +#define HRTIM_SET2R_TIMEVNT2_Msk (0x1UL << HRTIM_SET2R_TIMEVNT2_Pos) /*!< 0x00002000 */ +#define HRTIM_SET2R_TIMEVNT2 HRTIM_SET2R_TIMEVNT2_Msk /*!< Timer event 2 */ +#define HRTIM_SET2R_TIMEVNT3_Pos (14U) +#define HRTIM_SET2R_TIMEVNT3_Msk (0x1UL << HRTIM_SET2R_TIMEVNT3_Pos) /*!< 0x00004000 */ +#define HRTIM_SET2R_TIMEVNT3 HRTIM_SET2R_TIMEVNT3_Msk /*!< Timer event 3 */ +#define HRTIM_SET2R_TIMEVNT4_Pos (15U) +#define HRTIM_SET2R_TIMEVNT4_Msk (0x1UL << HRTIM_SET2R_TIMEVNT4_Pos) /*!< 0x00008000 */ +#define HRTIM_SET2R_TIMEVNT4 HRTIM_SET2R_TIMEVNT4_Msk /*!< Timer event 4 */ +#define HRTIM_SET2R_TIMEVNT5_Pos (16U) +#define HRTIM_SET2R_TIMEVNT5_Msk (0x1UL << HRTIM_SET2R_TIMEVNT5_Pos) /*!< 0x00010000 */ +#define HRTIM_SET2R_TIMEVNT5 HRTIM_SET2R_TIMEVNT5_Msk /*!< Timer event 5 */ +#define HRTIM_SET2R_TIMEVNT6_Pos (17U) +#define HRTIM_SET2R_TIMEVNT6_Msk (0x1UL << HRTIM_SET2R_TIMEVNT6_Pos) /*!< 0x00020000 */ +#define HRTIM_SET2R_TIMEVNT6 HRTIM_SET2R_TIMEVNT6_Msk /*!< Timer event 6 */ +#define HRTIM_SET2R_TIMEVNT7_Pos (18U) +#define HRTIM_SET2R_TIMEVNT7_Msk (0x1UL << HRTIM_SET2R_TIMEVNT7_Pos) /*!< 0x00040000 */ +#define HRTIM_SET2R_TIMEVNT7 HRTIM_SET2R_TIMEVNT7_Msk /*!< Timer event 7 */ +#define HRTIM_SET2R_TIMEVNT8_Pos (19U) +#define HRTIM_SET2R_TIMEVNT8_Msk (0x1UL << HRTIM_SET2R_TIMEVNT8_Pos) /*!< 0x00080000 */ +#define HRTIM_SET2R_TIMEVNT8 HRTIM_SET2R_TIMEVNT8_Msk /*!< Timer event 8 */ +#define HRTIM_SET2R_TIMEVNT9_Pos (20U) +#define HRTIM_SET2R_TIMEVNT9_Msk (0x1UL << HRTIM_SET2R_TIMEVNT9_Pos) /*!< 0x00100000 */ +#define HRTIM_SET2R_TIMEVNT9 HRTIM_SET2R_TIMEVNT9_Msk /*!< Timer event 9 */ + +#define HRTIM_SET2R_EXTVNT1_Pos (21U) +#define HRTIM_SET2R_EXTVNT1_Msk (0x1UL << HRTIM_SET2R_EXTVNT1_Pos) /*!< 0x00200000 */ +#define HRTIM_SET2R_EXTVNT1 HRTIM_SET2R_EXTVNT1_Msk /*!< External event 1 */ +#define HRTIM_SET2R_EXTVNT2_Pos (22U) +#define HRTIM_SET2R_EXTVNT2_Msk (0x1UL << HRTIM_SET2R_EXTVNT2_Pos) /*!< 0x00400000 */ +#define HRTIM_SET2R_EXTVNT2 HRTIM_SET2R_EXTVNT2_Msk /*!< External event 2 */ +#define HRTIM_SET2R_EXTVNT3_Pos (23U) +#define HRTIM_SET2R_EXTVNT3_Msk (0x1UL << HRTIM_SET2R_EXTVNT3_Pos) /*!< 0x00800000 */ +#define HRTIM_SET2R_EXTVNT3 HRTIM_SET2R_EXTVNT3_Msk /*!< External event 3 */ +#define HRTIM_SET2R_EXTVNT4_Pos (24U) +#define HRTIM_SET2R_EXTVNT4_Msk (0x1UL << HRTIM_SET2R_EXTVNT4_Pos) /*!< 0x01000000 */ +#define HRTIM_SET2R_EXTVNT4 HRTIM_SET2R_EXTVNT4_Msk /*!< External event 4 */ +#define HRTIM_SET2R_EXTVNT5_Pos (25U) +#define HRTIM_SET2R_EXTVNT5_Msk (0x1UL << HRTIM_SET2R_EXTVNT5_Pos) /*!< 0x02000000 */ +#define HRTIM_SET2R_EXTVNT5 HRTIM_SET2R_EXTVNT5_Msk /*!< External event 5 */ +#define HRTIM_SET2R_EXTVNT6_Pos (26U) +#define HRTIM_SET2R_EXTVNT6_Msk (0x1UL << HRTIM_SET2R_EXTVNT6_Pos) /*!< 0x04000000 */ +#define HRTIM_SET2R_EXTVNT6 HRTIM_SET2R_EXTVNT6_Msk /*!< External event 6 */ +#define HRTIM_SET2R_EXTVNT7_Pos (27U) +#define HRTIM_SET2R_EXTVNT7_Msk (0x1UL << HRTIM_SET2R_EXTVNT7_Pos) /*!< 0x08000000 */ +#define HRTIM_SET2R_EXTVNT7 HRTIM_SET2R_EXTVNT7_Msk /*!< External event 7 */ +#define HRTIM_SET2R_EXTVNT8_Pos (28U) +#define HRTIM_SET2R_EXTVNT8_Msk (0x1UL << HRTIM_SET2R_EXTVNT8_Pos) /*!< 0x10000000 */ +#define HRTIM_SET2R_EXTVNT8 HRTIM_SET2R_EXTVNT8_Msk /*!< External event 8 */ +#define HRTIM_SET2R_EXTVNT9_Pos (29U) +#define HRTIM_SET2R_EXTVNT9_Msk (0x1UL << HRTIM_SET2R_EXTVNT9_Pos) /*!< 0x20000000 */ +#define HRTIM_SET2R_EXTVNT9 HRTIM_SET2R_EXTVNT9_Msk /*!< External event 9 */ +#define HRTIM_SET2R_EXTVNT10_Pos (30U) +#define HRTIM_SET2R_EXTVNT10_Msk (0x1UL << HRTIM_SET2R_EXTVNT10_Pos) /*!< 0x40000000 */ +#define HRTIM_SET2R_EXTVNT10 HRTIM_SET2R_EXTVNT10_Msk /*!< External event 10 */ + +#define HRTIM_SET2R_UPDATE_Pos (31U) +#define HRTIM_SET2R_UPDATE_Msk (0x1UL << HRTIM_SET2R_UPDATE_Pos) /*!< 0x80000000 */ +#define HRTIM_SET2R_UPDATE HRTIM_SET2R_UPDATE_Msk /*!< Register update (transfer preload to active) */ + +/**** Bit definition for Slave Output 2 reset register ************************/ +#define HRTIM_RST2R_SRT_Pos (0U) +#define HRTIM_RST2R_SRT_Msk (0x1UL << HRTIM_RST2R_SRT_Pos) /*!< 0x00000001 */ +#define HRTIM_RST2R_SRT HRTIM_RST2R_SRT_Msk /*!< software reset trigger */ +#define HRTIM_RST2R_RESYNC_Pos (1U) +#define HRTIM_RST2R_RESYNC_Msk (0x1UL << HRTIM_RST2R_RESYNC_Pos) /*!< 0x00000002 */ +#define HRTIM_RST2R_RESYNC HRTIM_RST2R_RESYNC_Msk /*!< Timer A resynchronization */ +#define HRTIM_RST2R_PER_Pos (2U) +#define HRTIM_RST2R_PER_Msk (0x1UL << HRTIM_RST2R_PER_Pos) /*!< 0x00000004 */ +#define HRTIM_RST2R_PER HRTIM_RST2R_PER_Msk /*!< Timer A period */ +#define HRTIM_RST2R_CMP1_Pos (3U) +#define HRTIM_RST2R_CMP1_Msk (0x1UL << HRTIM_RST2R_CMP1_Pos) /*!< 0x00000008 */ +#define HRTIM_RST2R_CMP1 HRTIM_RST2R_CMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RST2R_CMP2_Pos (4U) +#define HRTIM_RST2R_CMP2_Msk (0x1UL << HRTIM_RST2R_CMP2_Pos) /*!< 0x00000010 */ +#define HRTIM_RST2R_CMP2 HRTIM_RST2R_CMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RST2R_CMP3_Pos (5U) +#define HRTIM_RST2R_CMP3_Msk (0x1UL << HRTIM_RST2R_CMP3_Pos) /*!< 0x00000020 */ +#define HRTIM_RST2R_CMP3 HRTIM_RST2R_CMP3_Msk /*!< Timer A compare 3 */ +#define HRTIM_RST2R_CMP4_Pos (6U) +#define HRTIM_RST2R_CMP4_Msk (0x1UL << HRTIM_RST2R_CMP4_Pos) /*!< 0x00000040 */ +#define HRTIM_RST2R_CMP4 HRTIM_RST2R_CMP4_Msk /*!< Timer A compare 4 */ +#define HRTIM_RST2R_MSTPER_Pos (7U) +#define HRTIM_RST2R_MSTPER_Msk (0x1UL << HRTIM_RST2R_MSTPER_Pos) /*!< 0x00000080 */ +#define HRTIM_RST2R_MSTPER HRTIM_RST2R_MSTPER_Msk /*!< Master period */ +#define HRTIM_RST2R_MSTCMP1_Pos (8U) +#define HRTIM_RST2R_MSTCMP1_Msk (0x1UL << HRTIM_RST2R_MSTCMP1_Pos) /*!< 0x00000100 */ +#define HRTIM_RST2R_MSTCMP1 HRTIM_RST2R_MSTCMP1_Msk /*!< Master compare 1 */ +#define HRTIM_RST2R_MSTCMP2_Pos (9U) +#define HRTIM_RST2R_MSTCMP2_Msk (0x1UL << HRTIM_RST2R_MSTCMP2_Pos) /*!< 0x00000200 */ +#define HRTIM_RST2R_MSTCMP2 HRTIM_RST2R_MSTCMP2_Msk /*!< Master compare 2 */ +#define HRTIM_RST2R_MSTCMP3_Pos (10U) +#define HRTIM_RST2R_MSTCMP3_Msk (0x1UL << HRTIM_RST2R_MSTCMP3_Pos) /*!< 0x00000400 */ +#define HRTIM_RST2R_MSTCMP3 HRTIM_RST2R_MSTCMP3_Msk /*!< Master compare 3 */ +#define HRTIM_RST2R_MSTCMP4_Pos (11U) +#define HRTIM_RST2R_MSTCMP4_Msk (0x1UL << HRTIM_RST2R_MSTCMP4_Pos) /*!< 0x00000800 */ +#define HRTIM_RST2R_MSTCMP4 HRTIM_RST2R_MSTCMP4_Msk /*!< Master compare 4 */ + +#define HRTIM_RST2R_TIMEVNT1_Pos (12U) +#define HRTIM_RST2R_TIMEVNT1_Msk (0x1UL << HRTIM_RST2R_TIMEVNT1_Pos) /*!< 0x00001000 */ +#define HRTIM_RST2R_TIMEVNT1 HRTIM_RST2R_TIMEVNT1_Msk /*!< Timer event 1 */ +#define HRTIM_RST2R_TIMEVNT2_Pos (13U) +#define HRTIM_RST2R_TIMEVNT2_Msk (0x1UL << HRTIM_RST2R_TIMEVNT2_Pos) /*!< 0x00002000 */ +#define HRTIM_RST2R_TIMEVNT2 HRTIM_RST2R_TIMEVNT2_Msk /*!< Timer event 2 */ +#define HRTIM_RST2R_TIMEVNT3_Pos (14U) +#define HRTIM_RST2R_TIMEVNT3_Msk (0x1UL << HRTIM_RST2R_TIMEVNT3_Pos) /*!< 0x00004000 */ +#define HRTIM_RST2R_TIMEVNT3 HRTIM_RST2R_TIMEVNT3_Msk /*!< Timer event 3 */ +#define HRTIM_RST2R_TIMEVNT4_Pos (15U) +#define HRTIM_RST2R_TIMEVNT4_Msk (0x1UL << HRTIM_RST2R_TIMEVNT4_Pos) /*!< 0x00008000 */ +#define HRTIM_RST2R_TIMEVNT4 HRTIM_RST2R_TIMEVNT4_Msk /*!< Timer event 4 */ +#define HRTIM_RST2R_TIMEVNT5_Pos (16U) +#define HRTIM_RST2R_TIMEVNT5_Msk (0x1UL << HRTIM_RST2R_TIMEVNT5_Pos) /*!< 0x00010000 */ +#define HRTIM_RST2R_TIMEVNT5 HRTIM_RST2R_TIMEVNT5_Msk /*!< Timer event 5 */ +#define HRTIM_RST2R_TIMEVNT6_Pos (17U) +#define HRTIM_RST2R_TIMEVNT6_Msk (0x1UL << HRTIM_RST2R_TIMEVNT6_Pos) /*!< 0x00020000 */ +#define HRTIM_RST2R_TIMEVNT6 HRTIM_RST2R_TIMEVNT6_Msk /*!< Timer event 6 */ +#define HRTIM_RST2R_TIMEVNT7_Pos (18U) +#define HRTIM_RST2R_TIMEVNT7_Msk (0x1UL << HRTIM_RST2R_TIMEVNT7_Pos) /*!< 0x00040000 */ +#define HRTIM_RST2R_TIMEVNT7 HRTIM_RST2R_TIMEVNT7_Msk /*!< Timer event 7 */ +#define HRTIM_RST2R_TIMEVNT8_Pos (19U) +#define HRTIM_RST2R_TIMEVNT8_Msk (0x1UL << HRTIM_RST2R_TIMEVNT8_Pos) /*!< 0x00080000 */ +#define HRTIM_RST2R_TIMEVNT8 HRTIM_RST2R_TIMEVNT8_Msk /*!< Timer event 8 */ +#define HRTIM_RST2R_TIMEVNT9_Pos (20U) +#define HRTIM_RST2R_TIMEVNT9_Msk (0x1UL << HRTIM_RST2R_TIMEVNT9_Pos) /*!< 0x00100000 */ +#define HRTIM_RST2R_TIMEVNT9 HRTIM_RST2R_TIMEVNT9_Msk /*!< Timer event 9 */ + +#define HRTIM_RST2R_EXTVNT1_Pos (21U) +#define HRTIM_RST2R_EXTVNT1_Msk (0x1UL << HRTIM_RST2R_EXTVNT1_Pos) /*!< 0x00200000 */ +#define HRTIM_RST2R_EXTVNT1 HRTIM_RST2R_EXTVNT1_Msk /*!< External event 1 */ +#define HRTIM_RST2R_EXTVNT2_Pos (22U) +#define HRTIM_RST2R_EXTVNT2_Msk (0x1UL << HRTIM_RST2R_EXTVNT2_Pos) /*!< 0x00400000 */ +#define HRTIM_RST2R_EXTVNT2 HRTIM_RST2R_EXTVNT2_Msk /*!< External event 2 */ +#define HRTIM_RST2R_EXTVNT3_Pos (23U) +#define HRTIM_RST2R_EXTVNT3_Msk (0x1UL << HRTIM_RST2R_EXTVNT3_Pos) /*!< 0x00800000 */ +#define HRTIM_RST2R_EXTVNT3 HRTIM_RST2R_EXTVNT3_Msk /*!< External event 3 */ +#define HRTIM_RST2R_EXTVNT4_Pos (24U) +#define HRTIM_RST2R_EXTVNT4_Msk (0x1UL << HRTIM_RST2R_EXTVNT4_Pos) /*!< 0x01000000 */ +#define HRTIM_RST2R_EXTVNT4 HRTIM_RST2R_EXTVNT4_Msk /*!< External event 4 */ +#define HRTIM_RST2R_EXTVNT5_Pos (25U) +#define HRTIM_RST2R_EXTVNT5_Msk (0x1UL << HRTIM_RST2R_EXTVNT5_Pos) /*!< 0x02000000 */ +#define HRTIM_RST2R_EXTVNT5 HRTIM_RST2R_EXTVNT5_Msk /*!< External event 5 */ +#define HRTIM_RST2R_EXTVNT6_Pos (26U) +#define HRTIM_RST2R_EXTVNT6_Msk (0x1UL << HRTIM_RST2R_EXTVNT6_Pos) /*!< 0x04000000 */ +#define HRTIM_RST2R_EXTVNT6 HRTIM_RST2R_EXTVNT6_Msk /*!< External event 6 */ +#define HRTIM_RST2R_EXTVNT7_Pos (27U) +#define HRTIM_RST2R_EXTVNT7_Msk (0x1UL << HRTIM_RST2R_EXTVNT7_Pos) /*!< 0x08000000 */ +#define HRTIM_RST2R_EXTVNT7 HRTIM_RST2R_EXTVNT7_Msk /*!< External event 7 */ +#define HRTIM_RST2R_EXTVNT8_Pos (28U) +#define HRTIM_RST2R_EXTVNT8_Msk (0x1UL << HRTIM_RST2R_EXTVNT8_Pos) /*!< 0x10000000 */ +#define HRTIM_RST2R_EXTVNT8 HRTIM_RST2R_EXTVNT8_Msk /*!< External event 8 */ +#define HRTIM_RST2R_EXTVNT9_Pos (29U) +#define HRTIM_RST2R_EXTVNT9_Msk (0x1UL << HRTIM_RST2R_EXTVNT9_Pos) /*!< 0x20000000 */ +#define HRTIM_RST2R_EXTVNT9 HRTIM_RST2R_EXTVNT9_Msk /*!< External event 9 */ +#define HRTIM_RST2R_EXTVNT10_Pos (30U) +#define HRTIM_RST2R_EXTVNT10_Msk (0x1UL << HRTIM_RST2R_EXTVNT10_Pos) /*!< 0x40000000 */ +#define HRTIM_RST2R_EXTVNT10 HRTIM_RST2R_EXTVNT10_Msk /*!< External event 10 */ +#define HRTIM_RST2R_UPDATE_Pos (31U) +#define HRTIM_RST2R_UPDATE_Msk (0x1UL << HRTIM_RST2R_UPDATE_Pos) /*!< 0x80000000 */ +#define HRTIM_RST2R_UPDATE HRTIM_RST2R_UPDATE_Msk /*!< Register update (transfer preload to active) */ + +/**** Bit definition for Slave external event filtering register 1 ***********/ +#define HRTIM_EEFR1_EE1LTCH_Pos (0U) +#define HRTIM_EEFR1_EE1LTCH_Msk (0x1UL << HRTIM_EEFR1_EE1LTCH_Pos) /*!< 0x00000001 */ +#define HRTIM_EEFR1_EE1LTCH HRTIM_EEFR1_EE1LTCH_Msk /*!< External Event 1 latch */ +#define HRTIM_EEFR1_EE1FLTR_Pos (1U) +#define HRTIM_EEFR1_EE1FLTR_Msk (0xFUL << HRTIM_EEFR1_EE1FLTR_Pos) /*!< 0x0000001E */ +#define HRTIM_EEFR1_EE1FLTR HRTIM_EEFR1_EE1FLTR_Msk /*!< External Event 1 filter mask */ +#define HRTIM_EEFR1_EE1FLTR_0 (0x1UL << HRTIM_EEFR1_EE1FLTR_Pos) /*!< 0x00000002 */ +#define HRTIM_EEFR1_EE1FLTR_1 (0x2UL << HRTIM_EEFR1_EE1FLTR_Pos) /*!< 0x00000004 */ +#define HRTIM_EEFR1_EE1FLTR_2 (0x4UL << HRTIM_EEFR1_EE1FLTR_Pos) /*!< 0x00000008 */ +#define HRTIM_EEFR1_EE1FLTR_3 (0x8UL << HRTIM_EEFR1_EE1FLTR_Pos) /*!< 0x00000010 */ + +#define HRTIM_EEFR1_EE2LTCH_Pos (6U) +#define HRTIM_EEFR1_EE2LTCH_Msk (0x1UL << HRTIM_EEFR1_EE2LTCH_Pos) /*!< 0x00000040 */ +#define HRTIM_EEFR1_EE2LTCH HRTIM_EEFR1_EE2LTCH_Msk /*!< External Event 2 latch */ +#define HRTIM_EEFR1_EE2FLTR_Pos (7U) +#define HRTIM_EEFR1_EE2FLTR_Msk (0xFUL << HRTIM_EEFR1_EE2FLTR_Pos) /*!< 0x00000780 */ +#define HRTIM_EEFR1_EE2FLTR HRTIM_EEFR1_EE2FLTR_Msk /*!< External Event 2 filter mask */ +#define HRTIM_EEFR1_EE2FLTR_0 (0x1UL << HRTIM_EEFR1_EE2FLTR_Pos) /*!< 0x00000080 */ +#define HRTIM_EEFR1_EE2FLTR_1 (0x2UL << HRTIM_EEFR1_EE2FLTR_Pos) /*!< 0x00000100 */ +#define HRTIM_EEFR1_EE2FLTR_2 (0x4UL << HRTIM_EEFR1_EE2FLTR_Pos) /*!< 0x00000200 */ +#define HRTIM_EEFR1_EE2FLTR_3 (0x8UL << HRTIM_EEFR1_EE2FLTR_Pos) /*!< 0x00000400 */ + +#define HRTIM_EEFR1_EE3LTCH_Pos (12U) +#define HRTIM_EEFR1_EE3LTCH_Msk (0x1UL << HRTIM_EEFR1_EE3LTCH_Pos) /*!< 0x00001000 */ +#define HRTIM_EEFR1_EE3LTCH HRTIM_EEFR1_EE3LTCH_Msk /*!< External Event 3 latch */ +#define HRTIM_EEFR1_EE3FLTR_Pos (13U) +#define HRTIM_EEFR1_EE3FLTR_Msk (0xFUL << HRTIM_EEFR1_EE3FLTR_Pos) /*!< 0x0001E000 */ +#define HRTIM_EEFR1_EE3FLTR HRTIM_EEFR1_EE3FLTR_Msk /*!< External Event 3 filter mask */ +#define HRTIM_EEFR1_EE3FLTR_0 (0x1UL << HRTIM_EEFR1_EE3FLTR_Pos) /*!< 0x00002000 */ +#define HRTIM_EEFR1_EE3FLTR_1 (0x2UL << HRTIM_EEFR1_EE3FLTR_Pos) /*!< 0x00004000 */ +#define HRTIM_EEFR1_EE3FLTR_2 (0x4UL << HRTIM_EEFR1_EE3FLTR_Pos) /*!< 0x00008000 */ +#define HRTIM_EEFR1_EE3FLTR_3 (0x8UL << HRTIM_EEFR1_EE3FLTR_Pos) /*!< 0x00010000 */ + +#define HRTIM_EEFR1_EE4LTCH_Pos (18U) +#define HRTIM_EEFR1_EE4LTCH_Msk (0x1UL << HRTIM_EEFR1_EE4LTCH_Pos) /*!< 0x00040000 */ +#define HRTIM_EEFR1_EE4LTCH HRTIM_EEFR1_EE4LTCH_Msk /*!< External Event 4 latch */ +#define HRTIM_EEFR1_EE4FLTR_Pos (19U) +#define HRTIM_EEFR1_EE4FLTR_Msk (0xFUL << HRTIM_EEFR1_EE4FLTR_Pos) /*!< 0x00780000 */ +#define HRTIM_EEFR1_EE4FLTR HRTIM_EEFR1_EE4FLTR_Msk /*!< External Event 4 filter mask */ +#define HRTIM_EEFR1_EE4FLTR_0 (0x1UL << HRTIM_EEFR1_EE4FLTR_Pos) /*!< 0x00080000 */ +#define HRTIM_EEFR1_EE4FLTR_1 (0x2UL << HRTIM_EEFR1_EE4FLTR_Pos) /*!< 0x00100000 */ +#define HRTIM_EEFR1_EE4FLTR_2 (0x4UL << HRTIM_EEFR1_EE4FLTR_Pos) /*!< 0x00200000 */ +#define HRTIM_EEFR1_EE4FLTR_3 (0x8UL << HRTIM_EEFR1_EE4FLTR_Pos) /*!< 0x00400000 */ + +#define HRTIM_EEFR1_EE5LTCH_Pos (24U) +#define HRTIM_EEFR1_EE5LTCH_Msk (0x1UL << HRTIM_EEFR1_EE5LTCH_Pos) /*!< 0x01000000 */ +#define HRTIM_EEFR1_EE5LTCH HRTIM_EEFR1_EE5LTCH_Msk /*!< External Event 5 latch */ +#define HRTIM_EEFR1_EE5FLTR_Pos (25U) +#define HRTIM_EEFR1_EE5FLTR_Msk (0xFUL << HRTIM_EEFR1_EE5FLTR_Pos) /*!< 0x1E000000 */ +#define HRTIM_EEFR1_EE5FLTR HRTIM_EEFR1_EE5FLTR_Msk /*!< External Event 5 filter mask */ +#define HRTIM_EEFR1_EE5FLTR_0 (0x1UL << HRTIM_EEFR1_EE5FLTR_Pos) /*!< 0x02000000 */ +#define HRTIM_EEFR1_EE5FLTR_1 (0x2UL << HRTIM_EEFR1_EE5FLTR_Pos) /*!< 0x04000000 */ +#define HRTIM_EEFR1_EE5FLTR_2 (0x4UL << HRTIM_EEFR1_EE5FLTR_Pos) /*!< 0x08000000 */ +#define HRTIM_EEFR1_EE5FLTR_3 (0x8UL << HRTIM_EEFR1_EE5FLTR_Pos) /*!< 0x10000000 */ + +/**** Bit definition for Slave external event filtering register 2 ***********/ +#define HRTIM_EEFR2_EE6LTCH_Pos (0U) +#define HRTIM_EEFR2_EE6LTCH_Msk (0x1UL << HRTIM_EEFR2_EE6LTCH_Pos) /*!< 0x00000001 */ +#define HRTIM_EEFR2_EE6LTCH HRTIM_EEFR2_EE6LTCH_Msk /*!< External Event 6 latch */ +#define HRTIM_EEFR2_EE6FLTR_Pos (1U) +#define HRTIM_EEFR2_EE6FLTR_Msk (0xFUL << HRTIM_EEFR2_EE6FLTR_Pos) /*!< 0x0000001E */ +#define HRTIM_EEFR2_EE6FLTR HRTIM_EEFR2_EE6FLTR_Msk /*!< External Event 6 filter mask */ +#define HRTIM_EEFR2_EE6FLTR_0 (0x1UL << HRTIM_EEFR2_EE6FLTR_Pos) /*!< 0x00000002 */ +#define HRTIM_EEFR2_EE6FLTR_1 (0x2UL << HRTIM_EEFR2_EE6FLTR_Pos) /*!< 0x00000004 */ +#define HRTIM_EEFR2_EE6FLTR_2 (0x4UL << HRTIM_EEFR2_EE6FLTR_Pos) /*!< 0x00000008 */ +#define HRTIM_EEFR2_EE6FLTR_3 (0x8UL << HRTIM_EEFR2_EE6FLTR_Pos) /*!< 0x00000010 */ + +#define HRTIM_EEFR2_EE7LTCH_Pos (6U) +#define HRTIM_EEFR2_EE7LTCH_Msk (0x1UL << HRTIM_EEFR2_EE7LTCH_Pos) /*!< 0x00000040 */ +#define HRTIM_EEFR2_EE7LTCH HRTIM_EEFR2_EE7LTCH_Msk /*!< External Event 7 latch */ +#define HRTIM_EEFR2_EE7FLTR_Pos (7U) +#define HRTIM_EEFR2_EE7FLTR_Msk (0xFUL << HRTIM_EEFR2_EE7FLTR_Pos) /*!< 0x00000780 */ +#define HRTIM_EEFR2_EE7FLTR HRTIM_EEFR2_EE7FLTR_Msk /*!< External Event 7 filter mask */ +#define HRTIM_EEFR2_EE7FLTR_0 (0x1UL << HRTIM_EEFR2_EE7FLTR_Pos) /*!< 0x00000080 */ +#define HRTIM_EEFR2_EE7FLTR_1 (0x2UL << HRTIM_EEFR2_EE7FLTR_Pos) /*!< 0x00000100 */ +#define HRTIM_EEFR2_EE7FLTR_2 (0x4UL << HRTIM_EEFR2_EE7FLTR_Pos) /*!< 0x00000200 */ +#define HRTIM_EEFR2_EE7FLTR_3 (0x8UL << HRTIM_EEFR2_EE7FLTR_Pos) /*!< 0x00000400 */ + +#define HRTIM_EEFR2_EE8LTCH_Pos (12U) +#define HRTIM_EEFR2_EE8LTCH_Msk (0x1UL << HRTIM_EEFR2_EE8LTCH_Pos) /*!< 0x00001000 */ +#define HRTIM_EEFR2_EE8LTCH HRTIM_EEFR2_EE8LTCH_Msk /*!< External Event 8 latch */ +#define HRTIM_EEFR2_EE8FLTR_Pos (13U) +#define HRTIM_EEFR2_EE8FLTR_Msk (0xFUL << HRTIM_EEFR2_EE8FLTR_Pos) /*!< 0x0001E000 */ +#define HRTIM_EEFR2_EE8FLTR HRTIM_EEFR2_EE8FLTR_Msk /*!< External Event 8 filter mask */ +#define HRTIM_EEFR2_EE8FLTR_0 (0x1UL << HRTIM_EEFR2_EE8FLTR_Pos) /*!< 0x00002000 */ +#define HRTIM_EEFR2_EE8FLTR_1 (0x2UL << HRTIM_EEFR2_EE8FLTR_Pos) /*!< 0x00004000 */ +#define HRTIM_EEFR2_EE8FLTR_2 (0x4UL << HRTIM_EEFR2_EE8FLTR_Pos) /*!< 0x00008000 */ +#define HRTIM_EEFR2_EE8FLTR_3 (0x8UL << HRTIM_EEFR2_EE8FLTR_Pos) /*!< 0x00010000 */ + +#define HRTIM_EEFR2_EE9LTCH_Pos (18U) +#define HRTIM_EEFR2_EE9LTCH_Msk (0x1UL << HRTIM_EEFR2_EE9LTCH_Pos) /*!< 0x00040000 */ +#define HRTIM_EEFR2_EE9LTCH HRTIM_EEFR2_EE9LTCH_Msk /*!< External Event 9 latch */ +#define HRTIM_EEFR2_EE9FLTR_Pos (19U) +#define HRTIM_EEFR2_EE9FLTR_Msk (0xFUL << HRTIM_EEFR2_EE9FLTR_Pos) /*!< 0x00780000 */ +#define HRTIM_EEFR2_EE9FLTR HRTIM_EEFR2_EE9FLTR_Msk /*!< External Event 9 filter mask */ +#define HRTIM_EEFR2_EE9FLTR_0 (0x1UL << HRTIM_EEFR2_EE9FLTR_Pos) /*!< 0x00080000 */ +#define HRTIM_EEFR2_EE9FLTR_1 (0x2UL << HRTIM_EEFR2_EE9FLTR_Pos) /*!< 0x00100000 */ +#define HRTIM_EEFR2_EE9FLTR_2 (0x4UL << HRTIM_EEFR2_EE9FLTR_Pos) /*!< 0x00200000 */ +#define HRTIM_EEFR2_EE9FLTR_3 (0x8UL << HRTIM_EEFR2_EE9FLTR_Pos) /*!< 0x00400000 */ + +#define HRTIM_EEFR2_EE10LTCH_Pos (24U) +#define HRTIM_EEFR2_EE10LTCH_Msk (0x1UL << HRTIM_EEFR2_EE10LTCH_Pos) /*!< 0x01000000 */ +#define HRTIM_EEFR2_EE10LTCH HRTIM_EEFR2_EE10LTCH_Msk /*!< External Event 10 latch */ +#define HRTIM_EEFR2_EE10FLTR_Pos (25U) +#define HRTIM_EEFR2_EE10FLTR_Msk (0xFUL << HRTIM_EEFR2_EE10FLTR_Pos) /*!< 0x1E000000 */ +#define HRTIM_EEFR2_EE10FLTR HRTIM_EEFR2_EE10FLTR_Msk /*!< External Event 10 filter mask */ +#define HRTIM_EEFR2_EE10FLTR_0 (0x1UL << HRTIM_EEFR2_EE10FLTR_Pos) /*!< 0x02000000 */ +#define HRTIM_EEFR2_EE10FLTR_1 (0x2UL << HRTIM_EEFR2_EE10FLTR_Pos) /*!< 0x04000000 */ +#define HRTIM_EEFR2_EE10FLTR_2 (0x4UL << HRTIM_EEFR2_EE10FLTR_Pos) /*!< 0x08000000 */ +#define HRTIM_EEFR2_EE10FLTR_3 (0x8UL << HRTIM_EEFR2_EE10FLTR_Pos) /*!< 0x10000000 */ + +/**** Bit definition for Slave Timer reset register ***************************/ + +#define HRTIM_RSTR_TIMFCMP1_Pos (0U) +#define HRTIM_RSTR_TIMFCMP1_Msk (0x1UL << HRTIM_RSTR_TIMFCMP1_Pos) /*!< 0x00000001 */ +#define HRTIM_RSTR_TIMFCMP1 HRTIM_RSTR_TIMFCMP1_Msk /*!< Timer F compare 1 */ +#define HRTIM_RSTR_UPDATE_Pos (1U) +#define HRTIM_RSTR_UPDATE_Msk (0x1UL << HRTIM_RSTR_UPDATE_Pos) /*!< 0x00000002 */ +#define HRTIM_RSTR_UPDATE HRTIM_RSTR_UPDATE_Msk /*!< Timer update */ +#define HRTIM_RSTR_CMP2_Pos (2U) +#define HRTIM_RSTR_CMP2_Msk (0x1UL << HRTIM_RSTR_CMP2_Pos) /*!< 0x00000004 */ +#define HRTIM_RSTR_CMP2 HRTIM_RSTR_CMP2_Msk /*!< Timer compare2 */ +#define HRTIM_RSTR_CMP4_Pos (3U) +#define HRTIM_RSTR_CMP4_Msk (0x1UL << HRTIM_RSTR_CMP4_Pos) /*!< 0x00000008 */ +#define HRTIM_RSTR_CMP4 HRTIM_RSTR_CMP4_Msk /*!< Timer compare4 */ +#define HRTIM_RSTR_MSTPER_Pos (4U) +#define HRTIM_RSTR_MSTPER_Msk (0x1UL << HRTIM_RSTR_MSTPER_Pos) /*!< 0x00000010 */ +#define HRTIM_RSTR_MSTPER HRTIM_RSTR_MSTPER_Msk /*!< Master period */ +#define HRTIM_RSTR_MSTCMP1_Pos (5U) +#define HRTIM_RSTR_MSTCMP1_Msk (0x1UL << HRTIM_RSTR_MSTCMP1_Pos) /*!< 0x00000020 */ +#define HRTIM_RSTR_MSTCMP1 HRTIM_RSTR_MSTCMP1_Msk /*!< Master compare1 */ +#define HRTIM_RSTR_MSTCMP2_Pos (6U) +#define HRTIM_RSTR_MSTCMP2_Msk (0x1UL << HRTIM_RSTR_MSTCMP2_Pos) /*!< 0x00000040 */ +#define HRTIM_RSTR_MSTCMP2 HRTIM_RSTR_MSTCMP2_Msk /*!< Master compare2 */ +#define HRTIM_RSTR_MSTCMP3_Pos (7U) +#define HRTIM_RSTR_MSTCMP3_Msk (0x1UL << HRTIM_RSTR_MSTCMP3_Pos) /*!< 0x00000080 */ +#define HRTIM_RSTR_MSTCMP3 HRTIM_RSTR_MSTCMP3_Msk /*!< Master compare3 */ +#define HRTIM_RSTR_MSTCMP4_Pos (8U) +#define HRTIM_RSTR_MSTCMP4_Msk (0x1UL << HRTIM_RSTR_MSTCMP4_Pos) /*!< 0x00000100 */ +#define HRTIM_RSTR_MSTCMP4 HRTIM_RSTR_MSTCMP4_Msk /*!< Master compare4 */ +#define HRTIM_RSTR_EXTEVNT1_Pos (9U) +#define HRTIM_RSTR_EXTEVNT1_Msk (0x1UL << HRTIM_RSTR_EXTEVNT1_Pos) /*!< 0x00000200 */ +#define HRTIM_RSTR_EXTEVNT1 HRTIM_RSTR_EXTEVNT1_Msk /*!< External event 1 */ +#define HRTIM_RSTR_EXTEVNT2_Pos (10U) +#define HRTIM_RSTR_EXTEVNT2_Msk (0x1UL << HRTIM_RSTR_EXTEVNT2_Pos) /*!< 0x00000400 */ +#define HRTIM_RSTR_EXTEVNT2 HRTIM_RSTR_EXTEVNT2_Msk /*!< External event 2 */ +#define HRTIM_RSTR_EXTEVNT3_Pos (11U) +#define HRTIM_RSTR_EXTEVNT3_Msk (0x1UL << HRTIM_RSTR_EXTEVNT3_Pos) /*!< 0x00000800 */ +#define HRTIM_RSTR_EXTEVNT3 HRTIM_RSTR_EXTEVNT3_Msk /*!< External event 3 */ +#define HRTIM_RSTR_EXTEVNT4_Pos (12U) +#define HRTIM_RSTR_EXTEVNT4_Msk (0x1UL << HRTIM_RSTR_EXTEVNT4_Pos) /*!< 0x00001000 */ +#define HRTIM_RSTR_EXTEVNT4 HRTIM_RSTR_EXTEVNT4_Msk /*!< External event 4 */ +#define HRTIM_RSTR_EXTEVNT5_Pos (13U) +#define HRTIM_RSTR_EXTEVNT5_Msk (0x1UL << HRTIM_RSTR_EXTEVNT5_Pos) /*!< 0x00002000 */ +#define HRTIM_RSTR_EXTEVNT5 HRTIM_RSTR_EXTEVNT5_Msk /*!< External event 5 */ +#define HRTIM_RSTR_EXTEVNT6_Pos (14U) +#define HRTIM_RSTR_EXTEVNT6_Msk (0x1UL << HRTIM_RSTR_EXTEVNT6_Pos) /*!< 0x00004000 */ +#define HRTIM_RSTR_EXTEVNT6 HRTIM_RSTR_EXTEVNT6_Msk /*!< External event 6 */ +#define HRTIM_RSTR_EXTEVNT7_Pos (15U) +#define HRTIM_RSTR_EXTEVNT7_Msk (0x1UL << HRTIM_RSTR_EXTEVNT7_Pos) /*!< 0x00008000 */ +#define HRTIM_RSTR_EXTEVNT7 HRTIM_RSTR_EXTEVNT7_Msk /*!< External event 7 */ +#define HRTIM_RSTR_EXTEVNT8_Pos (16U) +#define HRTIM_RSTR_EXTEVNT8_Msk (0x1UL << HRTIM_RSTR_EXTEVNT8_Pos) /*!< 0x00010000 */ +#define HRTIM_RSTR_EXTEVNT8 HRTIM_RSTR_EXTEVNT8_Msk /*!< External event 8 */ +#define HRTIM_RSTR_EXTEVNT9_Pos (17U) +#define HRTIM_RSTR_EXTEVNT9_Msk (0x1UL << HRTIM_RSTR_EXTEVNT9_Pos) /*!< 0x00020000 */ +#define HRTIM_RSTR_EXTEVNT9 HRTIM_RSTR_EXTEVNT9_Msk /*!< External event 9 */ +#define HRTIM_RSTR_EXTEVNT10_Pos (18U) +#define HRTIM_RSTR_EXTEVNT10_Msk (0x1UL << HRTIM_RSTR_EXTEVNT10_Pos) /*!< 0x00040000 */ +#define HRTIM_RSTR_EXTEVNT10 HRTIM_RSTR_EXTEVNT10_Msk /*!< External event 10 */ + +/* Slave Timer A reset enable bits upon other slave timers events */ +#define HRTIM_RSTR_TIMBCMP1_Pos (19U) +#define HRTIM_RSTR_TIMBCMP1_Msk (0x1UL << HRTIM_RSTR_TIMBCMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTR_TIMBCMP1 HRTIM_RSTR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_RSTR_TIMBCMP2_Pos (20U) +#define HRTIM_RSTR_TIMBCMP2_Msk (0x1UL << HRTIM_RSTR_TIMBCMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTR_TIMBCMP2 HRTIM_RSTR_TIMBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_RSTR_TIMBCMP4_Pos (21U) +#define HRTIM_RSTR_TIMBCMP4_Msk (0x1UL << HRTIM_RSTR_TIMBCMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTR_TIMBCMP4 HRTIM_RSTR_TIMBCMP4_Msk /*!< Timer B compare 4 */ + +#define HRTIM_RSTR_TIMCCMP1_Pos (22U) +#define HRTIM_RSTR_TIMCCMP1_Msk (0x1UL << HRTIM_RSTR_TIMCCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTR_TIMCCMP1 HRTIM_RSTR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_RSTR_TIMCCMP2_Pos (23U) +#define HRTIM_RSTR_TIMCCMP2_Msk (0x1UL << HRTIM_RSTR_TIMCCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTR_TIMCCMP2 HRTIM_RSTR_TIMCCMP2_Msk /*!< Timer C compare 2 */ +#define HRTIM_RSTR_TIMCCMP4_Pos (24U) +#define HRTIM_RSTR_TIMCCMP4_Msk (0x1UL << HRTIM_RSTR_TIMCCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTR_TIMCCMP4 HRTIM_RSTR_TIMCCMP4_Msk /*!< Timer C compare 4 */ + +#define HRTIM_RSTR_TIMDCMP1_Pos (25U) +#define HRTIM_RSTR_TIMDCMP1_Msk (0x1UL << HRTIM_RSTR_TIMDCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTR_TIMDCMP1 HRTIM_RSTR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_RSTR_TIMDCMP2_Pos (26U) +#define HRTIM_RSTR_TIMDCMP2_Msk (0x1UL << HRTIM_RSTR_TIMDCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTR_TIMDCMP2 HRTIM_RSTR_TIMDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_RSTR_TIMDCMP4_Pos (27U) +#define HRTIM_RSTR_TIMDCMP4_Msk (0x1UL << HRTIM_RSTR_TIMDCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTR_TIMDCMP4 HRTIM_RSTR_TIMDCMP4_Msk /*!< Timer D compare 4 */ + +#define HRTIM_RSTR_TIMECMP1_Pos (28U) +#define HRTIM_RSTR_TIMECMP1_Msk (0x1UL << HRTIM_RSTR_TIMECMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTR_TIMECMP1 HRTIM_RSTR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_RSTR_TIMECMP2_Pos (29U) +#define HRTIM_RSTR_TIMECMP2_Msk (0x1UL << HRTIM_RSTR_TIMECMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTR_TIMECMP2 HRTIM_RSTR_TIMECMP2_Msk /*!< Timer E compare 2 */ +#define HRTIM_RSTR_TIMECMP4_Pos (30U) +#define HRTIM_RSTR_TIMECMP4_Msk (0x1UL << HRTIM_RSTR_TIMECMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTR_TIMECMP4 HRTIM_RSTR_TIMECMP4_Msk /*!< Timer E compare 4 */ + +#define HRTIM_RSTR_TIMFCMP2_Pos (31U) +#define HRTIM_RSTR_TIMFCMP2_Msk (0x1UL << HRTIM_RSTR_TIMFCMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTR_TIMFCMP2 HRTIM_RSTR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +/* Slave Timer B reset enable bits upon other slave timers events */ +#define HRTIM_RSTBR_TIMACMP1_Pos (19U) +#define HRTIM_RSTBR_TIMACMP1_Msk (0x1UL << HRTIM_RSTBR_TIMACMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTBR_TIMACMP1 HRTIM_RSTBR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RSTBR_TIMACMP2_Pos (20U) +#define HRTIM_RSTBR_TIMACMP2_Msk (0x1UL << HRTIM_RSTBR_TIMACMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTBR_TIMACMP2 HRTIM_RSTBR_TIMACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RSTBR_TIMACMP4_Pos (21U) +#define HRTIM_RSTBR_TIMACMP4_Msk (0x1UL << HRTIM_RSTBR_TIMACMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTBR_TIMACMP4 HRTIM_RSTBR_TIMACMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RSTBR_TIMCCMP1_Pos (22U) +#define HRTIM_RSTBR_TIMCCMP1_Msk (0x1UL << HRTIM_RSTBR_TIMCCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTBR_TIMCCMP1 HRTIM_RSTBR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_RSTBR_TIMCCMP2_Pos (23U) +#define HRTIM_RSTBR_TIMCCMP2_Msk (0x1UL << HRTIM_RSTBR_TIMCCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTBR_TIMCCMP2 HRTIM_RSTBR_TIMCCMP2_Msk /*!< Timer C compare 2 */ +#define HRTIM_RSTBR_TIMCCMP4_Pos (24U) +#define HRTIM_RSTBR_TIMCCMP4_Msk (0x1UL << HRTIM_RSTBR_TIMCCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTBR_TIMCCMP4 HRTIM_RSTBR_TIMCCMP4_Msk /*!< Timer C compare 4 */ + +#define HRTIM_RSTBR_TIMDCMP1_Pos (25U) +#define HRTIM_RSTBR_TIMDCMP1_Msk (0x1UL << HRTIM_RSTBR_TIMDCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTBR_TIMDCMP1 HRTIM_RSTBR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_RSTBR_TIMDCMP2_Pos (26U) +#define HRTIM_RSTBR_TIMDCMP2_Msk (0x1UL << HRTIM_RSTBR_TIMDCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTBR_TIMDCMP2 HRTIM_RSTBR_TIMDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_RSTBR_TIMDCMP4_Pos (27U) +#define HRTIM_RSTBR_TIMDCMP4_Msk (0x1UL << HRTIM_RSTBR_TIMDCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTBR_TIMDCMP4 HRTIM_RSTBR_TIMDCMP4_Msk /*!< Timer D compare 4 */ + +#define HRTIM_RSTBR_TIMECMP1_Pos (28U) +#define HRTIM_RSTBR_TIMECMP1_Msk (0x1UL << HRTIM_RSTBR_TIMECMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTBR_TIMECMP1 HRTIM_RSTBR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_RSTBR_TIMECMP2_Pos (29U) +#define HRTIM_RSTBR_TIMECMP2_Msk (0x1UL << HRTIM_RSTBR_TIMECMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTBR_TIMECMP2 HRTIM_RSTBR_TIMECMP2_Msk /*!< Timer E compare 2 */ +#define HRTIM_RSTBR_TIMECMP4_Pos (30U) +#define HRTIM_RSTBR_TIMECMP4_Msk (0x1UL << HRTIM_RSTBR_TIMECMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTBR_TIMECMP4 HRTIM_RSTBR_TIMECMP4_Msk /*!< Timer E compare 4 */ + +#define HRTIM_RSTBR_TIMFCMP2_Pos (31U) +#define HRTIM_RSTBR_TIMFCMP2_Msk (0x1UL << HRTIM_RSTBR_TIMFCMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTBR_TIMFCMP2 HRTIM_RSTBR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +/* Slave Timer C reset enable bits upon other slave timers events */ +#define HRTIM_RSTCR_TIMACMP1_Pos (19U) +#define HRTIM_RSTCR_TIMACMP1_Msk (0x1UL << HRTIM_RSTCR_TIMACMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTCR_TIMACMP1 HRTIM_RSTCR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RSTCR_TIMACMP2_Pos (20U) +#define HRTIM_RSTCR_TIMACMP2_Msk (0x1UL << HRTIM_RSTCR_TIMACMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTCR_TIMACMP2 HRTIM_RSTCR_TIMACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RSTCR_TIMACMP4_Pos (21U) +#define HRTIM_RSTCR_TIMACMP4_Msk (0x1UL << HRTIM_RSTCR_TIMACMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTCR_TIMACMP4 HRTIM_RSTCR_TIMACMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RSTCR_TIMBCMP1_Pos (22U) +#define HRTIM_RSTCR_TIMBCMP1_Msk (0x1UL << HRTIM_RSTCR_TIMBCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTCR_TIMBCMP1 HRTIM_RSTCR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_RSTCR_TIMBCMP2_Pos (23U) +#define HRTIM_RSTCR_TIMBCMP2_Msk (0x1UL << HRTIM_RSTCR_TIMBCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTCR_TIMBCMP2 HRTIM_RSTCR_TIMBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_RSTCR_TIMBCMP4_Pos (24U) +#define HRTIM_RSTCR_TIMBCMP4_Msk (0x1UL << HRTIM_RSTCR_TIMBCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTCR_TIMBCMP4 HRTIM_RSTCR_TIMBCMP4_Msk /*!< Timer B compare 4 */ + +#define HRTIM_RSTCR_TIMDCMP1_Pos (25U) +#define HRTIM_RSTCR_TIMDCMP1_Msk (0x1UL << HRTIM_RSTCR_TIMDCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTCR_TIMDCMP1 HRTIM_RSTCR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_RSTCR_TIMDCMP2_Pos (26U) +#define HRTIM_RSTCR_TIMDCMP2_Msk (0x1UL << HRTIM_RSTCR_TIMDCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTCR_TIMDCMP2 HRTIM_RSTCR_TIMDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_RSTCR_TIMDCMP4_Pos (27U) +#define HRTIM_RSTCR_TIMDCMP4_Msk (0x1UL << HRTIM_RSTCR_TIMDCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTCR_TIMDCMP4 HRTIM_RSTCR_TIMDCMP4_Msk /*!< Timer D compare 4 */ + +#define HRTIM_RSTCR_TIMECMP1_Pos (28U) +#define HRTIM_RSTCR_TIMECMP1_Msk (0x1UL << HRTIM_RSTCR_TIMECMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTCR_TIMECMP1 HRTIM_RSTCR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_RSTCR_TIMECMP2_Pos (29U) +#define HRTIM_RSTCR_TIMECMP2_Msk (0x1UL << HRTIM_RSTCR_TIMECMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTCR_TIMECMP2 HRTIM_RSTCR_TIMECMP2_Msk /*!< Timer E compare 2 */ +#define HRTIM_RSTCR_TIMECMP4_Pos (30U) +#define HRTIM_RSTCR_TIMECMP4_Msk (0x1UL << HRTIM_RSTCR_TIMECMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTCR_TIMECMP4 HRTIM_RSTCR_TIMECMP4_Msk /*!< Timer E compare 4 */ + +#define HRTIM_RSTCR_TIMFCMP2_Pos (31U) +#define HRTIM_RSTCR_TIMFCMP2_Msk (0x1UL << HRTIM_RSTCR_TIMFCMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTCR_TIMFCMP2 HRTIM_RSTCR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +/* Slave Timer D reset enable bits upon other slave timers events */ +#define HRTIM_RSTDR_TIMACMP1_Pos (19U) +#define HRTIM_RSTDR_TIMACMP1_Msk (0x1UL << HRTIM_RSTDR_TIMACMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTDR_TIMACMP1 HRTIM_RSTDR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RSTDR_TIMACMP2_Pos (20U) +#define HRTIM_RSTDR_TIMACMP2_Msk (0x1UL << HRTIM_RSTDR_TIMACMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTDR_TIMACMP2 HRTIM_RSTDR_TIMACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RSTDR_TIMACMP4_Pos (21U) +#define HRTIM_RSTDR_TIMACMP4_Msk (0x1UL << HRTIM_RSTDR_TIMACMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTDR_TIMACMP4 HRTIM_RSTDR_TIMACMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RSTDR_TIMBCMP1_Pos (22U) +#define HRTIM_RSTDR_TIMBCMP1_Msk (0x1UL << HRTIM_RSTDR_TIMBCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTDR_TIMBCMP1 HRTIM_RSTDR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_RSTDR_TIMBCMP2_Pos (23U) +#define HRTIM_RSTDR_TIMBCMP2_Msk (0x1UL << HRTIM_RSTDR_TIMBCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTDR_TIMBCMP2 HRTIM_RSTDR_TIMBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_RSTDR_TIMBCMP4_Pos (24U) +#define HRTIM_RSTDR_TIMBCMP4_Msk (0x1UL << HRTIM_RSTDR_TIMBCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTDR_TIMBCMP4 HRTIM_RSTDR_TIMBCMP4_Msk /*!< Timer B compare 4 */ + +#define HRTIM_RSTDR_TIMCCMP1_Pos (25U) +#define HRTIM_RSTDR_TIMCCMP1_Msk (0x1UL << HRTIM_RSTDR_TIMCCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTDR_TIMCCMP1 HRTIM_RSTDR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_RSTDR_TIMCCMP2_Pos (26U) +#define HRTIM_RSTDR_TIMCCMP2_Msk (0x1UL << HRTIM_RSTDR_TIMCCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTDR_TIMCCMP2 HRTIM_RSTDR_TIMCCMP2_Msk /*!< Timer C compare 2 */ +#define HRTIM_RSTDR_TIMCCMP4_Pos (27U) +#define HRTIM_RSTDR_TIMCCMP4_Msk (0x1UL << HRTIM_RSTDR_TIMCCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTDR_TIMCCMP4 HRTIM_RSTDR_TIMCCMP4_Msk /*!< Timer C compare 4 */ + +#define HRTIM_RSTDR_TIMECMP1_Pos (28U) +#define HRTIM_RSTDR_TIMECMP1_Msk (0x1UL << HRTIM_RSTDR_TIMECMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTDR_TIMECMP1 HRTIM_RSTDR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_RSTDR_TIMECMP2_Pos (29U) +#define HRTIM_RSTDR_TIMECMP2_Msk (0x1UL << HRTIM_RSTDR_TIMECMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTDR_TIMECMP2 HRTIM_RSTDR_TIMECMP2_Msk /*!< Timer E compare 2 */ +#define HRTIM_RSTDR_TIMECMP4_Pos (30U) +#define HRTIM_RSTDR_TIMECMP4_Msk (0x1UL << HRTIM_RSTDR_TIMECMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTDR_TIMECMP4 HRTIM_RSTDR_TIMECMP4_Msk /*!< Timer E compare 4 */ + +#define HRTIM_RSTDR_TIMFCMP2_Pos (31U) +#define HRTIM_RSTDR_TIMFCMP2_Msk (0x1UL << HRTIM_RSTDR_TIMFCMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTDR_TIMFCMP2 HRTIM_RSTDR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +/* Slave Timer E reset enable bits upon other slave timers events */ +#define HRTIM_RSTER_TIMACMP1_Pos (19U) +#define HRTIM_RSTER_TIMACMP1_Msk (0x1UL << HRTIM_RSTER_TIMACMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTER_TIMACMP1 HRTIM_RSTER_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RSTER_TIMACMP2_Pos (20U) +#define HRTIM_RSTER_TIMACMP2_Msk (0x1UL << HRTIM_RSTER_TIMACMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTER_TIMACMP2 HRTIM_RSTER_TIMACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RSTER_TIMACMP4_Pos (21U) +#define HRTIM_RSTER_TIMACMP4_Msk (0x1UL << HRTIM_RSTER_TIMACMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTER_TIMACMP4 HRTIM_RSTER_TIMACMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RSTER_TIMBCMP1_Pos (22U) +#define HRTIM_RSTER_TIMBCMP1_Msk (0x1UL << HRTIM_RSTER_TIMBCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTER_TIMBCMP1 HRTIM_RSTER_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_RSTER_TIMBCMP2_Pos (23U) +#define HRTIM_RSTER_TIMBCMP2_Msk (0x1UL << HRTIM_RSTER_TIMBCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTER_TIMBCMP2 HRTIM_RSTER_TIMBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_RSTER_TIMBCMP4_Pos (24U) +#define HRTIM_RSTER_TIMBCMP4_Msk (0x1UL << HRTIM_RSTER_TIMBCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTER_TIMBCMP4 HRTIM_RSTER_TIMBCMP4_Msk /*!< Timer B compare 4 */ + +#define HRTIM_RSTER_TIMCCMP1_Pos (25U) +#define HRTIM_RSTER_TIMCCMP1_Msk (0x1UL << HRTIM_RSTER_TIMCCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTER_TIMCCMP1 HRTIM_RSTER_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_RSTER_TIMCCMP2_Pos (26U) +#define HRTIM_RSTER_TIMCCMP2_Msk (0x1UL << HRTIM_RSTER_TIMCCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTER_TIMCCMP2 HRTIM_RSTER_TIMCCMP2_Msk /*!< Timer C compare 2 */ +#define HRTIM_RSTER_TIMCCMP4_Pos (27U) +#define HRTIM_RSTER_TIMCCMP4_Msk (0x1UL << HRTIM_RSTER_TIMCCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTER_TIMCCMP4 HRTIM_RSTER_TIMCCMP4_Msk /*!< Timer C compare 4 */ + +#define HRTIM_RSTER_TIMDCMP1_Pos (28U) +#define HRTIM_RSTER_TIMDCMP1_Msk (0x1UL << HRTIM_RSTER_TIMDCMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTER_TIMDCMP1 HRTIM_RSTER_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_RSTER_TIMDCMP2_Pos (29U) +#define HRTIM_RSTER_TIMDCMP2_Msk (0x1UL << HRTIM_RSTER_TIMDCMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTER_TIMDCMP2 HRTIM_RSTER_TIMDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_RSTER_TIMDCMP4_Pos (30U) +#define HRTIM_RSTER_TIMDCMP4_Msk (0x1UL << HRTIM_RSTER_TIMDCMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTER_TIMDCMP4 HRTIM_RSTER_TIMDCMP4_Msk /*!< Timer D compare 4 */ + +#define HRTIM_RSTER_TIMFCMP2_Pos (31U) +#define HRTIM_RSTER_TIMFCMP2_Msk (0x1UL << HRTIM_RSTER_TIMFCMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTER_TIMFCMP2 HRTIM_RSTER_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +/* Slave Timer F reset enable bits upon other slave timers events */ +#define HRTIM_RSTFR_TIMACMP1_Pos (19U) +#define HRTIM_RSTFR_TIMACMP1_Msk (0x1UL << HRTIM_RSTFR_TIMACMP1_Pos) /*!< 0x00080000 */ +#define HRTIM_RSTFR_TIMACMP1 HRTIM_RSTFR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_RSTFR_TIMACMP2_Pos (20U) +#define HRTIM_RSTFR_TIMACMP2_Msk (0x1UL << HRTIM_RSTFR_TIMACMP2_Pos) /*!< 0x00100000 */ +#define HRTIM_RSTFR_TIMACMP2 HRTIM_RSTFR_TIMACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_RSTFR_TIMACMP4_Pos (21U) +#define HRTIM_RSTFR_TIMACMP4_Msk (0x1UL << HRTIM_RSTFR_TIMACMP4_Pos) /*!< 0x00200000 */ +#define HRTIM_RSTFR_TIMACMP4 HRTIM_RSTFR_TIMACMP4_Msk /*!< Timer A compare 4 */ + +#define HRTIM_RSTFR_TIMBCMP1_Pos (22U) +#define HRTIM_RSTFR_TIMBCMP1_Msk (0x1UL << HRTIM_RSTFR_TIMBCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_RSTFR_TIMBCMP1 HRTIM_RSTFR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_RSTFR_TIMBCMP2_Pos (23U) +#define HRTIM_RSTFR_TIMBCMP2_Msk (0x1UL << HRTIM_RSTFR_TIMBCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_RSTFR_TIMBCMP2 HRTIM_RSTFR_TIMBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_RSTFR_TIMBCMP4_Pos (24U) +#define HRTIM_RSTFR_TIMBCMP4_Msk (0x1UL << HRTIM_RSTFR_TIMBCMP4_Pos) /*!< 0x01000000 */ +#define HRTIM_RSTFR_TIMBCMP4 HRTIM_RSTFR_TIMBCMP4_Msk /*!< Timer B compare 4 */ + +#define HRTIM_RSTFR_TIMCCMP1_Pos (25U) +#define HRTIM_RSTFR_TIMCCMP1_Msk (0x1UL << HRTIM_RSTFR_TIMCCMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_RSTFR_TIMCCMP1 HRTIM_RSTFR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_RSTFR_TIMCCMP2_Pos (26U) +#define HRTIM_RSTFR_TIMCCMP2_Msk (0x1UL << HRTIM_RSTFR_TIMCCMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_RSTFR_TIMCCMP2 HRTIM_RSTFR_TIMCCMP2_Msk /*!< Timer C compare 2 */ +#define HRTIM_RSTFR_TIMCCMP4_Pos (27U) +#define HRTIM_RSTFR_TIMCCMP4_Msk (0x1UL << HRTIM_RSTFR_TIMCCMP4_Pos) /*!< 0x08000000 */ +#define HRTIM_RSTFR_TIMCCMP4 HRTIM_RSTFR_TIMCCMP4_Msk /*!< Timer C compare 4 */ + +#define HRTIM_RSTFR_TIMDCMP1_Pos (28U) +#define HRTIM_RSTFR_TIMDCMP1_Msk (0x1UL << HRTIM_RSTFR_TIMDCMP1_Pos) /*!< 0x10000000 */ +#define HRTIM_RSTFR_TIMDCMP1 HRTIM_RSTFR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_RSTFR_TIMDCMP2_Pos (29U) +#define HRTIM_RSTFR_TIMDCMP2_Msk (0x1UL << HRTIM_RSTFR_TIMDCMP2_Pos) /*!< 0x20000000 */ +#define HRTIM_RSTFR_TIMDCMP2 HRTIM_RSTFR_TIMDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_RSTFR_TIMDCMP4_Pos (30U) +#define HRTIM_RSTFR_TIMDCMP4_Msk (0x1UL << HRTIM_RSTFR_TIMDCMP4_Pos) /*!< 0x40000000 */ +#define HRTIM_RSTFR_TIMDCMP4 HRTIM_RSTFR_TIMDCMP4_Msk /*!< Timer D compare 4 */ + +#define HRTIM_RSTFR_TIMECMP2_Pos (31U) +#define HRTIM_RSTFR_TIMECMP2_Msk (0x1UL << HRTIM_RSTFR_TIMECMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_RSTFR_TIMECMP2 HRTIM_RSTFR_TIMECMP2_Msk /*!< Timer E compare 2 */ + +/**** Bit definition for Slave Timer Chopper register *************************/ +#define HRTIM_CHPR_CARFRQ_Pos (0U) +#define HRTIM_CHPR_CARFRQ_Msk (0xFUL << HRTIM_CHPR_CARFRQ_Pos) /*!< 0x0000000F */ +#define HRTIM_CHPR_CARFRQ HRTIM_CHPR_CARFRQ_Msk /*!< Timer carrier frequency value */ +#define HRTIM_CHPR_CARFRQ_0 (0x1UL << HRTIM_CHPR_CARFRQ_Pos) /*!< 0x00000001 */ +#define HRTIM_CHPR_CARFRQ_1 (0x2UL << HRTIM_CHPR_CARFRQ_Pos) /*!< 0x00000002 */ +#define HRTIM_CHPR_CARFRQ_2 (0x4UL << HRTIM_CHPR_CARFRQ_Pos) /*!< 0x00000004 */ +#define HRTIM_CHPR_CARFRQ_3 (0x8UL << HRTIM_CHPR_CARFRQ_Pos) /*!< 0x00000008 */ + +#define HRTIM_CHPR_CARDTY_Pos (4U) +#define HRTIM_CHPR_CARDTY_Msk (0x7UL << HRTIM_CHPR_CARDTY_Pos) /*!< 0x00000070 */ +#define HRTIM_CHPR_CARDTY HRTIM_CHPR_CARDTY_Msk /*!< Timer chopper duty cycle value */ +#define HRTIM_CHPR_CARDTY_0 (0x1UL << HRTIM_CHPR_CARDTY_Pos) /*!< 0x00000010 */ +#define HRTIM_CHPR_CARDTY_1 (0x2UL << HRTIM_CHPR_CARDTY_Pos) /*!< 0x00000020 */ +#define HRTIM_CHPR_CARDTY_2 (0x4UL << HRTIM_CHPR_CARDTY_Pos) /*!< 0x00000040 */ + +#define HRTIM_CHPR_STRPW_Pos (7U) +#define HRTIM_CHPR_STRPW_Msk (0xFUL << HRTIM_CHPR_STRPW_Pos) /*!< 0x00000780 */ +#define HRTIM_CHPR_STRPW HRTIM_CHPR_STRPW_Msk /*!< Timer start pulse width value */ +#define HRTIM_CHPR_STRPW_0 (0x1UL << HRTIM_CHPR_STRPW_Pos) /*!< 0x00000080 */ +#define HRTIM_CHPR_STRPW_1 (0x2UL << HRTIM_CHPR_STRPW_Pos) /*!< 0x00000100 */ +#define HRTIM_CHPR_STRPW_2 (0x4UL << HRTIM_CHPR_STRPW_Pos) /*!< 0x00000200 */ +#define HRTIM_CHPR_STRPW_3 (0x8UL << HRTIM_CHPR_STRPW_Pos) /*!< 0x00000400 */ + +/**** Bit definition for Slave Timer Capture 1 control register ***************/ +#define HRTIM_CPT1CR_SWCPT_Pos (0U) +#define HRTIM_CPT1CR_SWCPT_Msk (0x1UL << HRTIM_CPT1CR_SWCPT_Pos) /*!< 0x00000001 */ +#define HRTIM_CPT1CR_SWCPT HRTIM_CPT1CR_SWCPT_Msk /*!< Software capture */ +#define HRTIM_CPT1CR_UPDCPT_Pos (1U) +#define HRTIM_CPT1CR_UPDCPT_Msk (0x1UL << HRTIM_CPT1CR_UPDCPT_Pos) /*!< 0x00000002 */ +#define HRTIM_CPT1CR_UPDCPT HRTIM_CPT1CR_UPDCPT_Msk /*!< Update capture */ +#define HRTIM_CPT1CR_EXEV1CPT_Pos (2U) +#define HRTIM_CPT1CR_EXEV1CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV1CPT_Pos) /*!< 0x00000004 */ +#define HRTIM_CPT1CR_EXEV1CPT HRTIM_CPT1CR_EXEV1CPT_Msk /*!< External event 1 capture */ +#define HRTIM_CPT1CR_EXEV2CPT_Pos (3U) +#define HRTIM_CPT1CR_EXEV2CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV2CPT_Pos) /*!< 0x00000008 */ +#define HRTIM_CPT1CR_EXEV2CPT HRTIM_CPT1CR_EXEV2CPT_Msk /*!< External event 2 capture */ +#define HRTIM_CPT1CR_EXEV3CPT_Pos (4U) +#define HRTIM_CPT1CR_EXEV3CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV3CPT_Pos) /*!< 0x00000010 */ +#define HRTIM_CPT1CR_EXEV3CPT HRTIM_CPT1CR_EXEV3CPT_Msk /*!< External event 3 capture */ +#define HRTIM_CPT1CR_EXEV4CPT_Pos (5U) +#define HRTIM_CPT1CR_EXEV4CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV4CPT_Pos) /*!< 0x00000020 */ +#define HRTIM_CPT1CR_EXEV4CPT HRTIM_CPT1CR_EXEV4CPT_Msk /*!< External event 4 capture */ +#define HRTIM_CPT1CR_EXEV5CPT_Pos (6U) +#define HRTIM_CPT1CR_EXEV5CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV5CPT_Pos) /*!< 0x00000040 */ +#define HRTIM_CPT1CR_EXEV5CPT HRTIM_CPT1CR_EXEV5CPT_Msk /*!< External event 5 capture */ +#define HRTIM_CPT1CR_EXEV6CPT_Pos (7U) +#define HRTIM_CPT1CR_EXEV6CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV6CPT_Pos) /*!< 0x00000080 */ +#define HRTIM_CPT1CR_EXEV6CPT HRTIM_CPT1CR_EXEV6CPT_Msk /*!< External event 6 capture */ +#define HRTIM_CPT1CR_EXEV7CPT_Pos (8U) +#define HRTIM_CPT1CR_EXEV7CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV7CPT_Pos) /*!< 0x00000100 */ +#define HRTIM_CPT1CR_EXEV7CPT HRTIM_CPT1CR_EXEV7CPT_Msk /*!< External event 7 capture */ +#define HRTIM_CPT1CR_EXEV8CPT_Pos (9U) +#define HRTIM_CPT1CR_EXEV8CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV8CPT_Pos) /*!< 0x00000200 */ +#define HRTIM_CPT1CR_EXEV8CPT HRTIM_CPT1CR_EXEV8CPT_Msk /*!< External event 8 capture */ +#define HRTIM_CPT1CR_EXEV9CPT_Pos (10U) +#define HRTIM_CPT1CR_EXEV9CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV9CPT_Pos) /*!< 0x00000400 */ +#define HRTIM_CPT1CR_EXEV9CPT HRTIM_CPT1CR_EXEV9CPT_Msk /*!< External event 9 capture */ +#define HRTIM_CPT1CR_EXEV10CPT_Pos (11U) +#define HRTIM_CPT1CR_EXEV10CPT_Msk (0x1UL << HRTIM_CPT1CR_EXEV10CPT_Pos) /*!< 0x00000800 */ +#define HRTIM_CPT1CR_EXEV10CPT HRTIM_CPT1CR_EXEV10CPT_Msk /*!< External event 10 capture */ + +#define HRTIM_CPT1CR_TF1SET_Pos (0U) +#define HRTIM_CPT1CR_TF1SET_Msk (0x1UL << HRTIM_CPT1CR_TF1SET_Pos) /*!< 0x00000001 */ +#define HRTIM_CPT1CR_TF1SET HRTIM_CPT1CR_TF1SET_Msk /*!< Timer F output 1 set */ +#define HRTIM_CPT1CR_TF1RST_Pos (1U) +#define HRTIM_CPT1CR_TF1RST_Msk (0x1UL << HRTIM_CPT1CR_TF1RST_Pos) /*!< 0x00000002 */ +#define HRTIM_CPT1CR_TF1RST HRTIM_CPT1CR_TF1RST_Msk /*!< Timer F output 1 reset */ +#define HRTIM_CPT1CR_TIMFCMP1_Pos (2U) +#define HRTIM_CPT1CR_TIMFCMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMFCMP1_Pos) /*!< 0x00000004 */ +#define HRTIM_CPT1CR_TIMFCMP1 HRTIM_CPT1CR_TIMFCMP1_Msk /*!< Timer F compare 1 */ +#define HRTIM_CPT1CR_TIMFCMP2_Pos (3U) +#define HRTIM_CPT1CR_TIMFCMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMFCMP2_Pos) /*!< 0x00000008 */ +#define HRTIM_CPT1CR_TIMFCMP2 HRTIM_CPT1CR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +#define HRTIM_CPT1CR_TA1SET_Pos (12U) +#define HRTIM_CPT1CR_TA1SET_Msk (0x1UL << HRTIM_CPT1CR_TA1SET_Pos) /*!< 0x00001000 */ +#define HRTIM_CPT1CR_TA1SET HRTIM_CPT1CR_TA1SET_Msk /*!< Timer A output 1 set */ +#define HRTIM_CPT1CR_TA1RST_Pos (13U) +#define HRTIM_CPT1CR_TA1RST_Msk (0x1UL << HRTIM_CPT1CR_TA1RST_Pos) /*!< 0x00002000 */ +#define HRTIM_CPT1CR_TA1RST HRTIM_CPT1CR_TA1RST_Msk /*!< Timer A output 1 reset */ +#define HRTIM_CPT1CR_TIMACMP1_Pos (14U) +#define HRTIM_CPT1CR_TIMACMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMACMP1_Pos) /*!< 0x00004000 */ +#define HRTIM_CPT1CR_TIMACMP1 HRTIM_CPT1CR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_CPT1CR_TIMACMP2_Pos (15U) +#define HRTIM_CPT1CR_TIMACMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMACMP2_Pos) /*!< 0x00008000 */ +#define HRTIM_CPT1CR_TIMACMP2 HRTIM_CPT1CR_TIMACMP2_Msk /*!< Timer A compare 2 */ + +#define HRTIM_CPT1CR_TB1SET_Pos (16U) +#define HRTIM_CPT1CR_TB1SET_Msk (0x1UL << HRTIM_CPT1CR_TB1SET_Pos) /*!< 0x00010000 */ +#define HRTIM_CPT1CR_TB1SET HRTIM_CPT1CR_TB1SET_Msk /*!< Timer B output 1 set */ +#define HRTIM_CPT1CR_TB1RST_Pos (17U) +#define HRTIM_CPT1CR_TB1RST_Msk (0x1UL << HRTIM_CPT1CR_TB1RST_Pos) /*!< 0x00020000 */ +#define HRTIM_CPT1CR_TB1RST HRTIM_CPT1CR_TB1RST_Msk /*!< Timer B output 1 reset */ +#define HRTIM_CPT1CR_TIMBCMP1_Pos (18U) +#define HRTIM_CPT1CR_TIMBCMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMBCMP1_Pos) /*!< 0x00040000 */ +#define HRTIM_CPT1CR_TIMBCMP1 HRTIM_CPT1CR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_CPT1CR_TIMBCMP2_Pos (19U) +#define HRTIM_CPT1CR_TIMBCMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMBCMP2_Pos) /*!< 0x00080000 */ +#define HRTIM_CPT1CR_TIMBCMP2 HRTIM_CPT1CR_TIMBCMP2_Msk /*!< Timer B compare 2 */ + +#define HRTIM_CPT1CR_TC1SET_Pos (20U) +#define HRTIM_CPT1CR_TC1SET_Msk (0x1UL << HRTIM_CPT1CR_TC1SET_Pos) /*!< 0x00100000 */ +#define HRTIM_CPT1CR_TC1SET HRTIM_CPT1CR_TC1SET_Msk /*!< Timer C output 1 set */ +#define HRTIM_CPT1CR_TC1RST_Pos (21U) +#define HRTIM_CPT1CR_TC1RST_Msk (0x1UL << HRTIM_CPT1CR_TC1RST_Pos) /*!< 0x00200000 */ +#define HRTIM_CPT1CR_TC1RST HRTIM_CPT1CR_TC1RST_Msk /*!< Timer C output 1 reset */ +#define HRTIM_CPT1CR_TIMCCMP1_Pos (22U) +#define HRTIM_CPT1CR_TIMCCMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMCCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_CPT1CR_TIMCCMP1 HRTIM_CPT1CR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_CPT1CR_TIMCCMP2_Pos (23U) +#define HRTIM_CPT1CR_TIMCCMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMCCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_CPT1CR_TIMCCMP2 HRTIM_CPT1CR_TIMCCMP2_Msk /*!< Timer C compare 2 */ + +#define HRTIM_CPT1CR_TD1SET_Pos (24U) +#define HRTIM_CPT1CR_TD1SET_Msk (0x1UL << HRTIM_CPT1CR_TD1SET_Pos) /*!< 0x01000000 */ +#define HRTIM_CPT1CR_TD1SET HRTIM_CPT1CR_TD1SET_Msk /*!< Timer D output 1 set */ +#define HRTIM_CPT1CR_TD1RST_Pos (25U) +#define HRTIM_CPT1CR_TD1RST_Msk (0x1UL << HRTIM_CPT1CR_TD1RST_Pos) /*!< 0x02000000 */ +#define HRTIM_CPT1CR_TD1RST HRTIM_CPT1CR_TD1RST_Msk /*!< Timer D output 1 reset */ +#define HRTIM_CPT1CR_TIMDCMP1_Pos (26U) +#define HRTIM_CPT1CR_TIMDCMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMDCMP1_Pos) /*!< 0x04000000 */ +#define HRTIM_CPT1CR_TIMDCMP1 HRTIM_CPT1CR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_CPT1CR_TIMDCMP2_Pos (27U) +#define HRTIM_CPT1CR_TIMDCMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMDCMP2_Pos) /*!< 0x08000000 */ +#define HRTIM_CPT1CR_TIMDCMP2 HRTIM_CPT1CR_TIMDCMP2_Msk /*!< Timer D compare 2 */ + +#define HRTIM_CPT1CR_TE1SET_Pos (28U) +#define HRTIM_CPT1CR_TE1SET_Msk (0x1UL << HRTIM_CPT1CR_TE1SET_Pos) /*!< 0x10000000 */ +#define HRTIM_CPT1CR_TE1SET HRTIM_CPT1CR_TE1SET_Msk /*!< Timer E output 1 set */ +#define HRTIM_CPT1CR_TE1RST_Pos (29U) +#define HRTIM_CPT1CR_TE1RST_Msk (0x1UL << HRTIM_CPT1CR_TE1RST_Pos) /*!< 0x20000000 */ +#define HRTIM_CPT1CR_TE1RST HRTIM_CPT1CR_TE1RST_Msk /*!< Timer E output 1 reset */ +#define HRTIM_CPT1CR_TIMECMP1_Pos (30U) +#define HRTIM_CPT1CR_TIMECMP1_Msk (0x1UL << HRTIM_CPT1CR_TIMECMP1_Pos) /*!< 0x40000000 */ +#define HRTIM_CPT1CR_TIMECMP1 HRTIM_CPT1CR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_CPT1CR_TIMECMP2_Pos (31U) +#define HRTIM_CPT1CR_TIMECMP2_Msk (0x1UL << HRTIM_CPT1CR_TIMECMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_CPT1CR_TIMECMP2 HRTIM_CPT1CR_TIMECMP2_Msk /*!< Timer E compare 2 */ + +/**** Bit definition for Slave Timer Capture 2 control register ***************/ +#define HRTIM_CPT2CR_SWCPT_Pos (0U) +#define HRTIM_CPT2CR_SWCPT_Msk (0x1UL << HRTIM_CPT2CR_SWCPT_Pos) /*!< 0x00000001 */ +#define HRTIM_CPT2CR_SWCPT HRTIM_CPT2CR_SWCPT_Msk /*!< Software capture */ +#define HRTIM_CPT2CR_UPDCPT_Pos (1U) +#define HRTIM_CPT2CR_UPDCPT_Msk (0x1UL << HRTIM_CPT2CR_UPDCPT_Pos) /*!< 0x00000002 */ +#define HRTIM_CPT2CR_UPDCPT HRTIM_CPT2CR_UPDCPT_Msk /*!< Update capture */ +#define HRTIM_CPT2CR_EXEV1CPT_Pos (2U) +#define HRTIM_CPT2CR_EXEV1CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV1CPT_Pos) /*!< 0x00000004 */ +#define HRTIM_CPT2CR_EXEV1CPT HRTIM_CPT2CR_EXEV1CPT_Msk /*!< External event 1 capture */ +#define HRTIM_CPT2CR_EXEV2CPT_Pos (3U) +#define HRTIM_CPT2CR_EXEV2CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV2CPT_Pos) /*!< 0x00000008 */ +#define HRTIM_CPT2CR_EXEV2CPT HRTIM_CPT2CR_EXEV2CPT_Msk /*!< External event 2 capture */ +#define HRTIM_CPT2CR_EXEV3CPT_Pos (4U) +#define HRTIM_CPT2CR_EXEV3CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV3CPT_Pos) /*!< 0x00000010 */ +#define HRTIM_CPT2CR_EXEV3CPT HRTIM_CPT2CR_EXEV3CPT_Msk /*!< External event 3 capture */ +#define HRTIM_CPT2CR_EXEV4CPT_Pos (5U) +#define HRTIM_CPT2CR_EXEV4CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV4CPT_Pos) /*!< 0x00000020 */ +#define HRTIM_CPT2CR_EXEV4CPT HRTIM_CPT2CR_EXEV4CPT_Msk /*!< External event 4 capture */ +#define HRTIM_CPT2CR_EXEV5CPT_Pos (6U) +#define HRTIM_CPT2CR_EXEV5CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV5CPT_Pos) /*!< 0x00000040 */ +#define HRTIM_CPT2CR_EXEV5CPT HRTIM_CPT2CR_EXEV5CPT_Msk /*!< External event 5 capture */ +#define HRTIM_CPT2CR_EXEV6CPT_Pos (7U) +#define HRTIM_CPT2CR_EXEV6CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV6CPT_Pos) /*!< 0x00000080 */ +#define HRTIM_CPT2CR_EXEV6CPT HRTIM_CPT2CR_EXEV6CPT_Msk /*!< External event 6 capture */ +#define HRTIM_CPT2CR_EXEV7CPT_Pos (8U) +#define HRTIM_CPT2CR_EXEV7CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV7CPT_Pos) /*!< 0x00000100 */ +#define HRTIM_CPT2CR_EXEV7CPT HRTIM_CPT2CR_EXEV7CPT_Msk /*!< External event 7 capture */ +#define HRTIM_CPT2CR_EXEV8CPT_Pos (9U) +#define HRTIM_CPT2CR_EXEV8CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV8CPT_Pos) /*!< 0x00000200 */ +#define HRTIM_CPT2CR_EXEV8CPT HRTIM_CPT2CR_EXEV8CPT_Msk /*!< External event 8 capture */ +#define HRTIM_CPT2CR_EXEV9CPT_Pos (10U) +#define HRTIM_CPT2CR_EXEV9CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV9CPT_Pos) /*!< 0x00000400 */ +#define HRTIM_CPT2CR_EXEV9CPT HRTIM_CPT2CR_EXEV9CPT_Msk /*!< External event 9 capture */ +#define HRTIM_CPT2CR_EXEV10CPT_Pos (11U) +#define HRTIM_CPT2CR_EXEV10CPT_Msk (0x1UL << HRTIM_CPT2CR_EXEV10CPT_Pos) /*!< 0x00000800 */ +#define HRTIM_CPT2CR_EXEV10CPT HRTIM_CPT2CR_EXEV10CPT_Msk /*!< External event 10 capture */ + +#define HRTIM_CPT2CR_TF1SET_Pos (0U) +#define HRTIM_CPT2CR_TF1SET_Msk (0x1UL << HRTIM_CPT2CR_TF1SET_Pos) /*!< 0x00000001 */ +#define HRTIM_CPT2CR_TF1SET HRTIM_CPT2CR_TF1SET_Msk /*!< Timer F output 1 set */ +#define HRTIM_CPT2CR_TF1RST_Pos (1U) +#define HRTIM_CPT2CR_TF1RST_Msk (0x1UL << HRTIM_CPT2CR_TF1RST_Pos) /*!< 0x00000002 */ +#define HRTIM_CPT2CR_TF1RST HRTIM_CPT2CR_TF1RST_Msk /*!< Timer F output 1 reset */ +#define HRTIM_CPT2CR_TIMFCMP1_Pos (2U) +#define HRTIM_CPT2CR_TIMFCMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMFCMP1_Pos) /*!< 0x00000004 */ +#define HRTIM_CPT2CR_TIMFCMP1 HRTIM_CPT2CR_TIMFCMP1_Msk /*!< Timer F compare 1 */ +#define HRTIM_CPT2CR_TIMFCMP2_Pos (3U) +#define HRTIM_CPT2CR_TIMFCMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMFCMP2_Pos) /*!< 0x00000008 */ +#define HRTIM_CPT2CR_TIMFCMP2 HRTIM_CPT2CR_TIMFCMP2_Msk /*!< Timer F compare 2 */ + +#define HRTIM_CPT2CR_TA1SET_Pos (12U) +#define HRTIM_CPT2CR_TA1SET_Msk (0x1UL << HRTIM_CPT2CR_TA1SET_Pos) /*!< 0x00001000 */ +#define HRTIM_CPT2CR_TA1SET HRTIM_CPT2CR_TA1SET_Msk /*!< Timer A output 1 set */ +#define HRTIM_CPT2CR_TA1RST_Pos (13U) +#define HRTIM_CPT2CR_TA1RST_Msk (0x1UL << HRTIM_CPT2CR_TA1RST_Pos) /*!< 0x00002000 */ +#define HRTIM_CPT2CR_TA1RST HRTIM_CPT2CR_TA1RST_Msk /*!< Timer A output 1 reset */ +#define HRTIM_CPT2CR_TIMACMP1_Pos (14U) +#define HRTIM_CPT2CR_TIMACMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMACMP1_Pos) /*!< 0x00004000 */ +#define HRTIM_CPT2CR_TIMACMP1 HRTIM_CPT2CR_TIMACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_CPT2CR_TIMACMP2_Pos (15U) +#define HRTIM_CPT2CR_TIMACMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMACMP2_Pos) /*!< 0x00008000 */ +#define HRTIM_CPT2CR_TIMACMP2 HRTIM_CPT2CR_TIMACMP2_Msk /*!< Timer A compare 2 */ + +#define HRTIM_CPT2CR_TB1SET_Pos (16U) +#define HRTIM_CPT2CR_TB1SET_Msk (0x1UL << HRTIM_CPT2CR_TB1SET_Pos) /*!< 0x00010000 */ +#define HRTIM_CPT2CR_TB1SET HRTIM_CPT2CR_TB1SET_Msk /*!< Timer B output 1 set */ +#define HRTIM_CPT2CR_TB1RST_Pos (17U) +#define HRTIM_CPT2CR_TB1RST_Msk (0x1UL << HRTIM_CPT2CR_TB1RST_Pos) /*!< 0x00020000 */ +#define HRTIM_CPT2CR_TB1RST HRTIM_CPT2CR_TB1RST_Msk /*!< Timer B output 1 reset */ +#define HRTIM_CPT2CR_TIMBCMP1_Pos (18U) +#define HRTIM_CPT2CR_TIMBCMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMBCMP1_Pos) /*!< 0x00040000 */ +#define HRTIM_CPT2CR_TIMBCMP1 HRTIM_CPT2CR_TIMBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_CPT2CR_TIMBCMP2_Pos (19U) +#define HRTIM_CPT2CR_TIMBCMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMBCMP2_Pos) /*!< 0x00080000 */ +#define HRTIM_CPT2CR_TIMBCMP2 HRTIM_CPT2CR_TIMBCMP2_Msk /*!< Timer B compare 2 */ + +#define HRTIM_CPT2CR_TC1SET_Pos (20U) +#define HRTIM_CPT2CR_TC1SET_Msk (0x1UL << HRTIM_CPT2CR_TC1SET_Pos) /*!< 0x00100000 */ +#define HRTIM_CPT2CR_TC1SET HRTIM_CPT2CR_TC1SET_Msk /*!< Timer C output 1 set */ +#define HRTIM_CPT2CR_TC1RST_Pos (21U) +#define HRTIM_CPT2CR_TC1RST_Msk (0x1UL << HRTIM_CPT2CR_TC1RST_Pos) /*!< 0x00200000 */ +#define HRTIM_CPT2CR_TC1RST HRTIM_CPT2CR_TC1RST_Msk /*!< Timer C output 1 reset */ +#define HRTIM_CPT2CR_TIMCCMP1_Pos (22U) +#define HRTIM_CPT2CR_TIMCCMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMCCMP1_Pos) /*!< 0x00400000 */ +#define HRTIM_CPT2CR_TIMCCMP1 HRTIM_CPT2CR_TIMCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_CPT2CR_TIMCCMP2_Pos (23U) +#define HRTIM_CPT2CR_TIMCCMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMCCMP2_Pos) /*!< 0x00800000 */ +#define HRTIM_CPT2CR_TIMCCMP2 HRTIM_CPT2CR_TIMCCMP2_Msk /*!< Timer C compare 2 */ + +#define HRTIM_CPT2CR_TD1SET_Pos (24U) +#define HRTIM_CPT2CR_TD1SET_Msk (0x1UL << HRTIM_CPT2CR_TD1SET_Pos) /*!< 0x01000000 */ +#define HRTIM_CPT2CR_TD1SET HRTIM_CPT2CR_TD1SET_Msk /*!< Timer D output 1 set */ +#define HRTIM_CPT2CR_TD1RST_Pos (25U) +#define HRTIM_CPT2CR_TD1RST_Msk (0x1UL << HRTIM_CPT2CR_TD1RST_Pos) /*!< 0x02000000 */ +#define HRTIM_CPT2CR_TD1RST HRTIM_CPT2CR_TD1RST_Msk /*!< Timer D output 1 reset */ +#define HRTIM_CPT2CR_TIMDCMP1_Pos (26U) +#define HRTIM_CPT2CR_TIMDCMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMDCMP1_Pos) /*!< 0x04000000 */ +#define HRTIM_CPT2CR_TIMDCMP1 HRTIM_CPT2CR_TIMDCMP1_Msk /*!< Timer D compare 1 */ +#define HRTIM_CPT2CR_TIMDCMP2_Pos (27U) +#define HRTIM_CPT2CR_TIMDCMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMDCMP2_Pos) /*!< 0x08000000 */ +#define HRTIM_CPT2CR_TIMDCMP2 HRTIM_CPT2CR_TIMDCMP2_Msk /*!< Timer D compare 2 */ + +#define HRTIM_CPT2CR_TE1SET_Pos (28U) +#define HRTIM_CPT2CR_TE1SET_Msk (0x1UL << HRTIM_CPT2CR_TE1SET_Pos) /*!< 0x10000000 */ +#define HRTIM_CPT2CR_TE1SET HRTIM_CPT2CR_TE1SET_Msk /*!< Timer E output 1 set */ +#define HRTIM_CPT2CR_TE1RST_Pos (29U) +#define HRTIM_CPT2CR_TE1RST_Msk (0x1UL << HRTIM_CPT2CR_TE1RST_Pos) /*!< 0x20000000 */ +#define HRTIM_CPT2CR_TE1RST HRTIM_CPT2CR_TE1RST_Msk /*!< Timer E output 1 reset */ +#define HRTIM_CPT2CR_TIMECMP1_Pos (30U) +#define HRTIM_CPT2CR_TIMECMP1_Msk (0x1UL << HRTIM_CPT2CR_TIMECMP1_Pos) /*!< 0x40000000 */ +#define HRTIM_CPT2CR_TIMECMP1 HRTIM_CPT2CR_TIMECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_CPT2CR_TIMECMP2_Pos (31U) +#define HRTIM_CPT2CR_TIMECMP2_Msk (0x1UL << HRTIM_CPT2CR_TIMECMP2_Pos) /*!< 0x80000000 */ +#define HRTIM_CPT2CR_TIMECMP2 HRTIM_CPT2CR_TIMECMP2_Msk /*!< Timer E compare 2 */ + +/**** Bit definition for Slave Timer Output register **************************/ +#define HRTIM_OUTR_POL1_Pos (1U) +#define HRTIM_OUTR_POL1_Msk (0x1UL << HRTIM_OUTR_POL1_Pos) /*!< 0x00000002 */ +#define HRTIM_OUTR_POL1 HRTIM_OUTR_POL1_Msk /*!< Slave output 1 polarity */ +#define HRTIM_OUTR_IDLM1_Pos (2U) +#define HRTIM_OUTR_IDLM1_Msk (0x1UL << HRTIM_OUTR_IDLM1_Pos) /*!< 0x00000004 */ +#define HRTIM_OUTR_IDLM1 HRTIM_OUTR_IDLM1_Msk /*!< Slave output 1 idle mode */ +#define HRTIM_OUTR_IDLES1_Pos (3U) +#define HRTIM_OUTR_IDLES1_Msk (0x1UL << HRTIM_OUTR_IDLES1_Pos) /*!< 0x00000008 */ +#define HRTIM_OUTR_IDLES1 HRTIM_OUTR_IDLES1_Msk /*!< Slave output 1 idle state */ +#define HRTIM_OUTR_FAULT1_Pos (4U) +#define HRTIM_OUTR_FAULT1_Msk (0x3UL << HRTIM_OUTR_FAULT1_Pos) /*!< 0x00000030 */ +#define HRTIM_OUTR_FAULT1 HRTIM_OUTR_FAULT1_Msk /*!< Slave output 1 fault state */ +#define HRTIM_OUTR_FAULT1_0 (0x1UL << HRTIM_OUTR_FAULT1_Pos) /*!< 0x00000010 */ +#define HRTIM_OUTR_FAULT1_1 (0x2UL << HRTIM_OUTR_FAULT1_Pos) /*!< 0x00000020 */ +#define HRTIM_OUTR_CHP1_Pos (6U) +#define HRTIM_OUTR_CHP1_Msk (0x1UL << HRTIM_OUTR_CHP1_Pos) /*!< 0x00000040 */ +#define HRTIM_OUTR_CHP1 HRTIM_OUTR_CHP1_Msk /*!< Slave output 1 chopper enable */ +#define HRTIM_OUTR_DIDL1_Pos (7U) +#define HRTIM_OUTR_DIDL1_Msk (0x1UL << HRTIM_OUTR_DIDL1_Pos) /*!< 0x00000080 */ +#define HRTIM_OUTR_DIDL1 HRTIM_OUTR_DIDL1_Msk /*!< Slave output 1 dead time idle */ + +#define HRTIM_OUTR_DTEN_Pos (8U) +#define HRTIM_OUTR_DTEN_Msk (0x1UL << HRTIM_OUTR_DTEN_Pos) /*!< 0x00000100 */ +#define HRTIM_OUTR_DTEN HRTIM_OUTR_DTEN_Msk /*!< Slave output deadtime enable */ +#define HRTIM_OUTR_DLYPRTEN_Pos (9U) +#define HRTIM_OUTR_DLYPRTEN_Msk (0x1UL << HRTIM_OUTR_DLYPRTEN_Pos) /*!< 0x00000200 */ +#define HRTIM_OUTR_DLYPRTEN HRTIM_OUTR_DLYPRTEN_Msk /*!< Slave output delay protection enable */ +#define HRTIM_OUTR_DLYPRT_Pos (10U) +#define HRTIM_OUTR_DLYPRT_Msk (0x7UL << HRTIM_OUTR_DLYPRT_Pos) /*!< 0x00001C00 */ +#define HRTIM_OUTR_DLYPRT HRTIM_OUTR_DLYPRT_Msk /*!< Slave output delay protection */ +#define HRTIM_OUTR_DLYPRT_0 (0x1UL << HRTIM_OUTR_DLYPRT_Pos) /*!< 0x00000400 */ +#define HRTIM_OUTR_DLYPRT_1 (0x2UL << HRTIM_OUTR_DLYPRT_Pos) /*!< 0x00000800 */ +#define HRTIM_OUTR_DLYPRT_2 (0x4UL << HRTIM_OUTR_DLYPRT_Pos) /*!< 0x00001000 */ +#define HRTIM_OUTR_BIAR_Pos (14U) +#define HRTIM_OUTR_BIAR_Msk (0x1UL << HRTIM_OUTR_BIAR_Pos) /*!< 0x00004000 */ +#define HRTIM_OUTR_BIAR HRTIM_OUTR_BIAR_Msk /*!< Slave output Balanced Idle Automatic resume */ +#define HRTIM_OUTR_POL2_Pos (17U) +#define HRTIM_OUTR_POL2_Msk (0x1UL << HRTIM_OUTR_POL2_Pos) /*!< 0x00020000 */ +#define HRTIM_OUTR_POL2 HRTIM_OUTR_POL2_Msk /*!< Slave output 2 polarity */ +#define HRTIM_OUTR_IDLM2_Pos (18U) +#define HRTIM_OUTR_IDLM2_Msk (0x1UL << HRTIM_OUTR_IDLM2_Pos) /*!< 0x00040000 */ +#define HRTIM_OUTR_IDLM2 HRTIM_OUTR_IDLM2_Msk /*!< Slave output 2 idle mode */ +#define HRTIM_OUTR_IDLES2_Pos (19U) +#define HRTIM_OUTR_IDLES2_Msk (0x1UL << HRTIM_OUTR_IDLES2_Pos) /*!< 0x00080000 */ +#define HRTIM_OUTR_IDLES2 HRTIM_OUTR_IDLES2_Msk /*!< Slave output 2 idle state */ +#define HRTIM_OUTR_FAULT2_Pos (20U) +#define HRTIM_OUTR_FAULT2_Msk (0x3UL << HRTIM_OUTR_FAULT2_Pos) /*!< 0x00300000 */ +#define HRTIM_OUTR_FAULT2 HRTIM_OUTR_FAULT2_Msk /*!< Slave output 2 fault state */ +#define HRTIM_OUTR_FAULT2_0 (0x1UL << HRTIM_OUTR_FAULT2_Pos) /*!< 0x00100000 */ +#define HRTIM_OUTR_FAULT2_1 (0x2UL << HRTIM_OUTR_FAULT2_Pos) /*!< 0x00200000 */ +#define HRTIM_OUTR_CHP2_Pos (22U) +#define HRTIM_OUTR_CHP2_Msk (0x1UL << HRTIM_OUTR_CHP2_Pos) /*!< 0x00400000 */ +#define HRTIM_OUTR_CHP2 HRTIM_OUTR_CHP2_Msk /*!< Slave output 2 chopper enable */ +#define HRTIM_OUTR_DIDL2_Pos (23U) +#define HRTIM_OUTR_DIDL2_Msk (0x1UL << HRTIM_OUTR_DIDL2_Pos) /*!< 0x00800000 */ +#define HRTIM_OUTR_DIDL2 HRTIM_OUTR_DIDL2_Msk /*!< Slave output 2 dead time idle */ + +/**** Bit definition for Timerx Fault register ***************************/ +#define HRTIM_FLTR_FLT1EN_Pos (0U) +#define HRTIM_FLTR_FLT1EN_Msk (0x1UL << HRTIM_FLTR_FLT1EN_Pos) /*!< 0x00000001 */ +#define HRTIM_FLTR_FLT1EN HRTIM_FLTR_FLT1EN_Msk /*!< Fault 1 enable */ +#define HRTIM_FLTR_FLT2EN_Pos (1U) +#define HRTIM_FLTR_FLT2EN_Msk (0x1UL << HRTIM_FLTR_FLT2EN_Pos) /*!< 0x00000002 */ +#define HRTIM_FLTR_FLT2EN HRTIM_FLTR_FLT2EN_Msk /*!< Fault 2 enable */ +#define HRTIM_FLTR_FLT3EN_Pos (2U) +#define HRTIM_FLTR_FLT3EN_Msk (0x1UL << HRTIM_FLTR_FLT3EN_Pos) /*!< 0x00000004 */ +#define HRTIM_FLTR_FLT3EN HRTIM_FLTR_FLT3EN_Msk /*!< Fault 3 enable */ +#define HRTIM_FLTR_FLT4EN_Pos (3U) +#define HRTIM_FLTR_FLT4EN_Msk (0x1UL << HRTIM_FLTR_FLT4EN_Pos) /*!< 0x00000008 */ +#define HRTIM_FLTR_FLT4EN HRTIM_FLTR_FLT4EN_Msk /*!< Fault 4 enable */ +#define HRTIM_FLTR_FLT5EN_Pos (4U) +#define HRTIM_FLTR_FLT5EN_Msk (0x1UL << HRTIM_FLTR_FLT5EN_Pos) /*!< 0x00000010 */ +#define HRTIM_FLTR_FLT5EN HRTIM_FLTR_FLT5EN_Msk /*!< Fault 5 enable */ +#define HRTIM_FLTR_FLT6EN_Pos (5U) +#define HRTIM_FLTR_FLT6EN_Msk (0x1UL << HRTIM_FLTR_FLT6EN_Pos) /*!< 0x00000020 */ +#define HRTIM_FLTR_FLT6EN HRTIM_FLTR_FLT6EN_Msk /*!< Fault 6 enable */ +#define HRTIM_FLTR_FLTLCK_Pos (31U) +#define HRTIM_FLTR_FLTLCK_Msk (0x1UL << HRTIM_FLTR_FLTLCK_Pos) /*!< 0x80000000 */ +#define HRTIM_FLTR_FLTLCK HRTIM_FLTR_FLTLCK_Msk /*!< Fault sources lock */ + +/**** Bit definition for HRTIM Timerx control register 2 ****************/ +#define HRTIM_TIMCR2_DCDE_Pos (0U) +#define HRTIM_TIMCR2_DCDE_Msk (0x1UL << HRTIM_TIMCR2_DCDE_Pos) /*!< 0x00000001 */ +#define HRTIM_TIMCR2_DCDE HRTIM_TIMCR2_DCDE_Msk /*!< Dual Channel DAC trigger enable */ +#define HRTIM_TIMCR2_DCDS_Pos (1U) +#define HRTIM_TIMCR2_DCDS_Msk (0x1UL << HRTIM_TIMCR2_DCDS_Pos) /*!< 0x00000002 */ +#define HRTIM_TIMCR2_DCDS HRTIM_TIMCR2_DCDS_Msk /*!< Dual Channel DAC step trigger */ +#define HRTIM_TIMCR2_DCDR_Pos (2U) +#define HRTIM_TIMCR2_DCDR_Msk (0x1UL << HRTIM_TIMCR2_DCDR_Pos) /*!< 0x00000004 */ +#define HRTIM_TIMCR2_DCDR HRTIM_TIMCR2_DCDR_Msk /*!< Dual Channel DAC reset trigger */ +#define HRTIM_TIMCR2_UDM_Pos (4U) +#define HRTIM_TIMCR2_UDM_Msk (0x1UL << HRTIM_TIMCR2_UDM_Pos) /*!< 0x00000010 */ +#define HRTIM_TIMCR2_UDM HRTIM_TIMCR2_UDM_Msk /*!< Up-Down Mode*/ +#define HRTIM_TIMCR2_ROM_Pos (6U) +#define HRTIM_TIMCR2_ROM_Msk (0x3UL << HRTIM_TIMCR2_ROM_Pos) /*!< 0x000000C0 */ +#define HRTIM_TIMCR2_ROM HRTIM_TIMCR2_ROM_Msk /*!< Roll-over Mode */ +#define HRTIM_TIMCR2_ROM_0 (0x1UL << HRTIM_TIMCR2_ROM_Pos) /*!< 0x00000040 */ +#define HRTIM_TIMCR2_ROM_1 (0x2UL << HRTIM_TIMCR2_ROM_Pos) /*!< 0x00000080 */ +#define HRTIM_TIMCR2_OUTROM_Pos (8U) +#define HRTIM_TIMCR2_OUTROM_Msk (0x3UL << HRTIM_TIMCR2_OUTROM_Pos) /*!< 0x00000300 */ +#define HRTIM_TIMCR2_OUTROM HRTIM_TIMCR2_OUTROM_Msk /*!< Output Roll-Over Mode */ +#define HRTIM_TIMCR2_OUTROM_0 (0x1UL << HRTIM_TIMCR2_OUTROM_Pos) /*!< 0x00000100 */ +#define HRTIM_TIMCR2_OUTROM_1 (0x2UL << HRTIM_TIMCR2_OUTROM_Pos) /*!< 0x00000200 */ +#define HRTIM_TIMCR2_ADROM_Pos (10U) +#define HRTIM_TIMCR2_ADROM_Msk (0x3UL << HRTIM_TIMCR2_ADROM_Pos) /*!< 0x00000C00 */ +#define HRTIM_TIMCR2_ADROM HRTIM_TIMCR2_ADROM_Msk /*!< ADC Roll-Over Mode */ +#define HRTIM_TIMCR2_ADROM_0 (0x1UL << HRTIM_TIMCR2_ADROM_Pos) /*!< 0x00000400 */ +#define HRTIM_TIMCR2_ADROM_1 (0x2UL << HRTIM_TIMCR2_ADROM_Pos) /*!< 0x00000800 */ +#define HRTIM_TIMCR2_BMROM_Pos (12U) +#define HRTIM_TIMCR2_BMROM_Msk (0x3UL << HRTIM_TIMCR2_BMROM_Pos) /*!< 0x00003000 */ +#define HRTIM_TIMCR2_BMROM HRTIM_TIMCR2_BMROM_Msk /*!< Burst Mode Rollover Mode */ +#define HRTIM_TIMCR2_BMROM_0 (0x1UL << HRTIM_TIMCR2_BMROM_Pos) /*!< 0x00001000 */ +#define HRTIM_TIMCR2_BMROM_1 (0x2UL << HRTIM_TIMCR2_BMROM_Pos) /*!< 0x00002000 */ +#define HRTIM_TIMCR2_FEROM_Pos (14U) +#define HRTIM_TIMCR2_FEROM_Msk (0x3UL << HRTIM_TIMCR2_FEROM_Pos) /*!< 0x0000C000 */ +#define HRTIM_TIMCR2_FEROM HRTIM_TIMCR2_FEROM_Msk /*!< Fault and Event Rollover Mode */ +#define HRTIM_TIMCR2_FEROM_0 (0x1UL << HRTIM_TIMCR2_FEROM_Pos) /*!< 0x00004000 */ +#define HRTIM_TIMCR2_FEROM_1 (0x2UL << HRTIM_TIMCR2_FEROM_Pos) /*!< 0x00008000 */ +#define HRTIM_TIMCR2_GTCMP1_Pos (16U) +#define HRTIM_TIMCR2_GTCMP1_Msk (0x1UL << HRTIM_TIMCR2_GTCMP1_Pos) /*!< 0x00010000 */ +#define HRTIM_TIMCR2_GTCMP1 HRTIM_TIMCR2_GTCMP1_Msk /*!< Greater than Compare 1 PWM mode */ +#define HRTIM_TIMCR2_GTCMP3_Pos (17U) +#define HRTIM_TIMCR2_GTCMP3_Msk (0x1UL << HRTIM_TIMCR2_GTCMP3_Pos) /*!< 0x00020000 */ +#define HRTIM_TIMCR2_GTCMP3 HRTIM_TIMCR2_GTCMP3_Msk /*!< Greater than Compare 3 PWM mode */ +#define HRTIM_TIMCR2_TRGHLF_Pos (20U) +#define HRTIM_TIMCR2_TRGHLF_Msk (0x1UL << HRTIM_TIMCR2_TRGHLF_Pos) /*!< 0x00100000 */ +#define HRTIM_TIMCR2_TRGHLF HRTIM_TIMCR2_TRGHLF_Msk /*!< Triggered-Half mode */ + +/**** Bit definition for Slave external event filtering register 3 ***********/ +#define HRTIM_EEFR3_EEVACE_Pos (0U) +#define HRTIM_EEFR3_EEVACE_Msk (0x1UL << HRTIM_EEFR3_EEVACE_Pos) /*!< 0x00000001 */ +#define HRTIM_EEFR3_EEVACE HRTIM_EEFR3_EEVACE_Msk /*!< External Event A Counter Enable */ +#define HRTIM_EEFR3_EEVACRES_Pos (1U) +#define HRTIM_EEFR3_EEVACRES_Msk (0x1UL << HRTIM_EEFR3_EEVACRES_Pos) /*!< 0x00000002 */ +#define HRTIM_EEFR3_EEVACRES HRTIM_EEFR3_EEVACRES_Msk /*!< External Event A Counter Reset */ +#define HRTIM_EEFR3_EEVARSTM_Pos (2U) +#define HRTIM_EEFR3_EEVARSTM_Msk (0x1UL << HRTIM_EEFR3_EEVARSTM_Pos) /*!< 0x00000004 */ +#define HRTIM_EEFR3_EEVARSTM HRTIM_EEFR3_EEVARSTM_Msk /*!< External Event A Counter Reset Mode */ +#define HRTIM_EEFR3_EEVASEL_Pos (4U) +#define HRTIM_EEFR3_EEVASEL_Msk (0xFUL << HRTIM_EEFR3_EEVASEL_Pos) /*!< 0x000000F0 */ +#define HRTIM_EEFR3_EEVASEL HRTIM_EEFR3_EEVASEL_Msk /*!< External Event A Selection */ +#define HRTIM_EEFR3_EEVASEL_0 (0x1UL << HRTIM_EEFR3_EEVASEL_Pos) /*!< 0x00000010 */ +#define HRTIM_EEFR3_EEVASEL_1 (0x2UL << HRTIM_EEFR3_EEVASEL_Pos) /*!< 0x00000020 */ +#define HRTIM_EEFR3_EEVASEL_2 (0x4UL << HRTIM_EEFR3_EEVASEL_Pos) /*!< 0x00000040 */ +#define HRTIM_EEFR3_EEVASEL_3 (0x8UL << HRTIM_EEFR3_EEVASEL_Pos) /*!< 0x00000080 */ +#define HRTIM_EEFR3_EEVACNT_Pos (8U) +#define HRTIM_EEFR3_EEVACNT_Msk (0x3FUL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00003F00 */ +#define HRTIM_EEFR3_EEVACNT HRTIM_EEFR3_EEVACNT_Msk /*!< External Event A Selection */ +#define HRTIM_EEFR3_EEVACNT_0 (0x1UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00000100 */ +#define HRTIM_EEFR3_EEVACNT_1 (0x2UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00000200 */ +#define HRTIM_EEFR3_EEVACNT_2 (0x4UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00000400 */ +#define HRTIM_EEFR3_EEVACNT_3 (0x8UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00000800 */ +#define HRTIM_EEFR3_EEVACNT_4 (0x10UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00001000 */ +#define HRTIM_EEFR3_EEVACNT_5 (0x20UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x00002000 */ +#define HRTIM_EEFR3_EEVBCE_Pos (16U) +#define HRTIM_EEFR3_EEVBCE_Msk (0x1UL << HRTIM_EEFR3_EEVBCE_Pos) /*!< 0x00010000 */ +#define HRTIM_EEFR3_EEVBCE HRTIM_EEFR3_EEVBCE_Msk /*!< External Event B Counter Enable */ +#define HRTIM_EEFR3_EEVBCRES_Pos (17U) +#define HRTIM_EEFR3_EEVBCRES_Msk (0x1UL << HRTIM_EEFR3_EEVBCRES_Pos) /*!< 0x00020000 */ +#define HRTIM_EEFR3_EEVBCRES HRTIM_EEFR3_EEVBCRES_Msk /*!< External Event B Counter Reset */ +#define HRTIM_EEFR3_EEVBRSTM_Pos (18U) +#define HRTIM_EEFR3_EEVBRSTM_Msk (0x1UL << HRTIM_EEFR3_EEVBRSTM_Pos) /*!< 0x00040000 */ +#define HRTIM_EEFR3_EEVBRSTM HRTIM_EEFR3_EEVBRSTM_Msk /*!< External Event B Counter Reset Mode */ +#define HRTIM_EEFR3_EEVBSEL_Pos (20U) +#define HRTIM_EEFR3_EEVBSEL_Msk (0xFUL << HRTIM_EEFR3_EEVBSEL_Pos) /*!< 0x00F00000 */ +#define HRTIM_EEFR3_EEVBSEL HRTIM_EEFR3_EEVBSEL_Msk /*!< External Event B Selection */ +#define HRTIM_EEFR3_EEVBSEL_0 (0x1UL << HRTIM_EEFR3_EEVBSEL_Pos) /*!< 0x00100000 */ +#define HRTIM_EEFR3_EEVBSEL_1 (0x2UL << HRTIM_EEFR3_EEVBSEL_Pos) /*!< 0x00200000 */ +#define HRTIM_EEFR3_EEVBSEL_2 (0x4UL << HRTIM_EEFR3_EEVBSEL_Pos) /*!< 0x00400000 */ +#define HRTIM_EEFR3_EEVBSEL_3 (0x8UL << HRTIM_EEFR3_EEVBSEL_Pos) /*!< 0x00800000 */ +#define HRTIM_EEFR3_EEVBCNT_Pos (24U) +#define HRTIM_EEFR3_EEVBCNT_Msk (0x3FUL << HRTIM_EEFR3_EEVBCNT_Pos) /*!< 0x3F000000 */ +#define HRTIM_EEFR3_EEVBCNT HRTIM_EEFR3_EEVBCNT_Msk /*!< External Event B Counter */ +#define HRTIM_EEFR3_EEVBCNT_0 (0x1UL << HRTIM_EEFR3_EEVBCNT_Pos) /*!< 0x01000000 */ +#define HRTIM_EEFR3_EEVBCNT_1 (0x2UL << HRTIM_EEFR3_EEVBCNT_Pos) /*!< 0x02000000 */ +#define HRTIM_EEFR3_EEVBCNT_2 (0x4UL << HRTIM_EEFR3_EEVBCNT_Pos) /*!< 0x04000000 */ +#define HRTIM_EEFR3_EEVBCNT_3 (0x8UL << HRTIM_EEFR3_EEVBCNT_Pos) /*!< 0x08000000 */ +#define HRTIM_EEFR3_EEVBCNT_4 (0x10UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x10000000 */ +#define HRTIM_EEFR3_EEVBCNT_5 (0x20UL << HRTIM_EEFR3_EEVACNT_Pos) /*!< 0x20000000 */ + +/**** Bit definition for Common HRTIM Timer control register 1 ****************/ +#define HRTIM_CR1_MUDIS_Pos (0U) +#define HRTIM_CR1_MUDIS_Msk (0x1UL << HRTIM_CR1_MUDIS_Pos) /*!< 0x00000001 */ +#define HRTIM_CR1_MUDIS HRTIM_CR1_MUDIS_Msk /*!< Master update disable*/ +#define HRTIM_CR1_TAUDIS_Pos (1U) +#define HRTIM_CR1_TAUDIS_Msk (0x1UL << HRTIM_CR1_TAUDIS_Pos) /*!< 0x00000002 */ +#define HRTIM_CR1_TAUDIS HRTIM_CR1_TAUDIS_Msk /*!< Timer A update disable*/ +#define HRTIM_CR1_TBUDIS_Pos (2U) +#define HRTIM_CR1_TBUDIS_Msk (0x1UL << HRTIM_CR1_TBUDIS_Pos) /*!< 0x00000004 */ +#define HRTIM_CR1_TBUDIS HRTIM_CR1_TBUDIS_Msk /*!< Timer B update disable*/ +#define HRTIM_CR1_TCUDIS_Pos (3U) +#define HRTIM_CR1_TCUDIS_Msk (0x1UL << HRTIM_CR1_TCUDIS_Pos) /*!< 0x00000008 */ +#define HRTIM_CR1_TCUDIS HRTIM_CR1_TCUDIS_Msk /*!< Timer C update disable*/ +#define HRTIM_CR1_TDUDIS_Pos (4U) +#define HRTIM_CR1_TDUDIS_Msk (0x1UL << HRTIM_CR1_TDUDIS_Pos) /*!< 0x00000010 */ +#define HRTIM_CR1_TDUDIS HRTIM_CR1_TDUDIS_Msk /*!< Timer D update disable*/ +#define HRTIM_CR1_TEUDIS_Pos (5U) +#define HRTIM_CR1_TEUDIS_Msk (0x1UL << HRTIM_CR1_TEUDIS_Pos) /*!< 0x00000020 */ +#define HRTIM_CR1_TEUDIS HRTIM_CR1_TEUDIS_Msk /*!< Timer E update disable*/ +#define HRTIM_CR1_TFUDIS_Pos (6U) +#define HRTIM_CR1_TFUDIS_Msk (0x1UL << HRTIM_CR1_TFUDIS_Pos) /*!< 0x00000040 */ +#define HRTIM_CR1_TFUDIS HRTIM_CR1_TFUDIS_Msk /*!< Timer F update disable*/ +#define HRTIM_CR1_ADC1USRC_Pos (16U) +#define HRTIM_CR1_ADC1USRC_Msk (0x7UL << HRTIM_CR1_ADC1USRC_Pos) /*!< 0x00070000 */ +#define HRTIM_CR1_ADC1USRC HRTIM_CR1_ADC1USRC_Msk /*!< ADC Trigger 1 update source */ +#define HRTIM_CR1_ADC1USRC_0 (0x1UL << HRTIM_CR1_ADC1USRC_Pos) /*!< 0x00010000 */ +#define HRTIM_CR1_ADC1USRC_1 (0x2UL << HRTIM_CR1_ADC1USRC_Pos) /*!< 0x00020000 */ +#define HRTIM_CR1_ADC1USRC_2 (0x4UL << HRTIM_CR1_ADC1USRC_Pos) /*!< 0x00040000 */ +#define HRTIM_CR1_ADC2USRC_Pos (19U) +#define HRTIM_CR1_ADC2USRC_Msk (0x7UL << HRTIM_CR1_ADC2USRC_Pos) /*!< 0x00380000 */ +#define HRTIM_CR1_ADC2USRC HRTIM_CR1_ADC2USRC_Msk /*!< ADC Trigger 2 update source */ +#define HRTIM_CR1_ADC2USRC_0 (0x1UL << HRTIM_CR1_ADC2USRC_Pos) /*!< 0x00080000 */ +#define HRTIM_CR1_ADC2USRC_1 (0x2UL << HRTIM_CR1_ADC2USRC_Pos) /*!< 0x00100000 */ +#define HRTIM_CR1_ADC2USRC_2 (0x4UL << HRTIM_CR1_ADC2USRC_Pos) /*!< 0x00200000 */ +#define HRTIM_CR1_ADC3USRC_Pos (22U) +#define HRTIM_CR1_ADC3USRC_Msk (0x7UL << HRTIM_CR1_ADC3USRC_Pos) /*!< 0x01C00000 */ +#define HRTIM_CR1_ADC3USRC HRTIM_CR1_ADC3USRC_Msk /*!< ADC Trigger 3 update source */ +#define HRTIM_CR1_ADC3USRC_0 (0x1UL << HRTIM_CR1_ADC3USRC_Pos) /*!< 0x00400000 */ +#define HRTIM_CR1_ADC3USRC_1 (0x2UL << HRTIM_CR1_ADC3USRC_Pos) /*!< 0x00800000 */ +#define HRTIM_CR1_ADC3USRC_2 (0x4UL << HRTIM_CR1_ADC3USRC_Pos) /*!< 0x01000000 */ +#define HRTIM_CR1_ADC4USRC_Pos (25U) +#define HRTIM_CR1_ADC4USRC_Msk (0x7UL << HRTIM_CR1_ADC4USRC_Pos) /*!< 0x0E000000 */ +#define HRTIM_CR1_ADC4USRC HRTIM_CR1_ADC4USRC_Msk /*!< ADC Trigger 4 update source */ +#define HRTIM_CR1_ADC4USRC_0 (0x1UL << HRTIM_CR1_ADC4USRC_Pos) /*!< 0x02000000 */ +#define HRTIM_CR1_ADC4USRC_1 (0x2UL << HRTIM_CR1_ADC4USRC_Pos) /*!< 0x04000000 */ +#define HRTIM_CR1_ADC4USRC_2 (0x0UL << HRTIM_CR1_ADC4USRC_Pos) /*!< 0x0800000 */ + +/**** Bit definition for Common HRTIM Timer control register 2 ****************/ +#define HRTIM_CR2_MSWU_Pos (0U) +#define HRTIM_CR2_MSWU_Msk (0x1UL << HRTIM_CR2_MSWU_Pos) /*!< 0x00000001 */ +#define HRTIM_CR2_MSWU HRTIM_CR2_MSWU_Msk /*!< Master software update */ +#define HRTIM_CR2_TASWU_Pos (1U) +#define HRTIM_CR2_TASWU_Msk (0x1UL << HRTIM_CR2_TASWU_Pos) /*!< 0x00000002 */ +#define HRTIM_CR2_TASWU HRTIM_CR2_TASWU_Msk /*!< Timer A software update */ +#define HRTIM_CR2_TBSWU_Pos (2U) +#define HRTIM_CR2_TBSWU_Msk (0x1UL << HRTIM_CR2_TBSWU_Pos) /*!< 0x00000004 */ +#define HRTIM_CR2_TBSWU HRTIM_CR2_TBSWU_Msk /*!< Timer B software update */ +#define HRTIM_CR2_TCSWU_Pos (3U) +#define HRTIM_CR2_TCSWU_Msk (0x1UL << HRTIM_CR2_TCSWU_Pos) /*!< 0x00000008 */ +#define HRTIM_CR2_TCSWU HRTIM_CR2_TCSWU_Msk /*!< Timer C software update */ +#define HRTIM_CR2_TDSWU_Pos (4U) +#define HRTIM_CR2_TDSWU_Msk (0x1UL << HRTIM_CR2_TDSWU_Pos) /*!< 0x00000010 */ +#define HRTIM_CR2_TDSWU HRTIM_CR2_TDSWU_Msk /*!< Timer D software update */ +#define HRTIM_CR2_TESWU_Pos (5U) +#define HRTIM_CR2_TESWU_Msk (0x1UL << HRTIM_CR2_TESWU_Pos) /*!< 0x00000020 */ +#define HRTIM_CR2_TESWU HRTIM_CR2_TESWU_Msk /*!< Timer E software update */ +#define HRTIM_CR2_TFSWU_Pos (6U) +#define HRTIM_CR2_TFSWU_Msk (0x1UL << HRTIM_CR2_TFSWU_Pos) /*!< 0x00000040 */ +#define HRTIM_CR2_TFSWU HRTIM_CR2_TFSWU_Msk /*!< Timer F software update */ +#define HRTIM_CR2_MRST_Pos (8U) +#define HRTIM_CR2_MRST_Msk (0x1UL << HRTIM_CR2_MRST_Pos) /*!< 0x00000100 */ +#define HRTIM_CR2_MRST HRTIM_CR2_MRST_Msk /*!< Master count software reset */ +#define HRTIM_CR2_TARST_Pos (9U) +#define HRTIM_CR2_TARST_Msk (0x1UL << HRTIM_CR2_TARST_Pos) /*!< 0x00000200 */ +#define HRTIM_CR2_TARST HRTIM_CR2_TARST_Msk /*!< Timer A count software reset */ +#define HRTIM_CR2_TBRST_Pos (10U) +#define HRTIM_CR2_TBRST_Msk (0x1UL << HRTIM_CR2_TBRST_Pos) /*!< 0x00000400 */ +#define HRTIM_CR2_TBRST HRTIM_CR2_TBRST_Msk /*!< Timer B count software reset */ +#define HRTIM_CR2_TCRST_Pos (11U) +#define HRTIM_CR2_TCRST_Msk (0x1UL << HRTIM_CR2_TCRST_Pos) /*!< 0x00000800 */ +#define HRTIM_CR2_TCRST HRTIM_CR2_TCRST_Msk /*!< Timer C count software reset */ +#define HRTIM_CR2_TDRST_Pos (12U) +#define HRTIM_CR2_TDRST_Msk (0x1UL << HRTIM_CR2_TDRST_Pos) /*!< 0x00001000 */ +#define HRTIM_CR2_TDRST HRTIM_CR2_TDRST_Msk /*!< Timer D count software reset */ +#define HRTIM_CR2_TERST_Pos (13U) +#define HRTIM_CR2_TERST_Msk (0x1UL << HRTIM_CR2_TERST_Pos) /*!< 0x00002000 */ +#define HRTIM_CR2_TERST HRTIM_CR2_TERST_Msk /*!< Timer E count software reset */ +#define HRTIM_CR2_TFRST_Pos (14U) +#define HRTIM_CR2_TFRST_Msk (0x1UL << HRTIM_CR2_TFRST_Pos) /*!< 0x00004000 */ +#define HRTIM_CR2_TFRST HRTIM_CR2_TFRST_Msk /*!< Timer F count software reset */ +#define HRTIM_CR2_SWPA_Pos (16U) +#define HRTIM_CR2_SWPA_Msk (0x1UL << HRTIM_CR2_SWPA_Pos) /*!< 0x00010000 */ +#define HRTIM_CR2_SWPA HRTIM_CR2_SWPA_Msk /*!< Timer A swap outputs */ +#define HRTIM_CR2_SWPB_Pos (17U) +#define HRTIM_CR2_SWPB_Msk (0x1UL << HRTIM_CR2_SWPB_Pos) /*!< 0x00020000 */ +#define HRTIM_CR2_SWPB HRTIM_CR2_SWPB_Msk /*!< Timer B swap outputs */ +#define HRTIM_CR2_SWPC_Pos (18U) +#define HRTIM_CR2_SWPC_Msk (0x1UL << HRTIM_CR2_SWPC_Pos) /*!< 0x00040000 */ +#define HRTIM_CR2_SWPC HRTIM_CR2_SWPC_Msk /*!< Timer C swap outputs */ +#define HRTIM_CR2_SWPD_Pos (19U) +#define HRTIM_CR2_SWPD_Msk (0x1UL << HRTIM_CR2_SWPD_Pos) /*!< 0x00080000 */ +#define HRTIM_CR2_SWPD HRTIM_CR2_SWPD_Msk /*!< Timer D swap outputs */ +#define HRTIM_CR2_SWPE_Pos (20U) +#define HRTIM_CR2_SWPE_Msk (0x1UL << HRTIM_CR2_SWPE_Pos) /*!< 0x00100000 */ +#define HRTIM_CR2_SWPE HRTIM_CR2_SWPE_Msk /*!< Timer E swap outputs */ +#define HRTIM_CR2_SWPF_Pos (21U) +#define HRTIM_CR2_SWPF_Msk (0x1UL << HRTIM_CR2_SWPF_Pos) /*!< 0x00200000 */ +#define HRTIM_CR2_SWPF HRTIM_CR2_SWPF_Msk /*!< Timer F swap outputs */ + +/**** Bit definition for Common HRTIM Timer interrupt status register *********/ +#define HRTIM_ISR_FLT1_Pos (0U) +#define HRTIM_ISR_FLT1_Msk (0x1UL << HRTIM_ISR_FLT1_Pos) /*!< 0x00000001 */ +#define HRTIM_ISR_FLT1 HRTIM_ISR_FLT1_Msk /*!< Fault 1 interrupt flag */ +#define HRTIM_ISR_FLT2_Pos (1U) +#define HRTIM_ISR_FLT2_Msk (0x1UL << HRTIM_ISR_FLT2_Pos) /*!< 0x00000002 */ +#define HRTIM_ISR_FLT2 HRTIM_ISR_FLT2_Msk /*!< Fault 2 interrupt flag */ +#define HRTIM_ISR_FLT3_Pos (2U) +#define HRTIM_ISR_FLT3_Msk (0x1UL << HRTIM_ISR_FLT3_Pos) /*!< 0x00000004 */ +#define HRTIM_ISR_FLT3 HRTIM_ISR_FLT3_Msk /*!< Fault 3 interrupt flag */ +#define HRTIM_ISR_FLT4_Pos (3U) +#define HRTIM_ISR_FLT4_Msk (0x1UL << HRTIM_ISR_FLT4_Pos) /*!< 0x00000008 */ +#define HRTIM_ISR_FLT4 HRTIM_ISR_FLT4_Msk /*!< Fault 4 interrupt flag */ +#define HRTIM_ISR_FLT5_Pos (4U) +#define HRTIM_ISR_FLT5_Msk (0x1UL << HRTIM_ISR_FLT5_Pos) /*!< 0x00000010 */ +#define HRTIM_ISR_FLT5 HRTIM_ISR_FLT5_Msk /*!< Fault 5 interrupt flag */ +#define HRTIM_ISR_SYSFLT_Pos (5U) +#define HRTIM_ISR_SYSFLT_Msk (0x1UL << HRTIM_ISR_SYSFLT_Pos) /*!< 0x00000020 */ +#define HRTIM_ISR_SYSFLT HRTIM_ISR_SYSFLT_Msk /*!< System Fault interrupt flag */ +#define HRTIM_ISR_FLT6_Pos (6U) +#define HRTIM_ISR_FLT6_Msk (0x1UL << HRTIM_ISR_FLT6_Pos) /*!< 0x00000040 */ +#define HRTIM_ISR_FLT6 HRTIM_ISR_FLT6_Msk /*!< Fault 6 interrupt flag */ +#define HRTIM_ISR_DLLRDY_Pos (16U) +#define HRTIM_ISR_DLLRDY_Msk (0x1UL << HRTIM_ISR_DLLRDY_Pos) /*!< 0x00010000 */ +#define HRTIM_ISR_DLLRDY HRTIM_ISR_DLLRDY_Msk /*!< DLL ready interrupt flag */ +#define HRTIM_ISR_BMPER_Pos (17U) +#define HRTIM_ISR_BMPER_Msk (0x1UL << HRTIM_ISR_BMPER_Pos) /*!< 0x00020000 */ +#define HRTIM_ISR_BMPER HRTIM_ISR_BMPER_Msk /*!< Burst mode period interrupt flag */ + +/**** Bit definition for Common HRTIM Timer interrupt clear register **********/ +#define HRTIM_ICR_FLT1C_Pos (0U) +#define HRTIM_ICR_FLT1C_Msk (0x1UL << HRTIM_ICR_FLT1C_Pos) /*!< 0x00000001 */ +#define HRTIM_ICR_FLT1C HRTIM_ICR_FLT1C_Msk /*!< Fault 1 interrupt flag clear */ +#define HRTIM_ICR_FLT2C_Pos (1U) +#define HRTIM_ICR_FLT2C_Msk (0x1UL << HRTIM_ICR_FLT2C_Pos) /*!< 0x00000002 */ +#define HRTIM_ICR_FLT2C HRTIM_ICR_FLT2C_Msk /*!< Fault 2 interrupt flag clear */ +#define HRTIM_ICR_FLT3C_Pos (2U) +#define HRTIM_ICR_FLT3C_Msk (0x1UL << HRTIM_ICR_FLT3C_Pos) /*!< 0x00000004 */ +#define HRTIM_ICR_FLT3C HRTIM_ICR_FLT3C_Msk /*!< Fault 3 interrupt flag clear */ +#define HRTIM_ICR_FLT4C_Pos (3U) +#define HRTIM_ICR_FLT4C_Msk (0x1UL << HRTIM_ICR_FLT4C_Pos) /*!< 0x00000008 */ +#define HRTIM_ICR_FLT4C HRTIM_ICR_FLT4C_Msk /*!< Fault 4 interrupt flag clear */ +#define HRTIM_ICR_FLT5C_Pos (4U) +#define HRTIM_ICR_FLT5C_Msk (0x1UL << HRTIM_ICR_FLT5C_Pos) /*!< 0x00000010 */ +#define HRTIM_ICR_FLT5C HRTIM_ICR_FLT5C_Msk /*!< Fault 5 interrupt flag clear */ +#define HRTIM_ICR_SYSFLTC_Pos (5U) +#define HRTIM_ICR_SYSFLTC_Msk (0x1UL << HRTIM_ICR_SYSFLTC_Pos) /*!< 0x00000020 */ +#define HRTIM_ICR_SYSFLTC HRTIM_ICR_SYSFLTC_Msk /*!< System Fault interrupt flag clear */ + +#define HRTIM_ICR_FLT6C_Pos (6U) +#define HRTIM_ICR_FLT6C_Msk (0x1UL << HRTIM_ICR_FLT6C_Pos) /*!< 0x00000040 */ +#define HRTIM_ICR_FLT6C HRTIM_ICR_FLT6C_Msk /*!< Fault 6 interrupt flag clear */ + +#define HRTIM_ICR_DLLRDYC_Pos (16U) +#define HRTIM_ICR_DLLRDYC_Msk (0x1UL << HRTIM_ICR_DLLRDYC_Pos) /*!< 0x00010000 */ +#define HRTIM_ICR_DLLRDYC HRTIM_ICR_DLLRDYC_Msk /*!< DLL ready interrupt flag clear */ +#define HRTIM_ICR_BMPERC_Pos (17U) +#define HRTIM_ICR_BMPERC_Msk (0x1UL << HRTIM_ICR_BMPERC_Pos) /*!< 0x00020000 */ +#define HRTIM_ICR_BMPERC HRTIM_ICR_BMPERC_Msk /*!< Burst mode period interrupt flag clear */ + +/**** Bit definition for Common HRTIM Timer interrupt enable register *********/ +#define HRTIM_IER_FLT1_Pos (0U) +#define HRTIM_IER_FLT1_Msk (0x1UL << HRTIM_IER_FLT1_Pos) /*!< 0x00000001 */ +#define HRTIM_IER_FLT1 HRTIM_IER_FLT1_Msk /*!< Fault 1 interrupt enable */ +#define HRTIM_IER_FLT2_Pos (1U) +#define HRTIM_IER_FLT2_Msk (0x1UL << HRTIM_IER_FLT2_Pos) /*!< 0x00000002 */ +#define HRTIM_IER_FLT2 HRTIM_IER_FLT2_Msk /*!< Fault 2 interrupt enable */ +#define HRTIM_IER_FLT3_Pos (2U) +#define HRTIM_IER_FLT3_Msk (0x1UL << HRTIM_IER_FLT3_Pos) /*!< 0x00000004 */ +#define HRTIM_IER_FLT3 HRTIM_IER_FLT3_Msk /*!< Fault 3 interrupt enable */ +#define HRTIM_IER_FLT4_Pos (3U) +#define HRTIM_IER_FLT4_Msk (0x1UL << HRTIM_IER_FLT4_Pos) /*!< 0x00000008 */ +#define HRTIM_IER_FLT4 HRTIM_IER_FLT4_Msk /*!< Fault 4 interrupt enable */ +#define HRTIM_IER_FLT5_Pos (4U) +#define HRTIM_IER_FLT5_Msk (0x1UL << HRTIM_IER_FLT5_Pos) /*!< 0x00000010 */ +#define HRTIM_IER_FLT5 HRTIM_IER_FLT5_Msk /*!< Fault 5 interrupt enable */ +#define HRTIM_IER_SYSFLT_Pos (5U) +#define HRTIM_IER_SYSFLT_Msk (0x1UL << HRTIM_IER_SYSFLT_Pos) /*!< 0x00000020 */ +#define HRTIM_IER_SYSFLT HRTIM_IER_SYSFLT_Msk /*!< System Fault interrupt enable */ +#define HRTIM_IER_FLT6_Pos (6U) +#define HRTIM_IER_FLT6_Msk (0x1UL << HRTIM_IER_FLT6_Pos) /*!< 0x00000040 */ +#define HRTIM_IER_FLT6 HRTIM_IER_FLT6_Msk /*!< Fault 6 interrupt enable */ + +#define HRTIM_IER_DLLRDY_Pos (16U) +#define HRTIM_IER_DLLRDY_Msk (0x1UL << HRTIM_IER_DLLRDY_Pos) /*!< 0x00010000 */ +#define HRTIM_IER_DLLRDY HRTIM_IER_DLLRDY_Msk /*!< DLL ready interrupt enable */ +#define HRTIM_IER_BMPER_Pos (17U) +#define HRTIM_IER_BMPER_Msk (0x1UL << HRTIM_IER_BMPER_Pos) /*!< 0x00020000 */ +#define HRTIM_IER_BMPER HRTIM_IER_BMPER_Msk /*!< Burst mode period interrupt enable */ + +/**** Bit definition for Common HRTIM Timer output enable register ************/ +#define HRTIM_OENR_TA1OEN_Pos (0U) +#define HRTIM_OENR_TA1OEN_Msk (0x1UL << HRTIM_OENR_TA1OEN_Pos) /*!< 0x00000001 */ +#define HRTIM_OENR_TA1OEN HRTIM_OENR_TA1OEN_Msk /*!< Timer A Output 1 enable */ +#define HRTIM_OENR_TA2OEN_Pos (1U) +#define HRTIM_OENR_TA2OEN_Msk (0x1UL << HRTIM_OENR_TA2OEN_Pos) /*!< 0x00000002 */ +#define HRTIM_OENR_TA2OEN HRTIM_OENR_TA2OEN_Msk /*!< Timer A Output 2 enable */ +#define HRTIM_OENR_TB1OEN_Pos (2U) +#define HRTIM_OENR_TB1OEN_Msk (0x1UL << HRTIM_OENR_TB1OEN_Pos) /*!< 0x00000004 */ +#define HRTIM_OENR_TB1OEN HRTIM_OENR_TB1OEN_Msk /*!< Timer B Output 1 enable */ +#define HRTIM_OENR_TB2OEN_Pos (3U) +#define HRTIM_OENR_TB2OEN_Msk (0x1UL << HRTIM_OENR_TB2OEN_Pos) /*!< 0x00000008 */ +#define HRTIM_OENR_TB2OEN HRTIM_OENR_TB2OEN_Msk /*!< Timer B Output 2 enable */ +#define HRTIM_OENR_TC1OEN_Pos (4U) +#define HRTIM_OENR_TC1OEN_Msk (0x1UL << HRTIM_OENR_TC1OEN_Pos) /*!< 0x00000010 */ +#define HRTIM_OENR_TC1OEN HRTIM_OENR_TC1OEN_Msk /*!< Timer C Output 1 enable */ +#define HRTIM_OENR_TC2OEN_Pos (5U) +#define HRTIM_OENR_TC2OEN_Msk (0x1UL << HRTIM_OENR_TC2OEN_Pos) /*!< 0x00000020 */ +#define HRTIM_OENR_TC2OEN HRTIM_OENR_TC2OEN_Msk /*!< Timer C Output 2 enable */ +#define HRTIM_OENR_TD1OEN_Pos (6U) +#define HRTIM_OENR_TD1OEN_Msk (0x1UL << HRTIM_OENR_TD1OEN_Pos) /*!< 0x00000040 */ +#define HRTIM_OENR_TD1OEN HRTIM_OENR_TD1OEN_Msk /*!< Timer D Output 1 enable */ +#define HRTIM_OENR_TD2OEN_Pos (7U) +#define HRTIM_OENR_TD2OEN_Msk (0x1UL << HRTIM_OENR_TD2OEN_Pos) /*!< 0x00000080 */ +#define HRTIM_OENR_TD2OEN HRTIM_OENR_TD2OEN_Msk /*!< Timer D Output 2 enable */ +#define HRTIM_OENR_TE1OEN_Pos (8U) +#define HRTIM_OENR_TE1OEN_Msk (0x1UL << HRTIM_OENR_TE1OEN_Pos) /*!< 0x00000100 */ +#define HRTIM_OENR_TE1OEN HRTIM_OENR_TE1OEN_Msk /*!< Timer E Output 1 enable */ +#define HRTIM_OENR_TE2OEN_Pos (9U) +#define HRTIM_OENR_TE2OEN_Msk (0x1UL << HRTIM_OENR_TE2OEN_Pos) /*!< 0x00000200 */ +#define HRTIM_OENR_TE2OEN HRTIM_OENR_TE2OEN_Msk /*!< Timer E Output 2 enable */ +#define HRTIM_OENR_TF1OEN_Pos (10U) +#define HRTIM_OENR_TF1OEN_Msk (0x1UL << HRTIM_OENR_TF1OEN_Pos) /*!< 0x00000400 */ +#define HRTIM_OENR_TF1OEN HRTIM_OENR_TF1OEN_Msk /*!< Timer F Output 1 enable */ +#define HRTIM_OENR_TF2OEN_Pos (11U) +#define HRTIM_OENR_TF2OEN_Msk (0x1UL << HRTIM_OENR_TF2OEN_Pos) /*!< 0x00000800 */ +#define HRTIM_OENR_TF2OEN HRTIM_OENR_TF2OEN_Msk /*!< Timer F Output 2 enable */ + +/**** Bit definition for Common HRTIM Timer output disable register ***********/ +#define HRTIM_ODISR_TA1ODIS_Pos (0U) +#define HRTIM_ODISR_TA1ODIS_Msk (0x1UL << HRTIM_ODISR_TA1ODIS_Pos) /*!< 0x00000001 */ +#define HRTIM_ODISR_TA1ODIS HRTIM_ODISR_TA1ODIS_Msk /*!< Timer A Output 1 disable */ +#define HRTIM_ODISR_TA2ODIS_Pos (1U) +#define HRTIM_ODISR_TA2ODIS_Msk (0x1UL << HRTIM_ODISR_TA2ODIS_Pos) /*!< 0x00000002 */ +#define HRTIM_ODISR_TA2ODIS HRTIM_ODISR_TA2ODIS_Msk /*!< Timer A Output 2 disable */ +#define HRTIM_ODISR_TB1ODIS_Pos (2U) +#define HRTIM_ODISR_TB1ODIS_Msk (0x1UL << HRTIM_ODISR_TB1ODIS_Pos) /*!< 0x00000004 */ +#define HRTIM_ODISR_TB1ODIS HRTIM_ODISR_TB1ODIS_Msk /*!< Timer B Output 1 disable */ +#define HRTIM_ODISR_TB2ODIS_Pos (3U) +#define HRTIM_ODISR_TB2ODIS_Msk (0x1UL << HRTIM_ODISR_TB2ODIS_Pos) /*!< 0x00000008 */ +#define HRTIM_ODISR_TB2ODIS HRTIM_ODISR_TB2ODIS_Msk /*!< Timer B Output 2 disable */ +#define HRTIM_ODISR_TC1ODIS_Pos (4U) +#define HRTIM_ODISR_TC1ODIS_Msk (0x1UL << HRTIM_ODISR_TC1ODIS_Pos) /*!< 0x00000010 */ +#define HRTIM_ODISR_TC1ODIS HRTIM_ODISR_TC1ODIS_Msk /*!< Timer C Output 1 disable */ +#define HRTIM_ODISR_TC2ODIS_Pos (5U) +#define HRTIM_ODISR_TC2ODIS_Msk (0x1UL << HRTIM_ODISR_TC2ODIS_Pos) /*!< 0x00000020 */ +#define HRTIM_ODISR_TC2ODIS HRTIM_ODISR_TC2ODIS_Msk /*!< Timer C Output 2 disable */ +#define HRTIM_ODISR_TD1ODIS_Pos (6U) +#define HRTIM_ODISR_TD1ODIS_Msk (0x1UL << HRTIM_ODISR_TD1ODIS_Pos) /*!< 0x00000040 */ +#define HRTIM_ODISR_TD1ODIS HRTIM_ODISR_TD1ODIS_Msk /*!< Timer D Output 1 disable */ +#define HRTIM_ODISR_TD2ODIS_Pos (7U) +#define HRTIM_ODISR_TD2ODIS_Msk (0x1UL << HRTIM_ODISR_TD2ODIS_Pos) /*!< 0x00000080 */ +#define HRTIM_ODISR_TD2ODIS HRTIM_ODISR_TD2ODIS_Msk /*!< Timer D Output 2 disable */ +#define HRTIM_ODISR_TE1ODIS_Pos (8U) +#define HRTIM_ODISR_TE1ODIS_Msk (0x1UL << HRTIM_ODISR_TE1ODIS_Pos) /*!< 0x00000100 */ +#define HRTIM_ODISR_TE1ODIS HRTIM_ODISR_TE1ODIS_Msk /*!< Timer E Output 1 disable */ +#define HRTIM_ODISR_TE2ODIS_Pos (9U) +#define HRTIM_ODISR_TE2ODIS_Msk (0x1UL << HRTIM_ODISR_TE2ODIS_Pos) /*!< 0x00000200 */ +#define HRTIM_ODISR_TE2ODIS HRTIM_ODISR_TE2ODIS_Msk /*!< Timer E Output 2 disable */ +#define HRTIM_ODISR_TF1ODIS_Pos (10U) +#define HRTIM_ODISR_TF1ODIS_Msk (0x1UL << HRTIM_ODISR_TF1ODIS_Pos) /*!< 0x00000100 */ +#define HRTIM_ODISR_TF1ODIS HRTIM_ODISR_TF1ODIS_Msk /*!< Timer F Output 1 disable */ +#define HRTIM_ODISR_TF2ODIS_Pos (11U) +#define HRTIM_ODISR_TF2ODIS_Msk (0x1UL << HRTIM_ODISR_TF2ODIS_Pos) /*!< 0x00000200 */ +#define HRTIM_ODISR_TF2ODIS HRTIM_ODISR_TF2ODIS_Msk /*!< Timer F Output 2 disable */ + +/**** Bit definition for Common HRTIM Timer output disable status register *****/ +#define HRTIM_ODSR_TA1ODS_Pos (0U) +#define HRTIM_ODSR_TA1ODS_Msk (0x1UL << HRTIM_ODSR_TA1ODS_Pos) /*!< 0x00000001 */ +#define HRTIM_ODSR_TA1ODS HRTIM_ODSR_TA1ODS_Msk /*!< Timer A Output 1 disable status */ +#define HRTIM_ODSR_TA2ODS_Pos (1U) +#define HRTIM_ODSR_TA2ODS_Msk (0x1UL << HRTIM_ODSR_TA2ODS_Pos) /*!< 0x00000002 */ +#define HRTIM_ODSR_TA2ODS HRTIM_ODSR_TA2ODS_Msk /*!< Timer A Output 2 disable status */ +#define HRTIM_ODSR_TB1ODS_Pos (2U) +#define HRTIM_ODSR_TB1ODS_Msk (0x1UL << HRTIM_ODSR_TB1ODS_Pos) /*!< 0x00000004 */ +#define HRTIM_ODSR_TB1ODS HRTIM_ODSR_TB1ODS_Msk /*!< Timer B Output 1 disable status */ +#define HRTIM_ODSR_TB2ODS_Pos (3U) +#define HRTIM_ODSR_TB2ODS_Msk (0x1UL << HRTIM_ODSR_TB2ODS_Pos) /*!< 0x00000008 */ +#define HRTIM_ODSR_TB2ODS HRTIM_ODSR_TB2ODS_Msk /*!< Timer B Output 2 disable status */ +#define HRTIM_ODSR_TC1ODS_Pos (4U) +#define HRTIM_ODSR_TC1ODS_Msk (0x1UL << HRTIM_ODSR_TC1ODS_Pos) /*!< 0x00000010 */ +#define HRTIM_ODSR_TC1ODS HRTIM_ODSR_TC1ODS_Msk /*!< Timer C Output 1 disable status */ +#define HRTIM_ODSR_TC2ODS_Pos (5U) +#define HRTIM_ODSR_TC2ODS_Msk (0x1UL << HRTIM_ODSR_TC2ODS_Pos) /*!< 0x00000020 */ +#define HRTIM_ODSR_TC2ODS HRTIM_ODSR_TC2ODS_Msk /*!< Timer C Output 2 disable status */ +#define HRTIM_ODSR_TD1ODS_Pos (6U) +#define HRTIM_ODSR_TD1ODS_Msk (0x1UL << HRTIM_ODSR_TD1ODS_Pos) /*!< 0x00000040 */ +#define HRTIM_ODSR_TD1ODS HRTIM_ODSR_TD1ODS_Msk /*!< Timer D Output 1 disable status */ +#define HRTIM_ODSR_TD2ODS_Pos (7U) +#define HRTIM_ODSR_TD2ODS_Msk (0x1UL << HRTIM_ODSR_TD2ODS_Pos) /*!< 0x00000080 */ +#define HRTIM_ODSR_TD2ODS HRTIM_ODSR_TD2ODS_Msk /*!< Timer D Output 2 disable status */ +#define HRTIM_ODSR_TE1ODS_Pos (8U) +#define HRTIM_ODSR_TE1ODS_Msk (0x1UL << HRTIM_ODSR_TE1ODS_Pos) /*!< 0x00000100 */ +#define HRTIM_ODSR_TE1ODS HRTIM_ODSR_TE1ODS_Msk /*!< Timer E Output 1 disable status */ +#define HRTIM_ODSR_TE2ODS_Pos (9U) +#define HRTIM_ODSR_TE2ODS_Msk (0x1UL << HRTIM_ODSR_TE2ODS_Pos) /*!< 0x00000200 */ +#define HRTIM_ODSR_TE2ODS HRTIM_ODSR_TE2ODS_Msk /*!< Timer E Output 2 disable status */ +#define HRTIM_ODSR_TF1ODS_Pos (10U) +#define HRTIM_ODSR_TF1ODS_Msk (0x1UL << HRTIM_ODSR_TF1ODS_Pos) /*!< 0x00000100 */ +#define HRTIM_ODSR_TF1ODS HRTIM_ODSR_TF1ODS_Msk /*!< Timer F Output 1 disable status */ +#define HRTIM_ODSR_TF2ODS_Pos (11U) +#define HRTIM_ODSR_TF2ODS_Msk (0x1UL << HRTIM_ODSR_TF2ODS_Pos) /*!< 0x00000200 */ +#define HRTIM_ODSR_TF2ODS HRTIM_ODSR_TF2ODS_Msk /*!< Timer F Output 2 disable status */ + +/**** Bit definition for Common HRTIM Timer Burst mode control register ********/ +#define HRTIM_BMCR_BME_Pos (0U) +#define HRTIM_BMCR_BME_Msk (0x1UL << HRTIM_BMCR_BME_Pos) /*!< 0x00000001 */ +#define HRTIM_BMCR_BME HRTIM_BMCR_BME_Msk /*!< Burst mode enable */ +#define HRTIM_BMCR_BMOM_Pos (1U) +#define HRTIM_BMCR_BMOM_Msk (0x1UL << HRTIM_BMCR_BMOM_Pos) /*!< 0x00000002 */ +#define HRTIM_BMCR_BMOM HRTIM_BMCR_BMOM_Msk /*!< Burst mode operating mode */ +#define HRTIM_BMCR_BMCLK_Pos (2U) +#define HRTIM_BMCR_BMCLK_Msk (0xFUL << HRTIM_BMCR_BMCLK_Pos) /*!< 0x0000003C */ +#define HRTIM_BMCR_BMCLK HRTIM_BMCR_BMCLK_Msk /*!< Burst mode clock source */ +#define HRTIM_BMCR_BMCLK_0 (0x1UL << HRTIM_BMCR_BMCLK_Pos) /*!< 0x00000004 */ +#define HRTIM_BMCR_BMCLK_1 (0x2UL << HRTIM_BMCR_BMCLK_Pos) /*!< 0x00000008 */ +#define HRTIM_BMCR_BMCLK_2 (0x4UL << HRTIM_BMCR_BMCLK_Pos) /*!< 0x00000010 */ +#define HRTIM_BMCR_BMCLK_3 (0x8UL << HRTIM_BMCR_BMCLK_Pos) /*!< 0x00000020 */ +#define HRTIM_BMCR_BMPRSC_Pos (6U) +#define HRTIM_BMCR_BMPRSC_Msk (0xFUL << HRTIM_BMCR_BMPRSC_Pos) /*!< 0x000003C0 */ +#define HRTIM_BMCR_BMPRSC HRTIM_BMCR_BMPRSC_Msk /*!< Burst mode prescaler */ +#define HRTIM_BMCR_BMPRSC_0 (0x1UL << HRTIM_BMCR_BMPRSC_Pos) /*!< 0x00000040 */ +#define HRTIM_BMCR_BMPRSC_1 (0x2UL << HRTIM_BMCR_BMPRSC_Pos) /*!< 0x00000080 */ +#define HRTIM_BMCR_BMPRSC_2 (0x4UL << HRTIM_BMCR_BMPRSC_Pos) /*!< 0x00000100 */ +#define HRTIM_BMCR_BMPRSC_3 (0x8UL << HRTIM_BMCR_BMPRSC_Pos) /*!< 0x00000200 */ +#define HRTIM_BMCR_BMPREN_Pos (10U) +#define HRTIM_BMCR_BMPREN_Msk (0x1UL << HRTIM_BMCR_BMPREN_Pos) /*!< 0x00000400 */ +#define HRTIM_BMCR_BMPREN HRTIM_BMCR_BMPREN_Msk /*!< Burst mode Preload bit */ +#define HRTIM_BMCR_MTBM_Pos (16U) +#define HRTIM_BMCR_MTBM_Msk (0x1UL << HRTIM_BMCR_MTBM_Pos) /*!< 0x00010000 */ +#define HRTIM_BMCR_MTBM HRTIM_BMCR_MTBM_Msk /*!< Master Timer Burst mode */ +#define HRTIM_BMCR_TABM_Pos (17U) +#define HRTIM_BMCR_TABM_Msk (0x1UL << HRTIM_BMCR_TABM_Pos) /*!< 0x00020000 */ +#define HRTIM_BMCR_TABM HRTIM_BMCR_TABM_Msk /*!< Timer A Burst mode */ +#define HRTIM_BMCR_TBBM_Pos (18U) +#define HRTIM_BMCR_TBBM_Msk (0x1UL << HRTIM_BMCR_TBBM_Pos) /*!< 0x00040000 */ +#define HRTIM_BMCR_TBBM HRTIM_BMCR_TBBM_Msk /*!< Timer B Burst mode */ +#define HRTIM_BMCR_TCBM_Pos (19U) +#define HRTIM_BMCR_TCBM_Msk (0x1UL << HRTIM_BMCR_TCBM_Pos) /*!< 0x00080000 */ +#define HRTIM_BMCR_TCBM HRTIM_BMCR_TCBM_Msk /*!< Timer C Burst mode */ +#define HRTIM_BMCR_TDBM_Pos (20U) +#define HRTIM_BMCR_TDBM_Msk (0x1UL << HRTIM_BMCR_TDBM_Pos) /*!< 0x00100000 */ +#define HRTIM_BMCR_TDBM HRTIM_BMCR_TDBM_Msk /*!< Timer D Burst mode */ +#define HRTIM_BMCR_TEBM_Pos (21U) +#define HRTIM_BMCR_TEBM_Msk (0x1UL << HRTIM_BMCR_TEBM_Pos) /*!< 0x00200000 */ +#define HRTIM_BMCR_TEBM HRTIM_BMCR_TEBM_Msk /*!< Timer E Burst mode */ + +#define HRTIM_BMCR_TFBM_Pos (22U) +#define HRTIM_BMCR_TFBM_Msk (0x1UL << HRTIM_BMCR_TFBM_Pos) /*!< 0x00400000 */ +#define HRTIM_BMCR_TFBM HRTIM_BMCR_TFBM_Msk /*!< Timer F Burst mode */ + +#define HRTIM_BMCR_BMSTAT_Pos (31U) +#define HRTIM_BMCR_BMSTAT_Msk (0x1UL << HRTIM_BMCR_BMSTAT_Pos) /*!< 0x80000000 */ +#define HRTIM_BMCR_BMSTAT HRTIM_BMCR_BMSTAT_Msk /*!< Burst mode status */ + +/**** Bit definition for Common HRTIM Timer Burst mode Trigger register *******/ +#define HRTIM_BMTRGR_SW_Pos (0U) +#define HRTIM_BMTRGR_SW_Msk (0x1UL << HRTIM_BMTRGR_SW_Pos) /*!< 0x00000001 */ +#define HRTIM_BMTRGR_SW HRTIM_BMTRGR_SW_Msk /*!< Software start */ +#define HRTIM_BMTRGR_MSTRST_Pos (1U) +#define HRTIM_BMTRGR_MSTRST_Msk (0x1UL << HRTIM_BMTRGR_MSTRST_Pos) /*!< 0x00000002 */ +#define HRTIM_BMTRGR_MSTRST HRTIM_BMTRGR_MSTRST_Msk /*!< Master reset */ +#define HRTIM_BMTRGR_MSTREP_Pos (2U) +#define HRTIM_BMTRGR_MSTREP_Msk (0x1UL << HRTIM_BMTRGR_MSTREP_Pos) /*!< 0x00000004 */ +#define HRTIM_BMTRGR_MSTREP HRTIM_BMTRGR_MSTREP_Msk /*!< Master repetition */ +#define HRTIM_BMTRGR_MSTCMP1_Pos (3U) +#define HRTIM_BMTRGR_MSTCMP1_Msk (0x1UL << HRTIM_BMTRGR_MSTCMP1_Pos) /*!< 0x00000008 */ +#define HRTIM_BMTRGR_MSTCMP1 HRTIM_BMTRGR_MSTCMP1_Msk /*!< Master compare 1 */ +#define HRTIM_BMTRGR_MSTCMP2_Pos (4U) +#define HRTIM_BMTRGR_MSTCMP2_Msk (0x1UL << HRTIM_BMTRGR_MSTCMP2_Pos) /*!< 0x00000010 */ +#define HRTIM_BMTRGR_MSTCMP2 HRTIM_BMTRGR_MSTCMP2_Msk /*!< Master compare 2 */ +#define HRTIM_BMTRGR_MSTCMP3_Pos (5U) +#define HRTIM_BMTRGR_MSTCMP3_Msk (0x1UL << HRTIM_BMTRGR_MSTCMP3_Pos) /*!< 0x00000020 */ +#define HRTIM_BMTRGR_MSTCMP3 HRTIM_BMTRGR_MSTCMP3_Msk /*!< Master compare 3 */ +#define HRTIM_BMTRGR_MSTCMP4_Pos (6U) +#define HRTIM_BMTRGR_MSTCMP4_Msk (0x1UL << HRTIM_BMTRGR_MSTCMP4_Pos) /*!< 0x00000040 */ +#define HRTIM_BMTRGR_MSTCMP4 HRTIM_BMTRGR_MSTCMP4_Msk /*!< Master compare 4 */ +#define HRTIM_BMTRGR_TARST_Pos (7U) +#define HRTIM_BMTRGR_TARST_Msk (0x1UL << HRTIM_BMTRGR_TARST_Pos) /*!< 0x00000080 */ +#define HRTIM_BMTRGR_TARST HRTIM_BMTRGR_TARST_Msk /*!< Timer A reset */ +#define HRTIM_BMTRGR_TAREP_Pos (8U) +#define HRTIM_BMTRGR_TAREP_Msk (0x1UL << HRTIM_BMTRGR_TAREP_Pos) /*!< 0x00000100 */ +#define HRTIM_BMTRGR_TAREP HRTIM_BMTRGR_TAREP_Msk /*!< Timer A repetition */ +#define HRTIM_BMTRGR_TACMP1_Pos (9U) +#define HRTIM_BMTRGR_TACMP1_Msk (0x1UL << HRTIM_BMTRGR_TACMP1_Pos) /*!< 0x00000200 */ +#define HRTIM_BMTRGR_TACMP1 HRTIM_BMTRGR_TACMP1_Msk /*!< Timer A compare 1 */ +#define HRTIM_BMTRGR_TACMP2_Pos (10U) +#define HRTIM_BMTRGR_TACMP2_Msk (0x1UL << HRTIM_BMTRGR_TACMP2_Pos) /*!< 0x00000400 */ +#define HRTIM_BMTRGR_TACMP2 HRTIM_BMTRGR_TACMP2_Msk /*!< Timer A compare 2 */ +#define HRTIM_BMTRGR_TBRST_Pos (11U) +#define HRTIM_BMTRGR_TBRST_Msk (0x1UL << HRTIM_BMTRGR_TBRST_Pos) /*!< 0x00000800 */ +#define HRTIM_BMTRGR_TBRST HRTIM_BMTRGR_TBRST_Msk /*!< Timer B reset */ +#define HRTIM_BMTRGR_TBREP_Pos (12U) +#define HRTIM_BMTRGR_TBREP_Msk (0x1UL << HRTIM_BMTRGR_TBREP_Pos) /*!< 0x00001000 */ +#define HRTIM_BMTRGR_TBREP HRTIM_BMTRGR_TBREP_Msk /*!< Timer B repetition */ +#define HRTIM_BMTRGR_TBCMP1_Pos (13U) +#define HRTIM_BMTRGR_TBCMP1_Msk (0x1UL << HRTIM_BMTRGR_TBCMP1_Pos) /*!< 0x00002000 */ +#define HRTIM_BMTRGR_TBCMP1 HRTIM_BMTRGR_TBCMP1_Msk /*!< Timer B compare 1 */ +#define HRTIM_BMTRGR_TBCMP2_Pos (14U) +#define HRTIM_BMTRGR_TBCMP2_Msk (0x1UL << HRTIM_BMTRGR_TBCMP2_Pos) /*!< 0x00004000 */ +#define HRTIM_BMTRGR_TBCMP2 HRTIM_BMTRGR_TBCMP2_Msk /*!< Timer B compare 2 */ +#define HRTIM_BMTRGR_TCRST_Pos (15U) +#define HRTIM_BMTRGR_TCRST_Msk (0x1UL << HRTIM_BMTRGR_TCRST_Pos) /*!< 0x00008000 */ +#define HRTIM_BMTRGR_TCRST HRTIM_BMTRGR_TCRST_Msk /*!< Timer C reset */ +#define HRTIM_BMTRGR_TCREP_Pos (16U) +#define HRTIM_BMTRGR_TCREP_Msk (0x1UL << HRTIM_BMTRGR_TCREP_Pos) /*!< 0x00010000 */ +#define HRTIM_BMTRGR_TCREP HRTIM_BMTRGR_TCREP_Msk /*!< Timer C repetition */ +#define HRTIM_BMTRGR_TCCMP1_Pos (17U) +#define HRTIM_BMTRGR_TCCMP1_Msk (0x1UL << HRTIM_BMTRGR_TCCMP1_Pos) /*!< 0x00020000 */ +#define HRTIM_BMTRGR_TCCMP1 HRTIM_BMTRGR_TCCMP1_Msk /*!< Timer C compare 1 */ +#define HRTIM_BMTRGR_TFRST_Pos (18U) +#define HRTIM_BMTRGR_TFRST_Msk (0x1UL << HRTIM_BMTRGR_TFRST_Pos) /*!< 0x00040000 */ +#define HRTIM_BMTRGR_TFRST HRTIM_BMTRGR_TFRST_Msk /*!< Timer F reset */ +#define HRTIM_BMTRGR_TDRST_Pos (19U) +#define HRTIM_BMTRGR_TDRST_Msk (0x1UL << HRTIM_BMTRGR_TDRST_Pos) /*!< 0x00080000 */ +#define HRTIM_BMTRGR_TDRST HRTIM_BMTRGR_TDRST_Msk /*!< Timer D reset */ +#define HRTIM_BMTRGR_TDREP_Pos (20U) +#define HRTIM_BMTRGR_TDREP_Msk (0x1UL << HRTIM_BMTRGR_TDREP_Pos) /*!< 0x00100000 */ +#define HRTIM_BMTRGR_TDREP HRTIM_BMTRGR_TDREP_Msk /*!< Timer D repetition */ +#define HRTIM_BMTRGR_TFREP_Pos (21U) +#define HRTIM_BMTRGR_TFREP_Msk (0x1UL << HRTIM_BMTRGR_TFREP_Pos) /*!< 0x00200000 */ +#define HRTIM_BMTRGR_TFREP HRTIM_BMTRGR_TFREP_Msk /*!< Timer F repetition*/ +#define HRTIM_BMTRGR_TDCMP2_Pos (22U) +#define HRTIM_BMTRGR_TDCMP2_Msk (0x1UL << HRTIM_BMTRGR_TDCMP2_Pos) /*!< 0x00400000 */ +#define HRTIM_BMTRGR_TDCMP2 HRTIM_BMTRGR_TDCMP2_Msk /*!< Timer D compare 2 */ +#define HRTIM_BMTRGR_TFCMP1_Pos (23U) +#define HRTIM_BMTRGR_TFCMP1_Msk (0x1UL << HRTIM_BMTRGR_TFCMP1_Pos) /*!< 0x00800000 */ +#define HRTIM_BMTRGR_TFCMP1 HRTIM_BMTRGR_TFCMP1_Msk /*!< Timer F compare 1 */ +#define HRTIM_BMTRGR_TEREP_Pos (24U) +#define HRTIM_BMTRGR_TEREP_Msk (0x1UL << HRTIM_BMTRGR_TEREP_Pos) /*!< 0x01000000 */ +#define HRTIM_BMTRGR_TEREP HRTIM_BMTRGR_TEREP_Msk /*!< Timer E repetition */ +#define HRTIM_BMTRGR_TECMP1_Pos (25U) +#define HRTIM_BMTRGR_TECMP1_Msk (0x1UL << HRTIM_BMTRGR_TECMP1_Pos) /*!< 0x02000000 */ +#define HRTIM_BMTRGR_TECMP1 HRTIM_BMTRGR_TECMP1_Msk /*!< Timer E compare 1 */ +#define HRTIM_BMTRGR_TECMP2_Pos (26U) +#define HRTIM_BMTRGR_TECMP2_Msk (0x1UL << HRTIM_BMTRGR_TECMP2_Pos) /*!< 0x04000000 */ +#define HRTIM_BMTRGR_TECMP2 HRTIM_BMTRGR_TECMP2_Msk /*!< Timer E compare 2 */ +#define HRTIM_BMTRGR_TAEEV7_Pos (27U) +#define HRTIM_BMTRGR_TAEEV7_Msk (0x1UL << HRTIM_BMTRGR_TAEEV7_Pos) /*!< 0x08000000 */ +#define HRTIM_BMTRGR_TAEEV7 HRTIM_BMTRGR_TAEEV7_Msk /*!< Timer A period following External Event7 */ +#define HRTIM_BMTRGR_TDEEV8_Pos (28U) +#define HRTIM_BMTRGR_TDEEV8_Msk (0x1UL << HRTIM_BMTRGR_TDEEV8_Pos) /*!< 0x10000000 */ +#define HRTIM_BMTRGR_TDEEV8 HRTIM_BMTRGR_TDEEV8_Msk /*!< Timer D period following External Event8 */ +#define HRTIM_BMTRGR_EEV7_Pos (29U) +#define HRTIM_BMTRGR_EEV7_Msk (0x1UL << HRTIM_BMTRGR_EEV7_Pos) /*!< 0x20000000 */ +#define HRTIM_BMTRGR_EEV7 HRTIM_BMTRGR_EEV7_Msk /*!< External Event 7 */ +#define HRTIM_BMTRGR_EEV8_Pos (30U) +#define HRTIM_BMTRGR_EEV8_Msk (0x1UL << HRTIM_BMTRGR_EEV8_Pos) /*!< 0x40000000 */ +#define HRTIM_BMTRGR_EEV8 HRTIM_BMTRGR_EEV8_Msk /*!< External Event 8 */ +#define HRTIM_BMTRGR_OCHPEV_Pos (31U) +#define HRTIM_BMTRGR_OCHPEV_Msk (0x1UL << HRTIM_BMTRGR_OCHPEV_Pos) /*!< 0x80000000 */ +#define HRTIM_BMTRGR_OCHPEV HRTIM_BMTRGR_OCHPEV_Msk /*!< on-chip Event */ + +/******************* Bit definition for HRTIM_BMCMPR register ***************/ +#define HRTIM_BMCMPR_BMCMPR_Pos (0U) +#define HRTIM_BMCMPR_BMCMPR_Msk (0xFFFFUL << HRTIM_BMCMPR_BMCMPR_Pos) /*!< 0x0000FFFF */ +#define HRTIM_BMCMPR_BMCMPR HRTIM_BMCMPR_BMCMPR_Msk /*! Date: Mon, 1 Jun 2026 18:15:29 +0200 Subject: [PATCH 2/4] Add STM32 MCU foundation Add the STM32 platform entry point, chip CMake files, bspMcu startup code, a software reset wrapper, and the STM32 unit-test presets. The platform reuses the shared CMSIS core from libs/3rdparty/cmsis instead of carrying a local copy. --- CMakeLists.txt | 4 + CMakePresets.json | 54 +++ NOTICE.md | 3 +- doc/dev/index.rst | 1 + doc/dev/modules/stm32.rst | 22 + platforms/stm32/CMakeLists.txt | 20 + platforms/stm32/bsp/CMakeLists.txt | 1 + platforms/stm32/bsp/bspMcu/CMakeLists.txt | 18 + platforms/stm32/bsp/bspMcu/doc/index.rst | 22 + platforms/stm32/bsp/bspMcu/include/mcu/mcu.h | 24 + .../include/reset/softwareSystemReset.h | 22 + platforms/stm32/bsp/bspMcu/module.spec | 8 + .../bspMcu/src/reset/softwareSystemReset.cpp | 18 + .../bsp/bspMcu/startup/startup_stm32f413xx.s | 435 +++++++++++++++++ .../bsp/bspMcu/startup/startup_stm32g474xx.s | 449 ++++++++++++++++++ platforms/stm32/cmake/stm32f413zh.cmake | 15 + platforms/stm32/cmake/stm32g474re.cmake | 15 + platforms/stm32/unitTest/CMakeLists.txt | 1 + 18 files changed, 1131 insertions(+), 1 deletion(-) create mode 100644 doc/dev/modules/stm32.rst create mode 100644 platforms/stm32/CMakeLists.txt create mode 100644 platforms/stm32/bsp/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspMcu/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspMcu/doc/index.rst create mode 100644 platforms/stm32/bsp/bspMcu/include/mcu/mcu.h create mode 100644 platforms/stm32/bsp/bspMcu/include/reset/softwareSystemReset.h create mode 100644 platforms/stm32/bsp/bspMcu/module.spec create mode 100644 platforms/stm32/bsp/bspMcu/src/reset/softwareSystemReset.cpp create mode 100644 platforms/stm32/bsp/bspMcu/startup/startup_stm32f413xx.s create mode 100644 platforms/stm32/bsp/bspMcu/startup/startup_stm32g474xx.s create mode 100644 platforms/stm32/cmake/stm32f413zh.cmake create mode 100644 platforms/stm32/cmake/stm32g474re.cmake create mode 100644 platforms/stm32/unitTest/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d893a6a9a..840515f077c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,10 @@ if (BUILD_EXECUTABLE STREQUAL "unitTest") add_subdirectory(platforms/s32k1xx/bsp/canflex2Transceiver/test) add_subdirectory(platforms/s32k1xx/bsp/bspUart/test) + elseif (OPENBSW_PLATFORM STREQUAL "stm32") + + add_subdirectory(platforms/stm32/unitTest EXCLUDE_FROM_ALL) + else () message( FATAL_ERROR diff --git a/CMakePresets.json b/CMakePresets.json index ec6272009d2..19f96ee79a4 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -61,6 +61,32 @@ "OPENBSW_PLATFORM": "s32k1xx" } }, + { + "name": "tests-stm32-debug", + "displayName": "Configure for testing STM32 modules (debug)", + "description": "Configure for testing STM32 modules (debug)", + "inherits": "_config-base", + "binaryDir": "${sourceDir}/build/tests/stm32/Debug", + "cacheVariables": { + "CMAKE_DEFAULT_BUILD_TYPE": "Debug", + "CMAKE_CONFIGURATION_TYPES": "Debug", + "BUILD_EXECUTABLE": "unitTest", + "OPENBSW_PLATFORM": "stm32" + } + }, + { + "name": "tests-stm32-release", + "displayName": "Configure for testing STM32 modules (release)", + "description": "Configure for testing STM32 modules (release)", + "inherits": "_config-base", + "binaryDir": "${sourceDir}/build/tests/stm32/Release", + "cacheVariables": { + "CMAKE_DEFAULT_BUILD_TYPE": "Release", + "CMAKE_CONFIGURATION_TYPES": "Release", + "BUILD_EXECUTABLE": "unitTest", + "OPENBSW_PLATFORM": "stm32" + } + }, { "name": "posix-freertos", "displayName": "POSIX-FREERTOS compliant configuration", @@ -228,6 +254,20 @@ "configurePreset": "tests-s32k1xx-release", "configuration": "Release" }, + { + "name": "tests-stm32-debug", + "displayName": "Build tests of STM32 modules (debug)", + "description": "Build tests of STM32 modules (debug)", + "configurePreset": "tests-stm32-debug", + "configuration": "Debug" + }, + { + "name": "tests-stm32-release", + "displayName": "Build tests of STM32 modules (release)", + "description": "Build tests of STM32 modules (release)", + "configurePreset": "tests-stm32-release", + "configuration": "Release" + }, { "name": "posix-freertos", "displayName": "build POSIX-FREERTOS", @@ -305,6 +345,20 @@ "description": "Run tests of S32K1XX modules (release)", "configuration": "Release", "configurePreset": "tests-s32k1xx-release" + }, + { + "name": "tests-stm32-debug", + "displayName": "Run tests of STM32 modules (debug)", + "description": "Run tests of STM32 modules (debug)", + "configuration": "Debug", + "configurePreset": "tests-stm32-debug" + }, + { + "name": "tests-stm32-release", + "displayName": "Run tests of STM32 modules (release)", + "description": "Run tests of STM32 modules (release)", + "configuration": "Release", + "configurePreset": "tests-stm32-release" } ] } diff --git a/NOTICE.md b/NOTICE.md index 9be29d742b7..fcd5577cd22 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -47,7 +47,8 @@ We recommend to read their licenses, as their terms may differ from the terms de | ThreadX Linux Port | 6.4.3 | MIT | ``platforms/posix/3rdparty/threadx/LICENSE.md`` | | CMSIS | 6.1.0 | Apache v2 | ``libs/3rdparty/cmsis/LICENSE`` | | NXP S32K148 Headers | 1.1a | BSD-3 | ``platforms/s32k1xx/bsp/bspMcu/include/3rdparty/nxp/*.h`` | -| ST STM32 Device Headers | 2.6.11 / 1.2.6 | Apache v2 | ``platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE`` | +| ST STM32F4 Device Headers | 2.6.11 | Apache v2 | ``platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE`` | +| ST STM32G4 Device Headers | 1.2.6 | Apache v2 | ``platforms/stm32/bsp/bspMcu/include/3rdparty/st/LICENSE`` | | CodeCoverage | | BSD-3 | ``cmake/modules/CodeCoverage.cmake`` | ## MISRA diff --git a/doc/dev/index.rst b/doc/dev/index.rst index 00d174535f8..da03693a06d 100644 --- a/doc/dev/index.rst +++ b/doc/dev/index.rst @@ -178,6 +178,7 @@ Eclipse OpenBSW is a trademark of the Eclipse Foundation. modules/common modules/posix modules/s32k1xx + modules/stm32 modules/executables modules/mocks diff --git a/doc/dev/modules/stm32.rst b/doc/dev/modules/stm32.rst new file mode 100644 index 00000000000..66660f2761b --- /dev/null +++ b/doc/dev/modules/stm32.rst @@ -0,0 +1,22 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +STM32 +===== + +BSP +--- + +.. toctree:: + :maxdepth: 1 + :glob: + + ../../../platforms/stm32/bsp/**/doc/index diff --git a/platforms/stm32/CMakeLists.txt b/platforms/stm32/CMakeLists.txt new file mode 100644 index 00000000000..dbe6c9fd805 --- /dev/null +++ b/platforms/stm32/CMakeLists.txt @@ -0,0 +1,20 @@ +if (NOT BUILD_EXECUTABLE STREQUAL "unitTest") + if (NOT DEFINED STM32_CHIP) + message( + FATAL_ERROR + "STM32_CHIP must be defined (e.g., STM32F413ZH or STM32G474RE)") + endif () + + if (STM32_CHIP STREQUAL "STM32F413ZH") + include(${CMAKE_CURRENT_LIST_DIR}/cmake/stm32f413zh.cmake) + elseif (STM32_CHIP STREQUAL "STM32G474RE") + include(${CMAKE_CURRENT_LIST_DIR}/cmake/stm32g474re.cmake) + else () + message( + FATAL_ERROR + "Unsupported STM32_CHIP: ${STM32_CHIP}. Supported: STM32F413ZH, STM32G474RE" + ) + endif () + + add_subdirectory(bsp) +endif () diff --git a/platforms/stm32/bsp/CMakeLists.txt b/platforms/stm32/bsp/CMakeLists.txt new file mode 100644 index 00000000000..c377df0854c --- /dev/null +++ b/platforms/stm32/bsp/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(bspMcu) diff --git a/platforms/stm32/bsp/bspMcu/CMakeLists.txt b/platforms/stm32/bsp/bspMcu/CMakeLists.txt new file mode 100644 index 00000000000..f931f420073 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/CMakeLists.txt @@ -0,0 +1,18 @@ +enable_language(ASM) +add_library(bspMcu src/reset/softwareSystemReset.cpp ${STM32_STARTUP_ASM}) + +target_include_directories( + bspMcu PUBLIC include ${CMAKE_SOURCE_DIR}/libs/3rdparty/cmsis + ${CMAKE_SOURCE_DIR}/libs/3rdparty/cmsis/m-profile) + +if (STM32_FAMILY STREQUAL "F4") + target_include_directories(bspMcu PUBLIC include/3rdparty/st/stm32f4) +elseif (STM32_FAMILY STREQUAL "G4") + target_include_directories(bspMcu PUBLIC include/3rdparty/st/stm32g4) +endif () + +target_compile_definitions( + bspMcu PUBLIC ${STM32_DEVICE_UPPER} STM32_FAMILY_${STM32_FAMILY} + CAN_TYPE_${CAN_TYPE}) + +target_link_libraries(bspMcu PUBLIC platform) diff --git a/platforms/stm32/bsp/bspMcu/doc/index.rst b/platforms/stm32/bsp/bspMcu/doc/index.rst new file mode 100644 index 00000000000..e0ee61f3bf1 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/doc/index.rst @@ -0,0 +1,22 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspMcu +====== + +Overview +-------- + +The module ``bspMcu`` provides the MCU API for STM32F413xx and STM32G474xx. +``mcu/mcu.h`` selects the matching ST CMSIS device header from +``include/3rdparty/st`` and reuses the shared CMSIS core headers from +``libs/3rdparty/cmsis``. The module also contains the chip startup files and +a function for software system reset. diff --git a/platforms/stm32/bsp/bspMcu/include/mcu/mcu.h b/platforms/stm32/bsp/bspMcu/include/mcu/mcu.h new file mode 100644 index 00000000000..70616c1fe78 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/include/mcu/mcu.h @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +// Required by the local core_cm4.h include guard. +#define INCLUDE_CORE_CM4_IN_MCU_H + +#if defined(STM32F413xx) +#include "stm32f413xx.h" +#elif defined(STM32G474xx) +#include "stm32g474xx.h" +#else +#error "Unsupported STM32 device - define STM32F413xx or STM32G474xx" +#endif + +#undef INCLUDE_CORE_CM4_IN_MCU_H diff --git a/platforms/stm32/bsp/bspMcu/include/reset/softwareSystemReset.h b/platforms/stm32/bsp/bspMcu/include/reset/softwareSystemReset.h new file mode 100644 index 00000000000..726097e3ba7 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/include/reset/softwareSystemReset.h @@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +[[noreturn]] extern void softwareSystemReset(void); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/platforms/stm32/bsp/bspMcu/module.spec b/platforms/stm32/bsp/bspMcu/module.spec new file mode 100644 index 00000000000..3b4161c23d4 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/module.spec @@ -0,0 +1,8 @@ +maturity: raw +unit_test: false +format_check_exclude: + - "include/3rdparty/st/*/*.h" +sca_exclude: + '*': + - "include/3rdparty/st/*/*.h" +oss: true diff --git a/platforms/stm32/bsp/bspMcu/src/reset/softwareSystemReset.cpp b/platforms/stm32/bsp/bspMcu/src/reset/softwareSystemReset.cpp new file mode 100644 index 00000000000..65e31e40a04 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/src/reset/softwareSystemReset.cpp @@ -0,0 +1,18 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "reset/softwareSystemReset.h" + +#include "mcu/mcu.h" + +extern "C" +{ +[[noreturn]] void softwareSystemReset(void) { NVIC_SystemReset(); } +} diff --git a/platforms/stm32/bsp/bspMcu/startup/startup_stm32f413xx.s b/platforms/stm32/bsp/bspMcu/startup/startup_stm32f413xx.s new file mode 100644 index 00000000000..59c93de614e --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/startup/startup_stm32f413xx.s @@ -0,0 +1,435 @@ +/******************************************************************************** + * Copyright (c) 2017 STMicroelectronics + * Copyright (c) 2026 An Dao + * + * Startup for STM32F413xx: vector table and Reset_Handler, based on the + * STMicroelectronics CMSIS device startup template for STM32F4. Vector + * table layout per reference manual RM0430. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + + .syntax unified + .cpu cortex-m4 + .fpu fpv4-sp-d16 + .thumb + +.global g_pfnVectors +.global Default_Handler + +.word _sidata +.word _sdata +.word _edata +.word _sbss +.word _ebss + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack + +/* Copy .data from FLASH to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill .bss */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Enable FPU: set CP10/CP11 full access (required for ThreadX - FreeRTOS + enables this in port.c, but ThreadX does not) */ + ldr r0, =0xE000ED88 + ldr r1, [r0] + orr r1, r1, #(0xF << 20) + str r1, [r0] + dsb + isb + +/* Call SystemInit, C++ constructors, and main */ + bl SystemInit + bl __libc_init_array + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler + + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler + +/****************************************************************************** + * Vector table for STM32F413xx (102 external interrupts, RM0430 Table 40) + ******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + +g_pfnVectors: + /* Cortex-M4 system exceptions */ + .word _estack /* Top of Stack */ + .word Reset_Handler /* Reset Handler */ + .word NMI_Handler /* NMI Handler */ + .word HardFault_Handler /* Hard Fault Handler */ + .word MemManage_Handler /* MPU Fault Handler */ + .word BusFault_Handler /* Bus Fault Handler */ + .word UsageFault_Handler /* Usage Fault Handler */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word SVC_Handler /* SVCall Handler */ + .word DebugMon_Handler /* Debug Monitor Handler */ + .word 0 /* Reserved */ + .word PendSV_Handler /* PendSV Handler */ + .word SysTick_Handler /* SysTick Handler */ + + /* External interrupts - STM32F413xx (IRQn 0–101) */ + .word WWDG_IRQHandler /* 0: Window Watchdog */ + .word PVD_IRQHandler /* 1: PVD through EXTI */ + .word TAMP_STAMP_IRQHandler /* 2: Tamper and TimeStamp via EXTI */ + .word RTC_WKUP_IRQHandler /* 3: RTC Wakeup via EXTI */ + .word FLASH_IRQHandler /* 4: Flash global */ + .word RCC_IRQHandler /* 5: RCC global */ + .word EXTI0_IRQHandler /* 6: EXTI Line 0 */ + .word EXTI1_IRQHandler /* 7: EXTI Line 1 */ + .word EXTI2_IRQHandler /* 8: EXTI Line 2 */ + .word EXTI3_IRQHandler /* 9: EXTI Line 3 */ + .word EXTI4_IRQHandler /* 10: EXTI Line 4 */ + .word DMA1_Stream0_IRQHandler /* 11: DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* 12: DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* 13: DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* 14: DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* 15: DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* 16: DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* 17: DMA1 Stream 6 */ + .word ADC_IRQHandler /* 18: ADC1, ADC2, ADC3 */ + .word CAN1_TX_IRQHandler /* 19: CAN1 TX */ + .word CAN1_RX0_IRQHandler /* 20: CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* 21: CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* 22: CAN1 SCE */ + .word EXTI9_5_IRQHandler /* 23: EXTI Lines [9:5] */ + .word TIM1_BRK_TIM9_IRQHandler /* 24: TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* 25: TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* 26: TIM1 Trigger/Commut and TIM11 */ + .word TIM1_CC_IRQHandler /* 27: TIM1 Capture Compare */ + .word TIM2_IRQHandler /* 28: TIM2 */ + .word TIM3_IRQHandler /* 29: TIM3 */ + .word TIM4_IRQHandler /* 30: TIM4 */ + .word I2C1_EV_IRQHandler /* 31: I2C1 Event */ + .word I2C1_ER_IRQHandler /* 32: I2C1 Error */ + .word I2C2_EV_IRQHandler /* 33: I2C2 Event */ + .word I2C2_ER_IRQHandler /* 34: I2C2 Error */ + .word SPI1_IRQHandler /* 35: SPI1 */ + .word SPI2_IRQHandler /* 36: SPI2 */ + .word USART1_IRQHandler /* 37: USART1 */ + .word USART2_IRQHandler /* 38: USART2 */ + .word USART3_IRQHandler /* 39: USART3 */ + .word EXTI15_10_IRQHandler /* 40: EXTI Lines [15:10] */ + .word RTC_Alarm_IRQHandler /* 41: RTC Alarm (A and B) via EXTI */ + .word OTG_FS_WKUP_IRQHandler /* 42: USB OTG FS Wakeup via EXTI */ + .word TIM8_BRK_TIM12_IRQHandler /* 43: TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* 44: TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* 45: TIM8 Trigger/Commut and TIM14 */ + .word TIM8_CC_IRQHandler /* 46: TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* 47: DMA1 Stream 7 */ + .word 0 /* 48: Reserved (FSMC) */ + .word SDIO_IRQHandler /* 49: SDIO */ + .word TIM5_IRQHandler /* 50: TIM5 */ + .word SPI3_IRQHandler /* 51: SPI3 */ + .word UART4_IRQHandler /* 52: UART4 */ + .word UART5_IRQHandler /* 53: UART5 */ + .word TIM6_DAC_IRQHandler /* 54: TIM6 and DAC1&2 underrun */ + .word TIM7_IRQHandler /* 55: TIM7 */ + .word DMA2_Stream0_IRQHandler /* 56: DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* 57: DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* 58: DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* 59: DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* 60: DMA2 Stream 4 */ + .word DFSDM1_FLT0_IRQHandler /* 61: DFSDM1 Filter 0 */ + .word DFSDM1_FLT1_IRQHandler /* 62: DFSDM1 Filter 1 */ + .word CAN2_TX_IRQHandler /* 63: CAN2 TX */ + .word CAN2_RX0_IRQHandler /* 64: CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* 65: CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* 66: CAN2 SCE */ + .word OTG_FS_IRQHandler /* 67: USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* 68: DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* 69: DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* 70: DMA2 Stream 7 */ + .word USART6_IRQHandler /* 71: USART6 */ + .word I2C3_EV_IRQHandler /* 72: I2C3 Event */ + .word I2C3_ER_IRQHandler /* 73: I2C3 Error */ + .word CAN3_TX_IRQHandler /* 74: CAN3 TX */ + .word CAN3_RX0_IRQHandler /* 75: CAN3 RX0 */ + .word CAN3_RX1_IRQHandler /* 76: CAN3 RX1 */ + .word CAN3_SCE_IRQHandler /* 77: CAN3 SCE */ + .word 0 /* 78: Reserved */ + .word 0 /* 79: Reserved */ + .word RNG_IRQHandler /* 80: RNG */ + .word FPU_IRQHandler /* 81: FPU */ + .word UART7_IRQHandler /* 82: UART7 */ + .word UART8_IRQHandler /* 83: UART8 */ + .word SPI4_IRQHandler /* 84: SPI4 */ + .word SPI5_IRQHandler /* 85: SPI5 */ + .word 0 /* 86: Reserved */ + .word SAI1_IRQHandler /* 87: SAI1 */ + .word UART9_IRQHandler /* 88: UART9 */ + .word UART10_IRQHandler /* 89: UART10 */ + .word 0 /* 90: Reserved */ + .word 0 /* 91: Reserved */ + .word QUADSPI_IRQHandler /* 92: QuadSPI */ + .word 0 /* 93: Reserved */ + .word 0 /* 94: Reserved */ + .word FMPI2C1_EV_IRQHandler /* 95: FMPI2C1 Event */ + .word FMPI2C1_ER_IRQHandler /* 96: FMPI2C1 Error */ + .word LPTIM1_IRQHandler /* 97: LPTIM1 */ + .word DFSDM2_FLT0_IRQHandler /* 98: DFSDM2 Filter 0 */ + .word DFSDM2_FLT1_IRQHandler /* 99: DFSDM2 Filter 1 */ + .word DFSDM2_FLT2_IRQHandler /* 100: DFSDM2 Filter 2 */ + .word DFSDM2_FLT3_IRQHandler /* 101: DFSDM2 Filter 3 */ + + .size g_pfnVectors, .-g_pfnVectors + +/******************************************************************************* + * Weak aliases - all handlers default to infinite loop unless overridden + *******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + .weak CAN3_TX_IRQHandler + .thumb_set CAN3_TX_IRQHandler,Default_Handler + .weak CAN3_RX0_IRQHandler + .thumb_set CAN3_RX0_IRQHandler,Default_Handler + .weak CAN3_RX1_IRQHandler + .thumb_set CAN3_RX1_IRQHandler,Default_Handler + .weak CAN3_SCE_IRQHandler + .thumb_set CAN3_SCE_IRQHandler,Default_Handler + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + .weak UART9_IRQHandler + .thumb_set UART9_IRQHandler,Default_Handler + .weak UART10_IRQHandler + .thumb_set UART10_IRQHandler,Default_Handler + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + .weak FMPI2C1_EV_IRQHandler + .thumb_set FMPI2C1_EV_IRQHandler,Default_Handler + .weak FMPI2C1_ER_IRQHandler + .thumb_set FMPI2C1_ER_IRQHandler,Default_Handler + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + .weak DFSDM2_FLT0_IRQHandler + .thumb_set DFSDM2_FLT0_IRQHandler,Default_Handler + .weak DFSDM2_FLT1_IRQHandler + .thumb_set DFSDM2_FLT1_IRQHandler,Default_Handler + .weak DFSDM2_FLT2_IRQHandler + .thumb_set DFSDM2_FLT2_IRQHandler,Default_Handler + .weak DFSDM2_FLT3_IRQHandler + .thumb_set DFSDM2_FLT3_IRQHandler,Default_Handler + .section .text.SystemInit,"ax",%progbits + .weak SystemInit + .type SystemInit,%function +SystemInit: + bx lr + .size SystemInit, .-SystemInit diff --git a/platforms/stm32/bsp/bspMcu/startup/startup_stm32g474xx.s b/platforms/stm32/bsp/bspMcu/startup/startup_stm32g474xx.s new file mode 100644 index 00000000000..f5a4389c886 --- /dev/null +++ b/platforms/stm32/bsp/bspMcu/startup/startup_stm32g474xx.s @@ -0,0 +1,449 @@ +/******************************************************************************** + * Copyright (c) 2019 STMicroelectronics + * Copyright (c) 2026 An Dao + * + * Startup for STM32G474xx: vector table and Reset_Handler, based on the + * STMicroelectronics CMSIS device startup template for STM32G4. Vector + * table layout per reference manual RM0440. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + + .syntax unified + .cpu cortex-m4 + .fpu fpv4-sp-d16 + .thumb + +.global g_pfnVectors +.global Default_Handler + +.word _sidata +.word _sdata +.word _edata +.word _sbss +.word _ebss + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack + +/* Copy .data from FLASH to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill .bss */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Enable FPU: set CP10/CP11 full access (required for ThreadX - FreeRTOS + enables this in port.c, but ThreadX does not) */ + ldr r0, =0xE000ED88 + ldr r1, [r0] + orr r1, r1, #(0xF << 20) + str r1, [r0] + dsb + isb + +/* Call SystemInit, C++ constructors, and main */ + bl SystemInit + bl __libc_init_array + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler + + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler + +/****************************************************************************** + * Vector table for STM32G474xx (102 external interrupts, RM0440 Table 97) + ******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + +g_pfnVectors: + /* Cortex-M4 system exceptions */ + .word _estack /* Top of Stack */ + .word Reset_Handler /* Reset Handler */ + .word NMI_Handler /* NMI Handler */ + .word HardFault_Handler /* Hard Fault Handler */ + .word MemManage_Handler /* MPU Fault Handler */ + .word BusFault_Handler /* Bus Fault Handler */ + .word UsageFault_Handler /* Usage Fault Handler */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word SVC_Handler /* SVCall Handler */ + .word DebugMon_Handler /* Debug Monitor Handler */ + .word 0 /* Reserved */ + .word PendSV_Handler /* PendSV Handler */ + .word SysTick_Handler /* SysTick Handler */ + + /* External interrupts - STM32G474xx (IRQn 0–101) */ + .word WWDG_IRQHandler /* 0: Window Watchdog */ + .word PVD_PVM_IRQHandler /* 1: PVD/PVM through EXTI */ + .word RTC_TAMP_LSECSS_IRQHandler /* 2: RTC Tamper, TimeStamp, LSE CSS */ + .word RTC_WKUP_IRQHandler /* 3: RTC Wakeup through EXTI */ + .word FLASH_IRQHandler /* 4: Flash global */ + .word RCC_IRQHandler /* 5: RCC global */ + .word EXTI0_IRQHandler /* 6: EXTI Line 0 */ + .word EXTI1_IRQHandler /* 7: EXTI Line 1 */ + .word EXTI2_IRQHandler /* 8: EXTI Line 2 */ + .word EXTI3_IRQHandler /* 9: EXTI Line 3 */ + .word EXTI4_IRQHandler /* 10: EXTI Line 4 */ + .word DMA1_Channel1_IRQHandler /* 11: DMA1 Channel 1 */ + .word DMA1_Channel2_IRQHandler /* 12: DMA1 Channel 2 */ + .word DMA1_Channel3_IRQHandler /* 13: DMA1 Channel 3 */ + .word DMA1_Channel4_IRQHandler /* 14: DMA1 Channel 4 */ + .word DMA1_Channel5_IRQHandler /* 15: DMA1 Channel 5 */ + .word DMA1_Channel6_IRQHandler /* 16: DMA1 Channel 6 */ + .word DMA1_Channel7_IRQHandler /* 17: DMA1 Channel 7 */ + .word ADC1_2_IRQHandler /* 18: ADC1 and ADC2 */ + .word USB_HP_IRQHandler /* 19: USB High Priority */ + .word USB_LP_IRQHandler /* 20: USB Low Priority */ + .word FDCAN1_IT0_IRQHandler /* 21: FDCAN1 IT0 */ + .word FDCAN1_IT1_IRQHandler /* 22: FDCAN1 IT1 */ + .word EXTI9_5_IRQHandler /* 23: EXTI Lines [9:5] */ + .word TIM1_BRK_TIM15_IRQHandler /* 24: TIM1 Break and TIM15 */ + .word TIM1_UP_TIM16_IRQHandler /* 25: TIM1 Update and TIM16 */ + .word TIM1_TRG_COM_TIM17_IRQHandler /* 26: TIM1 Trigger/Commut and TIM17 */ + .word TIM1_CC_IRQHandler /* 27: TIM1 Capture Compare */ + .word TIM2_IRQHandler /* 28: TIM2 */ + .word TIM3_IRQHandler /* 29: TIM3 */ + .word TIM4_IRQHandler /* 30: TIM4 */ + .word I2C1_EV_IRQHandler /* 31: I2C1 Event */ + .word I2C1_ER_IRQHandler /* 32: I2C1 Error */ + .word I2C2_EV_IRQHandler /* 33: I2C2 Event */ + .word I2C2_ER_IRQHandler /* 34: I2C2 Error */ + .word SPI1_IRQHandler /* 35: SPI1 */ + .word SPI2_IRQHandler /* 36: SPI2 */ + .word USART1_IRQHandler /* 37: USART1 */ + .word USART2_IRQHandler /* 38: USART2 */ + .word USART3_IRQHandler /* 39: USART3 */ + .word EXTI15_10_IRQHandler /* 40: EXTI Lines [15:10] */ + .word RTC_Alarm_IRQHandler /* 41: RTC Alarm (A and B) via EXTI */ + .word USBWakeUp_IRQHandler /* 42: USB Wakeup via EXTI */ + .word TIM8_BRK_IRQHandler /* 43: TIM8 Break */ + .word TIM8_UP_IRQHandler /* 44: TIM8 Update */ + .word TIM8_TRG_COM_IRQHandler /* 45: TIM8 Trigger/Commutation */ + .word TIM8_CC_IRQHandler /* 46: TIM8 Capture Compare */ + .word ADC3_IRQHandler /* 47: ADC3 */ + .word FMC_IRQHandler /* 48: FMC */ + .word LPTIM1_IRQHandler /* 49: LPTIM1 */ + .word TIM5_IRQHandler /* 50: TIM5 */ + .word SPI3_IRQHandler /* 51: SPI3 */ + .word UART4_IRQHandler /* 52: UART4 */ + .word UART5_IRQHandler /* 53: UART5 */ + .word TIM6_DAC_IRQHandler /* 54: TIM6 and DAC1&3 underrun */ + .word TIM7_DAC_IRQHandler /* 55: TIM7 and DAC2&4 underrun */ + .word DMA2_Channel1_IRQHandler /* 56: DMA2 Channel 1 */ + .word DMA2_Channel2_IRQHandler /* 57: DMA2 Channel 2 */ + .word DMA2_Channel3_IRQHandler /* 58: DMA2 Channel 3 */ + .word DMA2_Channel4_IRQHandler /* 59: DMA2 Channel 4 */ + .word DMA2_Channel5_IRQHandler /* 60: DMA2 Channel 5 */ + .word ADC4_IRQHandler /* 61: ADC4 */ + .word ADC5_IRQHandler /* 62: ADC5 */ + .word UCPD1_IRQHandler /* 63: UCPD1 */ + .word COMP1_2_3_IRQHandler /* 64: COMP1, COMP2, COMP3 */ + .word COMP4_5_6_IRQHandler /* 65: COMP4, COMP5, COMP6 */ + .word COMP7_IRQHandler /* 66: COMP7 */ + .word HRTIM1_Master_IRQHandler /* 67: HRTIM Master Timer */ + .word HRTIM1_TIMA_IRQHandler /* 68: HRTIM Timer A */ + .word HRTIM1_TIMB_IRQHandler /* 69: HRTIM Timer B */ + .word HRTIM1_TIMC_IRQHandler /* 70: HRTIM Timer C */ + .word HRTIM1_TIMD_IRQHandler /* 71: HRTIM Timer D */ + .word HRTIM1_TIME_IRQHandler /* 72: HRTIM Timer E */ + .word HRTIM1_FLT_IRQHandler /* 73: HRTIM Fault */ + .word HRTIM1_TIMF_IRQHandler /* 74: HRTIM Timer F */ + .word CRS_IRQHandler /* 75: CRS */ + .word SAI1_IRQHandler /* 76: SAI1 */ + .word TIM20_BRK_IRQHandler /* 77: TIM20 Break */ + .word TIM20_UP_IRQHandler /* 78: TIM20 Update */ + .word TIM20_TRG_COM_IRQHandler /* 79: TIM20 Trigger/Commutation */ + .word TIM20_CC_IRQHandler /* 80: TIM20 Capture Compare */ + .word FPU_IRQHandler /* 81: FPU */ + .word I2C4_EV_IRQHandler /* 82: I2C4 Event */ + .word I2C4_ER_IRQHandler /* 83: I2C4 Error */ + .word SPI4_IRQHandler /* 84: SPI4 */ + .word 0 /* 85: Reserved */ + .word FDCAN2_IT0_IRQHandler /* 86: FDCAN2 IT0 */ + .word FDCAN2_IT1_IRQHandler /* 87: FDCAN2 IT1 */ + .word FDCAN3_IT0_IRQHandler /* 88: FDCAN3 IT0 */ + .word FDCAN3_IT1_IRQHandler /* 89: FDCAN3 IT1 */ + .word RNG_IRQHandler /* 90: RNG */ + .word LPUART1_IRQHandler /* 91: LPUART1 */ + .word I2C3_EV_IRQHandler /* 92: I2C3 Event */ + .word I2C3_ER_IRQHandler /* 93: I2C3 Error */ + .word DMAMUX_OVR_IRQHandler /* 94: DMAMUX overrun */ + .word QUADSPI_IRQHandler /* 95: QUADSPI */ + .word DMA1_Channel8_IRQHandler /* 96: DMA1 Channel 8 */ + .word DMA2_Channel6_IRQHandler /* 97: DMA2 Channel 6 */ + .word DMA2_Channel7_IRQHandler /* 98: DMA2 Channel 7 */ + .word DMA2_Channel8_IRQHandler /* 99: DMA2 Channel 8 */ + .word CORDIC_IRQHandler /* 100: CORDIC */ + .word FMAC_IRQHandler /* 101: FMAC */ + + .size g_pfnVectors, .-g_pfnVectors + +/******************************************************************************* + * Weak aliases - all handlers default to infinite loop unless overridden + *******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + .weak RTC_TAMP_LSECSS_IRQHandler + .thumb_set RTC_TAMP_LSECSS_IRQHandler,Default_Handler + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + .weak USB_HP_IRQHandler + .thumb_set USB_HP_IRQHandler,Default_Handler + .weak USB_LP_IRQHandler + .thumb_set USB_LP_IRQHandler,Default_Handler + .weak FDCAN1_IT0_IRQHandler + .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler + .weak FDCAN1_IT1_IRQHandler + .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + .weak USBWakeUp_IRQHandler + .thumb_set USBWakeUp_IRQHandler,Default_Handler + .weak TIM8_BRK_IRQHandler + .thumb_set TIM8_BRK_IRQHandler,Default_Handler + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + .weak TIM8_TRG_COM_IRQHandler + .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + .weak TIM7_DAC_IRQHandler + .thumb_set TIM7_DAC_IRQHandler,Default_Handler + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + .weak ADC4_IRQHandler + .thumb_set ADC4_IRQHandler,Default_Handler + .weak ADC5_IRQHandler + .thumb_set ADC5_IRQHandler,Default_Handler + .weak UCPD1_IRQHandler + .thumb_set UCPD1_IRQHandler,Default_Handler + .weak COMP1_2_3_IRQHandler + .thumb_set COMP1_2_3_IRQHandler,Default_Handler + .weak COMP4_5_6_IRQHandler + .thumb_set COMP4_5_6_IRQHandler,Default_Handler + .weak COMP7_IRQHandler + .thumb_set COMP7_IRQHandler,Default_Handler + .weak HRTIM1_Master_IRQHandler + .thumb_set HRTIM1_Master_IRQHandler,Default_Handler + .weak HRTIM1_TIMA_IRQHandler + .thumb_set HRTIM1_TIMA_IRQHandler,Default_Handler + .weak HRTIM1_TIMB_IRQHandler + .thumb_set HRTIM1_TIMB_IRQHandler,Default_Handler + .weak HRTIM1_TIMC_IRQHandler + .thumb_set HRTIM1_TIMC_IRQHandler,Default_Handler + .weak HRTIM1_TIMD_IRQHandler + .thumb_set HRTIM1_TIMD_IRQHandler,Default_Handler + .weak HRTIM1_TIME_IRQHandler + .thumb_set HRTIM1_TIME_IRQHandler,Default_Handler + .weak HRTIM1_FLT_IRQHandler + .thumb_set HRTIM1_FLT_IRQHandler,Default_Handler + .weak HRTIM1_TIMF_IRQHandler + .thumb_set HRTIM1_TIMF_IRQHandler,Default_Handler + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + .weak TIM20_BRK_IRQHandler + .thumb_set TIM20_BRK_IRQHandler,Default_Handler + .weak TIM20_UP_IRQHandler + .thumb_set TIM20_UP_IRQHandler,Default_Handler + .weak TIM20_TRG_COM_IRQHandler + .thumb_set TIM20_TRG_COM_IRQHandler,Default_Handler + .weak TIM20_CC_IRQHandler + .thumb_set TIM20_CC_IRQHandler,Default_Handler + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + .weak FDCAN2_IT0_IRQHandler + .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler + .weak FDCAN2_IT1_IRQHandler + .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler + .weak FDCAN3_IT0_IRQHandler + .thumb_set FDCAN3_IT0_IRQHandler,Default_Handler + .weak FDCAN3_IT1_IRQHandler + .thumb_set FDCAN3_IT1_IRQHandler,Default_Handler + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + .weak DMAMUX_OVR_IRQHandler + .thumb_set DMAMUX_OVR_IRQHandler,Default_Handler + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + .weak DMA1_Channel8_IRQHandler + .thumb_set DMA1_Channel8_IRQHandler,Default_Handler + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + .weak DMA2_Channel8_IRQHandler + .thumb_set DMA2_Channel8_IRQHandler,Default_Handler + .weak CORDIC_IRQHandler + .thumb_set CORDIC_IRQHandler,Default_Handler + .weak FMAC_IRQHandler + .thumb_set FMAC_IRQHandler,Default_Handler + .section .text.SystemInit,"ax",%progbits + .weak SystemInit + .type SystemInit,%function +SystemInit: + bx lr + .size SystemInit, .-SystemInit diff --git a/platforms/stm32/cmake/stm32f413zh.cmake b/platforms/stm32/cmake/stm32f413zh.cmake new file mode 100644 index 00000000000..4c52f9a54a4 --- /dev/null +++ b/platforms/stm32/cmake/stm32f413zh.cmake @@ -0,0 +1,15 @@ +# ******************************************************************************* +# Copyright (c) 2026 An Dao +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set(STM32_FAMILY "F4") +set(STM32_DEVICE_UPPER "STM32F413xx") +set(CAN_TYPE "BXCAN") +set(STM32_STARTUP_ASM + "${CMAKE_CURRENT_LIST_DIR}/../bsp/bspMcu/startup/startup_stm32f413xx.s") diff --git a/platforms/stm32/cmake/stm32g474re.cmake b/platforms/stm32/cmake/stm32g474re.cmake new file mode 100644 index 00000000000..64a70fabdc2 --- /dev/null +++ b/platforms/stm32/cmake/stm32g474re.cmake @@ -0,0 +1,15 @@ +# ******************************************************************************* +# Copyright (c) 2026 An Dao +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set(STM32_FAMILY "G4") +set(STM32_DEVICE_UPPER "STM32G474xx") +set(CAN_TYPE "FDCAN") +set(STM32_STARTUP_ASM + "${CMAKE_CURRENT_LIST_DIR}/../bsp/bspMcu/startup/startup_stm32g474xx.s") diff --git a/platforms/stm32/unitTest/CMakeLists.txt b/platforms/stm32/unitTest/CMakeLists.txt new file mode 100644 index 00000000000..d0b1953a923 --- /dev/null +++ b/platforms/stm32/unitTest/CMakeLists.txt @@ -0,0 +1 @@ +# add STM32 specific configuration modules and settings here From e5a7dd943a72e94cd78740fde5129b6dece7c166 Mon Sep 17 00:00:00 2001 From: nhuvaoanh123 Date: Tue, 2 Jun 2026 08:10:50 +0200 Subject: [PATCH 3/4] Add STM32 BSP peripheral drivers Add STM32 BSP modules for clock, UART, GPIO, timer, ADC, and EEPROM, plus interrupt handling primitives and the ETL platform glue. --- doc/dev/modules/stm32.rst | 2 +- platforms/stm32/CMakeLists.txt | 3 + platforms/stm32/bsp/CMakeLists.txt | 18 ++ platforms/stm32/bsp/bspAdc/CMakeLists.txt | 6 + platforms/stm32/bsp/bspAdc/include/adc/Adc.h | 54 ++++ platforms/stm32/bsp/bspAdc/module.spec | 2 + platforms/stm32/bsp/bspAdc/src/adc/Adc.cpp | 179 +++++++++++ platforms/stm32/bsp/bspClock/CMakeLists.txt | 10 + platforms/stm32/bsp/bspClock/doc/index.rst | 43 +++ .../bsp/bspClock/include/clock/clockConfig.h | 24 ++ platforms/stm32/bsp/bspClock/module.spec | 2 + .../stm32/bsp/bspClock/src/clockConfig_f4.cpp | 68 ++++ .../stm32/bsp/bspClock/src/clockConfig_g4.cpp | 101 ++++++ .../stm32/bsp/bspEepromDriver/CMakeLists.txt | 6 + .../include/eeprom/FlashEepromDriver.h | 59 ++++ .../stm32/bsp/bspEepromDriver/module.spec | 1 + .../src/eeprom/FlashEepromDriver.cpp | 303 ++++++++++++++++++ .../bsp/bspInterruptsImpl/CMakeLists.txt | 18 ++ .../stm32/bsp/bspInterruptsImpl/doc/index.rst | 111 +++++++ .../interrupts/suspendResumeAllInterrupts.h | 37 +++ .../interrupts/disableEnableAllInterrupts.h | 35 ++ .../stm32/bsp/bspInterruptsImpl/module.spec | 2 + .../bspInterruptsImpl/src/interrupt_manager.c | 14 + .../interrupts/suspendResumeAllInterrupts.h | 34 ++ platforms/stm32/bsp/bspIo/CMakeLists.txt | 6 + platforms/stm32/bsp/bspIo/include/io/Gpio.h | 80 +++++ .../bsp/bspIo/include/io/GpioPinConfig.h | 77 +++++ platforms/stm32/bsp/bspIo/module.spec | 2 + platforms/stm32/bsp/bspIo/src/io/Gpio.cpp | 175 ++++++++++ platforms/stm32/bsp/bspTimer/CMakeLists.txt | 3 + platforms/stm32/bsp/bspTimer/doc/index.rst | 35 ++ platforms/stm32/bsp/bspTimer/module.spec | 2 + .../src/bsp/SystemTimer/SystemTimer.cpp | 95 ++++++ platforms/stm32/bsp/bspUart/CMakeLists.txt | 13 + platforms/stm32/bsp/bspUart/doc/index.rst | 41 +++ .../stm32/bsp/bspUart/include/bsp/Uart.h | 43 +++ .../bsp/bspUart/include/bsp/UartParams.h | 34 ++ platforms/stm32/bsp/bspUart/module.spec | 2 + platforms/stm32/bsp/bspUart/src/Uart.cpp | 127 ++++++++ platforms/stm32/etlImpl/CMakeLists.txt | 3 + platforms/stm32/etlImpl/src/clocks.cpp | 30 ++ platforms/stm32/etlImpl/src/print.cpp | 14 + 42 files changed, 1913 insertions(+), 1 deletion(-) create mode 100644 platforms/stm32/bsp/bspAdc/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspAdc/include/adc/Adc.h create mode 100644 platforms/stm32/bsp/bspAdc/module.spec create mode 100644 platforms/stm32/bsp/bspAdc/src/adc/Adc.cpp create mode 100644 platforms/stm32/bsp/bspClock/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspClock/doc/index.rst create mode 100644 platforms/stm32/bsp/bspClock/include/clock/clockConfig.h create mode 100644 platforms/stm32/bsp/bspClock/module.spec create mode 100644 platforms/stm32/bsp/bspClock/src/clockConfig_f4.cpp create mode 100644 platforms/stm32/bsp/bspClock/src/clockConfig_g4.cpp create mode 100644 platforms/stm32/bsp/bspEepromDriver/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspEepromDriver/include/eeprom/FlashEepromDriver.h create mode 100644 platforms/stm32/bsp/bspEepromDriver/module.spec create mode 100644 platforms/stm32/bsp/bspEepromDriver/src/eeprom/FlashEepromDriver.cpp create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/doc/index.rst create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/freertos/include/interrupts/suspendResumeAllInterrupts.h create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/include/interrupts/disableEnableAllInterrupts.h create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/module.spec create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/src/interrupt_manager.c create mode 100644 platforms/stm32/bsp/bspInterruptsImpl/threadx/include/interrupts/suspendResumeAllInterrupts.h create mode 100644 platforms/stm32/bsp/bspIo/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspIo/include/io/Gpio.h create mode 100644 platforms/stm32/bsp/bspIo/include/io/GpioPinConfig.h create mode 100644 platforms/stm32/bsp/bspIo/module.spec create mode 100644 platforms/stm32/bsp/bspIo/src/io/Gpio.cpp create mode 100644 platforms/stm32/bsp/bspTimer/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspTimer/doc/index.rst create mode 100644 platforms/stm32/bsp/bspTimer/module.spec create mode 100644 platforms/stm32/bsp/bspTimer/src/bsp/SystemTimer/SystemTimer.cpp create mode 100644 platforms/stm32/bsp/bspUart/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspUart/doc/index.rst create mode 100644 platforms/stm32/bsp/bspUart/include/bsp/Uart.h create mode 100644 platforms/stm32/bsp/bspUart/include/bsp/UartParams.h create mode 100644 platforms/stm32/bsp/bspUart/module.spec create mode 100644 platforms/stm32/bsp/bspUart/src/Uart.cpp create mode 100644 platforms/stm32/etlImpl/CMakeLists.txt create mode 100644 platforms/stm32/etlImpl/src/clocks.cpp create mode 100644 platforms/stm32/etlImpl/src/print.cpp diff --git a/doc/dev/modules/stm32.rst b/doc/dev/modules/stm32.rst index 66660f2761b..3c7b5eb2891 100644 --- a/doc/dev/modules/stm32.rst +++ b/doc/dev/modules/stm32.rst @@ -19,4 +19,4 @@ BSP :maxdepth: 1 :glob: - ../../../platforms/stm32/bsp/**/doc/index + ../../../platforms/stm32/**/doc/index diff --git a/platforms/stm32/CMakeLists.txt b/platforms/stm32/CMakeLists.txt index dbe6c9fd805..d49dd6f1f71 100644 --- a/platforms/stm32/CMakeLists.txt +++ b/platforms/stm32/CMakeLists.txt @@ -17,4 +17,7 @@ if (NOT BUILD_EXECUTABLE STREQUAL "unitTest") endif () add_subdirectory(bsp) + + # ETL implementation + add_subdirectory(etlImpl) endif () diff --git a/platforms/stm32/bsp/CMakeLists.txt b/platforms/stm32/bsp/CMakeLists.txt index c377df0854c..41c252d17db 100644 --- a/platforms/stm32/bsp/CMakeLists.txt +++ b/platforms/stm32/bsp/CMakeLists.txt @@ -1 +1,19 @@ add_subdirectory(bspMcu) +add_subdirectory(bspClock) +add_subdirectory(bspInterruptsImpl) +add_subdirectory(bspUart) +add_subdirectory(bspTimer) +add_subdirectory(bspIo) +add_subdirectory(bspAdc) +add_subdirectory(bspEepromDriver) + +# Aggregated BSP target +add_library(socBsp INTERFACE) +target_link_libraries( + socBsp + INTERFACE bspClock + bspInterruptsImpl + bspIo + bspMcu + bspTimer + bspUart) diff --git a/platforms/stm32/bsp/bspAdc/CMakeLists.txt b/platforms/stm32/bsp/bspAdc/CMakeLists.txt new file mode 100644 index 00000000000..31856b6f58d --- /dev/null +++ b/platforms/stm32/bsp/bspAdc/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(bspAdc src/adc/Adc.cpp) +target_include_directories(bspAdc PUBLIC include) +target_link_libraries( + bspAdc + PUBLIC bspMcu + PRIVATE platform) diff --git a/platforms/stm32/bsp/bspAdc/include/adc/Adc.h b/platforms/stm32/bsp/bspAdc/include/adc/Adc.h new file mode 100644 index 00000000000..343d51920b7 --- /dev/null +++ b/platforms/stm32/bsp/bspAdc/include/adc/Adc.h @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include + +namespace bios +{ + +enum class AdcResolution : uint8_t +{ + BITS_12 = 0U, + BITS_10 = 1U, + BITS_8 = 2U, + BITS_6 = 3U +}; + +struct AdcConfig +{ + ADC_TypeDef* peripheral; + AdcResolution resolution; + uint8_t samplingTime; // SMPR code (0-7) +}; + +class Adc +{ +public: + explicit Adc(AdcConfig const& config); + + void init(); + uint16_t readChannel(uint8_t channel); + uint16_t readTemperature(); + uint16_t readVrefint(); + +private: + AdcConfig const fConfig; + bool fInitialized; + + void enableClock(); + void calibrate(); + void configureChannel(uint8_t channel); + uint16_t startAndRead(); +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bspAdc/module.spec b/platforms/stm32/bsp/bspAdc/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspAdc/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspAdc/src/adc/Adc.cpp b/platforms/stm32/bsp/bspAdc/src/adc/Adc.cpp new file mode 100644 index 00000000000..a8a65ae661f --- /dev/null +++ b/platforms/stm32/bsp/bspAdc/src/adc/Adc.cpp @@ -0,0 +1,179 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +namespace bios +{ + +Adc::Adc(AdcConfig const& config) : fConfig(config), fInitialized(false) {} + +void Adc::enableClock() +{ +#if defined(STM32G474xx) + RCC->AHB2ENR |= RCC_AHB2ENR_ADC12EN; + uint32_t volatile dummy = RCC->AHB2ENR; + (void)dummy; + + // Select system clock as ADC clock (ADCSEL = 01 in CCIPR) + RCC->CCIPR = (RCC->CCIPR & ~(3U << 28U)) | (1U << 28U); +#elif defined(STM32F413xx) + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + uint32_t volatile dummy = RCC->APB2ENR; + (void)dummy; +#endif +} + +void Adc::calibrate() +{ +#if defined(STM32G474xx) + ADC_TypeDef* adc = fConfig.peripheral; + + adc->CR &= ~ADC_CR_ADEN; + adc->CR &= ~ADC_CR_DEEPPWD; + adc->CR |= ADC_CR_ADVREGEN; + + // Wait for regulator startup (~20us) + for (uint32_t volatile i = 0U; i < 10000U; i++) {} + + adc->CR &= ~ADC_CR_ADCALDIF; + adc->CR |= ADC_CR_ADCAL; +#if !defined(UNIT_TEST) + while ((adc->CR & ADC_CR_ADCAL) != 0U) {} +#else + adc->CR &= ~ADC_CR_ADCAL; // Simulate calibration complete +#endif +#elif defined(STM32F413xx) + // STM32F4 ADC has no hardware calibration sequence + fConfig.peripheral->CR2 &= ~ADC_CR2_ADON; +#endif +} + +void Adc::init() +{ + enableClock(); + calibrate(); + + ADC_TypeDef* adc = fConfig.peripheral; + +#if defined(STM32G474xx) + adc->CFGR = (adc->CFGR & ~ADC_CFGR_RES) | (static_cast(fConfig.resolution) << 3U); + adc->CFGR &= ~(ADC_CFGR_CONT | ADC_CFGR_EXTEN); + adc->CFGR &= ~ADC_CFGR_ALIGN; + + adc->ISR |= ADC_ISR_ADRDY; // Write-1-to-clear ready flag + adc->CR |= ADC_CR_ADEN; + while ((adc->ISR & ADC_ISR_ADRDY) == 0U) {} +#elif defined(STM32F413xx) + adc->CR1 = (adc->CR1 & ~ADC_CR1_RES) | (static_cast(fConfig.resolution) << 24U); + adc->CR2 &= ~(ADC_CR2_CONT | ADC_CR2_ALIGN); + + ADC_Common_TypeDef* common = ADC123_COMMON; + common->CCR = (common->CCR & ~ADC_CCR_ADCPRE) | (1U << 16U); // PCLK2/4 + common->CCR |= ADC_CCR_TSVREFE; + + adc->CR2 |= ADC_CR2_ADON; +#endif + + fInitialized = true; +} + +void Adc::configureChannel(uint8_t channel) +{ + ADC_TypeDef* adc = fConfig.peripheral; + +#if defined(STM32G474xx) + adc->SQR1 = (adc->SQR1 & ~(ADC_SQR1_L | ADC_SQR1_SQ1)) + | (static_cast(channel) << 6U); // L=0 (1 conv), SQ1=channel + + if (channel < 10U) + { + uint32_t pos = channel * 3U; + adc->SMPR1 + = (adc->SMPR1 & ~(7U << pos)) | (static_cast(fConfig.samplingTime) << pos); + } + else + { + uint32_t pos = (channel - 10U) * 3U; + adc->SMPR2 + = (adc->SMPR2 & ~(7U << pos)) | (static_cast(fConfig.samplingTime) << pos); + } +#elif defined(STM32F413xx) + adc->SQR1 &= ~ADC_SQR1_L; // L=0 (1 conv) + adc->SQR3 = (adc->SQR3 & ~0x1FU) | (channel & 0x1FU); // SQ1=channel + + // F4: SMPR2 covers channels 0-9, SMPR1 covers 10-18 (reversed vs G4) + if (channel < 10U) + { + uint32_t pos = channel * 3U; + adc->SMPR2 + = (adc->SMPR2 & ~(7U << pos)) | (static_cast(fConfig.samplingTime) << pos); + } + else + { + uint32_t pos = (channel - 10U) * 3U; + adc->SMPR1 + = (adc->SMPR1 & ~(7U << pos)) | (static_cast(fConfig.samplingTime) << pos); + } +#endif +} + +uint16_t Adc::startAndRead() +{ + ADC_TypeDef* adc = fConfig.peripheral; + +#if defined(STM32G474xx) + adc->ISR |= ADC_ISR_EOC; // Write-1-to-clear EOC + adc->CR |= ADC_CR_ADSTART; + while ((adc->ISR & ADC_ISR_EOC) == 0U) {} + return static_cast(adc->DR); +#elif defined(STM32F413xx) + adc->SR &= ~ADC_SR_EOC; + adc->CR2 |= ADC_CR2_SWSTART; + while ((adc->SR & ADC_SR_EOC) == 0U) {} + return static_cast(adc->DR); +#else + return 0U; +#endif +} + +uint16_t Adc::readChannel(uint8_t channel) +{ + if (!fInitialized) + { + return 0U; + } + configureChannel(channel); + return startAndRead(); +} + +uint16_t Adc::readTemperature() +{ +#if defined(STM32G474xx) + return readChannel(16U); // VSENSE on ADC1 ch16 +#elif defined(STM32F413xx) + return readChannel(18U); // VSENSE on ADC1 ch18 +#else + return 0U; +#endif +} + +uint16_t Adc::readVrefint() +{ +#if defined(STM32G474xx) + return readChannel(18U); // VREFINT on ADC1 ch18 +#elif defined(STM32F413xx) + return readChannel(17U); // VREFINT on ADC1 ch17 +#else + return 0U; +#endif +} + +} // namespace bios diff --git a/platforms/stm32/bsp/bspClock/CMakeLists.txt b/platforms/stm32/bsp/bspClock/CMakeLists.txt new file mode 100644 index 00000000000..ee439b596a5 --- /dev/null +++ b/platforms/stm32/bsp/bspClock/CMakeLists.txt @@ -0,0 +1,10 @@ +# Clock configuration - chip-specific source selected by STM32_FAMILY +if (STM32_FAMILY STREQUAL "F4") + add_library(bspClock src/clockConfig_f4.cpp) +elseif (STM32_FAMILY STREQUAL "G4") + add_library(bspClock src/clockConfig_g4.cpp) +endif () + +target_include_directories(bspClock PUBLIC include) + +target_link_libraries(bspClock PRIVATE bspMcu) diff --git a/platforms/stm32/bsp/bspClock/doc/index.rst b/platforms/stm32/bsp/bspClock/doc/index.rst new file mode 100644 index 00000000000..6a423da77db --- /dev/null +++ b/platforms/stm32/bsp/bspClock/doc/index.rst @@ -0,0 +1,43 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspClock +======== + +Overview +-------- + +The ``bspClock`` module configures the system clock PLL for STM32F4 and STM32G4 +targets. Each family has its own translation unit (``clockConfig_f4.cpp``, +``clockConfig_g4.cpp``); the public API is a single ``extern "C"`` function +``configurePll()`` declared in ``clock/clockConfig.h``. It is called from the +startup code before ``main()`` and must not use heap, RTOS primitives, or BSW +services. On a PLL or oscillator timeout the system stays on HSI 16 MHz and +``SystemCoreClock`` is not updated. + +STM32F4 (STM32F413ZH) -- 96 MHz +------------------------------- + +- Clock source: HSE 8 MHz bypass (ST-LINK MCO on NUCLEO-F413ZH) +- PLL: M = 8, N = 384, P = 4 -> SYSCLK = 96 MHz +- AHB = 96 MHz, APB1 = 48 MHz (max 50 MHz per datasheet), APB2 = 96 MHz +- Flash latency: 3 wait states at 3.3 V, prefetch and caches enabled + +STM32G4 (STM32G474RE) -- 170 MHz +-------------------------------- + +- Clock source: HSI 16 MHz. HSE is not used because solder bridge SB15 may + not route the ST-LINK V3 MCO to PH0/OSC_IN on all NUCLEO-G474RE revisions. +- PLL: M = 4, N = 85, R = 2 -> SYSCLK = 170 MHz (voltage Range 1 boost mode) +- AHB = APB1 = APB2 = 170 MHz +- Flash latency: 4 wait states; ``FLASH_ACR`` is written read-modify-write to + preserve ``DBG_SWEN``. The switch above 150 MHz follows the AHB prescaler + transition sequence from RM0440 section 6.1.5. diff --git a/platforms/stm32/bsp/bspClock/include/clock/clockConfig.h b/platforms/stm32/bsp/bspClock/include/clock/clockConfig.h new file mode 100644 index 00000000000..2b7e0694111 --- /dev/null +++ b/platforms/stm32/bsp/bspClock/include/clock/clockConfig.h @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Implemented per target in clockConfig_*.cpp. Called from startup code +// before main(); must not use heap, RTOS primitives, or BSW services. +void configurePll(void); + +#ifdef __cplusplus +} +#endif diff --git a/platforms/stm32/bsp/bspClock/module.spec b/platforms/stm32/bsp/bspClock/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspClock/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspClock/src/clockConfig_f4.cpp b/platforms/stm32/bsp/bspClock/src/clockConfig_f4.cpp new file mode 100644 index 00000000000..5c131eb55ac --- /dev/null +++ b/platforms/stm32/bsp/bspClock/src/clockConfig_f4.cpp @@ -0,0 +1,68 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +uint32_t SystemCoreClock = 16000000U; // Default HSI, updated by configurePll() + +// Clock stabilization timeout (~100 ms at 16 MHz HSI = 1.6M cycles). +static constexpr uint32_t CLK_TIMEOUT = 1600000U; + +extern "C" void configurePll() +{ + // Enable HSE bypass (8 MHz from ST-LINK) + RCC->CR |= RCC_CR_HSEBYP | RCC_CR_HSEON; + { + uint32_t t = CLK_TIMEOUT; + while ((RCC->CR & RCC_CR_HSERDY) == 0U) + { + if (--t == 0U) + { + return; + } + } + } + + // Configure PLL: HSE / M=8 * N=384 / P=4 = 96 MHz + RCC->PLLCFGR = (8U << RCC_PLLCFGR_PLLM_Pos) // M = 8 -> VCO input = 1 MHz + | (384U << RCC_PLLCFGR_PLLN_Pos) // N = 384 -> VCO = 384 MHz + | (1U << RCC_PLLCFGR_PLLP_Pos) // P = 4 (register value 1) -> 96 MHz + | RCC_PLLCFGR_PLLSRC_HSE; + + RCC->CR |= RCC_CR_PLLON; + { + uint32_t t = CLK_TIMEOUT; + while ((RCC->CR & RCC_CR_PLLRDY) == 0U) + { + if (--t == 0U) + { + return; + } + } + } + + // Flash latency 3 WS for 96 MHz @ 3.3V + FLASH->ACR = FLASH_ACR_LATENCY_3WS | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN; + + // AHB = SYSCLK, APB1 = SYSCLK/2, APB2 = SYSCLK + RCC->CFGR = RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_SW_PLL; + { + uint32_t t = CLK_TIMEOUT; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + { + if (--t == 0U) + { + return; + } + } + } + + SystemCoreClock = 96000000U; +} diff --git a/platforms/stm32/bsp/bspClock/src/clockConfig_g4.cpp b/platforms/stm32/bsp/bspClock/src/clockConfig_g4.cpp new file mode 100644 index 00000000000..e3cd334e376 --- /dev/null +++ b/platforms/stm32/bsp/bspClock/src/clockConfig_g4.cpp @@ -0,0 +1,101 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +uint32_t SystemCoreClock = 16000000U; // Default HSI, updated by configurePll() + +// Clock stabilization timeout (~100 ms at 16 MHz HSI = 1.6M cycles). +// On timeout the system stays on HSI 16 MHz and SystemCoreClock is NOT +// updated, indicating to downstream code that PLL init failed. +static constexpr uint32_t CLK_TIMEOUT = 1600000U; + +extern "C" void configurePll() +{ + RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN; + uint32_t volatile dummy = RCC->APB1ENR1; // Read-back for clock enable delay + (void)dummy; + + // Enable Range 1 boost mode (required for >150 MHz) + PWR->CR5 &= ~PWR_CR5_R1MODE; + // Wait for voltage scaling to stabilize + { + uint32_t t = CLK_TIMEOUT; + while ((PWR->SR2 & PWR_SR2_VOSF) != 0U) + { + if (--t == 0U) + { + return; + } + } + } + + // Configure PLL: HSI / M=4 * N=85 / R=2 = 170 MHz. + // HSI instead of HSE: NUCLEO-G474RE solder bridge SB15 may not route + // ST-LINK V3 MCO to PH0/OSC_IN on all board revisions. + RCC->PLLCFGR = (3U << RCC_PLLCFGR_PLLM_Pos) // M = 4 (register value M-1 = 3) + | (85U << RCC_PLLCFGR_PLLN_Pos) // N = 85 + | RCC_PLLCFGR_PLLSRC_HSI + | RCC_PLLCFGR_PLLREN; // Enable PLL R output (SYSCLK source) + + RCC->CR |= RCC_CR_PLLON; + { + uint32_t t = CLK_TIMEOUT; + while ((RCC->CR & RCC_CR_PLLRDY) == 0U) + { + if (--t == 0U) + { + return; + } + } + } + + // Flash latency 4 WS for 170 MHz @ 3.3V boost mode + // Preserve DBG_SWEN (bit 18) - clearing it kills SWD debug flash access + { + uint32_t acr = FLASH->ACR; + acr &= ~FLASH_ACR_LATENCY_Msk; // Clear only latency bits, keep DBG_SWEN etc + acr |= FLASH_ACR_LATENCY_4WS | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN; + FLASH->ACR = acr; + } + // Verify flash latency readback before switching clock (RM0440 section 3.3.3) + { + uint32_t t = CLK_TIMEOUT; + while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_4WS) + { + if (--t == 0U) + { + return; + } + } + } + + // Boost-mode >150 MHz transition: set AHB prescaler /2 before clock switch + RCC->CFGR = RCC_CFGR_HPRE_DIV2 | RCC_CFGR_SW_PLL; + { + uint32_t t = CLK_TIMEOUT; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + { + if (--t == 0U) + { + return; + } + } + } + + // Wait >= 1 us for voltage regulator to settle at new frequency + // At 170/2 = 85 MHz, 100 cycles > 1 us + for (uint32_t volatile i = 0U; i < 100U; i++) {} + + // Restore AHB prescaler to /1 + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE_Msk) | RCC_CFGR_HPRE_DIV1; + + SystemCoreClock = 170000000U; +} diff --git a/platforms/stm32/bsp/bspEepromDriver/CMakeLists.txt b/platforms/stm32/bsp/bspEepromDriver/CMakeLists.txt new file mode 100644 index 00000000000..4b70b48601c --- /dev/null +++ b/platforms/stm32/bsp/bspEepromDriver/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(bspEepromDriver src/eeprom/FlashEepromDriver.cpp) +target_include_directories(bspEepromDriver PUBLIC include) +target_link_libraries( + bspEepromDriver + PUBLIC bspMcu bsp + PRIVATE platform) diff --git a/platforms/stm32/bsp/bspEepromDriver/include/eeprom/FlashEepromDriver.h b/platforms/stm32/bsp/bspEepromDriver/include/eeprom/FlashEepromDriver.h new file mode 100644 index 00000000000..65add360aeb --- /dev/null +++ b/platforms/stm32/bsp/bspEepromDriver/include/eeprom/FlashEepromDriver.h @@ -0,0 +1,59 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace eeprom +{ + +// EEPROM emulation in internal flash using two pages in a ping-pong scheme: +// the active page holds current data behind a magic marker, the inactive +// page is erased and reprogrammed on each write, then the roles swap. +class FlashEepromDriver : public IEepromDriver +{ +public: + struct Config + { + uintptr_t page0Address; + uintptr_t page1Address; + uint32_t pageSize; + }; + + explicit FlashEepromDriver(Config const& config); + + bsp::BspReturnCode init() override; + bsp::BspReturnCode write(uint32_t address, uint8_t const* buffer, uint32_t length) override; + bsp::BspReturnCode read(uint32_t address, uint8_t* buffer, uint32_t length) override; + + bsp::BspReturnCode erase(); + +private: + static uint32_t const MAGIC = 0xEE50AA55U; // Page validity marker + + Config const fConfig; + uint8_t fActivePage; + + uintptr_t activePageAddress() const; + uintptr_t inactivePageAddress() const; + + bool isPageValid(uintptr_t pageAddr) const; + bsp::BspReturnCode erasePage(uintptr_t pageAddr); + bsp::BspReturnCode programPage(uintptr_t destAddr, uint8_t const* data, uint32_t length); + + bsp::BspReturnCode unlockFlash(); + void lockFlash(); + bsp::BspReturnCode waitForFlash(); +}; + +} // namespace eeprom diff --git a/platforms/stm32/bsp/bspEepromDriver/module.spec b/platforms/stm32/bsp/bspEepromDriver/module.spec new file mode 100644 index 00000000000..87faef85b71 --- /dev/null +++ b/platforms/stm32/bsp/bspEepromDriver/module.spec @@ -0,0 +1 @@ +oss: true diff --git a/platforms/stm32/bsp/bspEepromDriver/src/eeprom/FlashEepromDriver.cpp b/platforms/stm32/bsp/bspEepromDriver/src/eeprom/FlashEepromDriver.cpp new file mode 100644 index 00000000000..db96d3c9e45 --- /dev/null +++ b/platforms/stm32/bsp/bspEepromDriver/src/eeprom/FlashEepromDriver.cpp @@ -0,0 +1,303 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +#include +#include + +namespace eeprom +{ + +FlashEepromDriver::FlashEepromDriver(Config const& config) : fConfig(config), fActivePage(0U) {} + +bsp::BspReturnCode FlashEepromDriver::init() +{ + if (isPageValid(fConfig.page0Address)) + { + fActivePage = 0U; + } + else if (isPageValid(fConfig.page1Address)) + { + fActivePage = 1U; + } + else + { + // Neither page valid - format page 0 + if (erasePage(fConfig.page0Address) != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + + if (unlockFlash() != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + uint32_t const magic = MAGIC; + if (programPage(fConfig.page0Address, reinterpret_cast(&magic), 4U) + != bsp::BSP_OK) + { + lockFlash(); + return bsp::BSP_ERROR; + } + lockFlash(); + fActivePage = 0U; + } + + return bsp::BSP_OK; +} + +bsp::BspReturnCode FlashEepromDriver::read(uint32_t address, uint8_t* buffer, uint32_t length) +{ + uint32_t dataOffset = 4U; // Skip magic word + if ((address + length) > (fConfig.pageSize - dataOffset)) + { + return bsp::BSP_ERROR; + } + + uintptr_t srcAddr = activePageAddress() + dataOffset + address; + std::memcpy(buffer, reinterpret_cast(srcAddr), length); + return bsp::BSP_OK; +} + +bsp::BspReturnCode +FlashEepromDriver::write(uint32_t address, uint8_t const* buffer, uint32_t length) +{ + uint32_t dataOffset = 4U; + uint32_t dataSize = fConfig.pageSize - dataOffset; + + if ((address + length) > dataSize) + { + return bsp::BSP_ERROR; + } + + // Static buffer for page copy - avoids stack allocation in the safety task. + // Sized for G474RE (2KB pages). F413ZH uses 128KB sectors which are too + // large for this ping-pong scheme; use sector-level storage instead. + static uint8_t pageBuf[2048]; + if (dataSize > sizeof(pageBuf)) + { + return bsp::BSP_ERROR; + } + + std::memcpy(pageBuf, reinterpret_cast(activePageAddress() + dataOffset), dataSize); + std::memcpy(&pageBuf[address], buffer, length); + + uintptr_t inactiveAddr = inactivePageAddress(); + if (erasePage(inactiveAddr) != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + + if (unlockFlash() != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + + uint32_t const magic = MAGIC; + if (programPage(inactiveAddr, reinterpret_cast(&magic), 4U) != bsp::BSP_OK) + { + lockFlash(); + return bsp::BSP_ERROR; + } + + if (programPage(inactiveAddr + dataOffset, pageBuf, dataSize) != bsp::BSP_OK) + { + lockFlash(); + return bsp::BSP_ERROR; + } + + lockFlash(); + + uintptr_t oldActiveAddr = activePageAddress(); + (void)erasePage(oldActiveAddr); + + fActivePage = (fActivePage == 0U) ? 1U : 0U; + + return bsp::BSP_OK; +} + +bsp::BspReturnCode FlashEepromDriver::erase() +{ + if (erasePage(fConfig.page0Address) != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + if (erasePage(fConfig.page1Address) != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + return init(); +} + +uintptr_t FlashEepromDriver::activePageAddress() const +{ + return (fActivePage == 0U) ? fConfig.page0Address : fConfig.page1Address; +} + +uintptr_t FlashEepromDriver::inactivePageAddress() const +{ + return (fActivePage == 0U) ? fConfig.page1Address : fConfig.page0Address; +} + +bool FlashEepromDriver::isPageValid(uintptr_t pageAddr) const +{ + uint32_t const magic = *reinterpret_cast(pageAddr); + return magic == MAGIC; +} + +bsp::BspReturnCode FlashEepromDriver::unlockFlash() +{ + if ((FLASH->CR & FLASH_CR_LOCK) != 0U) + { + FLASH->KEYR = 0x45670123U; + FLASH->KEYR = 0xCDEF89ABU; + } + if ((FLASH->CR & FLASH_CR_LOCK) != 0U) + { + return bsp::BSP_ERROR; + } + return bsp::BSP_OK; +} + +void FlashEepromDriver::lockFlash() { FLASH->CR |= FLASH_CR_LOCK; } + +bsp::BspReturnCode FlashEepromDriver::waitForFlash() +{ + uint32_t timeout = 0xFFFFFFU; + while ((FLASH->SR & FLASH_SR_BSY) != 0U) + { + if (--timeout == 0U) + { + return bsp::BSP_ERROR; + } + } + return bsp::BSP_OK; +} + +bsp::BspReturnCode FlashEepromDriver::erasePage(uintptr_t pageAddr) +{ + if (unlockFlash() != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + + if (waitForFlash() != bsp::BSP_OK) + { + lockFlash(); + return bsp::BSP_ERROR; + } + +#if defined(STM32G474xx) + // STM32G4: page erase + uint32_t pageNum = (pageAddr - 0x08000000U) / fConfig.pageSize; + FLASH->CR = (FLASH->CR & ~(FLASH_CR_PNB_Msk)) | (pageNum << FLASH_CR_PNB_Pos) | FLASH_CR_PER; + FLASH->CR |= FLASH_CR_STRT; +#elif defined(STM32F413xx) + // STM32F4: sector erase - determine sector from address + // Simplified: assume pageAddr maps directly to a sector number + // For sectors 12-15 (dual bank), SNB field encodes sector + bank + uint32_t sector = 0U; + if (pageAddr >= 0x08100000U) + { + sector = ((pageAddr - 0x08100000U) / 0x4000U) + 16U; // Bank 2 + } + else + { + sector = (pageAddr - 0x08000000U) / 0x20000U; // 128KB sectors (simplified) + } + FLASH->CR = (FLASH->CR & ~(FLASH_CR_SNB_Msk)) | (sector << FLASH_CR_SNB_Pos) | FLASH_CR_SER; + FLASH->CR |= FLASH_CR_STRT; +#endif + + bsp::BspReturnCode result = waitForFlash(); + +#if defined(STM32G474xx) + FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_STRT); +#elif defined(STM32F413xx) + FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_STRT); +#endif + + lockFlash(); + return result; +} + +bsp::BspReturnCode +FlashEepromDriver::programPage(uintptr_t destAddr, uint8_t const* data, uint32_t length) +{ + if (waitForFlash() != bsp::BSP_OK) + { + return bsp::BSP_ERROR; + } + +#if defined(STM32G474xx) + // STM32G4 flash requires double-word (64-bit) programming + FLASH->CR |= FLASH_CR_PG; + + uint32_t i = 0U; + while (i < length) + { + uint32_t word0 = 0xFFFFFFFFU; + uint32_t word1 = 0xFFFFFFFFU; + + uint32_t remaining = length - i; + if (remaining > 0U) + { + std::memcpy(&word0, &data[i], (remaining >= 4U) ? 4U : remaining); + } + if (remaining > 4U) + { + uint32_t r2 = remaining - 4U; + std::memcpy(&word1, &data[i + 4U], (r2 >= 4U) ? 4U : r2); + } + + *reinterpret_cast(destAddr + i) = word0; + *reinterpret_cast(destAddr + i + 4U) = word1; + + if (waitForFlash() != bsp::BSP_OK) + { + FLASH->CR &= ~FLASH_CR_PG; + return bsp::BSP_ERROR; + } + + i += 8U; + } + + FLASH->CR &= ~FLASH_CR_PG; +#elif defined(STM32F413xx) + // STM32F4: word (32-bit) programming, PSIZE = x32 + FLASH->CR |= FLASH_CR_PG; + FLASH->CR = (FLASH->CR & ~FLASH_CR_PSIZE) | FLASH_CR_PSIZE_1; + + uint32_t i = 0U; + while (i < length) + { + uint32_t word = 0xFFFFFFFFU; + uint32_t remaining = length - i; + std::memcpy(&word, &data[i], (remaining >= 4U) ? 4U : remaining); + + *reinterpret_cast(destAddr + i) = word; + + if (waitForFlash() != bsp::BSP_OK) + { + FLASH->CR &= ~FLASH_CR_PG; + return bsp::BSP_ERROR; + } + + i += 4U; + } + + FLASH->CR &= ~FLASH_CR_PG; +#endif + + return bsp::BSP_OK; +} + +} // namespace eeprom diff --git a/platforms/stm32/bsp/bspInterruptsImpl/CMakeLists.txt b/platforms/stm32/bsp/bspInterruptsImpl/CMakeLists.txt new file mode 100644 index 00000000000..a2f0521d556 --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/CMakeLists.txt @@ -0,0 +1,18 @@ +if (NOT BUILD_EXECUTABLE STREQUAL "unitTest") + set(bspInterruptsImplName "bspInterruptsImpl") +else () + set(bspInterruptsImplName "bspInterruptsImplUt") +endif () + +add_library(${bspInterruptsImplName} src/interrupt_manager.c) + +target_include_directories(${bspInterruptsImplName} PUBLIC include) + +if (BUILD_TARGET_RTOS STREQUAL "FREERTOS") + target_include_directories(${bspInterruptsImplName} PUBLIC freertos/include) +elseif (BUILD_TARGET_RTOS STREQUAL "THREADX") + target_include_directories(${bspInterruptsImplName} PUBLIC threadx/include) + target_link_libraries(${bspInterruptsImplName} PUBLIC threadX) +endif () + +target_link_libraries(${bspInterruptsImplName} PRIVATE bspMcu platform) diff --git a/platforms/stm32/bsp/bspInterruptsImpl/doc/index.rst b/platforms/stm32/bsp/bspInterruptsImpl/doc/index.rst new file mode 100644 index 00000000000..023a6c52388 --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/doc/index.rst @@ -0,0 +1,111 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspInterruptsImpl +================= + +Overview +-------- + +The ``bspInterruptsImpl`` module provides interrupt management for STM32 +Cortex-M4 targets. It implements global interrupt disable/enable primitives and +integrates with FreeRTOS for context-safe critical sections. + +Global Interrupt Disable / Enable +--------------------------------- + +The header ``interrupts/disableEnableAllInterrupts.h`` provides two inline +assembly functions: + +``disableAllInterrupts()`` + Executes ``CPSID I`` to set the ``PRIMASK`` register, masking all + interrupts except NMI and HardFault. Followed by ``ISB``, ``DSB``, and + ``DMB`` barrier instructions to ensure the mask takes effect before any + subsequent memory access or instruction fetch. + +``enableAllInterrupts()`` + Executes ``ISB``, ``DSB``, and ``DMB`` barriers first, then ``CPSIE I`` to + clear ``PRIMASK`` and re-enable interrupts. The barrier-before-enable + ordering ensures all pending memory operations complete before interrupts + can fire. + +Both functions are declared ``static inline`` with +``__attribute__((always_inline))`` to guarantee zero-overhead inlining at every +call site. + +PRIMASK vs BASEPRI +------------------ + +The Cortex-M4 offers two mechanisms for interrupt masking: + +**PRIMASK (bare-metal variant)** + Setting PRIMASK to 1 disables all configurable interrupts (priority levels + 0--15). Only NMI (priority -2) and HardFault (priority -1) remain active. + This is the approach used by ``disableAllInterrupts()`` / + ``enableAllInterrupts()`` and is suitable for bare-metal critical sections + where no RTOS is running. + +**BASEPRI (FreeRTOS variant)** + FreeRTOS uses ``BASEPRI`` instead of ``PRIMASK`` for its critical sections. + Setting ``BASEPRI`` to ``configMAX_SYSCALL_INTERRUPT_PRIORITY`` masks only + interrupts at or below that priority threshold, leaving higher-priority + (lower numeric value) interrupts unmasked. This allows time-critical ISRs + (e.g., motor control, safety watchdog) to preempt FreeRTOS critical + sections. + + FreeRTOS-aware critical section macros (``taskENTER_CRITICAL`` / + ``taskEXIT_CRITICAL``) use this BASEPRI approach internally. The + ``bspInterruptsImpl`` module provides the ``SuspendResumeAllInterruptsScopedLock`` + RAII wrapper for C++ code that needs interrupt-safe sections compatible with + both variants. + +NVIC Priority Configuration +--------------------------- + +The STM32 Cortex-M4 implements 4-bit priority grouping (``__NVIC_PRIO_BITS = 4`` +from the CMSIS device header), yielding 16 priority levels (0 = highest, +15 = lowest). + +Priority assignment guidelines: + +- Priorities 0--3: Reserved for time-critical hardware ISRs that must not be + blocked by FreeRTOS critical sections (above + ``configMAX_SYSCALL_INTERRUPT_PRIORITY``). +- Priorities 4--15: Available for ISRs that may call FreeRTOS API functions + (``xSemaphoreGiveFromISR``, ``xQueueSendFromISR``, etc.). + +The FreeRTOS Cortex-M4 port layer uses the CMSIS ``__enable_irq()`` / +``__disable_irq()`` intrinsics directly for global interrupt control. + +Scoped Lock +----------- + +The ``SuspendResumeAllInterruptsScopedLock`` class (from the ``interrupts`` +namespace) provides RAII-style interrupt locking: + +.. code-block:: cpp + + { + const ESR_UNUSED interrupts::SuspendResumeAllInterruptsScopedLock lock; + // Critical section -- interrupts disabled + } + // Interrupts restored to previous state + +This pattern is used throughout the BSP (e.g., ``bspTimer`` tick accumulation) +to ensure interrupt state is always restored, even if an early return or +exception occurs. + +Dependencies +------------ + +- ARM Cortex-M4 ``PRIMASK`` and ``BASEPRI`` special registers +- CMSIS ``__enable_irq()`` / ``__disable_irq()`` intrinsics +- FreeRTOS ``configMAX_SYSCALL_INTERRUPT_PRIORITY`` (when FreeRTOS is active) diff --git a/platforms/stm32/bsp/bspInterruptsImpl/freertos/include/interrupts/suspendResumeAllInterrupts.h b/platforms/stm32/bsp/bspInterruptsImpl/freertos/include/interrupts/suspendResumeAllInterrupts.h new file mode 100644 index 00000000000..f07607f40c3 --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/freertos/include/interrupts/suspendResumeAllInterrupts.h @@ -0,0 +1,37 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include "platform/estdint.h" + +typedef int32_t OldIntEnabledStatusValueType; +#define getOldIntEnabledStatusValueAndSuspendAllInterrupts \ + getMachineStateRegisterValueAndSuspendAllInterrupts + +// clang-format off +static inline __attribute__((always_inline)) +uint32_t getMachineStateRegisterValueAndSuspendAllInterrupts(void) +{ + uint32_t _PRIMASK; + __asm volatile (" mrs %0, PRIMASK\n" + " cpsid i\n" + : "=r" (_PRIMASK)); + return(_PRIMASK); +} +static inline __attribute__((always_inline)) +void resumeAllInterrupts(uint32_t oldMachineStateRegisterValue) +{ + __asm volatile (" msr PRIMASK,%[Input]\n" + ::[Input] "r" (oldMachineStateRegisterValue) + ); +} + +// clang-format on diff --git a/platforms/stm32/bsp/bspInterruptsImpl/include/interrupts/disableEnableAllInterrupts.h b/platforms/stm32/bsp/bspInterruptsImpl/include/interrupts/disableEnableAllInterrupts.h new file mode 100644 index 00000000000..3ebce505af9 --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/include/interrupts/disableEnableAllInterrupts.h @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +// clang-format off +static inline __attribute__((always_inline)) +void disableAllInterrupts(void) +{ +asm( +"cpsid i;" +"ISB;" +"DSB;" +"DMB;" +); +} +static inline __attribute__((always_inline)) +void enableAllInterrupts(void) +{ +asm ( +"ISB;" +"DSB;" +"DMB;" +"cpsie i;" +); +} + +// clang-format on diff --git a/platforms/stm32/bsp/bspInterruptsImpl/module.spec b/platforms/stm32/bsp/bspInterruptsImpl/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspInterruptsImpl/src/interrupt_manager.c b/platforms/stm32/bsp/bspInterruptsImpl/src/interrupt_manager.c new file mode 100644 index 00000000000..279d556a09d --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/src/interrupt_manager.c @@ -0,0 +1,14 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +// Placeholder - interrupt manager for STM32. +// NVIC priorities are configured by the application during board bring-up. diff --git a/platforms/stm32/bsp/bspInterruptsImpl/threadx/include/interrupts/suspendResumeAllInterrupts.h b/platforms/stm32/bsp/bspInterruptsImpl/threadx/include/interrupts/suspendResumeAllInterrupts.h new file mode 100644 index 00000000000..435f9d524c9 --- /dev/null +++ b/platforms/stm32/bsp/bspInterruptsImpl/threadx/include/interrupts/suspendResumeAllInterrupts.h @@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include + +#include + +static inline __attribute__((always_inline)) void setThreadXInitialized(){}; + +typedef uint32_t OldIntEnabledStatusValueType; + +#define getMachineStateRegisterValueAndSuspendAllInterrupts \ + getOldIntEnabledStatusValueAndSuspendAllInterrupts + +static inline __attribute__((always_inline)) OldIntEnabledStatusValueType +getOldIntEnabledStatusValueAndSuspendAllInterrupts(void) +{ + return tx_interrupt_control(TX_INT_DISABLE); +} + +static inline __attribute__((always_inline)) void +resumeAllInterrupts(OldIntEnabledStatusValueType const oldIntEnabledStatusValue) +{ + tx_interrupt_control(oldIntEnabledStatusValue); +} diff --git a/platforms/stm32/bsp/bspIo/CMakeLists.txt b/platforms/stm32/bsp/bspIo/CMakeLists.txt new file mode 100644 index 00000000000..882c15e6af6 --- /dev/null +++ b/platforms/stm32/bsp/bspIo/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(bspIo src/io/Gpio.cpp) +target_include_directories(bspIo PUBLIC include) +target_link_libraries( + bspIo + PUBLIC bspMcu + PRIVATE platform) diff --git a/platforms/stm32/bsp/bspIo/include/io/Gpio.h b/platforms/stm32/bsp/bspIo/include/io/Gpio.h new file mode 100644 index 00000000000..245a2870500 --- /dev/null +++ b/platforms/stm32/bsp/bspIo/include/io/Gpio.h @@ -0,0 +1,80 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include + +namespace bios +{ + +// MODER register values +enum class GpioMode : uint8_t +{ + INPUT = 0U, + OUTPUT = 1U, + ALTERNATE = 2U, + ANALOG = 3U +}; + +// OTYPER register values +enum class GpioOutputType : uint8_t +{ + PUSH_PULL = 0U, + OPEN_DRAIN = 1U +}; + +// OSPEEDR register values +enum class GpioSpeed : uint8_t +{ + LOW = 0U, + MEDIUM = 1U, + HIGH = 2U, + VERY_HIGH = 3U +}; + +// PUPDR register values +enum class GpioPull : uint8_t +{ + NONE = 0U, + UP = 1U, + DOWN = 2U +}; + +struct GpioConfig +{ + GPIO_TypeDef* port; + uint8_t pin; // 0-15 + GpioMode mode; + GpioOutputType otype; + GpioSpeed speed; + GpioPull pull; + uint8_t af; // Alternate function number (0-15) +}; + +class Gpio +{ +public: + Gpio() = delete; + + static void enablePortClock(GPIO_TypeDef* port); + static void configure(GpioConfig const& cfg); + static void setMode(GPIO_TypeDef* port, uint8_t pin, GpioMode mode); + static void setOutputType(GPIO_TypeDef* port, uint8_t pin, GpioOutputType otype); + static void setSpeed(GPIO_TypeDef* port, uint8_t pin, GpioSpeed speed); + static void setPull(GPIO_TypeDef* port, uint8_t pin, GpioPull pull); + static void setAlternateFunction(GPIO_TypeDef* port, uint8_t pin, uint8_t af); + static bool readPin(GPIO_TypeDef* port, uint8_t pin); + static void writePin(GPIO_TypeDef* port, uint8_t pin, bool high); + static void togglePin(GPIO_TypeDef* port, uint8_t pin); +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bspIo/include/io/GpioPinConfig.h b/platforms/stm32/bsp/bspIo/include/io/GpioPinConfig.h new file mode 100644 index 00000000000..c540ba7e2e2 --- /dev/null +++ b/platforms/stm32/bsp/bspIo/include/io/GpioPinConfig.h @@ -0,0 +1,77 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include + +namespace bios +{ +namespace pins +{ + +#if defined(STM32F413xx) +// NUCLEO-F413ZH board pins + +// LD1 (green LED) +static constexpr GpioConfig LED1 + = {GPIOB, 0U, GpioMode::OUTPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +// LD2 (blue LED) +static constexpr GpioConfig LED2 + = {GPIOB, 7U, GpioMode::OUTPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +// LD3 (red LED) +static constexpr GpioConfig LED3 + = {GPIOB, 14U, GpioMode::OUTPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +// User button B1 (external pull-down on board) +static constexpr GpioConfig USER_BUTTON + = {GPIOC, 13U, GpioMode::INPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +static constexpr GpioConfig CAN1_RX = { + GPIOD, 0U, GpioMode::ALTERNATE, GpioOutputType::PUSH_PULL, GpioSpeed::HIGH, GpioPull::UP, 9U}; + +static constexpr GpioConfig CAN1_TX + = {GPIOD, + 1U, + GpioMode::ALTERNATE, + GpioOutputType::PUSH_PULL, + GpioSpeed::VERY_HIGH, + GpioPull::NONE, + 9U}; + +#elif defined(STM32G474xx) +// NUCLEO-G474RE board pins + +// LD2 (green LED) +static constexpr GpioConfig LED2 + = {GPIOA, 5U, GpioMode::OUTPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +// User button B1 (external pull-up on board) +static constexpr GpioConfig USER_BUTTON + = {GPIOC, 13U, GpioMode::INPUT, GpioOutputType::PUSH_PULL, GpioSpeed::LOW, GpioPull::NONE, 0U}; + +static constexpr GpioConfig FDCAN1_RX = { + GPIOA, 11U, GpioMode::ALTERNATE, GpioOutputType::PUSH_PULL, GpioSpeed::HIGH, GpioPull::UP, 9U}; + +static constexpr GpioConfig FDCAN1_TX + = {GPIOA, + 12U, + GpioMode::ALTERNATE, + GpioOutputType::PUSH_PULL, + GpioSpeed::VERY_HIGH, + GpioPull::NONE, + 9U}; + +#endif + +} // namespace pins +} // namespace bios diff --git a/platforms/stm32/bsp/bspIo/module.spec b/platforms/stm32/bsp/bspIo/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspIo/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspIo/src/io/Gpio.cpp b/platforms/stm32/bsp/bspIo/src/io/Gpio.cpp new file mode 100644 index 00000000000..0c05aef10f2 --- /dev/null +++ b/platforms/stm32/bsp/bspIo/src/io/Gpio.cpp @@ -0,0 +1,175 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +namespace bios +{ + +void Gpio::enablePortClock(GPIO_TypeDef* port) +{ +#if defined(STM32G474xx) + if (port == GPIOA) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; + } + else if (port == GPIOB) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN; + } + else if (port == GPIOC) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN; + } +#if defined(GPIOD) + else if (port == GPIOD) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIODEN; + } +#endif +#if defined(GPIOE) + else if (port == GPIOE) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOEEN; + } +#endif +#if defined(GPIOF) + else if (port == GPIOF) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOFEN; + } +#endif +#if defined(GPIOG) + else if (port == GPIOG) + { + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOGEN; + } +#endif +#elif defined(STM32F413xx) + if (port == GPIOA) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; + } + else if (port == GPIOB) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; + } + else if (port == GPIOC) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN; + } + else if (port == GPIOD) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; + } +#if defined(GPIOE) + else if (port == GPIOE) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN; + } +#endif +#if defined(GPIOF) + else if (port == GPIOF) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOFEN; + } +#endif +#if defined(GPIOG) + else if (port == GPIOG) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOGEN; + } +#endif +#if defined(GPIOH) + else if (port == GPIOH) + { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN; + } +#endif +#endif + // Read-back for clock stabilization + uint32_t volatile dummy; + (void)dummy; +#if defined(STM32G474xx) + dummy = RCC->AHB2ENR; +#elif defined(STM32F413xx) + dummy = RCC->AHB1ENR; +#endif + (void)dummy; +} + +void Gpio::configure(GpioConfig const& cfg) +{ + enablePortClock(cfg.port); + setMode(cfg.port, cfg.pin, cfg.mode); + setOutputType(cfg.port, cfg.pin, cfg.otype); + setSpeed(cfg.port, cfg.pin, cfg.speed); + setPull(cfg.port, cfg.pin, cfg.pull); + if ((cfg.mode == GpioMode::ALTERNATE) && (cfg.af <= 15U)) + { + setAlternateFunction(cfg.port, cfg.pin, cfg.af); + } +} + +void Gpio::setMode(GPIO_TypeDef* port, uint8_t pin, GpioMode mode) +{ + uint32_t pos = pin * 2U; + port->MODER = (port->MODER & ~(3U << pos)) | (static_cast(mode) << pos); +} + +void Gpio::setOutputType(GPIO_TypeDef* port, uint8_t pin, GpioOutputType otype) +{ + if (otype == GpioOutputType::OPEN_DRAIN) + { + port->OTYPER |= (1U << pin); + } + else + { + port->OTYPER &= ~(1U << pin); + } +} + +void Gpio::setSpeed(GPIO_TypeDef* port, uint8_t pin, GpioSpeed speed) +{ + uint32_t pos = pin * 2U; + port->OSPEEDR = (port->OSPEEDR & ~(3U << pos)) | (static_cast(speed) << pos); +} + +void Gpio::setPull(GPIO_TypeDef* port, uint8_t pin, GpioPull pull) +{ + uint32_t pos = pin * 2U; + port->PUPDR = (port->PUPDR & ~(3U << pos)) | (static_cast(pull) << pos); +} + +void Gpio::setAlternateFunction(GPIO_TypeDef* port, uint8_t pin, uint8_t af) +{ + uint8_t afrIdx = (pin < 8U) ? 0U : 1U; + uint8_t afrPin = (pin < 8U) ? pin : (pin - 8U); + uint32_t pos = afrPin * 4U; + port->AFR[afrIdx] = (port->AFR[afrIdx] & ~(0xFU << pos)) | (static_cast(af) << pos); +} + +bool Gpio::readPin(GPIO_TypeDef* port, uint8_t pin) { return (port->IDR & (1U << pin)) != 0U; } + +void Gpio::writePin(GPIO_TypeDef* port, uint8_t pin, bool high) +{ + if (high) + { + port->BSRR = (1U << pin); + } + else + { + port->BSRR = (1U << (pin + 16U)); + } +} + +void Gpio::togglePin(GPIO_TypeDef* port, uint8_t pin) { port->ODR ^= (1U << pin); } + +} // namespace bios diff --git a/platforms/stm32/bsp/bspTimer/CMakeLists.txt b/platforms/stm32/bsp/bspTimer/CMakeLists.txt new file mode 100644 index 00000000000..26b7596d8f5 --- /dev/null +++ b/platforms/stm32/bsp/bspTimer/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(bspTimer src/bsp/SystemTimer/SystemTimer.cpp) + +target_link_libraries(bspTimer PUBLIC bsp bspMcu bspInterrupts) diff --git a/platforms/stm32/bsp/bspTimer/doc/index.rst b/platforms/stm32/bsp/bspTimer/doc/index.rst new file mode 100644 index 00000000000..8e87df71638 --- /dev/null +++ b/platforms/stm32/bsp/bspTimer/doc/index.rst @@ -0,0 +1,35 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspTimer +======== + +Overview +-------- + +The ``bspTimer`` module implements the system timer for STM32 Cortex-M4 +targets using the ARM Data Watchpoint and Trace (DWT) cycle counter +(``CYCCNT``) -- a core debug unit register available on all Cortex-M4 devices +-- so no chip-specific peripheral timer is required. + +The 32-bit ``CYCCNT`` is extended to a 64-bit monotonic microsecond counter; +updates run under ``SuspendResumeAllInterruptsScopedLock``. The core clock +frequency used for the cycles-to-microseconds conversion is fixed at compile +time: + +- 96 MHz for STM32F4 (STM32F413ZH) +- 170 MHz for STM32G4 (STM32G474RE) + +The family is selected via the ``STM32_FAMILY_F4`` / ``STM32_FAMILY_G4`` +compile definitions from the bspMcu CMake configuration. + +The DWT timer is independent of SysTick: FreeRTOS uses SysTick for its tick +interrupt while the BSP system timer uses DWT for high-resolution timestamps. diff --git a/platforms/stm32/bsp/bspTimer/module.spec b/platforms/stm32/bsp/bspTimer/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspTimer/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspTimer/src/bsp/SystemTimer/SystemTimer.cpp b/platforms/stm32/bsp/bspTimer/src/bsp/SystemTimer/SystemTimer.cpp new file mode 100644 index 00000000000..e46be2a0123 --- /dev/null +++ b/platforms/stm32/bsp/bspTimer/src/bsp/SystemTimer/SystemTimer.cpp @@ -0,0 +1,95 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "bsp/timer/SystemTimer.h" + +#include "interrupts/SuspendResumeAllInterruptsScopedLock.h" +#include "mcu/mcu.h" + +namespace +{ +#if defined(STM32_FAMILY_F4) +uint32_t const DWT_FREQ_MHZ = 96U; // F413ZH: 96 MHz HCLK +#elif defined(STM32_FAMILY_G4) +uint32_t const DWT_FREQ_MHZ = 170U; // G474RE: 170 MHz HCLK +#else +#error "Define STM32_FAMILY_F4 or STM32_FAMILY_G4" +#endif + +uint32_t const TICK_FREQ_MHZ = 1U; // 1 tick = 1 us + +struct +{ + uint64_t ticks; + uint32_t lastDwt; +} state = {0, 0}; + +// DWT registers (ARMv7-M architecture reference) +uint32_t volatile& DWT_CTRL = *reinterpret_cast(0xE0001000U); +uint32_t volatile& DWT_CYCCNT = *reinterpret_cast(0xE0001004U); +uint32_t volatile& DEMCR = *reinterpret_cast(0xE000EDFCU); + +uint64_t updateTicks() +{ + const ESR_UNUSED interrupts::SuspendResumeAllInterruptsScopedLock lock; + uint32_t const curDwt = DWT_CYCCNT; + state.ticks += static_cast((curDwt - state.lastDwt) / DWT_FREQ_MHZ); + state.lastDwt = curDwt; + return state.ticks; +} + +} // namespace + +extern "C" +{ +void initSystemTimer() +{ + const ESR_UNUSED interrupts::SuspendResumeAllInterruptsScopedLock lock; + + DEMCR = DEMCR | 0x01000000U; // TRCENA + DWT_CYCCNT = 0; + DWT_CTRL = DWT_CTRL | 0x00000001U; // CYCCNTENA + + state.ticks = 0; + state.lastDwt = 0; +} + +uint64_t getSystemTicks(void) { return updateTicks(); } + +uint32_t getSystemTicks32Bit(void) { return static_cast(updateTicks()); } + +uint64_t getSystemTimeNs(void) { return updateTicks() * 1000U / TICK_FREQ_MHZ; } + +uint64_t getSystemTimeUs(void) { return updateTicks() / TICK_FREQ_MHZ; } + +uint32_t getSystemTimeUs32Bit(void) { return static_cast(updateTicks() / TICK_FREQ_MHZ); } + +uint64_t getSystemTimeMs(void) { return updateTicks() / TICK_FREQ_MHZ / 1000U; } + +uint32_t getSystemTimeMs32Bit(void) +{ + return static_cast(updateTicks() / TICK_FREQ_MHZ / 1000U); +} + +uint64_t systemTicksToTimeUs(uint64_t const ticks) { return ticks / TICK_FREQ_MHZ; } + +uint64_t systemTicksToTimeNs(uint64_t const ticks) { return ticks * 1000U / TICK_FREQ_MHZ; } + +uint32_t getFastTicks(void) { return DWT_CYCCNT; } + +uint32_t getFastTicksPerSecond(void) { return DWT_FREQ_MHZ * 1000000U; } + +void sysDelayUs(uint32_t const delay) +{ + uint64_t const start = getSystemTimeUs(); + while (getSystemTimeUs() < start + delay) {} +} + +} // extern "C" diff --git a/platforms/stm32/bsp/bspUart/CMakeLists.txt b/platforms/stm32/bsp/bspUart/CMakeLists.txt new file mode 100644 index 00000000000..2498a80301b --- /dev/null +++ b/platforms/stm32/bsp/bspUart/CMakeLists.txt @@ -0,0 +1,13 @@ +if (BUILD_EXECUTABLE STREQUAL "unitTest") + # Header-only for unit tests (no hardware-dependent Uart.cpp) + add_library(bspUart INTERFACE) + target_include_directories(bspUart INTERFACE include) + target_link_libraries(bspUart INTERFACE bsp) +else () + add_library(bspUart src/Uart.cpp) + target_include_directories(bspUart PUBLIC include) + target_link_libraries( + bspUart + PUBLIC bsp + PRIVATE bspMcu) +endif () diff --git a/platforms/stm32/bsp/bspUart/doc/index.rst b/platforms/stm32/bsp/bspUart/doc/index.rst new file mode 100644 index 00000000000..fdaf963be51 --- /dev/null +++ b/platforms/stm32/bsp/bspUart/doc/index.rst @@ -0,0 +1,41 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspUart Driver +============== + +Overview +-------- + +The ``bspUart`` module provides a polling-mode UART driver for debug console +output on STM32 targets. It is used by the logger subsystem and the command +shell for human-readable output over the ST-LINK Virtual COM Port (VCP). The +driver is the ``bsp::Uart`` class and satisfies the ``UartConcept`` +compile-time interface check (``BSP_UART_CONCEPT_CHECKER``). + +All I/O is synchronous polling; no DMA or interrupts are used, which avoids +NVIC configuration dependencies at the cost of blocking the caller during +transmission. + +Configuration +------------- + +Each UART instance is described by a ``UartConfig`` struct in a compile-time +table (``_uartConfigs[]``): USART peripheral, GPIO port and TX/RX pins, +alternate function number, and baud rate register value (typically 115200 +baud for the debug console). + +Board configuration: + +- **NUCLEO-F413ZH** -- USART3 on PD8 (TX) / PD9 (RX), AF7. VCP via ST-LINK + V2-1. +- **NUCLEO-G474RE** -- USART2 on PA2 (TX) / PA3 (RX), AF7. VCP via ST-LINK + V3. diff --git a/platforms/stm32/bsp/bspUart/include/bsp/Uart.h b/platforms/stm32/bsp/bspUart/include/bsp/Uart.h new file mode 100644 index 00000000000..6923323216a --- /dev/null +++ b/platforms/stm32/bsp/bspUart/include/bsp/Uart.h @@ -0,0 +1,43 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include + +namespace bsp +{ + +class Uart +{ +public: + enum class Id : size_t; + + size_t write(::etl::span const data); + size_t read(::etl::span data); + void init(); + bool isInitialized() const; + bool waitForTxReady(); + + static Uart& getInstance(Id id); + + struct UartConfig; + Uart(Uart::Id id); + +private: + bool writeByte(uint8_t data); + + UartConfig const& _uartConfig; + static UartConfig const _uartConfigs[]; +}; + +BSP_UART_CONCEPT_CHECKER(Uart) + +} // namespace bsp diff --git a/platforms/stm32/bsp/bspUart/include/bsp/UartParams.h b/platforms/stm32/bsp/bspUart/include/bsp/UartParams.h new file mode 100644 index 00000000000..a21f14706ce --- /dev/null +++ b/platforms/stm32/bsp/bspUart/include/bsp/UartParams.h @@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include "bsp/Uart.h" + +#include + +namespace bsp +{ + +struct Uart::UartConfig +{ + USART_TypeDef* usart; + GPIO_TypeDef* gpioPort; + uint8_t txPin; + uint8_t rxPin; + uint8_t af; + uint32_t brr; + uint32_t rccGpioEnBit; + uint32_t rccUsartEnBit; + uint32_t volatile* rccGpioEnReg; + uint32_t volatile* rccUsartEnReg; +}; + +} // namespace bsp diff --git a/platforms/stm32/bsp/bspUart/module.spec b/platforms/stm32/bsp/bspUart/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspUart/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspUart/src/Uart.cpp b/platforms/stm32/bsp/bspUart/src/Uart.cpp new file mode 100644 index 00000000000..e10084bc992 --- /dev/null +++ b/platforms/stm32/bsp/bspUart/src/Uart.cpp @@ -0,0 +1,127 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "bsp/UartParams.h" + +using bsp::Uart; + +static uint32_t const WRITE_TIMEOUT = 100000U; + +// STM32F4 uses SR/DR registers, STM32G4 uses ISR/TDR/RDR registers +#if defined(STM32F413xx) +#define UART_TX_EMPTY_FLAG USART_SR_TXE +#define UART_RX_READY_FLAG USART_SR_RXNE +#define UART_GET_STATUS(u) ((u)->SR) +#define UART_WRITE_DATA(u, d) ((u)->DR = (d)) +#define UART_READ_DATA(u) ((u)->DR & 0xFFU) +#elif defined(STM32G474xx) +#define UART_TX_EMPTY_FLAG USART_ISR_TXE +#define UART_RX_READY_FLAG USART_ISR_RXNE_RXFNE +#define UART_GET_STATUS(u) ((u)->ISR) +#define UART_WRITE_DATA(u, d) ((u)->TDR = (d)) +#define UART_READ_DATA(u) ((u)->RDR & 0xFFU) +#endif + +static void configureGpio(Uart::UartConfig const& cfg) +{ + *cfg.rccGpioEnReg |= cfg.rccGpioEnBit; + + cfg.gpioPort->MODER &= ~(3U << (cfg.txPin * 2U)); + cfg.gpioPort->MODER |= (2U << (cfg.txPin * 2U)); + uint32_t const txAfrIdx = cfg.txPin / 8U; + uint32_t const txAfrPos = (cfg.txPin % 8U) * 4U; + cfg.gpioPort->AFR[txAfrIdx] &= ~(0xFU << txAfrPos); + cfg.gpioPort->AFR[txAfrIdx] |= (static_cast(cfg.af) << txAfrPos); + + cfg.gpioPort->MODER &= ~(3U << (cfg.rxPin * 2U)); + cfg.gpioPort->MODER |= (2U << (cfg.rxPin * 2U)); + uint32_t const rxAfrIdx = cfg.rxPin / 8U; + uint32_t const rxAfrPos = (cfg.rxPin % 8U) * 4U; + cfg.gpioPort->AFR[rxAfrIdx] &= ~(0xFU << rxAfrPos); + cfg.gpioPort->AFR[rxAfrIdx] |= (static_cast(cfg.af) << rxAfrPos); +} + +Uart::Uart(Uart::Id id) : _uartConfig(_uartConfigs[static_cast(id)]) {} + +void Uart::init() +{ + configureGpio(_uartConfig); + + *_uartConfig.rccUsartEnReg |= _uartConfig.rccUsartEnBit; + + // BRR must be written while UE is cleared + _uartConfig.usart->CR1 = 0; + _uartConfig.usart->BRR = _uartConfig.brr; + _uartConfig.usart->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; +} + +bool Uart::isInitialized() const +{ + return (_uartConfig.usart->CR1 & (USART_CR1_TE | USART_CR1_RE)) != 0; +} + +bool Uart::waitForTxReady() +{ + uint32_t count = 0U; + + if (!isInitialized()) + { + init(); + } + + while ((UART_GET_STATUS(_uartConfig.usart) & UART_TX_EMPTY_FLAG) == 0) + { + if (++count > WRITE_TIMEOUT) + { + return false; + } + } + return true; +} + +bool Uart::writeByte(uint8_t data) +{ + if ((UART_GET_STATUS(_uartConfig.usart) & UART_TX_EMPTY_FLAG) != 0) + { + UART_WRITE_DATA(_uartConfig.usart, static_cast(data) & 0xFFU); + return waitForTxReady(); + } + return false; +} + +size_t Uart::write(::etl::span const data) +{ + size_t counter = 0; + + while (counter < data.size()) + { + if (!writeByte(data[counter])) + { + break; + } + counter++; + } + + return counter; +} + +size_t Uart::read(::etl::span data) +{ + size_t bytesRead = 0; + + while ((UART_GET_STATUS(_uartConfig.usart) & UART_RX_READY_FLAG) != 0 + && bytesRead < data.size()) + { + data[bytesRead] = static_cast(UART_READ_DATA(_uartConfig.usart)); + bytesRead++; + } + + return bytesRead; +} diff --git a/platforms/stm32/etlImpl/CMakeLists.txt b/platforms/stm32/etlImpl/CMakeLists.txt new file mode 100644 index 00000000000..c3f4d59b292 --- /dev/null +++ b/platforms/stm32/etlImpl/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(etlImpl src/print.cpp src/clocks.cpp) + +target_link_libraries(etlImpl PRIVATE etl bsp util) diff --git a/platforms/stm32/etlImpl/src/clocks.cpp b/platforms/stm32/etlImpl/src/clocks.cpp new file mode 100644 index 00000000000..fa1ab9ae743 --- /dev/null +++ b/platforms/stm32/etlImpl/src/clocks.cpp @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include +#include + +extern "C" +{ +etl::chrono::high_resolution_clock::rep etl_get_high_resolution_clock() +{ + return etl::chrono::high_resolution_clock::rep{static_cast(getSystemTimeNs())}; +} + +etl::chrono::system_clock::rep etl_get_system_clock() +{ + return etl::chrono::system_clock::rep(static_cast(getSystemTimeUs())); +} + +etl::chrono::steady_clock::rep etl_get_steady_clock() +{ + return etl::chrono::steady_clock::rep(static_cast(getSystemTimeMs() / 1000)); +} +} diff --git a/platforms/stm32/etlImpl/src/print.cpp b/platforms/stm32/etlImpl/src/print.cpp new file mode 100644 index 00000000000..9d14f512b7b --- /dev/null +++ b/platforms/stm32/etlImpl/src/print.cpp @@ -0,0 +1,14 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include +#include + +extern "C" void etl_putchar(int c) { putByteToStdout(static_cast(c)); } From 494ae7841d7434ed97d5da1f498e59e9bc472d79 Mon Sep 17 00:00:00 2001 From: nhuvaoanh123 Date: Tue, 2 Jun 2026 08:16:56 +0200 Subject: [PATCH 4/4] Add STM32 CAN drivers and bxCAN transceiver Add bxCAN and FDCAN device drivers with STM32 CAN tests. Add the bxCAN transceiver adapter and unit-test registration. --- CMakeLists.txt | 11 +- platforms/stm32/CMakeLists.txt | 3 + platforms/stm32/bsp/CMakeLists.txt | 49 +- platforms/stm32/bsp/bspCan/CMakeLists.txt | 16 + platforms/stm32/bsp/bspCan/doc/index.rst | 70 + .../bsp/bspCan/include/can/BxCanDevice.h | 215 + .../bsp/bspCan/include/can/FdCanDevice.h | 215 + platforms/stm32/bsp/bspCan/module.spec | 2 + .../stm32/bsp/bspCan/src/can/BxCanDevice.cpp | 382 ++ .../stm32/bsp/bspCan/src/can/FdCanDevice.cpp | 485 ++ .../stm32/bsp/bspCan/test/CMakeLists.txt | 15 + .../stm32/bsp/bspCan/test/include/mcu/mcu.h | 12 + .../bspCan/test/src/can/BxCanDeviceTest.cpp | 4110 +++++++++++++++++ .../bsp/bspCan/test/src/can/FakeHwHelpers.h | 170 + .../bspCan/test/src/can/FdCanDeviceTest.cpp | 3657 +++++++++++++++ .../stm32/bsp/bxCanTransceiver/CMakeLists.txt | 21 + .../stm32/bsp/bxCanTransceiver/doc/index.rst | 45 + .../can/transceiver/bxcan/BxCanTransceiver.h | 105 + .../stm32/bsp/bxCanTransceiver/module.spec | 2 + .../transceiver/bxcan/BxCanTransceiver.cpp | 310 ++ .../bsp/bxCanTransceiver/test/CMakeLists.txt | 15 + .../test/mock/include/can/BxCanDevice.h | 66 + .../test/src/can/BxCanTransceiverTest.cpp | 943 ++++ 23 files changed, 10897 insertions(+), 22 deletions(-) create mode 100644 platforms/stm32/bsp/bspCan/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspCan/doc/index.rst create mode 100644 platforms/stm32/bsp/bspCan/include/can/BxCanDevice.h create mode 100644 platforms/stm32/bsp/bspCan/include/can/FdCanDevice.h create mode 100644 platforms/stm32/bsp/bspCan/module.spec create mode 100644 platforms/stm32/bsp/bspCan/src/can/BxCanDevice.cpp create mode 100644 platforms/stm32/bsp/bspCan/src/can/FdCanDevice.cpp create mode 100644 platforms/stm32/bsp/bspCan/test/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bspCan/test/include/mcu/mcu.h create mode 100644 platforms/stm32/bsp/bspCan/test/src/can/BxCanDeviceTest.cpp create mode 100644 platforms/stm32/bsp/bspCan/test/src/can/FakeHwHelpers.h create mode 100644 platforms/stm32/bsp/bspCan/test/src/can/FdCanDeviceTest.cpp create mode 100644 platforms/stm32/bsp/bxCanTransceiver/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bxCanTransceiver/doc/index.rst create mode 100644 platforms/stm32/bsp/bxCanTransceiver/include/can/transceiver/bxcan/BxCanTransceiver.h create mode 100644 platforms/stm32/bsp/bxCanTransceiver/module.spec create mode 100644 platforms/stm32/bsp/bxCanTransceiver/src/can/transceiver/bxcan/BxCanTransceiver.cpp create mode 100644 platforms/stm32/bsp/bxCanTransceiver/test/CMakeLists.txt create mode 100644 platforms/stm32/bsp/bxCanTransceiver/test/mock/include/can/BxCanDevice.h create mode 100644 platforms/stm32/bsp/bxCanTransceiver/test/src/can/BxCanTransceiverTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 840515f077c..2e3aceca614 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,13 @@ if (BUILD_EXECUTABLE STREQUAL "unitTest") add_subdirectory(platforms/posix/bsp/bspEepromDriver/test) add_subdirectory(platforms/posix/bsp/socketCanTransceiver/test) + elseif (OPENBSW_PLATFORM STREQUAL "stm32") + + add_subdirectory(platforms/stm32/unitTest EXCLUDE_FROM_ALL) + + add_subdirectory(platforms/stm32/bsp/bspCan/test) + add_subdirectory(platforms/stm32/bsp/bxCanTransceiver/test) + elseif (OPENBSW_PLATFORM STREQUAL "s32k1xx") add_subdirectory(platforms/s32k1xx/unitTest EXCLUDE_FROM_ALL) @@ -197,10 +204,6 @@ if (BUILD_EXECUTABLE STREQUAL "unitTest") add_subdirectory(platforms/s32k1xx/bsp/canflex2Transceiver/test) add_subdirectory(platforms/s32k1xx/bsp/bspUart/test) - elseif (OPENBSW_PLATFORM STREQUAL "stm32") - - add_subdirectory(platforms/stm32/unitTest EXCLUDE_FROM_ALL) - else () message( FATAL_ERROR diff --git a/platforms/stm32/CMakeLists.txt b/platforms/stm32/CMakeLists.txt index d49dd6f1f71..7315f7f7653 100644 --- a/platforms/stm32/CMakeLists.txt +++ b/platforms/stm32/CMakeLists.txt @@ -20,4 +20,7 @@ if (NOT BUILD_EXECUTABLE STREQUAL "unitTest") # ETL implementation add_subdirectory(etlImpl) +else () + # Unit-test builds compile the transceivers against mock devices. + add_subdirectory(bsp) endif () diff --git a/platforms/stm32/bsp/CMakeLists.txt b/platforms/stm32/bsp/CMakeLists.txt index 41c252d17db..0fdb650d9bd 100644 --- a/platforms/stm32/bsp/CMakeLists.txt +++ b/platforms/stm32/bsp/CMakeLists.txt @@ -1,19 +1,32 @@ -add_subdirectory(bspMcu) -add_subdirectory(bspClock) -add_subdirectory(bspInterruptsImpl) -add_subdirectory(bspUart) -add_subdirectory(bspTimer) -add_subdirectory(bspIo) -add_subdirectory(bspAdc) -add_subdirectory(bspEepromDriver) +if (BUILD_EXECUTABLE STREQUAL "unitTest") + # Unit test builds: only compile transceivers (with mock devices). Skip + # hardware-dependent modules (bspMcu, bspClock, bspCan, etc.). + add_subdirectory(bxCanTransceiver) + add_subdirectory(bspUart) +else () + add_subdirectory(bspMcu) + add_subdirectory(bspClock) + add_subdirectory(bspInterruptsImpl) + add_subdirectory(bspUart) + add_subdirectory(bspTimer) + add_subdirectory(bspIo) + add_subdirectory(bspAdc) + add_subdirectory(bspEepromDriver) + add_subdirectory(bspCan) -# Aggregated BSP target -add_library(socBsp INTERFACE) -target_link_libraries( - socBsp - INTERFACE bspClock - bspInterruptsImpl - bspIo - bspMcu - bspTimer - bspUart) + # CAN transceiver - selected by chip family + if (CAN_TYPE STREQUAL "BXCAN") + add_subdirectory(bxCanTransceiver) + endif () + + # Aggregated BSP target + add_library(socBsp INTERFACE) + target_link_libraries( + socBsp + INTERFACE bspClock + bspInterruptsImpl + bspIo + bspMcu + bspTimer + bspUart) +endif () diff --git a/platforms/stm32/bsp/bspCan/CMakeLists.txt b/platforms/stm32/bsp/bspCan/CMakeLists.txt new file mode 100644 index 00000000000..17b17e1549b --- /dev/null +++ b/platforms/stm32/bsp/bspCan/CMakeLists.txt @@ -0,0 +1,16 @@ +# Low-level CAN device drivers - chip-specific source selected by CAN_TYPE +if (CAN_TYPE STREQUAL "BXCAN") + add_library(bspCan src/can/BxCanDevice.cpp) + target_include_directories(bspCan PUBLIC include) + target_link_libraries( + bspCan + PUBLIC bspMcu cpp2can etl + PRIVATE platform) +elseif (CAN_TYPE STREQUAL "FDCAN") + add_library(bspCan src/can/FdCanDevice.cpp) + target_include_directories(bspCan PUBLIC include) + target_link_libraries( + bspCan + PUBLIC bspMcu cpp2can etl + PRIVATE platform) +endif () diff --git a/platforms/stm32/bsp/bspCan/doc/index.rst b/platforms/stm32/bsp/bspCan/doc/index.rst new file mode 100644 index 00000000000..8a03bcac5cb --- /dev/null +++ b/platforms/stm32/bsp/bspCan/doc/index.rst @@ -0,0 +1,70 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bspCan +====== + +Overview +-------- + +The ``bspCan`` module provides low-level register drivers for the two CAN +peripherals found across the STM32 family: + +- ``BxCanDevice`` -- bare-metal driver for the **bxCAN** controller on STM32F4 + (CAN1/CAN2/CAN3). +- ``FdCanDevice`` -- bare-metal driver for the **FDCAN** controller on STM32G4 + (FDCAN1/FDCAN2/FDCAN3). + +Both classes expose the same logical interface -- ``init()``, ``start()``, +``stop()``, ``transmit()``, ``receiveISR()`` -- so the transceiver layer can +wrap either one behind the OpenBSW ``AbstractCANTransceiver`` API. All CAN +communication is classic CAN at 500 kbps; the FDCAN peripheral is CAN FD +capable but is configured with ``FDOE = 0`` and ``BRSE = 0``. + +BxCanDevice (STM32F4) +--------------------- + +- ``Config`` carries the peripheral base address, bit timing (``prescaler``, + ``bs1``, ``bs2``, ``sjw``, written to ``CAN->BTR`` with ``-1`` encoding) and + the TX/RX GPIO port/pin/alternate-function mapping. +- ``init()`` enables the APB1 clock, configures the GPIO pins, enters init + mode, sets ``ABOM`` and ``TXFP``, programs bit timing and installs an + accept-all filter. ``start()`` leaves init mode and enables ``FMPIE0``. +- TX uses the 3 hardware mailboxes; ``transmit()`` returns ``false`` when all + are full. ``TMEIE`` is enabled while TX is pending and masked again by + ``transmitISR()`` once all mailboxes are idle. +- RX drains hardware FIFO0 (3 deep) into a 32-entry circular software queue, + optionally applying a software bit-field filter. +- Filters: bank 0 in 32-bit mask mode (accept all) or banks 0..13 in 32-bit + identifier-list mode (2 standard IDs per bank, max 28 IDs). + +FdCanDevice (STM32G4) +--------------------- + +- ``Config`` carries the peripheral base address, nominal bit timing + (``prescaler``, ``nts1``, ``nts2``, ``nsjw``, written to ``FDCAN->NBTP``) + and the TX/RX GPIO mapping. The FDCAN kernel clock is set to PCLK1. +- The message RAM layout is fixed in hardware. Each instance owns 212 words + (FDCAN1 at ``SRAMCAN_BASE + 0x000``, FDCAN2 at ``+0x350``, FDCAN3 at + ``+0x6A0``); RX/TX elements are spaced 18 words (72 bytes) apart: + + - Standard ID filters: 28 x 1 word, ``0x000``--``0x06F`` + - Extended ID filters: 8 x 2 words, ``0x070``--``0x0AF`` + - RX FIFO 0: 3 x 18 words, ``0x0B0``--``0x187`` + - RX FIFO 1: 3 x 18 words, ``0x188``--``0x25F`` + - TX event FIFO: 3 x 2 words, ``0x260``--``0x277`` + - TX buffers: 3 x 18 words, ``0x278``--``0x34F`` + +- ``transmit()`` writes the TX element at ``ramBase + 0x278 + putIdx * 72``; + ``receiveISR()`` snapshots the RX FIFO 0 fill level once and drains exactly + that many elements into the same 32-entry software queue as ``BxCanDevice``. +- Filters: accept-all via ``RXGFC`` (``ANFS = 0``, ``ANFE = 0``) or up to 28 + exact-match standard-ID filter elements, rejecting non-matching frames. diff --git a/platforms/stm32/bsp/bspCan/include/can/BxCanDevice.h b/platforms/stm32/bsp/bspCan/include/can/BxCanDevice.h new file mode 100644 index 00000000000..a87a9a65e8c --- /dev/null +++ b/platforms/stm32/bsp/bspCan/include/can/BxCanDevice.h @@ -0,0 +1,215 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace bios +{ + +/** + * \brief Low-level bxCAN hardware abstraction for STM32F4. + * + * Manages a bxCAN peripheral: initialization, bit timing, TX mailboxes, + * RX FIFOs, filter banks, and error counters. Does not implement the + * OpenBSW transceiver interface - that is BxCanTransceiver's job. + */ +class BxCanDevice +{ +public: + struct Config + { + CAN_TypeDef* baseAddress; + uint32_t prescaler; + uint32_t bs1; + uint32_t bs2; + uint32_t sjw; + GPIO_TypeDef* rxGpioPort; + uint8_t rxPin; + uint8_t rxAf; + GPIO_TypeDef* txGpioPort; + uint8_t txPin; + uint8_t txAf; + }; + + static constexpr uint32_t RX_QUEUE_SIZE = 32U; + + /** + * \brief Construct a BxCanDevice from a hardware configuration. + * \param config Peripheral base address, bit-timing, and GPIO pin mapping. + */ + explicit BxCanDevice(Config const& config); + + /** + * \brief Initialise the bxCAN peripheral. + * + * Enables the APB1 clock, configures TX/RX GPIO pins, enters init mode, + * programs bit timing, and installs an accept-all hardware filter. + * Must be called before start(). + * \return true on success, false if hardware timeout. + * \note Thread context only - not safe to call from ISR. + */ + bool init(); + + /** + * \brief Leave init mode and begin normal CAN operation. + * + * Drains any stale FIFO0 frames, clears the overrun flag, and enables + * the FMPIE0 (FIFO-message-pending) RX interrupt. + * \return true on success, false if hardware timeout. + * \note Requires a preceding init() call; returns false if not initialised. + */ + bool start(); + + /** + * \brief Disable CAN interrupts and re-enter init mode. + * + * Masks both FMPIE0 (RX) and TMEIE (TX-mailbox-empty) interrupts, + * then requests hardware init mode. + */ + void stop(); + + /** + * \brief Queue a CAN frame for transmission. + * + * Scans TX mailboxes 0-2 for an empty slot, writes the frame's ID, DLC, + * and payload, then sets TXRQ to trigger hardware transmission. + * Enables TMEIE so that transmitISR() fires on completion. + * + * \param frame The CAN frame to transmit (standard or extended ID). + * \return true if the frame was placed in a mailbox, false if all 3 are full. + * + * \note Thread context - must not be called concurrently with transmitISR() + * without external locking. + */ + bool transmit(::can::CANFrame const& frame); + + /** + * \brief ISR handler: drain hardware RX FIFO0 into the software queue. + * + * Reads all pending frames from FIFO0. Each frame is optionally checked + * against a software bit-field filter before being stored in the circular + * RX queue. If the queue is full the FIFO entry is released without storing. + * + * \param filterBitField Byte array indexed by (CAN-ID / 8); bit (CAN-ID % 8) + * set means "accept". Pass nullptr to accept all. + * \return Number of frames actually enqueued. + * + * \note ISR context - called from CAN1_RX0_IRQHandler. + */ + uint8_t receiveISR(uint8_t const* filterBitField); + + /** + * \brief ISR handler: acknowledge completed transmissions. + * + * Clears RQCP flags for all 3 mailboxes. If every mailbox is now empty, + * disables TMEIE to avoid spurious TX interrupts. + * + * \note ISR context - called from CAN1_TX_IRQHandler. + */ + void transmitISR(); + + /** + * \brief Check whether the CAN controller is in bus-off state. + * \return true if the BOFF bit in CAN->ESR is set. + */ + bool isBusOff() const; + + /** + * \brief Read the transmit error counter from CAN->ESR. + * \return TEC value (0-255). + */ + uint8_t getTxErrorCounter() const; + + /** + * \brief Read the receive error counter from CAN->ESR. + * \return REC value (0-255). + */ + uint8_t getRxErrorCounter() const; + + /** + * \brief Configure filter bank 0 in 32-bit mask mode to accept all frames. + * + * Enters filter init mode, sets mask = 0 / id = 0 (accept everything), + * assigns to FIFO0, and leaves filter init mode. + * + * \note Must be called while the peripheral is in init mode. + */ + void configureAcceptAllFilter(); + + /** + * \brief Configure filter banks in 32-bit identifier-list mode. + * + * Packs up to 2 standard IDs per filter bank (banks 0..13). + * If count is odd the last bank duplicates the final ID. + * + * \param idList Array of standard 11-bit CAN IDs to accept. + * \param count Number of entries in idList (max 28). + * + * \note Must be called while the peripheral is in init mode. + */ + void configureFilterList(uint32_t const* idList, uint8_t count); + + /** + * \brief Mask the FMPIE0 interrupt (FIFO0 message-pending). + * + * Used by the transceiver layer to create a critical section around + * RX queue access so that receiveISR() cannot modify the queue + * concurrently. + * + * \note Thread context - called before reading the RX queue. + */ + void disableRxInterrupt(); + + /** + * \brief Re-enable the FMPIE0 interrupt after queue access is complete. + * \note Thread context - called after reading the RX queue. + */ + void enableRxInterrupt(); + + /** + * \brief Access a received frame by index within the circular queue. + * \param index Zero-based offset from the queue head (0 .. getRxCount()-1). + * \return Const reference to the CANFrame at the given position. + */ + ::can::CANFrame const& getRxFrame(uint8_t index) const; + + /** + * \brief Return the number of unread frames in the software RX queue. + * \return Frame count (0 .. RX_QUEUE_SIZE). + */ + uint8_t getRxCount() const; + + /** + * \brief Advance the queue head past all current frames, resetting count to 0. + * + * \note Must be called with the RX interrupt disabled (disableRxInterrupt()) + * to avoid a race with receiveISR(). + */ + void clearRxQueue(); + +private: + Config const fConfig; + ::can::CANFrame fRxQueue[RX_QUEUE_SIZE]; + uint8_t fRxHead; + uint8_t fRxCount; + bool fInitialized; + + bool enterInitMode(); + bool leaveInitMode(); + void configureBitTiming(); + void configureGpio(); + void enablePeripheralClock(); +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bspCan/include/can/FdCanDevice.h b/platforms/stm32/bsp/bspCan/include/can/FdCanDevice.h new file mode 100644 index 00000000000..f2328ebb0b9 --- /dev/null +++ b/platforms/stm32/bsp/bspCan/include/can/FdCanDevice.h @@ -0,0 +1,215 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +namespace bios +{ + +/** + * \brief Low-level FDCAN hardware abstraction for STM32G4. + * + * Manages an FDCAN peripheral: initialization, bit timing, TX FIFO, + * RX FIFOs, message-RAM filter elements, and error counters. Used in + * classic CAN mode. Does not implement the OpenBSW transceiver interface. + */ +class FdCanDevice +{ +public: + struct Config + { + FDCAN_GlobalTypeDef* baseAddress; + uint32_t prescaler; + uint32_t nts1; + uint32_t nts2; + uint32_t nsjw; + GPIO_TypeDef* rxGpioPort; + uint8_t rxPin; + uint8_t rxAf; + GPIO_TypeDef* txGpioPort; + uint8_t txPin; + uint8_t txAf; + }; + + /// Maximum number of frames buffered in the software RX queue. + static constexpr uint32_t RX_QUEUE_SIZE = 32U; + + /// HW filter ID list (set before open/start, nullptr = accept all) + uint32_t const* fFilterIds = nullptr; + uint8_t fFilterCount = 0U; + + /** + * \brief Construct an FdCanDevice from a hardware configuration. + * \param config Peripheral base address, bit timing, and GPIO pin map. + */ + explicit FdCanDevice(Config const& config); + + /** + * \brief Construct with a TX-complete callback delegate (matches FlexCANDevice pattern). + * \param config Hardware configuration. + * \param frameSentCallback Delegate invoked from transmitISR() when a listener TX completes. + */ + FdCanDevice(Config const& config, ::etl::delegate frameSentCallback); + + /** + * \brief Initialise the FDCAN peripheral (clock, GPIO, bit timing, message RAM). + * + * Leaves the peripheral in init mode; call start() to begin bus communication. + * \return true on success, false if hardware timeout (e.g. init mode not entered). + * \note Must be called from thread context before any other method. + */ + bool init(); + + /** + * \brief Configure interrupts and leave init mode to start bus communication. + * + * Enables RF0NE (RX FIFO 0 new element) interrupt at startup. TCE (TX + * complete) is managed per-TX by transmit(frame, true) and disabled by + * transmitISR(), matching S32K's selective interrupt pattern. All + * interrupts route to line 0 (ILS=0). Clears INIT to join the bus. + * \return true on success, false if hardware timeout. + * \note Must be called after init(). + */ + bool start(); + + /** + * \brief Disable CAN interrupts and re-enter init mode, detaching from the bus. + */ + void stop(); + + /** + * \brief Queue a CAN frame for transmission via the hardware TX FIFO. + * \param frame Classic CAN frame (standard or extended ID, up to 8 bytes). + * \return true if the frame was placed in the TX FIFO, false if FIFO is full. + * \note Safe to call from thread context. The actual transmission completes + * asynchronously; transmitISR() clears the completion flag. + */ + bool transmit(::can::CANFrame const& frame); + + /** + * \brief Queue a CAN frame with optional TX-complete interrupt control. + * \param frame Classic CAN frame to transmit. + * \param txInterruptNeeded If true, enable TCE before TX (for listener callback). + * If false, do not enable TCE (fire-and-forget). + * \return true if queued, false if FIFO full. + * \note Matches FlexCANDevice::transmit(frame, bufIdx, txInterruptNeeded) contract. + */ + bool transmit(::can::CANFrame const& frame, bool txInterruptNeeded); + + /** + * \brief Drain RX FIFO 0 into the software queue. Called from the RX ISR. + * + * Takes a snapshot of the current fill level and drains only that many + * elements, preventing an infinite loop on a busy bus. Frames whose + * CAN ID is not set in @p filterBitField are acknowledged but discarded. + * + * \param filterBitField Bit-field indexed by CAN ID; a set bit means + * "accept this ID". Pass nullptr to accept all. + * \return Number of frames actually stored in the software RX queue. + * \note ISR context only. Clears RF0N, RF0F, and RF0L interrupt flags. + */ + uint8_t receiveISR(uint8_t const* filterBitField); + + /** + * \brief Handle TX-complete interrupt: disable TCE, clear TC flag, invoke + * callback delegate. Matches FlexCANDevice::transmitISR() contract. + * \note ISR context only (interrupt line 0, ILS=0). + */ + void transmitISR(); + + /** + * \brief Check whether the FDCAN peripheral is in bus-off state. + * \return true if the BO bit in FDCAN->PSR is set. + */ + bool isBusOff() const; + + /** + * \brief Read the transmit error counter from FDCAN->ECR. + * \return Current TEC value (0-255). + */ + uint8_t getTxErrorCounter() const; + + /** + * \brief Read the receive error counter from FDCAN->ECR. + * \return Current REC value (0-127). + */ + uint8_t getRxErrorCounter() const; + + /** + * \brief Configure the global filter to accept all standard and extended IDs + * into RX FIFO 0 (no hardware filtering). + * \note Must be called while the peripheral is in init mode. + */ + void configureAcceptAllFilter(); + + /** + * \brief Program standard-ID filter elements in message RAM for exact-match + * acceptance, rejecting all non-matching frames. + * \param idList Array of 11-bit standard CAN IDs to accept. + * \param count Number of entries in @p idList (max 28). + * \note Must be called while the peripheral is in init mode. + */ + void configureFilterList(uint32_t const* idList, uint8_t count); + + /** + * \brief Retrieve a received frame from the software RX queue by index. + * \param index Logical index (0 .. getRxCount()-1), relative to fRxHead. + * \return Const reference to the CANFrame at the given queue position. + */ + ::can::CANFrame const& getRxFrame(uint8_t index) const; + + /** + * \brief Return the number of frames currently buffered in the software RX queue. + * \return Frame count (0 .. RX_QUEUE_SIZE). + */ + uint8_t getRxCount() const; + + /** + * \brief Advance the queue head past all currently stored frames and reset count. + * \note Call from thread context after processing all frames returned by getRxFrame(). + */ + void clearRxQueue(); + + /** + * \brief Mask the RF0NE interrupt (RX FIFO 0 new element). + * \note Used to prevent ISR re-entry while the thread drains the queue. + */ + void disableRxInterrupt(); + + /** + * \brief Unmask the RF0NE interrupt (RX FIFO 0 new element). + */ + void enableRxInterrupt(); + + /// Returns the number of pending frames in the hardware RX FIFO0. + uint32_t getHwFifoFillLevel() const; + +private: + Config const fConfig; + ::can::CANFrame fRxQueue[RX_QUEUE_SIZE]; + uint8_t fRxHead; + uint8_t fRxCount; + bool fInitialized; + ::etl::delegate fFrameSentCallback; + + bool enterInitMode(); + bool leaveInitMode(); + void configureBitTiming(); + void configureMessageRam(); + void configureGpio(); + void enablePeripheralClock(); +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bspCan/module.spec b/platforms/stm32/bsp/bspCan/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bspCan/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bspCan/src/can/BxCanDevice.cpp b/platforms/stm32/bsp/bspCan/src/can/BxCanDevice.cpp new file mode 100644 index 00000000000..578e3287de2 --- /dev/null +++ b/platforms/stm32/bsp/bspCan/src/can/BxCanDevice.cpp @@ -0,0 +1,382 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +namespace bios +{ + +BxCanDevice::BxCanDevice(Config const& config) +: fConfig(config), fRxQueue{}, fRxHead(0U), fRxCount(0U), fInitialized(false) +{} + +void BxCanDevice::enablePeripheralClock() +{ + // Enable CAN1 clock on APB1 + RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; + // Small delay for clock stabilization + uint32_t volatile dummy = RCC->APB1ENR; + (void)dummy; +} + +void BxCanDevice::configureGpio() +{ + GPIO_TypeDef* txPort = fConfig.txGpioPort; + GPIO_TypeDef* rxPort = fConfig.rxGpioPort; + + // TX pin: AF mode, push-pull, high speed + txPort->MODER &= ~(3U << (fConfig.txPin * 2U)); + txPort->MODER |= (2U << (fConfig.txPin * 2U)); + txPort->OSPEEDR |= (3U << (fConfig.txPin * 2U)); + if (fConfig.txPin < 8U) + { + txPort->AFR[0] &= ~(0xFU << (fConfig.txPin * 4U)); + txPort->AFR[0] |= (static_cast(fConfig.txAf) << (fConfig.txPin * 4U)); + } + else + { + txPort->AFR[1] &= ~(0xFU << ((fConfig.txPin - 8U) * 4U)); + txPort->AFR[1] |= (static_cast(fConfig.txAf) << ((fConfig.txPin - 8U) * 4U)); + } + + // RX pin: AF mode, pull-up + rxPort->MODER &= ~(3U << (fConfig.rxPin * 2U)); + rxPort->MODER |= (2U << (fConfig.rxPin * 2U)); + rxPort->PUPDR &= ~(3U << (fConfig.rxPin * 2U)); + rxPort->PUPDR |= (1U << (fConfig.rxPin * 2U)); // Pull-up + if (fConfig.rxPin < 8U) + { + rxPort->AFR[0] &= ~(0xFU << (fConfig.rxPin * 4U)); + rxPort->AFR[0] |= (static_cast(fConfig.rxAf) << (fConfig.rxPin * 4U)); + } + else + { + rxPort->AFR[1] &= ~(0xFU << ((fConfig.rxPin - 8U) * 4U)); + rxPort->AFR[1] |= (static_cast(fConfig.rxAf) << ((fConfig.rxPin - 8U) * 4U)); + } +} + +bool BxCanDevice::enterInitMode() +{ + fConfig.baseAddress->MCR |= CAN_MCR_INRQ; +#if !defined(UNIT_TEST) + uint32_t timeout = 100000U; + while ((fConfig.baseAddress->MSR & CAN_MSR_INAK) == 0U) + { + if (--timeout == 0U) + { + return false; + } + } +#else + // In unit tests, MSR doesn't auto-track MCR. Simulate HW behavior. + fConfig.baseAddress->MSR |= CAN_MSR_INAK; +#endif + return true; +} + +bool BxCanDevice::leaveInitMode() +{ + fConfig.baseAddress->MCR &= ~CAN_MCR_INRQ; +#if !defined(UNIT_TEST) + uint32_t timeout = 100000U; + while ((fConfig.baseAddress->MSR & CAN_MSR_INAK) != 0U) + { + if (--timeout == 0U) + { + return false; + } + } +#else + fConfig.baseAddress->MSR &= ~CAN_MSR_INAK; +#endif + return true; +} + +void BxCanDevice::configureBitTiming() +{ + // BTR: SJW | BS2 | BS1 | BRP (prescaler - 1) + fConfig.baseAddress->BTR = ((fConfig.sjw - 1U) << CAN_BTR_SJW_Pos) + | ((fConfig.bs2 - 1U) << CAN_BTR_TS2_Pos) + | ((fConfig.bs1 - 1U) << CAN_BTR_TS1_Pos) | (fConfig.prescaler - 1U); +} + +bool BxCanDevice::init() +{ + enablePeripheralClock(); + configureGpio(); + + if (!enterInitMode()) + { + return false; + } + + // Exit sleep mode + fConfig.baseAddress->MCR &= ~CAN_MCR_SLEEP; + + // Configure: auto bus-off management, auto retransmission, TX FIFO priority + fConfig.baseAddress->MCR |= CAN_MCR_ABOM | CAN_MCR_TXFP; + + configureBitTiming(); + configureAcceptAllFilter(); + + fInitialized = true; + return true; +} + +bool BxCanDevice::start() +{ + if (!fInitialized) + { + return false; + } + + if (!leaveInitMode()) + { + return false; + } + + // Drain any frames that arrived while in init mode +#if !defined(UNIT_TEST) + while ((fConfig.baseAddress->RF0R & CAN_RF0R_FMP0) != 0U) + { + fConfig.baseAddress->RF0R |= CAN_RF0R_RFOM0; + } +#endif + // Clear overrun flag + fConfig.baseAddress->RF0R |= CAN_RF0R_FOVR0; + + fConfig.baseAddress->IER |= CAN_IER_FMPIE0; + return true; +} + +void BxCanDevice::stop() +{ + fConfig.baseAddress->IER &= ~(CAN_IER_FMPIE0 | CAN_IER_TMEIE); + enterInitMode(); +} + +bool BxCanDevice::transmit(::can::CANFrame const& frame) +{ + CAN_TypeDef* can = fConfig.baseAddress; + + // Find an empty TX mailbox + uint8_t mailbox = 0xFFU; + if ((can->TSR & CAN_TSR_TME0) != 0U) + { + mailbox = 0U; + } + else if ((can->TSR & CAN_TSR_TME1) != 0U) + { + mailbox = 1U; + } + else if ((can->TSR & CAN_TSR_TME2) != 0U) + { + mailbox = 2U; + } + else + { + return false; // All mailboxes full + } + + // Set ID (standard 11-bit) + uint32_t id = frame.getId(); + if ((id & 0x80000000U) != 0U) + { + // Extended ID + can->sTxMailBox[mailbox].TIR = ((id & 0x1FFFFFFFU) << CAN_TI0R_EXID_Pos) | CAN_TI0R_IDE; + } + else + { + // Standard ID + can->sTxMailBox[mailbox].TIR = ((id & 0x7FFU) << CAN_TI0R_STID_Pos); + } + + // Set DLC + uint8_t dlc = frame.getPayloadLength(); + can->sTxMailBox[mailbox].TDTR = (dlc & 0xFU); + + // Set data bytes + uint8_t const* data = frame.getPayload(); + can->sTxMailBox[mailbox].TDLR + = static_cast(data[0]) | (static_cast(data[1]) << 8U) + | (static_cast(data[2]) << 16U) | (static_cast(data[3]) << 24U); + can->sTxMailBox[mailbox].TDHR + = static_cast(data[4]) | (static_cast(data[5]) << 8U) + | (static_cast(data[6]) << 16U) | (static_cast(data[7]) << 24U); + + // Request transmission + can->sTxMailBox[mailbox].TIR |= CAN_TI0R_TXRQ; + + // Enable TX mailbox empty interrupt now that we have pending TX + can->IER |= CAN_IER_TMEIE; + + return true; +} + +uint8_t BxCanDevice::receiveISR(uint8_t const* filterBitField) +{ + CAN_TypeDef* can = fConfig.baseAddress; + uint8_t received = 0U; + + // Snapshot fill level (same pattern as FDCAN receiveISR). + // Prevents infinite loop if HW latches new frames during drain. + uint8_t toDrain = static_cast(can->RF0R & CAN_RF0R_FMP0); + while (toDrain > 0U) + { + toDrain--; + if (fRxCount >= RX_QUEUE_SIZE) + { + // Queue full - release FIFO entry without storing + can->RF0R |= CAN_RF0R_RFOM0; + continue; + } + + // Read ID + uint32_t rir = can->sFIFOMailBox[0].RIR; + uint32_t id; + if ((rir & CAN_RI0R_IDE) != 0U) + { + id = ((rir >> CAN_RI0R_EXID_Pos) & 0x1FFFFFFFU) | 0x80000000U; + } + else + { + id = (rir >> CAN_RI0R_STID_Pos) & 0x7FFU; + } + + // Filter check using BitFieldFilter byte array (if provided) + if (filterBitField != nullptr) + { + uint32_t byteIndex = id / 8U; + uint32_t bitIndex = id % 8U; + if ((filterBitField[byteIndex] & (1U << bitIndex)) == 0U) + { + can->RF0R |= CAN_RF0R_RFOM0; + continue; + } + } + + // Read DLC and data + uint8_t dlc = static_cast(can->sFIFOMailBox[0].RDTR & 0xFU); + uint32_t rdlr = can->sFIFOMailBox[0].RDLR; + uint32_t rdhr = can->sFIFOMailBox[0].RDHR; + + uint8_t data[8]; + data[0] = static_cast(rdlr); + data[1] = static_cast(rdlr >> 8U); + data[2] = static_cast(rdlr >> 16U); + data[3] = static_cast(rdlr >> 24U); + data[4] = static_cast(rdhr); + data[5] = static_cast(rdhr >> 8U); + data[6] = static_cast(rdhr >> 16U); + data[7] = static_cast(rdhr >> 24U); + + // Store in queue + uint8_t idx = (fRxHead + fRxCount) % RX_QUEUE_SIZE; + fRxQueue[idx] = ::can::CANFrame(id, data, dlc); + fRxCount++; + received++; + + // Release FIFO entry + can->RF0R |= CAN_RF0R_RFOM0; + } + + return received; +} + +void BxCanDevice::transmitISR() +{ + // Clear TX request completed flags + fConfig.baseAddress->TSR |= CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2; + + // Disable TMEIE if all mailboxes are now empty (prevents spurious interrupts) + if ((fConfig.baseAddress->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) + == (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) + { + fConfig.baseAddress->IER &= ~CAN_IER_TMEIE; + } +} + +bool BxCanDevice::isBusOff() const { return (fConfig.baseAddress->ESR & CAN_ESR_BOFF) != 0U; } + +uint8_t BxCanDevice::getTxErrorCounter() const +{ + return static_cast((fConfig.baseAddress->ESR >> CAN_ESR_TEC_Pos) & 0xFFU); +} + +uint8_t BxCanDevice::getRxErrorCounter() const +{ + return static_cast((fConfig.baseAddress->ESR >> CAN_ESR_REC_Pos) & 0xFFU); +} + +void BxCanDevice::configureAcceptAllFilter() +{ + // Filter bank 0: accept all standard + extended frames into FIFO0 + CAN_TypeDef* can = fConfig.baseAddress; + can->FMR |= CAN_FMR_FINIT; // Enter filter init mode + can->FA1R &= ~(1U << 0U); // Deactivate filter 0 + can->sFilterRegister[0].FR1 = 0U; // ID = 0 (don't care) + can->sFilterRegister[0].FR2 = 0U; // Mask = 0 (accept all) + can->FS1R |= (1U << 0U); // 32-bit scale + can->FM1R &= ~(1U << 0U); // Mask mode (not list) + can->FFA1R &= ~(1U << 0U); // Assign to FIFO0 + can->FA1R |= (1U << 0U); // Activate filter 0 + can->FMR &= ~CAN_FMR_FINIT; // Leave filter init mode +} + +void BxCanDevice::configureFilterList(uint32_t const* idList, uint8_t count) +{ + CAN_TypeDef* can = fConfig.baseAddress; + can->FMR |= CAN_FMR_FINIT; + + // Use filter banks 0..N/2 in 32-bit list mode (2 IDs per bank) + uint8_t bankIdx = 0U; + for (uint8_t i = 0U; i < count && bankIdx < 14U; i += 2U, bankIdx++) + { + can->FA1R &= ~(1U << bankIdx); + can->FS1R |= (1U << bankIdx); // 32-bit scale + can->FM1R |= (1U << bankIdx); // List mode + + // Standard IDs shifted to STID position + can->sFilterRegister[bankIdx].FR1 = (idList[i] << CAN_RI0R_STID_Pos); + if ((i + 1U) < count) + { + can->sFilterRegister[bankIdx].FR2 = (idList[i + 1U] << CAN_RI0R_STID_Pos); + } + else + { + can->sFilterRegister[bankIdx].FR2 = (idList[i] << CAN_RI0R_STID_Pos); + } + + can->FFA1R &= ~(1U << bankIdx); // FIFO0 + can->FA1R |= (1U << bankIdx); // Activate + } + + can->FMR &= ~CAN_FMR_FINIT; +} + +::can::CANFrame const& BxCanDevice::getRxFrame(uint8_t index) const +{ + return fRxQueue[(fRxHead + index) % RX_QUEUE_SIZE]; +} + +uint8_t BxCanDevice::getRxCount() const { return fRxCount; } + +void BxCanDevice::clearRxQueue() +{ + fRxHead = (fRxHead + fRxCount) % RX_QUEUE_SIZE; + fRxCount = 0U; +} + +void BxCanDevice::disableRxInterrupt() { fConfig.baseAddress->IER &= ~CAN_IER_FMPIE0; } + +void BxCanDevice::enableRxInterrupt() { fConfig.baseAddress->IER |= CAN_IER_FMPIE0; } + +} // namespace bios diff --git a/platforms/stm32/bsp/bspCan/src/can/FdCanDevice.cpp b/platforms/stm32/bsp/bspCan/src/can/FdCanDevice.cpp new file mode 100644 index 00000000000..bfb4021b97f --- /dev/null +++ b/platforms/stm32/bsp/bspCan/src/can/FdCanDevice.cpp @@ -0,0 +1,485 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +namespace bios +{ + +// STM32G4 FDCAN message RAM layout (fixed, per instance): +// Each FDCAN instance has 212 words (848 bytes) of message RAM. +// FDCAN1 starts at SRAMCAN_BASE + 0x000 +// FDCAN2 starts at SRAMCAN_BASE + 0x350 +// FDCAN3 starts at SRAMCAN_BASE + 0x6A0 +// +// Layout within each instance (offsets from instance base; RX/TX elements +// are spaced 18 words / 72 bytes apart regardless of configured data size): +// Standard ID filters: 28 elements x 1 word = 28 words (0x000 - 0x06F) +// Extended ID filters: 8 elements x 2 words = 16 words (0x070 - 0x0AF) +// RX FIFO0: 3 elements x 18 words = 54 words (0x0B0 - 0x187) +// RX FIFO1: 3 elements x 18 words = 54 words (0x188 - 0x25F) +// TX Event FIFO: 3 elements x 2 words = 6 words (0x260 - 0x277) +// TX Buffers: 3 elements x 18 words = 54 words (0x278 - 0x34F) + +// uintptr_t so host unit tests with 64-bit fake RAM addresses work; on the +// 32-bit target this is identical to uint32_t. +static uintptr_t getInstanceRamBase(FDCAN_GlobalTypeDef* fdcan) +{ + if (fdcan == FDCAN1) + { + return SRAMCAN_BASE; + } +#if defined(FDCAN2) + if (fdcan == FDCAN2) + { + return SRAMCAN_BASE + 0x350U; + } +#endif +#if defined(FDCAN3) + if (fdcan == FDCAN3) + { + return SRAMCAN_BASE + 0x6A0U; + } +#endif + return SRAMCAN_BASE; +} + +static constexpr uint32_t STD_FILTER_OFFSET = 0x000U; +static constexpr uint32_t RX_FIFO0_OFFSET = 0x0B0U; +// STM32G4 message RAM: TX buffers at 0x278 (not 0x128 as standard M_CAN) +static constexpr uint32_t TX_BUFFER_OFFSET = 0x278U; + +FdCanDevice::FdCanDevice(Config const& config) +: fConfig(config), fRxQueue{}, fRxHead(0U), fRxCount(0U), fInitialized(false), fFrameSentCallback() +{} + +FdCanDevice::FdCanDevice(Config const& config, ::etl::delegate frameSentCallback) +: fConfig(config) +, fRxQueue{} +, fRxHead(0U) +, fRxCount(0U) +, fInitialized(false) +, fFrameSentCallback(frameSentCallback) +{} + +void FdCanDevice::enablePeripheralClock() +{ + // Enable FDCAN clock on APB1 + RCC->APB1ENR1 |= RCC_APB1ENR1_FDCANEN; + uint32_t volatile dummy = RCC->APB1ENR1; + (void)dummy; + + // Select FDCAN kernel clock = PCLK1 (FDCANSEL=10 in CCIPR1[25:24]) + // Default after reset is HSE (00), which may not be enabled. + RCC->CCIPR = (RCC->CCIPR & ~(3U << 24U)) | (2U << 24U); +} + +void FdCanDevice::configureGpio() +{ + GPIO_TypeDef* txPort = fConfig.txGpioPort; + GPIO_TypeDef* rxPort = fConfig.rxGpioPort; + + txPort->MODER &= ~(3U << (fConfig.txPin * 2U)); + txPort->MODER |= (2U << (fConfig.txPin * 2U)); + txPort->OSPEEDR |= (3U << (fConfig.txPin * 2U)); + if (fConfig.txPin < 8U) + { + txPort->AFR[0] &= ~(0xFU << (fConfig.txPin * 4U)); + txPort->AFR[0] |= (static_cast(fConfig.txAf) << (fConfig.txPin * 4U)); + } + else + { + txPort->AFR[1] &= ~(0xFU << ((fConfig.txPin - 8U) * 4U)); + txPort->AFR[1] |= (static_cast(fConfig.txAf) << ((fConfig.txPin - 8U) * 4U)); + } + + rxPort->MODER &= ~(3U << (fConfig.rxPin * 2U)); + rxPort->MODER |= (2U << (fConfig.rxPin * 2U)); + rxPort->PUPDR &= ~(3U << (fConfig.rxPin * 2U)); + rxPort->PUPDR |= (1U << (fConfig.rxPin * 2U)); + if (fConfig.rxPin < 8U) + { + rxPort->AFR[0] &= ~(0xFU << (fConfig.rxPin * 4U)); + rxPort->AFR[0] |= (static_cast(fConfig.rxAf) << (fConfig.rxPin * 4U)); + } + else + { + rxPort->AFR[1] &= ~(0xFU << ((fConfig.rxPin - 8U) * 4U)); + rxPort->AFR[1] |= (static_cast(fConfig.rxAf) << ((fConfig.rxPin - 8U) * 4U)); + } +} + +static constexpr uint32_t INIT_TIMEOUT_CYCLES = 100000U; + +bool FdCanDevice::enterInitMode() +{ + fConfig.baseAddress->CCCR |= FDCAN_CCCR_INIT; + uint32_t timeout = INIT_TIMEOUT_CYCLES; + while ((fConfig.baseAddress->CCCR & FDCAN_CCCR_INIT) == 0U) + { + if (--timeout == 0U) + { + return false; + } + } + // Enable configuration change + fConfig.baseAddress->CCCR |= FDCAN_CCCR_CCE; + return true; +} + +bool FdCanDevice::leaveInitMode() +{ + fConfig.baseAddress->CCCR &= ~FDCAN_CCCR_INIT; + uint32_t timeout = INIT_TIMEOUT_CYCLES; + while ((fConfig.baseAddress->CCCR & FDCAN_CCCR_INIT) != 0U) + { + if (--timeout == 0U) + { + return false; + } + } + return true; +} + +void FdCanDevice::configureBitTiming() +{ + // Nominal bit timing for classic CAN mode + // NBTP: NSJW | NBRP | NTSEG1 | NTSEG2 + fConfig.baseAddress->NBTP = ((fConfig.nsjw) << FDCAN_NBTP_NSJW_Pos) + | ((fConfig.prescaler - 1U) << FDCAN_NBTP_NBRP_Pos) + | ((fConfig.nts1) << FDCAN_NBTP_NTSEG1_Pos) + | ((fConfig.nts2) << FDCAN_NBTP_NTSEG2_Pos); +} + +void FdCanDevice::configureMessageRam() +{ + // STM32G4 has fixed message RAM layout - no configuration registers. + // RXGFC configures global filter behavior and list sizes only. + fConfig.baseAddress->RXGFC = (0U << FDCAN_RXGFC_LSS_Pos) | (0U << FDCAN_RXGFC_LSE_Pos); + + // TX buffer: use FIFO/queue mode + fConfig.baseAddress->TXBC = 0U; // FIFO mode (TFQM=0) +} + +bool FdCanDevice::init() +{ + enablePeripheralClock(); + configureGpio(); + + if (!enterInitMode()) + { + return false; + } + + // Classic CAN mode (no FD), auto retransmission disabled + fConfig.baseAddress->CCCR &= ~FDCAN_CCCR_FDOE; + fConfig.baseAddress->CCCR &= ~FDCAN_CCCR_BRSE; + + configureBitTiming(); + configureMessageRam(); + configureAcceptAllFilter(); + + fInitialized = true; + return true; +} + +bool FdCanDevice::start() +{ + if (!fInitialized) + { + return false; + } + + // Configure HW filter in init mode (before leaveInitMode) + if (fFilterIds != nullptr && fFilterCount > 0U) + { + configureFilterList(fFilterIds, fFilterCount); + } + else + { + configureAcceptAllFilter(); + } + + // Enable RX interrupt only at startup. TCE is managed per-TX by + // transmit(frame, true) and disabled by transmitISR() - matching S32K's + // selective per-buffer interrupt enable/disable pattern. + fConfig.baseAddress->IE = FDCAN_IE_RF0NE; + fConfig.baseAddress->ILS = 0U; + fConfig.baseAddress->ILE = FDCAN_ILE_EINT0; + fConfig.baseAddress->TXBTIE = 0x7U; // Required for TC generation per RM0440 + + if (!leaveInitMode()) + { + return false; + } + + // Write IE again after leaving init mode (persistence workaround). + fConfig.baseAddress->IE = FDCAN_IE_RF0NE; + return true; +} + +void FdCanDevice::stop() +{ + fConfig.baseAddress->IE &= ~(FDCAN_IE_RF0NE | FDCAN_IE_TCE); + enterInitMode(); +} + +bool FdCanDevice::transmit(::can::CANFrame const& frame) +{ + FDCAN_GlobalTypeDef* fdcan = fConfig.baseAddress; + + // Check TX FIFO free level + if ((fdcan->TXFQS & FDCAN_TXFQS_TFFL) == 0U) + { + return false; // TX FIFO full + } + + // Get put index + uint32_t putIdx = (fdcan->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos; + + // Calculate TX buffer element address in message RAM + // STM32G4 FDCAN uses 18-word (72-byte) element spacing in message RAM, + // regardless of configured data field size (TXESC). Section boundaries + // are fixed at max element size. + static constexpr uint32_t TX_ELEMENT_SIZE = 72U; // 18 words x 4 bytes + uintptr_t ramBase = getInstanceRamBase(fdcan); + uint32_t* txBuf + = reinterpret_cast(ramBase + TX_BUFFER_OFFSET + (putIdx * TX_ELEMENT_SIZE)); + + // Word 0: ID + uint32_t id = frame.getId(); + if ((id & 0x80000000U) != 0U) + { + txBuf[0] = ((id & 0x1FFFFFFFU)) | (1U << 30U); // XTD bit + } + else + { + txBuf[0] = ((id & 0x7FFU) << 18U); + } + + // Word 1: DLC, no FD, no BRS + uint8_t dlc = frame.getPayloadLength(); + txBuf[1] = (static_cast(dlc) << 16U); + + // Words 2-3: Data + uint8_t const* data = frame.getPayload(); + txBuf[2] = static_cast(data[0]) | (static_cast(data[1]) << 8U) + | (static_cast(data[2]) << 16U) | (static_cast(data[3]) << 24U); + txBuf[3] = static_cast(data[4]) | (static_cast(data[5]) << 8U) + | (static_cast(data[6]) << 16U) | (static_cast(data[7]) << 24U); + + // Request transmission + fdcan->TXBAR = (1U << putIdx); + + return true; +} + +bool FdCanDevice::transmit(::can::CANFrame const& frame, bool txInterruptNeeded) +{ + if (txInterruptNeeded) + { + // Match S32K enableTransmitInterrupt(): clear flag first, then enable mask. + // FlexCANDevice.h:132-136: + // fpDevice->IFLAG1 = fTxInterruptMask0; // clear flag + // fpDevice->IMASK1 |= fTxInterruptMask0; // enable mask + fConfig.baseAddress->IR = FDCAN_IR_TC; // clear stale TC flag + fConfig.baseAddress->IE |= FDCAN_IE_TCE; // enable TC interrupt + } + // S32K: enableTransmitInterrupt() called BEFORE CODE=TRANSMIT. + // Here: TCE enabled BEFORE TXBAR write (inside transmit()). + return transmit(frame); +} + +} // namespace bios + +namespace bios +{ // reopen + +uint8_t FdCanDevice::receiveISR(uint8_t const* filterBitField) +{ + FDCAN_GlobalTypeDef* fdcan = fConfig.baseAddress; + uintptr_t ramBase = getInstanceRamBase(fdcan); + uint8_t received = 0U; + + // NOTE: RF0NE disable moved to CanSystem ISR trampoline (if needed). + // Disabling here is unsafe because receiveTask() may not run if the + // async dispatch is dedup-dropped, permanently blocking all RX. + + // NOTE: RF0L (message lost) is cleared below with RF0N and RF0F. + // Production code could increment an overrun counter here if needed. + + // Clear RF0N BEFORE reading F0FL so late arrivals re-trigger ISR + // (once RF0NE is re-enabled by receiveTask). + fdcan->IR = FDCAN_IR_RF0N | FDCAN_IR_RF0F | FDCAN_IR_RF0L; + + // Snapshot fill level - drain only what's here now. + uint8_t toDrain + = static_cast((fdcan->RXF0S & FDCAN_RXF0S_F0FL) >> FDCAN_RXF0S_F0FL_Pos); + + while (toDrain > 0U) + { + toDrain--; + + if (fRxCount >= RX_QUEUE_SIZE) + { + // Acknowledge without storing + uint32_t getIdx = (fdcan->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos; + fdcan->RXF0A = getIdx; + continue; + } + + uint32_t getIdx = (fdcan->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos; + + // Read RX FIFO element from message RAM + // STM32G4 FDCAN uses 18-word (72-byte) element spacing in message RAM. + static constexpr uint32_t RX_ELEMENT_SIZE = 72U; // 18 words x 4 bytes + uint32_t const* rxBuf = reinterpret_cast( + ramBase + RX_FIFO0_OFFSET + (getIdx * RX_ELEMENT_SIZE)); + + // Word 0: ID + uint32_t r0 = rxBuf[0]; + uint32_t id; + if ((r0 & (1U << 30U)) != 0U) + { + id = (r0 & 0x1FFFFFFFU) | 0x80000000U; // Extended + } + else + { + id = (r0 >> 18U) & 0x7FFU; // Standard + } + + if (filterBitField != nullptr) + { + uint32_t byteIndex = id / 8U; + uint32_t bitIndex = id % 8U; + if ((filterBitField[byteIndex] & (1U << bitIndex)) == 0U) + { + fdcan->RXF0A = getIdx; + continue; + } + } + + // Word 1: DLC + uint32_t r1 = rxBuf[1]; + uint8_t dlc = static_cast((r1 >> 16U) & 0xFU); + + // Words 2-3: Data + uint32_t d0 = rxBuf[2]; + uint32_t d1 = rxBuf[3]; + uint8_t data[8]; + data[0] = static_cast(d0); + data[1] = static_cast(d0 >> 8U); + data[2] = static_cast(d0 >> 16U); + data[3] = static_cast(d0 >> 24U); + data[4] = static_cast(d1); + data[5] = static_cast(d1 >> 8U); + data[6] = static_cast(d1 >> 16U); + data[7] = static_cast(d1 >> 24U); + + // Store in queue + uint8_t idx = (fRxHead + fRxCount) % RX_QUEUE_SIZE; + fRxQueue[idx] = ::can::CANFrame(id, data, dlc); + fRxCount++; + received++; + + // Acknowledge + fdcan->RXF0A = getIdx; + } + + // RF0N was already cleared at entry - no need to clear again here. + // Any frame arriving during the drain loop will re-set RF0N and + // trigger a new ISR after we return. + return received; +} + +void FdCanDevice::transmitISR() +{ + FDCAN_GlobalTypeDef* fdcan = fConfig.baseAddress; + + // Disable TCE (match S32K disableTransmitInterrupt pattern) + fdcan->IE &= ~FDCAN_IE_TCE; + + // Clear TC flag + fdcan->IR = FDCAN_IR_TC; + + // Invoke callback delegate if set (match FlexCANDevice::transmitISR) + if (fFrameSentCallback.is_valid()) + { + fFrameSentCallback(); + } +} + +bool FdCanDevice::isBusOff() const { return (fConfig.baseAddress->PSR & FDCAN_PSR_BO) != 0U; } + +uint8_t FdCanDevice::getTxErrorCounter() const +{ + return static_cast((fConfig.baseAddress->ECR >> FDCAN_ECR_TEC_Pos) & 0xFFU); +} + +uint8_t FdCanDevice::getRxErrorCounter() const +{ + return static_cast((fConfig.baseAddress->ECR >> FDCAN_ECR_REC_Pos) & 0x7FU); +} + +void FdCanDevice::configureAcceptAllFilter() +{ + // Accept all frames: set global filter to accept non-matching into FIFO0 + fConfig.baseAddress->RXGFC + = (0U << FDCAN_RXGFC_ANFS_Pos) // Accept non-matching std into RX FIFO0 + | (0U << FDCAN_RXGFC_ANFE_Pos); // Accept non-matching ext into RX FIFO0 +} + +void FdCanDevice::configureFilterList(uint32_t const* idList, uint8_t count) +{ + uintptr_t ramBase = getInstanceRamBase(fConfig.baseAddress); + + // Reject non-matching, configure standard ID filter elements + fConfig.baseAddress->RXGFC = (2U << FDCAN_RXGFC_ANFS_Pos) // Reject non-matching std + | (2U << FDCAN_RXGFC_ANFE_Pos) // Reject non-matching ext + | (static_cast(count) << FDCAN_RXGFC_LSS_Pos); + + // Write filter elements to message RAM (standard filter area) + uint32_t* filterRam = reinterpret_cast(ramBase + STD_FILTER_OFFSET); + + for (uint8_t i = 0U; i < count && i < 28U; i++) + { + // Standard filter element: classic filter (ID + mask) for exact match + // SFT = 10 (classic), SFEC = 001 (store in RX FIFO0) + // SFID1 = target ID, SFID2 = 0x7FF (all 11 bits must match) + filterRam[i] = (2U << 30U) // SFT = 10 (classic filter) + | (1U << 27U) // SFEC = store in FIFO0 + | ((idList[i] & 0x7FFU) << 16U) // SFID1 = filter ID + | 0x7FFU; // SFID2 = mask (exact match) + } +} + +::can::CANFrame const& FdCanDevice::getRxFrame(uint8_t index) const +{ + return fRxQueue[(fRxHead + index) % RX_QUEUE_SIZE]; +} + +uint8_t FdCanDevice::getRxCount() const { return fRxCount; } + +void FdCanDevice::clearRxQueue() +{ + fRxHead = (fRxHead + fRxCount) % RX_QUEUE_SIZE; + fRxCount = 0U; +} + +void FdCanDevice::disableRxInterrupt() { fConfig.baseAddress->IE &= ~FDCAN_IE_RF0NE; } + +void FdCanDevice::enableRxInterrupt() { fConfig.baseAddress->IE |= FDCAN_IE_RF0NE; } + +uint32_t FdCanDevice::getHwFifoFillLevel() const +{ + return (fConfig.baseAddress->RXF0S & FDCAN_RXF0S_F0FL) >> FDCAN_RXF0S_F0FL_Pos; +} + +} // namespace bios diff --git a/platforms/stm32/bsp/bspCan/test/CMakeLists.txt b/platforms/stm32/bsp/bspCan/test/CMakeLists.txt new file mode 100644 index 00000000000..08d6151d36e --- /dev/null +++ b/platforms/stm32/bsp/bspCan/test/CMakeLists.txt @@ -0,0 +1,15 @@ +add_executable(BxCanDeviceTest src/can/BxCanDeviceTest.cpp) + +target_include_directories(BxCanDeviceTest PRIVATE include ../include ../src) + +target_link_libraries(BxCanDeviceTest PRIVATE cpp2can etl gmock gtest_main) + +gtest_discover_tests(BxCanDeviceTest PROPERTIES LABELS "BxCanDeviceTest") + +add_executable(FdCanDeviceTest src/can/FdCanDeviceTest.cpp) + +target_include_directories(FdCanDeviceTest PRIVATE include ../include ../src) + +target_link_libraries(FdCanDeviceTest PRIVATE cpp2can etl gmock gtest_main) + +gtest_discover_tests(FdCanDeviceTest PROPERTIES LABELS "FdCanDeviceTest") diff --git a/platforms/stm32/bsp/bspCan/test/include/mcu/mcu.h b/platforms/stm32/bsp/bspCan/test/include/mcu/mcu.h new file mode 100644 index 00000000000..4b86cd649d5 --- /dev/null +++ b/platforms/stm32/bsp/bspCan/test/include/mcu/mcu.h @@ -0,0 +1,12 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// Fake mcu.h for unit tests - types defined in test file +#pragma once diff --git a/platforms/stm32/bsp/bspCan/test/src/can/BxCanDeviceTest.cpp b/platforms/stm32/bsp/bspCan/test/src/can/BxCanDeviceTest.cpp new file mode 100644 index 00000000000..0867d082632 --- /dev/null +++ b/platforms/stm32/bsp/bspCan/test/src/can/BxCanDeviceTest.cpp @@ -0,0 +1,4110 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// Test-only hardware fakes - must be defined before any STM32 header inclusion. + +#include +#include +#include +#include +#include + +// Provide __IO as volatile (same as CMSIS) +#ifndef __IO +#define __IO volatile +#endif + +// --- Fake GPIO_TypeDef (matches STM32F4 layout) --- +typedef struct +{ + __IO uint32_t MODER; + __IO uint32_t OTYPER; + __IO uint32_t OSPEEDR; + __IO uint32_t PUPDR; + __IO uint32_t IDR; + __IO uint32_t ODR; + __IO uint32_t BSRR; + __IO uint32_t LCKR; + __IO uint32_t AFR[2]; + __IO uint32_t BRR; +} GPIO_TypeDef; + +// --- Fake RCC_TypeDef (matches STM32F4 layout - need APB1ENR) --- +typedef struct +{ + __IO uint32_t CR; + __IO uint32_t PLLCFGR; + __IO uint32_t CFGR; + __IO uint32_t CIR; + __IO uint32_t AHB1RSTR; + __IO uint32_t AHB2RSTR; + __IO uint32_t AHB3RSTR; + uint32_t RESERVED0; + __IO uint32_t APB1RSTR; + __IO uint32_t APB2RSTR; + uint32_t RESERVED1[2]; + __IO uint32_t AHB1ENR; + __IO uint32_t AHB2ENR; + __IO uint32_t AHB3ENR; + uint32_t RESERVED2; + __IO uint32_t APB1ENR; + __IO uint32_t APB2ENR; + uint32_t RESERVED3[2]; + __IO uint32_t AHB1LPENR; + __IO uint32_t AHB2LPENR; + __IO uint32_t AHB3LPENR; + uint32_t RESERVED4; + __IO uint32_t APB1LPENR; + __IO uint32_t APB2LPENR; + uint32_t RESERVED5[2]; + __IO uint32_t BDCR; + __IO uint32_t CSR; + uint32_t RESERVED6[2]; + __IO uint32_t SSCGR; + __IO uint32_t PLLI2SCFGR; +} RCC_TypeDef; + +// --- Fake CAN TX mailbox --- +typedef struct +{ + __IO uint32_t TIR; + __IO uint32_t TDTR; + __IO uint32_t TDLR; + __IO uint32_t TDHR; +} CAN_TxMailBox_TypeDef; + +// --- Fake CAN FIFO mailbox --- +typedef struct +{ + __IO uint32_t RIR; + __IO uint32_t RDTR; + __IO uint32_t RDLR; + __IO uint32_t RDHR; +} CAN_FIFOMailBox_TypeDef; + +// --- Fake CAN filter register --- +typedef struct +{ + __IO uint32_t FR1; + __IO uint32_t FR2; +} CAN_FilterRegister_TypeDef; + +// --- Fake CAN_TypeDef (matches STM32F4 layout) --- +// MSR.INAK (bit 0) must mirror MCR.INRQ (bit 0) for init mode busy-waits. +// We use a C++ struct with a getter-like mechanism: a helper function +// called before each test ensures MSR tracks MCR. +typedef struct +{ + __IO uint32_t MCR; + __IO uint32_t MSR; + __IO uint32_t TSR; + __IO uint32_t RF0R; + __IO uint32_t RF1R; + __IO uint32_t IER; + __IO uint32_t ESR; + __IO uint32_t BTR; + uint32_t RESERVED0[88]; + CAN_TxMailBox_TypeDef sTxMailBox[3]; + CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; + uint32_t RESERVED1[12]; + __IO uint32_t FMR; + __IO uint32_t FM1R; + uint32_t RESERVED2; + __IO uint32_t FS1R; + uint32_t RESERVED3; + __IO uint32_t FFA1R; + uint32_t RESERVED4; + __IO uint32_t FA1R; + uint32_t RESERVED5[8]; + CAN_FilterRegister_TypeDef sFilterRegister[28]; +} CAN_TypeDef; + +// Hook: sync MSR.INAK to match MCR.INRQ after production code writes MCR. +// We patch this into the production code's enterInitMode/leaveInitMode by +// redefining the MSR register read to auto-sync from MCR first. +// CAN_MSR_INAK is bit 0, CAN_MCR_INRQ is bit 0 - same position. +// Override CAN1 macro +#define CAN1 (&fakeCan) + +// --- Static fake peripherals --- +static RCC_TypeDef fakeRcc; +static CAN_TypeDef fakeCan; +static GPIO_TypeDef fakeTxGpio; +static GPIO_TypeDef fakeRxGpio; + +// --- Override hardware macros to point at our fakes --- +#define RCC (&fakeRcc) +#define CAN1 (&fakeCan) + +// --- bxCAN register bit definitions (from stm32f413xx.h / stm32f4xx.h) --- + +// MCR bits +#define CAN_MCR_INRQ_Pos (0U) +#define CAN_MCR_INRQ (0x1UL << CAN_MCR_INRQ_Pos) +#define CAN_MCR_SLEEP_Pos (1U) +#define CAN_MCR_SLEEP (0x1UL << CAN_MCR_SLEEP_Pos) +#define CAN_MCR_TXFP_Pos (2U) +#define CAN_MCR_TXFP (0x1UL << CAN_MCR_TXFP_Pos) +#define CAN_MCR_RFLM_Pos (3U) +#define CAN_MCR_RFLM (0x1UL << CAN_MCR_RFLM_Pos) +#define CAN_MCR_NART_Pos (4U) +#define CAN_MCR_NART (0x1UL << CAN_MCR_NART_Pos) +#define CAN_MCR_AWUM_Pos (5U) +#define CAN_MCR_AWUM (0x1UL << CAN_MCR_AWUM_Pos) +#define CAN_MCR_ABOM_Pos (6U) +#define CAN_MCR_ABOM (0x1UL << CAN_MCR_ABOM_Pos) +#define CAN_MCR_TTCM_Pos (7U) +#define CAN_MCR_TTCM (0x1UL << CAN_MCR_TTCM_Pos) + +// MSR bits +#define CAN_MSR_INAK_Pos (0U) +#define CAN_MSR_INAK (0x1UL << CAN_MSR_INAK_Pos) + +// TSR bits +#define CAN_TSR_RQCP0_Pos (0U) +#define CAN_TSR_RQCP0 (0x1UL << CAN_TSR_RQCP0_Pos) +#define CAN_TSR_RQCP1_Pos (8U) +#define CAN_TSR_RQCP1 (0x1UL << CAN_TSR_RQCP1_Pos) +#define CAN_TSR_RQCP2_Pos (16U) +#define CAN_TSR_RQCP2 (0x1UL << CAN_TSR_RQCP2_Pos) +#define CAN_TSR_TME0_Pos (26U) +#define CAN_TSR_TME0 (0x1UL << CAN_TSR_TME0_Pos) +#define CAN_TSR_TME1_Pos (27U) +#define CAN_TSR_TME1 (0x1UL << CAN_TSR_TME1_Pos) +#define CAN_TSR_TME2_Pos (28U) +#define CAN_TSR_TME2 (0x1UL << CAN_TSR_TME2_Pos) + +// RF0R bits +#define CAN_RF0R_FMP0_Pos (0U) +#define CAN_RF0R_FMP0 (0x3UL << CAN_RF0R_FMP0_Pos) +#define CAN_RF0R_FOVR0_Pos (4U) +#define CAN_RF0R_FOVR0 (0x1UL << CAN_RF0R_FOVR0_Pos) +#define CAN_RF0R_RFOM0_Pos (5U) +#define CAN_RF0R_RFOM0 (0x1UL << CAN_RF0R_RFOM0_Pos) + +// IER bits +#define CAN_IER_TMEIE_Pos (0U) +#define CAN_IER_TMEIE (0x1UL << CAN_IER_TMEIE_Pos) +#define CAN_IER_FMPIE0_Pos (1U) +#define CAN_IER_FMPIE0 (0x1UL << CAN_IER_FMPIE0_Pos) + +// ESR bits +#define CAN_ESR_BOFF_Pos (2U) +#define CAN_ESR_BOFF (0x1UL << CAN_ESR_BOFF_Pos) +#define CAN_ESR_TEC_Pos (16U) +#define CAN_ESR_REC_Pos (24U) + +// BTR bits +#define CAN_BTR_BRP_Pos (0U) +#define CAN_BTR_TS1_Pos (16U) +#define CAN_BTR_TS2_Pos (20U) +#define CAN_BTR_SJW_Pos (24U) +#define CAN_BTR_SILM_Pos (31U) +#define CAN_BTR_SILM (0x1UL << CAN_BTR_SILM_Pos) +#define CAN_BTR_LBKM_Pos (30U) +#define CAN_BTR_LBKM (0x1UL << CAN_BTR_LBKM_Pos) + +// TIR bits (TX mailbox identifier register) +#define CAN_TI0R_TXRQ_Pos (0U) +#define CAN_TI0R_TXRQ (0x1UL << CAN_TI0R_TXRQ_Pos) +#define CAN_TI0R_RTR_Pos (1U) +#define CAN_TI0R_RTR (0x1UL << CAN_TI0R_RTR_Pos) +#define CAN_TI0R_IDE_Pos (2U) +#define CAN_TI0R_IDE (0x1UL << CAN_TI0R_IDE_Pos) +#define CAN_TI0R_EXID_Pos (3U) +#define CAN_TI0R_STID_Pos (21U) + +// RIR bits (RX mailbox identifier register) +#define CAN_RI0R_RTR_Pos (1U) +#define CAN_RI0R_RTR (0x1UL << CAN_RI0R_RTR_Pos) +#define CAN_RI0R_IDE_Pos (2U) +#define CAN_RI0R_IDE (0x1UL << CAN_RI0R_IDE_Pos) +#define CAN_RI0R_EXID_Pos (3U) +#define CAN_RI0R_STID_Pos (21U) + +// FMR bits +#define CAN_FMR_FINIT_Pos (0U) +#define CAN_FMR_FINIT (0x1UL << CAN_FMR_FINIT_Pos) + +// RCC APB1ENR +#define RCC_APB1ENR_CAN1EN_Pos (25U) +#define RCC_APB1ENR_CAN1EN (0x1UL << RCC_APB1ENR_CAN1EN_Pos) + +// Prevent the real mcu.h from being included +#define MCU_MCU_H +#define MCU_TYPEDEFS_H + +// Provide the CANFrame include path directly +#include + +// Now include the driver header - it will see our faked types +#include + +// Include the implementation directly so it compiles with our fakes. +#include + +#include + +class BxCanDeviceTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Zero all fake peripherals + memset(&fakeRcc, 0, sizeof(fakeRcc)); + memset(&fakeCan, 0, sizeof(fakeCan)); + memset(&fakeTxGpio, 0, sizeof(fakeTxGpio)); + memset(&fakeRxGpio, 0, sizeof(fakeRxGpio)); + + // The MSR.INAK bit: after setting MCR.INRQ, the hardware sets INAK. + // In our fake, writing to MCR doesn't auto-set MSR.INAK, so we + // pre-set it so enterInitMode's while-loop terminates immediately. + fakeCan.MSR = CAN_MSR_INAK; + } + + bios::BxCanDevice::Config makeDefaultConfig() + { + bios::BxCanDevice::Config cfg{}; + cfg.baseAddress = &fakeCan; + cfg.prescaler = 4U; // BRP = prescaler - 1 = 3 + cfg.bs1 = 13U; // TS1 + cfg.bs2 = 2U; // TS2 + cfg.sjw = 1U; // SJW + cfg.rxGpioPort = &fakeRxGpio; + cfg.rxPin = 11U; // PA11 (high pin, tests AFR[1] path) + cfg.rxAf = 9U; // AF9 + cfg.txGpioPort = &fakeTxGpio; + cfg.txPin = 5U; // PB5 (low pin, tests AFR[0] path) + cfg.txAf = 9U; // AF9 + return cfg; + } + + // Helper: put device into initialized state + std::unique_ptr makeInitedDevice() + { + auto cfg = makeDefaultConfig(); + auto dev = std::make_unique(cfg); + dev->init(); + return dev; + } + + // Helper: put device into initialized + started state + std::unique_ptr makeStartedDevice() + { + auto dev = makeInitedDevice(); + // Clear INAK so leaveInitMode succeeds + fakeCan.MSR &= ~CAN_MSR_INAK; + // Mark all TX mailboxes empty + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->start(); + return dev; + } + + // Helper: place a standard frame in RX FIFO0 + void placeRxFrameStd(uint32_t canId, uint8_t dlc, uint8_t const* data) + { + fakeCan.sFIFOMailBox[0].RIR = (canId << CAN_RI0R_STID_Pos); + fakeCan.sFIFOMailBox[0].RDTR = dlc & 0xFU; + if (data != nullptr) + { + fakeCan.sFIFOMailBox[0].RDLR = static_cast(data[0]) + | (static_cast(data[1]) << 8U) + | (static_cast(data[2]) << 16U) + | (static_cast(data[3]) << 24U); + fakeCan.sFIFOMailBox[0].RDHR = static_cast(data[4]) + | (static_cast(data[5]) << 8U) + | (static_cast(data[6]) << 16U) + | (static_cast(data[7]) << 24U); + } + } + + // Helper: place an extended frame in RX FIFO0 + void placeRxFrameExt(uint32_t canId, uint8_t dlc, uint8_t const* data) + { + fakeCan.sFIFOMailBox[0].RIR = ((canId & 0x1FFFFFFFU) << CAN_RI0R_EXID_Pos) | CAN_RI0R_IDE; + fakeCan.sFIFOMailBox[0].RDTR = dlc & 0xFU; + if (data != nullptr) + { + fakeCan.sFIFOMailBox[0].RDLR = static_cast(data[0]) + | (static_cast(data[1]) << 8U) + | (static_cast(data[2]) << 16U) + | (static_cast(data[3]) << 24U); + fakeCan.sFIFOMailBox[0].RDHR = static_cast(data[4]) + | (static_cast(data[5]) << 8U) + | (static_cast(data[6]) << 16U) + | (static_cast(data[7]) << 24U); + } + } + + // Simulate FIFO with N frames: set FMP0 to N, then on each RFOM write + // decrement. For simplicity, we use a counter pattern: set FMP0 = count, + // and the test hooks RFOM clearing to decrement. Since we can't hook writes + // to volatile, we simulate by setting FMP0 directly and calling receiveISR + // which reads FMP0, processes, sets RFOM (which ORs RF0R). We handle this + // by setting FMP0 = 1 for single-frame tests. + void setFifoCount(uint8_t count) + { + fakeCan.RF0R = (fakeCan.RF0R & ~CAN_RF0R_FMP0) | (count & 0x3U); + } + + // Helper: create a CANFrame with standard ID + ::can::CANFrame makeFrame(uint32_t id, uint8_t const* data, uint8_t dlc) + { + return ::can::CANFrame(id, data, dlc); + } + + // Helper: create a CANFrame with extended ID (sets bit 31) + ::can::CANFrame makeExtFrame(uint32_t rawId, uint8_t const* data, uint8_t dlc) + { + return ::can::CANFrame(rawId | 0x80000000U, data, dlc); + } + + // bxCAN hardware simulation: the driver loops on (RF0R & FMP0) and sets + // RFOM0 to release each frame. In real HW, RFOM0 auto-decrements FMP0. + // Our fake struct can't do this, so we spin a background thread that + // watches for RFOM0 being set and clears FMP0 accordingly. + + // Helper: receive exactly N frames via receiveISR with FIFO simulation. + // Spins a thread that simulates hardware FMP0 decrement on RFOM0 write. + uint8_t receiveFrames( + bios::BxCanDevice& dev, + uint8_t const* filter, + uint8_t const* data, + uint32_t const* ids, + bool const* extended, + uint8_t const* dlcs, + uint8_t totalFrames) + { + // For multi-frame, we'd need complex simulation. + // For simplicity in most tests, we use the single-frame helper. + // This function handles the general case with a background thread. + if (totalFrames == 0U) + { + fakeCan.RF0R = 0U; + return dev.receiveISR(filter); + } + + // We simulate by placing frame 0 and using a thread to decrement FMP0. + // Frame data is loaded from the arrays. + uint8_t frameIdx = 0U; + auto loadFrame = [&](uint8_t idx) + { + if (extended != nullptr && extended[idx]) + { + placeRxFrameExt(ids[idx], dlcs[idx], data + idx * 8U); + } + else + { + placeRxFrameStd(ids[idx], dlcs[idx], data + idx * 8U); + } + }; + + // Load first frame and set FMP0 + loadFrame(0); + fakeCan.RF0R = totalFrames; + + // Launch a thread that watches for RFOM0 and simulates HW behavior + std::atomic done{false}; + std::thread hwSim( + [&]() + { + uint8_t remaining = totalFrames; + while (!done.load(std::memory_order_relaxed)) + { + uint32_t rf0r = fakeCan.RF0R; + if ((rf0r & CAN_RF0R_RFOM0) != 0U) + { + remaining--; + if (remaining > 0U && (frameIdx + 1U) < totalFrames) + { + frameIdx++; + loadFrame(frameIdx); + } + // Clear RFOM0 and set new FMP0 + fakeCan.RF0R = remaining; + if (remaining == 0U) + { + done.store(true, std::memory_order_relaxed); + } + } + } + }); + + uint8_t result = dev.receiveISR(filter); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + return result; + } + + // Simplified single-frame receive helper + uint8_t receiveSingleFrame( + bios::BxCanDevice& dev, + uint32_t id, + bool isExtended, + uint8_t dlc, + uint8_t const* data, + uint8_t const* filter = nullptr) + { + if (isExtended) + { + placeRxFrameExt(id, dlc, data); + } + else + { + placeRxFrameStd(id, dlc, data); + } + fakeCan.RF0R = 1U; // 1 frame pending + + // Thread to simulate HW: when RFOM0 is set, clear FMP0 + std::atomic done{false}; + std::thread hwSim( + [&]() + { + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + fakeCan.RF0R = 0U; + done.store(true, std::memory_order_relaxed); + return; + } + } + }); + + uint8_t result = dev.receiveISR(filter); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + return result; + } +}; + +TEST_F(BxCanDeviceTest, initEnablesPeripheralClock) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + + EXPECT_EQ(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); +} + +TEST_F(BxCanDeviceTest, initConfiguresGpioTxAlternateFunctionLowPin) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + + // TX pin = 5 (low register AFR[0]), AF9 + uint32_t txModer = (fakeTxGpio.MODER >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txModer, 2U); // Alternate function mode + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (cfg.txPin * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); + + // Very high speed + uint32_t txSpeed = (fakeTxGpio.OSPEEDR >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txSpeed, 3U); +} + +TEST_F(BxCanDeviceTest, initConfiguresGpioRxAlternateFunctionHighPin) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + + // RX pin = 11 (high register AFR[1]), AF9 + uint32_t rxModer = (fakeRxGpio.MODER >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(rxModer, 2U); + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((cfg.rxPin - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); + + // Pull-up for RX + uint32_t rxPupdr = (fakeRxGpio.PUPDR >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(rxPupdr, 1U); +} + +TEST_F(BxCanDeviceTest, initConfiguresGpioRxLowPin) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 4U; + cfg.rxAf = 7U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[0] >> (cfg.rxPin * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 7U); +} + +TEST_F(BxCanDeviceTest, initConfiguresGpioTxHighPin) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 12U; + cfg.txAf = 9U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[1] >> ((cfg.txPin - 8U) * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); +} + +TEST_F(BxCanDeviceTest, initEntersInitMode) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // After init(), INRQ should be set (we stay in init mode until start()) + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, initClearsSleepMode) +{ + fakeCan.MCR = CAN_MCR_SLEEP; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.MCR & CAN_MCR_SLEEP, 0U); +} + +TEST_F(BxCanDeviceTest, initEnablesAbomAndTxfp) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_ABOM, 0U); + EXPECT_NE(fakeCan.MCR & CAN_MCR_TXFP, 0U); +} + +TEST_F(BxCanDeviceTest, initConfiguresBitTiming) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + uint32_t brp = btr & 0x3FFU; + uint32_t ts1 = (btr >> CAN_BTR_TS1_Pos) & 0xFU; + uint32_t ts2 = (btr >> CAN_BTR_TS2_Pos) & 0x7U; + uint32_t sjw = (btr >> CAN_BTR_SJW_Pos) & 0x3U; + + EXPECT_EQ(brp, cfg.prescaler - 1U); + EXPECT_EQ(ts1, cfg.bs1 - 1U); + EXPECT_EQ(ts2, cfg.bs2 - 1U); + EXPECT_EQ(sjw, cfg.sjw - 1U); +} + +TEST_F(BxCanDeviceTest, initSetsInitializedFlag) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + // start() before init() should be a no-op (not initialized) + fakeCan.MSR &= ~CAN_MSR_INAK; + dev.start(); + // FMPIE0 should NOT be set since start() returns early + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + // Now init and start should work + fakeCan.MSR |= CAN_MSR_INAK; + dev.init(); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev.start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, startLeavesInitMode) +{ + auto dev = makeInitedDevice(); + // leaveInitMode clears INRQ, then busy-waits for INAK=0 + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_EQ(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, startDrainsStaleFifo) +{ + auto dev = makeInitedDevice(); + // Simulate 1 stale frame in FIFO0 + fakeCan.RF0R = 1U; + fakeCan.MSR &= ~CAN_MSR_INAK; + + // start() should drain: while (FMP0 != 0) set RFOM0 + // In our fake, after one iteration RF0R = 1 | RFOM0 = 0x21, FMP0 still 1. + // This would loop forever. For this test, simulate HW clearing. + std::atomic done{false}; + std::thread hwSim( + [&]() + { + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + fakeCan.RF0R = 0U; + done.store(true, std::memory_order_relaxed); + return; + } + } + }); + + dev->start(); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + + // After drain, FMPIE0 should be enabled + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, startClearsOverrunFlag) +{ + auto dev = makeInitedDevice(); + fakeCan.MSR &= ~CAN_MSR_INAK; + fakeCan.RF0R = 0U; // No stale frames + dev->start(); + // FOVR0 should have been set (to clear it - write-1-to-clear) + EXPECT_NE(fakeCan.RF0R & CAN_RF0R_FOVR0, 0U); +} + +TEST_F(BxCanDeviceTest, startEnablesFmpie0) +{ + auto dev = makeStartedDevice(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, stopDisablesFmpie0AndTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; // Simulate TMEIE was enabled + fakeCan.MSR |= CAN_MSR_INAK; // So enterInitMode completes + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, stopEntersInitMode) +{ + auto dev = makeStartedDevice(); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, transmitFindsEmptyMailbox0) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + + uint8_t data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + ::can::CANFrame frame(0x100, data, 8U); + EXPECT_TRUE(dev->transmit(frame)); + + // Should use mailbox 0 (first empty) + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, transmitStandardIdEncoding) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x7AB, data, 0U); + dev->transmit(frame); + + uint32_t stid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x7ABU); + // IDE bit should NOT be set for standard ID + EXPECT_EQ(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitExtendedIdEncoding) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + // Extended ID: set bit 31 in CANFrame ID per CanId convention + ::can::CANFrame frame(0x80012345U, data, 0U); + dev->transmit(frame); + + // IDE bit should be set + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); + // EXID field + uint32_t exid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_EXID_Pos) & 0x1FFFFFFFU; + EXPECT_EQ(exid, 0x12345U); +} + +TEST_F(BxCanDeviceTest, transmitDlcEncoding) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 5U); + dev->transmit(frame); + + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 5U); +} + +TEST_F(BxCanDeviceTest, transmitPayloadBytes) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}; + ::can::CANFrame frame(0x100, data, 8U); + dev->transmit(frame); + + // TDLR: bytes 0-3 (LSB first) + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDLR), 0xAAU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDLR >> 8U), 0xBBU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDLR >> 16U), 0xCCU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDLR >> 24U), 0xDDU); + + // TDHR: bytes 4-7 + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDHR), 0xEEU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDHR >> 8U), 0xFFU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDHR >> 16U), 0x11U); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDHR >> 24U), 0x22U); +} + +TEST_F(BxCanDeviceTest, transmitSetsTxrq) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 1U); + dev->transmit(frame); + + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, transmitEnablesTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + fakeCan.IER &= ~CAN_IER_TMEIE; // Clear TMEIE first + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 1U); + dev->transmit(frame); + + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitAll3FullReturnsFalse) +{ + auto dev = makeStartedDevice(); + // No TME bits set = all mailboxes occupied + fakeCan.TSR = 0U; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 1U); + EXPECT_FALSE(dev->transmit(frame)); +} + +TEST_F(BxCanDeviceTest, transmitMailboxPriority012) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + ::can::CANFrame frame1(0x100, data, 1U); + ::can::CANFrame frame2(0x200, data, 1U); + ::can::CANFrame frame3(0x300, data, 1U); + + // All empty: first TX goes to mailbox 0 + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmit(frame1); + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); + + // Only mailbox 1 and 2 empty: next TX goes to mailbox 1 + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmit(frame2); + EXPECT_NE(fakeCan.sTxMailBox[1].TIR & CAN_TI0R_TXRQ, 0U); + + // Only mailbox 2 empty: next TX goes to mailbox 2 + fakeCan.TSR = CAN_TSR_TME2; + dev->transmit(frame3); + EXPECT_NE(fakeCan.sTxMailBox[2].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, transmitZeroPayload) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 0U); +} + +TEST_F(BxCanDeviceTest, transmitMaxPayload8Bytes) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + ::can::CANFrame frame(0x100, data, 8U); + EXPECT_TRUE(dev->transmit(frame)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 8U); +} + +TEST_F(BxCanDeviceTest, transmitUsesMailbox1WhenOnly1Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME1; // Only mailbox 1 empty + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x200, data, 1U); + EXPECT_TRUE(dev->transmit(frame)); + uint32_t stid = (fakeCan.sTxMailBox[1].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x200U); +} + +TEST_F(BxCanDeviceTest, receiveIsrNoFramesReturnsZero) +{ + auto dev = makeStartedDevice(); + fakeCan.RF0R = 0U; // No frames pending + uint8_t count = dev->receiveISR(nullptr); + EXPECT_EQ(count, 0U); +} + +TEST_F(BxCanDeviceTest, receiveIsrDrainsFifo0SingleFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; + uint8_t count = receiveSingleFrame(*dev, 0x123U, false, 8U, data); + EXPECT_EQ(count, 1U); +} + +TEST_F(BxCanDeviceTest, receiveIsrStandardIdFromRir) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x456U, false, 1U, data); + + auto const& frame = dev->getRxFrame(0); + EXPECT_EQ(frame.getId(), 0x456U); +} + +TEST_F(BxCanDeviceTest, receiveIsrExtendedIdFromRir) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x1ABCDEFU, true, 1U, data); + + auto const& frame = dev->getRxFrame(0); + // Extended IDs have bit 31 set in the CANFrame ID + EXPECT_EQ(frame.getId(), 0x1ABCDEFU | 0x80000000U); +} + +TEST_F(BxCanDeviceTest, receiveIsrDlcFromRdtr) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 5U, data); + + EXPECT_EQ(dev->getRxFrame(0).getPayloadLength(), 5U); +} + +TEST_F(BxCanDeviceTest, receiveIsrPayloadByteOrder) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}; + receiveSingleFrame(*dev, 0x100U, false, 8U, data); + + auto const& frame = dev->getRxFrame(0); + uint8_t const* payload = frame.getPayload(); + EXPECT_EQ(payload[0], 0xAAU); + EXPECT_EQ(payload[1], 0xBBU); + EXPECT_EQ(payload[2], 0xCCU); + EXPECT_EQ(payload[3], 0xDDU); + EXPECT_EQ(payload[4], 0xEEU); + EXPECT_EQ(payload[5], 0xFFU); + EXPECT_EQ(payload[6], 0x11U); + EXPECT_EQ(payload[7], 0x22U); +} + +TEST_F(BxCanDeviceTest, receiveIsrReleasesRfom) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + // After receive, RF0R should have been written with RFOM0 + // (our HW sim cleared it, but the driver wrote it) + // We verify by checking that the frame was received successfully + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(BxCanDeviceTest, receiveIsrFrameCountReturn) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t count = receiveSingleFrame(*dev, 0x100U, false, 1U, data); + EXPECT_EQ(count, 1U); +} + +TEST_F(BxCanDeviceTest, receiveIsrQueueFullDropsFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + + // Fill the queue to capacity (32 frames) + for (uint8_t i = 0U; i < 32U; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + + // 33rd frame: should be dropped but FIFO still released + // Set up frame and FMP0=1 + placeRxFrameStd(0x200U, 1U, data); + fakeCan.RF0R = 1U; + + std::atomic done{false}; + std::thread hwSim( + [&]() + { + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + fakeCan.RF0R = 0U; + done.store(true, std::memory_order_relaxed); + return; + } + } + }); + + uint8_t count = dev->receiveISR(nullptr); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + + // Frame was dropped (queue still 32, not 33) + EXPECT_EQ(dev->getRxCount(), 32U); + EXPECT_EQ(count, 0U); // No frames enqueued +} + +TEST_F(BxCanDeviceTest, receiveIsrNullFilterAcceptsAll) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t count = receiveSingleFrame(*dev, 0x7FFU, false, 1U, data, nullptr); + EXPECT_EQ(count, 1U); +} + +TEST_F(BxCanDeviceTest, receiveIsrBitfieldFilterAccept) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Create filter that accepts ID 0x100 (byte 32, bit 0) + uint8_t filter[256] = {}; + filter[0x100 / 8U] |= (1U << (0x100 % 8U)); // Set bit for ID 0x100 + + uint8_t count = receiveSingleFrame(*dev, 0x100U, false, 1U, data, filter); + EXPECT_EQ(count, 1U); +} + +TEST_F(BxCanDeviceTest, receiveIsrBitfieldFilterReject) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Create filter that does NOT accept ID 0x100 + uint8_t filter[256] = {}; + // filter[0x100/8] bit for 0x100 is NOT set + + uint8_t count = receiveSingleFrame(*dev, 0x100U, false, 1U, data, filter); + EXPECT_EQ(count, 0U); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, receiveIsrMultipleFramesDrain) +{ + auto dev = makeStartedDevice(); + uint8_t data1[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + uint8_t data2[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02}; + + // Receive first frame + receiveSingleFrame(*dev, 0x100U, false, 8U, data1); + // Receive second frame + receiveSingleFrame(*dev, 0x200U, false, 8U, data2); + + EXPECT_EQ(dev->getRxCount(), 2U); + + auto const& f1 = dev->getRxFrame(0); + EXPECT_EQ(f1.getId(), 0x100U); + EXPECT_EQ(f1.getPayload()[0], 0x11U); + + auto const& f2 = dev->getRxFrame(1); + EXPECT_EQ(f2.getId(), 0x200U); + EXPECT_EQ(f2.getPayload()[0], 0xAAU); +} + +TEST_F(BxCanDeviceTest, receiveIsrStaleFrameDrain) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Receive a frame, then clear, then receive again + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + receiveSingleFrame(*dev, 0x200U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(BxCanDeviceTest, transmitIsrClearsRqcp0) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_RQCP0; + dev->transmitISR(); + // RQCP0 should be set (write-1-to-clear in real HW, but in fake it ORs) + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrClearsRqcp1) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_RQCP1; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP1, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrClearsRqcp2) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_RQCP2; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP2, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrClearsAllRqcpFlags) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + dev->transmitISR(); + // All RQCP flags should be written (ORed in) + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP0, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP1, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP2, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrDisablesTmeieWhenAllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + // All 3 mailboxes empty + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieWhenNotAllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + // Only mailbox 0 empty, 1 and 2 still pending + fakeCan.TSR = CAN_TSR_TME0; + dev->transmitISR(); + // After ORing RQCP flags, TME0 is still set but TME1/TME2 are not + // So (TSR & (TME0|TME1|TME2)) != (TME0|TME1|TME2), TMEIE stays enabled + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, rxQueueInitiallyZero) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + EXPECT_EQ(dev.getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, rxQueueCorrectFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE}; + receiveSingleFrame(*dev, 0x321U, false, 8U, data); + + auto const& frame = dev->getRxFrame(0); + EXPECT_EQ(frame.getId(), 0x321U); + EXPECT_EQ(frame.getPayloadLength(), 8U); + EXPECT_EQ(frame.getPayload()[0], 0xDEU); + EXPECT_EQ(frame.getPayload()[7], 0xBEU); +} + +TEST_F(BxCanDeviceTest, rxQueueCountAfterReceive) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + receiveSingleFrame(*dev, 0x101U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 2U); +} + +TEST_F(BxCanDeviceTest, rxQueueClearResets) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + receiveSingleFrame(*dev, 0x101U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 2U); + + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, rxQueueWrapAround) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill queue partially, clear, fill again to cause wrap-around + for (uint8_t i = 0U; i < 30U; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + // Now head is at 30. Fill 10 more to wrap around past 32 + for (uint8_t i = 0U; i < 10U; i++) + { + data[0] = i + 1U; + receiveSingleFrame(*dev, 0x200U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 10U); + + // Verify first and last frame + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(9).getId(), 0x209U); +} + +TEST_F(BxCanDeviceTest, rxQueueCapacity32) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint8_t i = 0U; i < 32U; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + + // Verify all frames are accessible + for (uint8_t i = 0U; i < 32U; i++) + { + EXPECT_EQ(dev->getRxFrame(i).getId(), 0x100U + i); + } +} + +TEST_F(BxCanDeviceTest, disableRxInterruptClearsFmpie0) +{ + auto dev = makeStartedDevice(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); // Enabled after start + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, enableRxInterruptSetsFmpie0) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, disableRxInterruptPreservesOtherBits) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; // Set another bit + dev->disableRxInterrupt(); + // TMEIE should still be set + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, enableRxInterruptPreservesOtherBits) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = CAN_IER_TMEIE; // Only TMEIE set, FMPIE0 cleared + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, isBusOffReadsBoffBit) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_FALSE(dev->isBusOff()); + + fakeCan.ESR = CAN_ESR_BOFF; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(BxCanDeviceTest, isBusOffFalseWhenNotSet) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_FALSE(dev->isBusOff()); +} + +TEST_F(BxCanDeviceTest, getTxErrorCounterReadsEsr) +{ + auto dev = makeStartedDevice(); + // TEC is bits [23:16] of ESR + fakeCan.ESR = (128U << CAN_ESR_TEC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 128U); +} + +TEST_F(BxCanDeviceTest, getRxErrorCounterReadsEsr) +{ + auto dev = makeStartedDevice(); + // REC is bits [31:24] of ESR + fakeCan.ESR = (64U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 64U); +} + +TEST_F(BxCanDeviceTest, errorCounterMaxValue255) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (255U << CAN_ESR_TEC_Pos) | (255U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 255U); + EXPECT_EQ(dev->getRxErrorCounter(), 255U); +} + +TEST_F(BxCanDeviceTest, errorCounterZero) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_EQ(dev->getTxErrorCounter(), 0U); + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterEntersFilterInitMode) +{ + auto dev = makeInitedDevice(); + // After init(), configureAcceptAllFilter was called. + // FINIT should be cleared (we left filter init mode) + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterBank0MaskMode) +{ + auto dev = makeInitedDevice(); + // Bank 0 should be in mask mode (FM1R bit 0 = 0) + EXPECT_EQ(fakeCan.FM1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterBank032BitScale) +{ + auto dev = makeInitedDevice(); + // Bank 0 should be 32-bit scale (FS1R bit 0 = 1) + EXPECT_NE(fakeCan.FS1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterBank0AllPass) +{ + auto dev = makeInitedDevice(); + // FR1 = 0 (ID = 0, don't care), FR2 = 0 (mask = 0, accept all) + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterBank0Active) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterAssignedToFifo0) +{ + auto dev = makeInitedDevice(); + // FFA1R bit 0 = 0 means FIFO0 + EXPECT_EQ(fakeCan.FFA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListModeConfigures) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U, 0x300U, 0x400U}; + dev->configureFilterList(ids, 4U); + + // FINIT should be cleared after configuration + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); + + // Banks 0 and 1 should be in list mode (FM1R bits set) + EXPECT_NE(fakeCan.FM1R & (1U << 0U), 0U); + EXPECT_NE(fakeCan.FM1R & (1U << 1U), 0U); + + // Bank 0: FR1 = 0x100 << STID_Pos, FR2 = 0x200 << STID_Pos + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x100U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x200U << CAN_RI0R_STID_Pos); + + // Bank 1: FR1 = 0x300 << STID_Pos, FR2 = 0x400 << STID_Pos + EXPECT_EQ(fakeCan.sFilterRegister[1].FR1, 0x300U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR2, 0x400U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListModeOddCountDuplicatesLast) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U, 0x300U}; + dev->configureFilterList(ids, 3U); + + // Bank 0: FR1 = 0x100, FR2 = 0x200 + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x100U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x200U << CAN_RI0R_STID_Pos); + + // Bank 1: FR1 = 0x300, FR2 = 0x300 (duplicated) + EXPECT_EQ(fakeCan.sFilterRegister[1].FR1, 0x300U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR2, 0x300U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, bitTimingPrescalerEncoding) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 8U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t brp = fakeCan.BTR & 0x3FFU; + EXPECT_EQ(brp, 7U); // prescaler - 1 +} + +TEST_F(BxCanDeviceTest, bitTimingBs1Encoding) +{ + auto cfg = makeDefaultConfig(); + cfg.bs1 = 15U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t ts1 = (fakeCan.BTR >> CAN_BTR_TS1_Pos) & 0xFU; + EXPECT_EQ(ts1, 14U); // bs1 - 1 +} + +TEST_F(BxCanDeviceTest, bitTimingBs2Encoding) +{ + auto cfg = makeDefaultConfig(); + cfg.bs2 = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t ts2 = (fakeCan.BTR >> CAN_BTR_TS2_Pos) & 0x7U; + EXPECT_EQ(ts2, 3U); // bs2 - 1 +} + +TEST_F(BxCanDeviceTest, bitTimingSjwEncoding) +{ + auto cfg = makeDefaultConfig(); + cfg.sjw = 2U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t sjw = (fakeCan.BTR >> CAN_BTR_SJW_Pos) & 0x3U; + EXPECT_EQ(sjw, 1U); // sjw - 1 +} + +TEST_F(BxCanDeviceTest, bitTimingMinValues) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + cfg.bs1 = 1U; + cfg.bs2 = 1U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 0U); // BRP = 0 + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 0U); // TS1 = 0 + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 0U); // TS2 = 0 + EXPECT_EQ((btr >> CAN_BTR_SJW_Pos) & 0x3U, 0U); // SJW = 0 +} + +TEST_F(BxCanDeviceTest, bitTimingCan500kbpsAt42MHz) +{ + // Typical config: 42 MHz APB1, 500 kbps: prescaler=6, BS1=11, BS2=2, SJW=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 6U; + cfg.bs1 = 11U; + cfg.bs2 = 2U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 5U); // BRP = 5 + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 10U); // TS1 = 10 + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 1U); // TS2 = 1 + EXPECT_EQ((btr >> CAN_BTR_SJW_Pos) & 0x3U, 0U); // SJW = 0 +} + +TEST_F(BxCanDeviceTest, doubleInitDoesNotCrash) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // Second init should work without issues + dev.init(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, stopRestart) +{ + auto dev = makeStartedDevice(); + + // Stop + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + // Restart + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitBeforeInitStillTransmits) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + // Don't call init() or start() + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 1U); + // transmit() does not gate on fInitialized - it only checks TME bits + EXPECT_TRUE(dev.transmit(frame)); +} + +TEST_F(BxCanDeviceTest, startBeforeInitIsNoop) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + // start() without init() should return early + fakeCan.MSR &= ~CAN_MSR_INAK; + dev.start(); + // FMPIE0 should NOT be set + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, extendedIdFullRange) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + // Max 29-bit extended ID + uint8_t data[8] = {}; + ::can::CANFrame frame(0x9FFFFFFFU, data, 0U); // 0x80000000 | 0x1FFFFFFF + dev->transmit(frame); + + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); + uint32_t exid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_EXID_Pos) & 0x1FFFFFFFU; + EXPECT_EQ(exid, 0x1FFFFFFFU); +} + +TEST_F(BxCanDeviceTest, extendedIdMinRange) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x80000000U, data, 0U); // Extended ID = 0 + dev->transmit(frame); + + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); + uint32_t exid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_EXID_Pos) & 0x1FFFFFFFU; + EXPECT_EQ(exid, 0U); +} + +TEST_F(BxCanDeviceTest, filterIdBoundary0x000) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t filter[256] = {}; + filter[0] |= 1U; // Accept ID 0 + + uint8_t count = receiveSingleFrame(*dev, 0x000U, false, 1U, data, filter); + EXPECT_EQ(count, 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0U); +} + +TEST_F(BxCanDeviceTest, filterIdBoundary0x7FF) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t filter[256] = {}; + filter[0x7FF / 8U] |= (1U << (0x7FF % 8U)); // Accept ID 0x7FF + + uint8_t count = receiveSingleFrame(*dev, 0x7FFU, false, 1U, data, filter); + EXPECT_EQ(count, 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x7FFU); +} + +TEST_F(BxCanDeviceTest, multipleReceiveCycles) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Cycle 1: receive and clear + for (uint8_t i = 0U; i < 5U; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 5U); + dev->clearRxQueue(); + + // Cycle 2: receive and clear + for (uint8_t i = 0U; i < 3U; i++) + { + receiveSingleFrame(*dev, 0x200U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + dev->clearRxQueue(); + + // Cycle 3: verify empty + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, concurrentTxMailboxes) +{ + auto dev = makeStartedDevice(); + uint8_t data1[8] = {0x01}; + uint8_t data2[8] = {0x02}; + uint8_t data3[8] = {0x03}; + + // Fill all 3 mailboxes + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data1, 1U))); + + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x200U, data2, 1U))); + + fakeCan.TSR = CAN_TSR_TME2; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x300U, data3, 1U))); + + // All full now + fakeCan.TSR = 0U; + EXPECT_FALSE(dev->transmit(::can::CANFrame(0x400U, data1, 1U))); + + // Verify each mailbox has correct ID + uint32_t id0 = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + uint32_t id1 = (fakeCan.sTxMailBox[1].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + uint32_t id2 = (fakeCan.sTxMailBox[2].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(id0, 0x100U); + EXPECT_EQ(id1, 0x200U); + EXPECT_EQ(id2, 0x300U); + + // Verify each mailbox has correct data byte 0 + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[0].TDLR), 0x01U); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[1].TDLR), 0x02U); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[2].TDLR), 0x03U); +} + +TEST_F(BxCanDeviceTest, filterListSingleId) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x555U}; + dev->configureFilterList(ids, 1U); + + // Bank 0: FR1 = 0x555 << STID, FR2 = 0x555 << STID (duplicated for odd) + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x555U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x555U << CAN_RI0R_STID_Pos); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); // Activated +} + +TEST_F(BxCanDeviceTest, filterListBanksActivated) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U, 0x300U, 0x400U, 0x500U, 0x600U}; + dev->configureFilterList(ids, 6U); + + // 3 banks should be activated (6 IDs / 2 per bank) + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); + EXPECT_NE(fakeCan.FA1R & (1U << 1U), 0U); + EXPECT_NE(fakeCan.FA1R & (1U << 2U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListAllAssignedToFifo0) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U, 0x300U, 0x400U}; + dev->configureFilterList(ids, 4U); + + EXPECT_EQ(fakeCan.FFA1R & (1U << 0U), 0U); + EXPECT_EQ(fakeCan.FFA1R & (1U << 1U), 0U); +} + +TEST_F(BxCanDeviceTest, receiveIsrExtendedIdRecovery) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x42}; + + // Receive extended ID + receiveSingleFrame(*dev, 0x12345U, true, 1U, data); + auto const& frame = dev->getRxFrame(0); + EXPECT_EQ(frame.getId(), 0x12345U | 0x80000000U); + EXPECT_EQ(frame.getPayload()[0], 0x42U); +} + +TEST_F(BxCanDeviceTest, transmitIsrThenTransmitAgain) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Transmit first frame + fakeCan.TSR = CAN_TSR_TME0; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + + // Simulate TX complete: all mailboxes empty + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); // TMEIE disabled + + // Transmit again: TMEIE should be re-enabled + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x200U, data, 1U))); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, getRxFrameIndexWraps) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill 31 frames, clear, then add 2 more (head at 31) + for (uint8_t i = 0U; i < 31U; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + // Head is now at 31. Add 2 frames -> indices 31 and 0 (wrapped) + receiveSingleFrame(*dev, 0x500U, false, 1U, data); + receiveSingleFrame(*dev, 0x501U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 2U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x500U); + EXPECT_EQ(dev->getRxFrame(1).getId(), 0x501U); +} + +TEST_F(BxCanDeviceTest, isBusOffWithOtherEsrBitsSet) +{ + auto dev = makeStartedDevice(); + // Set TEC and REC but NOT BOFF + fakeCan.ESR = (100U << CAN_ESR_TEC_Pos) | (50U << CAN_ESR_REC_Pos); + EXPECT_FALSE(dev->isBusOff()); + + // Now set BOFF too + fakeCan.ESR |= CAN_ESR_BOFF; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(BxCanDeviceTest, transmitStandardIdZero) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x000U, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t stid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0U); + EXPECT_EQ(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitStandardIdMax0x7FF) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x7FFU, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t stid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x7FFU); +} + +TEST_F(BxCanDeviceTest, clockEnableIsIdempotent) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t apb1_1 = fakeRcc.APB1ENR; + dev.init(); + uint32_t apb1_2 = fakeRcc.APB1ENR; + // Should still have CAN1EN set, no extra bits + EXPECT_EQ(apb1_1, apb1_2); +} + +TEST_F(BxCanDeviceTest, receiveIsrZeroDlcFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 0U, data); + + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getPayloadLength(), 0U); +} + +TEST_F(BxCanDeviceTest, receiveIsrMaxDlc8Frame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + receiveSingleFrame(*dev, 0x100U, false, 8U, data); + + EXPECT_EQ(dev->getRxFrame(0).getPayloadLength(), 8U); +} + +TEST_F(BxCanDeviceTest, clearRxQueueAdvancesHead) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Receive 5 frames, clear, then receive 3 more + for (uint8_t i = 0; i < 5; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + for (uint8_t i = 0; i < 3; i++) + { + data[0] = 0xA0U + i; + receiveSingleFrame(*dev, 0x300U + i, false, 1U, data); + } + + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x300U); + EXPECT_EQ(dev->getRxFrame(0).getPayload()[0], 0xA0U); + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x302U); +} + +TEST_F(BxCanDeviceTest, filterListMaxBanks14) +{ + auto dev = makeInitedDevice(); + // 28 IDs = 14 banks (max for configureFilterList) + uint32_t ids[28]; + for (uint8_t i = 0; i < 28; i++) + { + ids[i] = 0x100U + i; + } + dev->configureFilterList(ids, 28U); + + // All 14 banks should be activated + for (uint8_t b = 0; b < 14; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b << " not active"; + } +} + +TEST_F(BxCanDeviceTest, transmitToMailbox2Only) +{ + auto dev = makeStartedDevice(); + // Only mailbox 2 is empty + fakeCan.TSR = CAN_TSR_TME2; + + uint8_t data[8] = {0xFF}; + ::can::CANFrame frame(0x3FFU, data, 1U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t stid = (fakeCan.sTxMailBox[2].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x3FFU); + EXPECT_EQ(static_cast(fakeCan.sTxMailBox[2].TDLR), 0xFFU); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFinitToggle) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + + // Before init, FMR should be 0 + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); + + dev.init(); + + // After init (which calls configureAcceptAllFilter), FINIT should be cleared + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); +} + +TEST_F(BxCanDeviceTest, disableEnableRxInterruptCycle) +{ + auto dev = makeStartedDevice(); + + // Initially enabled after start + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + // Disable-enable-disable cycle + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, errorCounterIndependentTecRec) +{ + auto dev = makeStartedDevice(); + // Set TEC=200, REC=50 + fakeCan.ESR = (200U << CAN_ESR_TEC_Pos) | (50U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 200U); + EXPECT_EQ(dev->getRxErrorCounter(), 50U); + + // Change to TEC=10, REC=250 + fakeCan.ESR = (10U << CAN_ESR_TEC_Pos) | (250U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 10U); + EXPECT_EQ(dev->getRxErrorCounter(), 250U); +} + +TEST_F(BxCanDeviceTest, receiveMultipleThenTransmit) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x42}; + + // Receive 3 frames + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + receiveSingleFrame(*dev, 0x101U, false, 1U, data); + receiveSingleFrame(*dev, 0x102U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 3U); + + // Transmit should still work independently + fakeCan.TSR = CAN_TSR_TME0; + ::can::CANFrame txFrame(0x200U, data, 1U); + EXPECT_TRUE(dev->transmit(txFrame)); + + // RX queue unaffected + EXPECT_EQ(dev->getRxCount(), 3U); +} + +TEST_F(BxCanDeviceTest, initDoubleInitPreservesBtrSettings) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 5U; + cfg.bs1 = 10U; + cfg.bs2 = 3U; + cfg.sjw = 2U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t btr1 = fakeCan.BTR; + dev.init(); + uint32_t btr2 = fakeCan.BTR; + EXPECT_EQ(btr1, btr2); +} + +TEST_F(BxCanDeviceTest, initBtrPrescaler1) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 0U); +} + +TEST_F(BxCanDeviceTest, initBtrPrescaler1024) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1024U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 1023U); +} + +TEST_F(BxCanDeviceTest, initBtrBs1Max16) +{ + auto cfg = makeDefaultConfig(); + cfg.bs1 = 16U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t ts1 = (fakeCan.BTR >> CAN_BTR_TS1_Pos) & 0xFU; + EXPECT_EQ(ts1, 15U); +} + +TEST_F(BxCanDeviceTest, initBtrBs2Max8) +{ + auto cfg = makeDefaultConfig(); + cfg.bs2 = 8U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t ts2 = (fakeCan.BTR >> CAN_BTR_TS2_Pos) & 0x7U; + EXPECT_EQ(ts2, 7U); +} + +TEST_F(BxCanDeviceTest, initBtrSjwMax4) +{ + auto cfg = makeDefaultConfig(); + cfg.sjw = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t sjw = (fakeCan.BTR >> CAN_BTR_SJW_Pos) & 0x3U; + EXPECT_EQ(sjw, 3U); +} + +TEST_F(BxCanDeviceTest, initGpioTxPin0LowAf) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 0U; + cfg.txAf = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (0U * 4U)) & 0xFU; + EXPECT_EQ(txAf, 4U); + uint32_t txModer = (fakeTxGpio.MODER >> (0U * 2U)) & 3U; + EXPECT_EQ(txModer, 2U); +} + +TEST_F(BxCanDeviceTest, initGpioTxPin7BoundaryLow) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 7U; + cfg.txAf = 11U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (7U * 4U)) & 0xFU; + EXPECT_EQ(txAf, 11U); +} + +TEST_F(BxCanDeviceTest, initGpioRxPin8BoundaryHigh) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 8U; + cfg.rxAf = 5U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((8U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 5U); +} + +TEST_F(BxCanDeviceTest, initGpioRxPin15Max) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 15U; + cfg.rxAf = 9U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((15U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); +} + +TEST_F(BxCanDeviceTest, initClearsSleepModeWhenAlreadyClear) +{ + fakeCan.MCR = 0U; // SLEEP already clear + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.MCR & CAN_MCR_SLEEP, 0U); +} + +TEST_F(BxCanDeviceTest, initAbomFlagSetAfterInit) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_ABOM, 0U); +} + +TEST_F(BxCanDeviceTest, initTxfpFlagSetAfterInit) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_TXFP, 0U); +} + +TEST_F(BxCanDeviceTest, initClockEnableBitPosition25) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & (1U << 25U), 0U); +} + +TEST_F(BxCanDeviceTest, initClockDoesNotAffectOtherApb1Bits) +{ + fakeRcc.APB1ENR = 0x12345678U; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // Other bits should still be set + EXPECT_NE(fakeRcc.APB1ENR & 0x12345678U, 0U); + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); +} + +TEST_F(BxCanDeviceTest, initInrqSetBeforeLeaveInit) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // After init we are still in init mode (INRQ set) + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, initGpioTxSpeedVeryHigh) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t txSpeed = (fakeTxGpio.OSPEEDR >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txSpeed, 3U); +} + +TEST_F(BxCanDeviceTest, initGpioRxPullUp) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t rxPupdr = (fakeRxGpio.PUPDR >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(rxPupdr, 1U); +} + +TEST_F(BxCanDeviceTest, initBtrFieldsDoNotOverlap) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 512U; + cfg.bs1 = 16U; + cfg.bs2 = 8U; + cfg.sjw = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + uint32_t brp = btr & 0x3FFU; + uint32_t ts1 = (btr >> CAN_BTR_TS1_Pos) & 0xFU; + uint32_t ts2 = (btr >> CAN_BTR_TS2_Pos) & 0x7U; + uint32_t sjw = (btr >> CAN_BTR_SJW_Pos) & 0x3U; + EXPECT_EQ(brp, 511U); + EXPECT_EQ(ts1, 15U); + EXPECT_EQ(ts2, 7U); + EXPECT_EQ(sjw, 3U); +} + +TEST_F(BxCanDeviceTest, initFilterConfiguredAcceptAll) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // Accept-all filter should be configured after init + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0U); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, startWithoutInitDoesNotSetFmpie0) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev.start(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, doubleStartDoesNotCrash) +{ + auto dev = makeStartedDevice(); + // Second start: re-enter init mode briefly, then leave again + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, stopThenRestartClearsAndReenablesFmpie0) +{ + auto dev = makeStartedDevice(); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, startClearsInrq) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_EQ(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, stopSetsInrq) +{ + auto dev = makeStartedDevice(); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); +} + +TEST_F(BxCanDeviceTest, startClearsFovrFlag) +{ + auto dev = makeInitedDevice(); + fakeCan.MSR &= ~CAN_MSR_INAK; + fakeCan.RF0R = 0U; + dev->start(); + // FOVR0 should have been written (write-1-to-clear) + EXPECT_NE(fakeCan.RF0R & CAN_RF0R_FOVR0, 0U); +} + +TEST_F(BxCanDeviceTest, startNoStaleFifoFrames) +{ + auto dev = makeInitedDevice(); + fakeCan.RF0R = 0U; // No stale frames + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, stopDisablesTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, stopDisablesFmpie0) +{ + auto dev = makeStartedDevice(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, stopThenStartTwice) +{ + auto dev = makeStartedDevice(); + + // Stop + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + + // Start again + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + // Stop again + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + + // Start once more + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, startPreservesAbomFlag) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_ABOM, 0U); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + // ABOM should still be set after leaving init mode + EXPECT_NE(fakeCan.MCR & CAN_MCR_ABOM, 0U); +} + +TEST_F(BxCanDeviceTest, startPreservesTxfpFlag) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_TXFP, 0U); + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_TXFP, 0U); +} + +TEST_F(BxCanDeviceTest, stopThenInitThenStart) +{ + auto dev = makeStartedDevice(); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + + // Re-init + dev->init(); + EXPECT_NE(fakeCan.MCR & CAN_MCR_INRQ, 0U); + + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, startIerOnlyFmpie0Set) +{ + auto dev = makeInitedDevice(); + fakeCan.IER = 0U; + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + // After start, only FMPIE0 should be enabled (not TMEIE) + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, stopClearsIerCompletely) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.IER & (CAN_IER_FMPIE0 | CAN_IER_TMEIE), 0U); +} + +TEST_F(BxCanDeviceTest, startAfterStopRxQueuePreserved) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + + // RX queue should still have the frame + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + + fakeCan.MSR &= ~CAN_MSR_INAK; + dev->start(); + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(BxCanDeviceTest, startSetsMailboxesEmptyForSubsequentTx) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); +} + +TEST_F(BxCanDeviceTest, stopDoesNotAffectBtrRegister) +{ + auto dev = makeStartedDevice(); + uint32_t btrBefore = fakeCan.BTR; + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + EXPECT_EQ(fakeCan.BTR, btrBefore); +} + +TEST_F(BxCanDeviceTest, startWithFifo2StaleFrames) +{ + auto dev = makeInitedDevice(); + fakeCan.RF0R = 2U; // 2 stale frames + fakeCan.MSR &= ~CAN_MSR_INAK; + + // Background thread to simulate HW draining + std::atomic done{false}; + std::thread hwSim( + [&]() + { + uint8_t remaining = 2U; + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + remaining--; + fakeCan.RF0R = remaining; + if (remaining == 0U) + { + done.store(true, std::memory_order_relaxed); + return; + } + } + } + }); + + dev->start(); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, stopPreservesFilterConfiguration) +{ + auto dev = makeStartedDevice(); + // Check filter is configured after init/start + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); + uint32_t fa1rBefore = fakeCan.FA1R; + + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + + // Filter config should not be touched by stop + EXPECT_EQ(fakeCan.FA1R, fa1rBefore); +} + +TEST_F(BxCanDeviceTest, enableRxInterruptFromZeroIer) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = 0U; + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, disableRxInterruptIdempotent) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, enableRxInterruptIdempotent) +{ + auto dev = makeStartedDevice(); + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitEnablesTmeieFromCleanIer) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = CAN_IER_FMPIE0; // Only FMPIE0 set + fakeCan.TSR = CAN_TSR_TME0; + + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + // FMPIE0 should still be set + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrDisablesTmeieAllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieMailbox0Busy) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + // Mailbox 0 busy, 1 and 2 empty + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieMailbox1Busy) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + // Mailbox 1 busy, 0 and 2 empty + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieMailbox2Busy) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + // Mailbox 2 busy, 0 and 1 empty + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieAllBusy) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = 0U; // All mailboxes busy + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieOnlyMailbox0Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieOnlyMailbox1Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME1; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrKeepsTmeieOnlyMailbox2Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, disableRxInterruptDoesNotAffectTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + dev->disableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, enableRxInterruptDoesNotAffectTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = CAN_IER_TMEIE; // Only TMEIE set + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrDoesNotAffectFmpie0) +{ + auto dev = makeStartedDevice(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + // FMPIE0 should still be set + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, ierBitIsolationFmpie0Only) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = 0U; + dev->enableRxInterrupt(); + // Only FMPIE0 (bit 1) should be set + EXPECT_EQ(fakeCan.IER, CAN_IER_FMPIE0); +} + +TEST_F(BxCanDeviceTest, ierBitIsolationTmeieFromTransmit) +{ + auto dev = makeStartedDevice(); + fakeCan.IER = 0U; + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + // TMEIE (bit 0) should be set + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, multipleTxThenIsrCycleIerState) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // TX -> TMEIE enabled + fakeCan.TSR = CAN_TSR_TME0; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + + // ISR with all empty -> TMEIE disabled + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); + + // TX again -> TMEIE re-enabled + fakeCan.TSR = CAN_TSR_TME1; + dev->transmit(::can::CANFrame(0x200U, data, 1U)); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); + + // ISR with all empty again -> TMEIE disabled + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, disableRxInterruptThenReceiveDoesNotEnqueue) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + // Manually call receiveISR (would normally be called by HW interrupt) + uint8_t data[8] = {}; + // receiveISR can still be called manually, it does not check IER + placeRxFrameStd(0x100U, 1U, data); + fakeCan.RF0R = 1U; + + std::atomic done{false}; + std::thread hwSim( + [&]() + { + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + fakeCan.RF0R = 0U; + done.store(true, std::memory_order_relaxed); + return; + } + } + }); + + uint8_t count = dev->receiveISR(nullptr); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + // receiveISR still works even if FMPIE0 disabled (just won't be called by HW) + EXPECT_EQ(count, 1U); +} + +TEST_F(BxCanDeviceTest, enableDisableRxInterruptRapidToggle) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 10; i++) + { + dev->disableRxInterrupt(); + EXPECT_EQ(fakeCan.IER & CAN_IER_FMPIE0, 0U); + dev->enableRxInterrupt(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + } +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFs1rBit0Set) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.FS1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFm1rBit0Clear) +{ + auto dev = makeInitedDevice(); + EXPECT_EQ(fakeCan.FM1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFfa1rBit0Clear) +{ + auto dev = makeInitedDevice(); + EXPECT_EQ(fakeCan.FFA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFa1rBit0Set) +{ + auto dev = makeInitedDevice(); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterFinitClearedAfterConfig) +{ + auto dev = makeInitedDevice(); + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); +} + +TEST_F(BxCanDeviceTest, filterListMode2Ids) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + + EXPECT_NE(fakeCan.FM1R & (1U << 0U), 0U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x100U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x200U << CAN_RI0R_STID_Pos); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListMode1IdDuplicatesInBank) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x7FFU}; + dev->configureFilterList(ids, 1U); + + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x7FFU << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x7FFU << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListMode3IdsOdd) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x10U, 0x20U, 0x30U}; + dev->configureFilterList(ids, 3U); + + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x10U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x20U << CAN_RI0R_STID_Pos); + // Bank 1: odd count -> last ID duplicated + EXPECT_EQ(fakeCan.sFilterRegister[1].FR1, 0x30U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR2, 0x30U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListMode5IdsOdd) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x10U, 0x20U, 0x30U, 0x40U, 0x50U}; + dev->configureFilterList(ids, 5U); + + // Bank 0: IDs 0 and 1 + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x10U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x20U << CAN_RI0R_STID_Pos); + // Bank 1: IDs 2 and 3 + EXPECT_EQ(fakeCan.sFilterRegister[1].FR1, 0x30U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR2, 0x40U << CAN_RI0R_STID_Pos); + // Bank 2: ID 4 duplicated + EXPECT_EQ(fakeCan.sFilterRegister[2].FR1, 0x50U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[2].FR2, 0x50U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListMode6Ids3Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U, 0x300U, 0x400U, 0x500U, 0x600U}; + dev->configureFilterList(ids, 6U); + + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); + EXPECT_NE(fakeCan.FA1R & (1U << 1U), 0U); + EXPECT_NE(fakeCan.FA1R & (1U << 2U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListMode8Ids4Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x10U, 0x20U, 0x30U, 0x40U, 0x50U, 0x60U, 0x70U, 0x80U}; + dev->configureFilterList(ids, 8U); + + for (uint8_t b = 0; b < 4; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b; + } + EXPECT_EQ(fakeCan.sFilterRegister[3].FR1, 0x70U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[3].FR2, 0x80U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListMode14Ids7Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[14]; + for (uint8_t i = 0; i < 14; i++) + { + ids[i] = 0x100U + i; + } + dev->configureFilterList(ids, 14U); + + for (uint8_t b = 0; b < 7; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b; + } +} + +TEST_F(BxCanDeviceTest, filterListMode28IdsMax14Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[28]; + for (uint8_t i = 0; i < 28; i++) + { + ids[i] = 0x10U + i; + } + dev->configureFilterList(ids, 28U); + + for (uint8_t b = 0; b < 14; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b; + EXPECT_NE(fakeCan.FM1R & (1U << b), 0U) << "Bank " << (int)b << " list mode"; + } +} + +TEST_F(BxCanDeviceTest, filterListFinitClearedAfterConfig) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + EXPECT_EQ(fakeCan.FMR & CAN_FMR_FINIT, 0U); +} + +TEST_F(BxCanDeviceTest, filterListFs1r32BitScale) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + EXPECT_NE(fakeCan.FS1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListFm1rListMode) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + EXPECT_NE(fakeCan.FM1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListFfa1rFifo0Assignment) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + EXPECT_EQ(fakeCan.FFA1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, filterListIdZero) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x000U, 0x000U}; + dev->configureFilterList(ids, 2U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x000U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x000U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListIdMax0x7FF) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x7FFU, 0x7FFU}; + dev->configureFilterList(ids, 2U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x7FFU << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x7FFU << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListOverwritesPreviousAcceptAll) +{ + auto dev = makeInitedDevice(); + // After init, accept-all filter is configured (mask mode) + EXPECT_EQ(fakeCan.FM1R & (1U << 0U), 0U); // Mask mode + + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + // Now should be list mode + EXPECT_NE(fakeCan.FM1R & (1U << 0U), 0U); +} + +TEST_F(BxCanDeviceTest, acceptAllFilterOverwritesPreviousListFilter) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x100U, 0x200U}; + dev->configureFilterList(ids, 2U); + EXPECT_NE(fakeCan.FM1R & (1U << 0U), 0U); + + // Re-configure accept-all + dev->configureAcceptAllFilter(); + EXPECT_EQ(fakeCan.FM1R & (1U << 0U), 0U); // Back to mask mode + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0U); +} + +TEST_F(BxCanDeviceTest, filterListFr1CorrectShift) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x001U, 0x002U}; + dev->configureFilterList(ids, 2U); + // STID_Pos is 21, so 0x001 << 21 = 0x00200000 + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x00200000U); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x00400000U); +} + +TEST_F(BxCanDeviceTest, filterListBank0And1IndependentFr) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x111U, 0x222U, 0x333U, 0x444U}; + dev->configureFilterList(ids, 4U); + + EXPECT_EQ(fakeCan.sFilterRegister[0].FR1, 0x111U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[0].FR2, 0x222U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR1, 0x333U << CAN_RI0R_STID_Pos); + EXPECT_EQ(fakeCan.sFilterRegister[1].FR2, 0x444U << CAN_RI0R_STID_Pos); +} + +TEST_F(BxCanDeviceTest, filterListSequentialIds) +{ + auto dev = makeInitedDevice(); + uint32_t ids[] = {0x400U, 0x401U, 0x402U, 0x403U, 0x404U, 0x405U}; + dev->configureFilterList(ids, 6U); + + for (uint8_t b = 0; b < 3; b++) + { + uint32_t expected1 = (0x400U + b * 2U) << CAN_RI0R_STID_Pos; + uint32_t expected2 = (0x401U + b * 2U) << CAN_RI0R_STID_Pos; + EXPECT_EQ(fakeCan.sFilterRegister[b].FR1, expected1) << "Bank " << (int)b; + EXPECT_EQ(fakeCan.sFilterRegister[b].FR2, expected2) << "Bank " << (int)b; + } +} + +TEST_F(BxCanDeviceTest, filterList10Ids5Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[10]; + for (uint8_t i = 0; i < 10; i++) + { + ids[i] = 0x200U + i; + } + dev->configureFilterList(ids, 10U); + + for (uint8_t b = 0; b < 5; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b; + } +} + +TEST_F(BxCanDeviceTest, filterList20Ids10Banks) +{ + auto dev = makeInitedDevice(); + uint32_t ids[20]; + for (uint8_t i = 0; i < 20; i++) + { + ids[i] = 0x300U + i; + } + dev->configureFilterList(ids, 20U); + + for (uint8_t b = 0; b < 10; b++) + { + EXPECT_NE(fakeCan.FA1R & (1U << b), 0U) << "Bank " << (int)b; + } +} + +TEST_F(BxCanDeviceTest, filterListReconfigureLeavesOldBanksActive) +{ + auto dev = makeInitedDevice(); + + // First configure 6 IDs (3 banks) + uint32_t ids1[] = {0x100U, 0x200U, 0x300U, 0x400U, 0x500U, 0x600U}; + dev->configureFilterList(ids1, 6U); + EXPECT_NE(fakeCan.FA1R & (1U << 2U), 0U); + + // Now reconfigure with just 2 IDs (1 bank) + uint32_t ids2[] = {0x700U, 0x701U}; + dev->configureFilterList(ids2, 2U); + EXPECT_NE(fakeCan.FA1R & (1U << 0U), 0U); + // configureFilterList does NOT deactivate banks beyond the new list - + // bank 2 from the previous configuration remains active + EXPECT_NE(fakeCan.FA1R & (1U << 2U), 0U); +} + +TEST_F(BxCanDeviceTest, txMailbox0SelectedWhenAllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txMailbox1SelectedWhen0Full) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.sTxMailBox[1].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txMailbox2SelectedWhen01Full) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME2; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.sTxMailBox[2].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txAllFullReturnsFalse) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + uint8_t data[8] = {}; + EXPECT_FALSE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); +} + +TEST_F(BxCanDeviceTest, txTmeBit000AllFull) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; // TME0=0, TME1=0, TME2=0 + uint8_t data[8] = {}; + EXPECT_FALSE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); +} + +TEST_F(BxCanDeviceTest, txTmeBit100Only0Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + uint32_t stid = (fakeCan.sTxMailBox[0].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x100U); +} + +TEST_F(BxCanDeviceTest, txTmeBit010Only1Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME1; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + uint32_t stid = (fakeCan.sTxMailBox[1].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x100U); +} + +TEST_F(BxCanDeviceTest, txTmeBit001Only2Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME2; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + uint32_t stid = (fakeCan.sTxMailBox[2].TIR >> CAN_TI0R_STID_Pos) & 0x7FFU; + EXPECT_EQ(stid, 0x100U); +} + +TEST_F(BxCanDeviceTest, txTmeBit110Only01Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + // Should pick mailbox 0 (first empty) + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txTmeBit101Only02Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME2; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txTmeBit011Only12Empty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + EXPECT_NE(fakeCan.sTxMailBox[1].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txTmeBit111AllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + uint8_t data[8] = {}; + EXPECT_TRUE(dev->transmit(::can::CANFrame(0x100U, data, 1U))); + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txTxrqSetInSelectedMailbox) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME1; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x200U, data, 1U)); + EXPECT_NE(fakeCan.sTxMailBox[1].TIR & CAN_TI0R_TXRQ, 0U); +} + +TEST_F(BxCanDeviceTest, txStandardIdNotIde) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); +} + +TEST_F(BxCanDeviceTest, txExtendedIdSetsIde) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x80000100U, data, 1U)); + EXPECT_NE(fakeCan.sTxMailBox[0].TIR & CAN_TI0R_IDE, 0U); +} + +TEST_F(BxCanDeviceTest, txDlc0) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {}; + dev->transmit(::can::CANFrame(0x100U, data, 0U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 0U); +} + +TEST_F(BxCanDeviceTest, txDlc1) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA}; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 1U); +} + +TEST_F(BxCanDeviceTest, txDlc2) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB}; + dev->transmit(::can::CANFrame(0x100U, data, 2U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 2U); +} + +TEST_F(BxCanDeviceTest, txDlc3) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC}; + dev->transmit(::can::CANFrame(0x100U, data, 3U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 3U); +} + +TEST_F(BxCanDeviceTest, txDlc4) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD}; + dev->transmit(::can::CANFrame(0x100U, data, 4U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 4U); +} + +TEST_F(BxCanDeviceTest, txDlc5) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE}; + dev->transmit(::can::CANFrame(0x100U, data, 5U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 5U); +} + +TEST_F(BxCanDeviceTest, txDlc6) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + dev->transmit(::can::CANFrame(0x100U, data, 6U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 6U); +} + +TEST_F(BxCanDeviceTest, txDlc7) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11}; + dev->transmit(::can::CANFrame(0x100U, data, 7U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 7U); +} + +TEST_F(BxCanDeviceTest, txDlc8) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0; + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}; + dev->transmit(::can::CANFrame(0x100U, data, 8U)); + EXPECT_EQ(fakeCan.sTxMailBox[0].TDTR & 0xFU, 8U); +} + +TEST_F(BxCanDeviceTest, transmitIsrWritesRqcp0) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrWritesRqcp1) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP1, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrWritesRqcp2) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP2, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme000KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = 0U; // All busy + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme001KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme010KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME1; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme011KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme100KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme101KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme110KeepsTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrTme111DisablesTmeie) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrPreservesFmpie0) +{ + auto dev = makeStartedDevice(); + fakeCan.IER |= CAN_IER_TMEIE; + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrNoTmeieWhenNotPreviouslySet) +{ + auto dev = makeStartedDevice(); + fakeCan.IER &= ~CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrCalledMultipleTimesIdempotent) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + fakeCan.IER |= CAN_IER_TMEIE; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrThenTransmitReenablesTmeie) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + fakeCan.IER |= CAN_IER_TMEIE; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); + + fakeCan.TSR = CAN_TSR_TME0; + dev->transmit(::can::CANFrame(0x100U, data, 1U)); + EXPECT_NE(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrRqcpSetEvenWhenAllEmpty) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP0, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP1, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP2, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrRqcpSetEvenWhenAllBusy) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = 0U; + dev->transmitISR(); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP0, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP1, 0U); + EXPECT_NE(fakeCan.TSR & CAN_TSR_RQCP2, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrWithRqcpAlreadySet) +{ + auto dev = makeStartedDevice(); + fakeCan.TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2 | CAN_TSR_TME0 | CAN_TSR_TME1 + | CAN_TSR_TME2; + fakeCan.IER |= CAN_IER_TMEIE; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); +} + +TEST_F(BxCanDeviceTest, transmitIsrRapidCallsDoNotCorruptIer) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 10; i++) + { + fakeCan.IER |= CAN_IER_TMEIE; + fakeCan.TSR = CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2; + dev->transmitISR(); + EXPECT_EQ(fakeCan.IER & CAN_IER_TMEIE, 0U); + EXPECT_NE(fakeCan.IER & CAN_IER_FMPIE0, 0U); + } +} + +TEST_F(BxCanDeviceTest, busOffClearWhenBoffBitClear) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_FALSE(dev->isBusOff()); +} + +TEST_F(BxCanDeviceTest, busOffSetWhenBoffBitSet) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = CAN_ESR_BOFF; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(BxCanDeviceTest, busOffWithTecMaxAndBoff) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = CAN_ESR_BOFF | (255U << CAN_ESR_TEC_Pos); + EXPECT_TRUE(dev->isBusOff()); + EXPECT_EQ(dev->getTxErrorCounter(), 255U); +} + +TEST_F(BxCanDeviceTest, tecZero) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_EQ(dev->getTxErrorCounter(), 0U); +} + +TEST_F(BxCanDeviceTest, tec128) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (128U << CAN_ESR_TEC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 128U); +} + +TEST_F(BxCanDeviceTest, tec255) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (255U << CAN_ESR_TEC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 255U); +} + +TEST_F(BxCanDeviceTest, tec1) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (1U << CAN_ESR_TEC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 1U); +} + +TEST_F(BxCanDeviceTest, recZero) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = 0U; + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(BxCanDeviceTest, rec64) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (64U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 64U); +} + +TEST_F(BxCanDeviceTest, rec127) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (127U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 127U); +} + +TEST_F(BxCanDeviceTest, rec255) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (255U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 255U); +} + +TEST_F(BxCanDeviceTest, rec1) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (1U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 1U); +} + +TEST_F(BxCanDeviceTest, tecAndRecSimultaneous) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (100U << CAN_ESR_TEC_Pos) | (200U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 100U); + EXPECT_EQ(dev->getRxErrorCounter(), 200U); +} + +TEST_F(BxCanDeviceTest, busOffDoesNotAffectErrorCounters) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = CAN_ESR_BOFF | (50U << CAN_ESR_TEC_Pos) | (75U << CAN_ESR_REC_Pos); + EXPECT_TRUE(dev->isBusOff()); + EXPECT_EQ(dev->getTxErrorCounter(), 50U); + EXPECT_EQ(dev->getRxErrorCounter(), 75U); +} + +TEST_F(BxCanDeviceTest, errorCountersChangeOverTime) +{ + auto dev = makeStartedDevice(); + fakeCan.ESR = (10U << CAN_ESR_TEC_Pos) | (20U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 10U); + EXPECT_EQ(dev->getRxErrorCounter(), 20U); + + fakeCan.ESR = (150U << CAN_ESR_TEC_Pos) | (200U << CAN_ESR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 150U); + EXPECT_EQ(dev->getRxErrorCounter(), 200U); + + fakeCan.ESR = 0U; + EXPECT_EQ(dev->getTxErrorCounter(), 0U); + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(BxCanDeviceTest, getRxCountInitiallyZero) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + EXPECT_EQ(dev.getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, getRxCountAfterOneFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(BxCanDeviceTest, getRxCountAfter5Frames) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + for (uint8_t i = 0; i < 5; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 5U); +} + +TEST_F(BxCanDeviceTest, getRxCountAfter32Frames) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + for (uint8_t i = 0; i < 32; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); +} + +TEST_F(BxCanDeviceTest, clearRxQueueSetsCountToZero) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, clearRxQueueMultipleTimes) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, clearRxQueueOnEmptyQueue) +{ + auto dev = makeStartedDevice(); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(BxCanDeviceTest, rxQueueWrappingWithExactCapacity) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to 30 frames, clear, then fill to 32 (wraps around) + for (uint8_t i = 0; i < 30; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + for (uint8_t i = 0; i < 32; i++) + { + data[0] = i; + receiveSingleFrame(*dev, 0x200U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(31).getId(), 0x21FU); +} + +TEST_F(BxCanDeviceTest, rxQueueHeadAdvancesOnClear) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint8_t i = 0; i < 10; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + // Head should now be at 10 + receiveSingleFrame(*dev, 0x500U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x500U); +} + +TEST_F(BxCanDeviceTest, rxQueueMultipleCycleFillAndClear) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (int cycle = 0; cycle < 5; cycle++) + { + for (uint8_t i = 0; i < 8; i++) + { + receiveSingleFrame(*dev, 0x100U * (cycle + 1) + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 8U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + } +} + +TEST_F(BxCanDeviceTest, rxQueueFrameContentAfterWrapping) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill 28 frames, clear, then add 8 more (wraps 28+8=36 > 32) + for (uint8_t i = 0; i < 28; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + for (uint8_t i = 0; i < 8; i++) + { + data[0] = 0xA0U + i; + receiveSingleFrame(*dev, 0x300U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 8U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x300U); + EXPECT_EQ(dev->getRxFrame(0).getPayload()[0], 0xA0U); + EXPECT_EQ(dev->getRxFrame(7).getId(), 0x307U); + EXPECT_EQ(dev->getRxFrame(7).getPayload()[0], 0xA7U); +} + +TEST_F(BxCanDeviceTest, rxQueueFullThen33rdDropped) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint8_t i = 0; i < 32; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + + // 33rd frame should be dropped + placeRxFrameStd(0x999U, 1U, data); + fakeCan.RF0R = 1U; + std::atomic done{false}; + std::thread hwSim( + [&]() + { + while (!done.load(std::memory_order_relaxed)) + { + if ((fakeCan.RF0R & CAN_RF0R_RFOM0) != 0U) + { + fakeCan.RF0R = 0U; + done.store(true, std::memory_order_relaxed); + return; + } + } + }); + uint8_t count = dev->receiveISR(nullptr); + done.store(true, std::memory_order_relaxed); + hwSim.join(); + EXPECT_EQ(count, 0U); + EXPECT_EQ(dev->getRxCount(), 32U); +} + +TEST_F(BxCanDeviceTest, rxQueueClearThenFillToCapacity) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint8_t i = 0; i < 32; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + for (uint8_t i = 0; i < 32; i++) + { + receiveSingleFrame(*dev, 0x200U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(31).getId(), 0x21FU); +} + +TEST_F(BxCanDeviceTest, rxQueueGetFrameIndex0) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x42}; + receiveSingleFrame(*dev, 0x123U, false, 1U, data); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x123U); + EXPECT_EQ(dev->getRxFrame(0).getPayload()[0], 0x42U); +} + +TEST_F(BxCanDeviceTest, rxQueueGetFrameLastIndex) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint8_t i = 0; i < 10; i++) + { + data[0] = i; + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxFrame(9).getId(), 0x109U); + EXPECT_EQ(dev->getRxFrame(9).getPayload()[0], 9U); +} + +TEST_F(BxCanDeviceTest, rxQueueStandardAndExtendedMixed) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + receiveSingleFrame(*dev, 0x1ABCDU, true, 1U, data); + receiveSingleFrame(*dev, 0x200U, false, 1U, data); + + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + EXPECT_EQ(dev->getRxFrame(1).getId(), 0x1ABCDU | 0x80000000U); + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x200U); +} + +TEST_F(BxCanDeviceTest, rxQueueDifferentDlcValues) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + for (uint8_t dlc = 0; dlc <= 8; dlc++) + { + receiveSingleFrame(*dev, 0x100U + dlc, false, dlc, data); + } + EXPECT_EQ(dev->getRxCount(), 9U); + for (uint8_t dlc = 0; dlc <= 8; dlc++) + { + EXPECT_EQ(dev->getRxFrame(dlc).getPayloadLength(), dlc); + } +} + +TEST_F(BxCanDeviceTest, rxQueueReceiveClearReceive) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + receiveSingleFrame(*dev, 0x100U, false, 1U, data); + receiveSingleFrame(*dev, 0x101U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 2U); + + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + receiveSingleFrame(*dev, 0x200U, false, 1U, data); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(BxCanDeviceTest, rxQueueWrappingPreservesDataIntegrity) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill 31 frames and clear + for (uint8_t i = 0; i < 31; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + // Fill 5 more (wraps around position 31 -> 0 -> 1 -> 2 -> 3 -> 4) + for (uint8_t i = 0; i < 5; i++) + { + data[0] = 0xF0U + i; + receiveSingleFrame(*dev, 0x400U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 5U); + for (uint8_t i = 0; i < 5; i++) + { + EXPECT_EQ(dev->getRxFrame(i).getId(), 0x400U + i); + EXPECT_EQ(dev->getRxFrame(i).getPayload()[0], 0xF0U + i); + } +} + +TEST_F(BxCanDeviceTest, rxQueueFullExactly32) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + for (uint8_t i = 0; i < 32; i++) + { + data[0] = i; + receiveSingleFrame(*dev, i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + for (uint8_t i = 0; i < 32; i++) + { + EXPECT_EQ(dev->getRxFrame(i).getId(), static_cast(i)); + EXPECT_EQ(dev->getRxFrame(i).getPayload()[0], i); + } +} + +TEST_F(BxCanDeviceTest, rxQueueClearAfterFullThenRefill) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to capacity + for (uint8_t i = 0; i < 32; i++) + { + receiveSingleFrame(*dev, 0x100U + i, false, 1U, data); + } + dev->clearRxQueue(); + + // Fill again to capacity + for (uint8_t i = 0; i < 32; i++) + { + data[0] = 0x80U + i; + receiveSingleFrame(*dev, 0x300U + i, false, 1U, data); + } + EXPECT_EQ(dev->getRxCount(), 32U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x300U); + EXPECT_EQ(dev->getRxFrame(31).getId(), 0x31FU); +} + +TEST_F(BxCanDeviceTest, rxQueueFilterRejectDoesNotIncrementCount) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t filter[256] = {}; + // Only accept ID 0x100 + filter[0x100 / 8U] |= (1U << (0x100 % 8U)); + + // Try to receive ID 0x200 (rejected) + uint8_t count = receiveSingleFrame(*dev, 0x200U, false, 1U, data, filter); + EXPECT_EQ(count, 0U); + EXPECT_EQ(dev->getRxCount(), 0U); + + // Now receive ID 0x100 (accepted) + count = receiveSingleFrame(*dev, 0x100U, false, 1U, data, filter); + EXPECT_EQ(count, 1U); + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(BxCanDeviceTest, rxQueueFilterAcceptMultipleIds) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + uint8_t filter[256] = {}; + filter[0x100 / 8U] |= (1U << (0x100 % 8U)); + filter[0x200 / 8U] |= (1U << (0x200 % 8U)); + filter[0x300 / 8U] |= (1U << (0x300 % 8U)); + + receiveSingleFrame(*dev, 0x100U, false, 1U, data, filter); + receiveSingleFrame(*dev, 0x150U, false, 1U, data, filter); // Rejected + receiveSingleFrame(*dev, 0x200U, false, 1U, data, filter); + receiveSingleFrame(*dev, 0x250U, false, 1U, data, filter); // Rejected + receiveSingleFrame(*dev, 0x300U, false, 1U, data, filter); + + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + EXPECT_EQ(dev->getRxFrame(1).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x300U); +} + +TEST_F(BxCanDeviceTest, btrBrpField10Bits) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1024U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t brp = fakeCan.BTR & 0x3FFU; + EXPECT_EQ(brp, 1023U); +} + +TEST_F(BxCanDeviceTest, btrTs1Field4Bits) +{ + auto cfg = makeDefaultConfig(); + cfg.bs1 = 16U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t ts1 = (fakeCan.BTR >> CAN_BTR_TS1_Pos) & 0xFU; + EXPECT_EQ(ts1, 15U); +} + +TEST_F(BxCanDeviceTest, btrTs2Field3Bits) +{ + auto cfg = makeDefaultConfig(); + cfg.bs2 = 8U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t ts2 = (fakeCan.BTR >> CAN_BTR_TS2_Pos) & 0x7U; + EXPECT_EQ(ts2, 7U); +} + +TEST_F(BxCanDeviceTest, btrSjwField2Bits) +{ + auto cfg = makeDefaultConfig(); + cfg.sjw = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t sjw = (fakeCan.BTR >> CAN_BTR_SJW_Pos) & 0x3U; + EXPECT_EQ(sjw, 3U); +} + +TEST_F(BxCanDeviceTest, btrPrescaler2) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 2U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 1U); +} + +TEST_F(BxCanDeviceTest, btrPrescaler100) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 100U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 99U); +} + +TEST_F(BxCanDeviceTest, btrPrescaler256) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 256U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 255U); +} + +TEST_F(BxCanDeviceTest, btrCan250kbpsAt42MHz) +{ + // 42 MHz APB1, 250 kbps: prescaler=12, BS1=11, BS2=2, SJW=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 12U; + cfg.bs1 = 11U; + cfg.bs2 = 2U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 11U); + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 10U); + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 1U); + EXPECT_EQ((btr >> CAN_BTR_SJW_Pos) & 0x3U, 0U); +} + +TEST_F(BxCanDeviceTest, btrCan1MbpsAt42MHz) +{ + // 42 MHz APB1, 1 Mbps: prescaler=3, BS1=11, BS2=2, SJW=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 3U; + cfg.bs1 = 11U; + cfg.bs2 = 2U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 2U); + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 10U); + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 1U); +} + +TEST_F(BxCanDeviceTest, btrCan125kbpsAt36MHz) +{ + // 36 MHz APB1, 125 kbps: prescaler=18, BS1=13, BS2=2, SJW=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 18U; + cfg.bs1 = 13U; + cfg.bs2 = 2U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 17U); + EXPECT_EQ((fakeCan.BTR >> CAN_BTR_TS1_Pos) & 0xFU, 12U); + EXPECT_EQ((fakeCan.BTR >> CAN_BTR_TS2_Pos) & 0x7U, 1U); +} + +TEST_F(BxCanDeviceTest, btrAllFieldsMaxValues) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1024U; + cfg.bs1 = 16U; + cfg.bs2 = 8U; + cfg.sjw = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 1023U); + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 15U); + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 7U); + EXPECT_EQ((btr >> CAN_BTR_SJW_Pos) & 0x3U, 3U); +} + +TEST_F(BxCanDeviceTest, btrAllFieldsMinValues) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + cfg.bs1 = 1U; + cfg.bs2 = 1U; + cfg.sjw = 1U; + bios::BxCanDevice dev(cfg); + dev.init(); + + uint32_t btr = fakeCan.BTR; + EXPECT_EQ(btr & 0x3FFU, 0U); + EXPECT_EQ((btr >> CAN_BTR_TS1_Pos) & 0xFU, 0U); + EXPECT_EQ((btr >> CAN_BTR_TS2_Pos) & 0x7U, 0U); + EXPECT_EQ((btr >> CAN_BTR_SJW_Pos) & 0x3U, 0U); +} + +TEST_F(BxCanDeviceTest, btrNoSilentOrLoopbackMode) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // SILM and LBKM should not be set for normal operation + EXPECT_EQ(fakeCan.BTR & CAN_BTR_SILM, 0U); + EXPECT_EQ(fakeCan.BTR & CAN_BTR_LBKM, 0U); +} + +TEST_F(BxCanDeviceTest, btrRewrittenOnDoubleInit) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 4U; + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 3U); + + // Corrupt BTR + fakeCan.BTR = 0xFFFFFFFFU; + + // Re-init should restore correct BTR + dev.init(); + EXPECT_EQ(fakeCan.BTR & 0x3FFU, 3U); +} + +TEST_F(BxCanDeviceTest, btrBs1Value8) +{ + auto cfg = makeDefaultConfig(); + cfg.bs1 = 8U; + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t ts1 = (fakeCan.BTR >> CAN_BTR_TS1_Pos) & 0xFU; + EXPECT_EQ(ts1, 7U); +} + +TEST_F(BxCanDeviceTest, clockEnableSetsApb1enrBit25) +{ + fakeRcc.APB1ENR = 0U; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & (1U << 25U), 0U); +} + +TEST_F(BxCanDeviceTest, clockEnablePreservesOtherBitsInApb1enr) +{ + fakeRcc.APB1ENR = 0x00000001U; // Some other peripheral enabled + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & 0x00000001U, 0U); + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); +} + +TEST_F(BxCanDeviceTest, clockEnableIdempotentMultipleInits) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + uint32_t v1 = fakeRcc.APB1ENR; + dev.init(); + uint32_t v2 = fakeRcc.APB1ENR; + dev.init(); + uint32_t v3 = fakeRcc.APB1ENR; + EXPECT_EQ(v1, v2); + EXPECT_EQ(v2, v3); +} + +TEST_F(BxCanDeviceTest, clockEnableBeforeGpioConfig) +{ + // After init, both clock and GPIO should be configured + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); + uint32_t txModer = (fakeTxGpio.MODER >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txModer, 2U); +} + +TEST_F(BxCanDeviceTest, clockEnableWithAllApb1BitsSet) +{ + fakeRcc.APB1ENR = 0xFFFFFFFFU; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // All bits should still be set + EXPECT_EQ(fakeRcc.APB1ENR, 0xFFFFFFFFU); +} + +TEST_F(BxCanDeviceTest, clockEnableBitExactValue) +{ + fakeRcc.APB1ENR = 0U; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, (1U << 25U)); +} + +TEST_F(BxCanDeviceTest, clockEnableDoesNotTouchApb2enr) +{ + fakeRcc.APB2ENR = 0U; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeRcc.APB2ENR, 0U); +} + +TEST_F(BxCanDeviceTest, clockEnableDoesNotTouchAhb1enr) +{ + fakeRcc.AHB1ENR = 0U; + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + // Note: GPIO clock enable might set AHB1ENR bits, + // but CAN clock should only touch APB1ENR + // We just verify CAN1EN is in APB1ENR + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); +} + +TEST_F(BxCanDeviceTest, clockEnableWithNeighborBitsPreserved) +{ + // Set bits 24 and 26 (neighbors of bit 25) + fakeRcc.APB1ENR = (1U << 24U) | (1U << 26U); + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR & (1U << 24U), 0U); + EXPECT_NE(fakeRcc.APB1ENR & (1U << 25U), 0U); + EXPECT_NE(fakeRcc.APB1ENR & (1U << 26U), 0U); +} + +TEST_F(BxCanDeviceTest, clockEnableAfterStopAndReInit) +{ + auto dev = makeStartedDevice(); + fakeCan.MSR |= CAN_MSR_INAK; + dev->stop(); + + // Re-init + dev->init(); + EXPECT_NE(fakeRcc.APB1ENR & RCC_APB1ENR_CAN1EN, 0U); +} + +TEST_F(BxCanDeviceTest, gpioRxPullUpConfigured) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + + // RX pin should have pull-up (PUPDR = 01) + uint32_t pupdr = (fakeRxGpio.PUPDR >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(pupdr, 1U); +} + +TEST_F(BxCanDeviceTest, gpioTxHighSpeedConfigured) +{ + auto cfg = makeDefaultConfig(); + bios::BxCanDevice dev(cfg); + dev.init(); + + // TX pin should have high speed (OSPEEDR = 11) + uint32_t speed = (fakeTxGpio.OSPEEDR >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(speed, 3U); +} + +TEST_F(BxCanDeviceTest, rxQueueCapacityConstant) +{ + EXPECT_EQ(bios::BxCanDevice::RX_QUEUE_SIZE, 32U); +} diff --git a/platforms/stm32/bsp/bspCan/test/src/can/FakeHwHelpers.h b/platforms/stm32/bsp/bspCan/test/src/can/FakeHwHelpers.h new file mode 100644 index 00000000000..54151b0e51f --- /dev/null +++ b/platforms/stm32/bsp/bspCan/test/src/can/FakeHwHelpers.h @@ -0,0 +1,170 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +/** + * \file FakeHwHelpers.h + * \brief Smart fake register helpers for STM32 unit tests. + * + * Solves three problems that prevent tests from running on x86_64 host: + * + * 1. HW busy-wait loops: Production code writes a control bit then polls + * a status bit that hardware would auto-set/clear. These helpers hook + * into the fake register structs to simulate the state transitions. + * + * 2. 64-bit pointer truncation: Provides FAKE_ADDR() macro that safely + * creates a testable address from a static array on any platform. + * + * 3. Message RAM access: Provides a fake message RAM region with proper + * addressing that works on both 32-bit and 64-bit hosts. + */ + +#pragma once + +#include +#include + +// ============================================================================ +// Portable address casting - works on both 32-bit ARM and 64-bit host +// ============================================================================ + +/// Cast a pointer to the address type used by the production code (uint32_t). +/// On 64-bit host this truncates, but the production code will cast it back +/// to a pointer via reinterpret_cast(addr) which restores the full address +/// ONLY if the original pointer is in the low 4GB. We use static arrays which +/// on most x86_64 systems are in the low address space. +/// +/// For tests that need message RAM pointer arithmetic, use FakeMessageRam instead. +static inline uint32_t ptrToU32(void* p) +{ + return static_cast(reinterpret_cast(p)); +} + +// ============================================================================ +// BxCAN state simulation +// ============================================================================ + +/// Call after each write to fake CAN->MCR to simulate MSR tracking. +/// When INRQ is set in MCR, hardware sets INAK in MSR. +/// When INRQ is cleared, hardware clears INAK. +struct BxCanStateTracker +{ + /// Bit positions (must match CAN_MCR_INRQ and CAN_MSR_INAK) + static constexpr uint32_t MCR_INRQ = (1U << 0); + static constexpr uint32_t MSR_INAK = (1U << 0); + + /// Call this after writing to fakeCan.MCR + static void syncMsrFromMcr(uint32_t volatile& mcr, uint32_t volatile& msr) + { + if ((mcr & MCR_INRQ) != 0U) + { + msr |= MSR_INAK; // entering init mode + } + else + { + msr &= ~MSR_INAK; // leaving init mode + } + } +}; + +// ============================================================================ +// FDCAN state simulation +// ============================================================================ + +struct FdCanStateTracker +{ + static constexpr uint32_t CCCR_INIT = (1U << 0); + + /// Call this after writing to fakeFdcan.CCCR + static void syncCccrInit(uint32_t volatile& cccr) + { + // On real HW, writing INIT=1 is reflected immediately. + // Writing INIT=0 clears it after the peripheral finishes. + // In the fake, the write already sets/clears the bit directly + // since we're writing to a RAM variable. No extra action needed. + // The production code's while-loop checks the same variable + // and will see the change immediately. + (void)cccr; + } +}; + +// ============================================================================ +// ADC state simulation +// ============================================================================ + +struct AdcStateTracker +{ + /// After writing ADCAL=1 to CR, hardware clears it when calibration done. + /// We clear it immediately since there's no real calibration to do. + static void clearAdcalAfterWrite(uint32_t volatile& cr, uint32_t adcalBit) { cr &= ~adcalBit; } + + /// After writing ADEN=1 to CR, hardware sets ADRDY in ISR. + static void setAdrdyAfterEnable( + uint32_t volatile& cr, uint32_t volatile& isr, uint32_t adenBit, uint32_t adrdyBit) + { + if ((cr & adenBit) != 0U) + { + isr |= adrdyBit; + } + } + + /// After writing ADSTART=1, hardware sets EOC when conversion done. + static void setEocAfterStart( + uint32_t volatile& cr, uint32_t volatile& isr, uint32_t adstartBit, uint32_t eocBit) + { + if ((cr & adstartBit) != 0U) + { + isr |= eocBit; + } + } +}; + +// ============================================================================ +// Flash state simulation +// ============================================================================ + +struct FlashStateTracker +{ + /// Flash BSY bit is always 0 in fake (operation completes instantly). + /// The production waitForFlash() checks FLASH->SR & BSY - as long as + /// we memset SR to 0 in SetUp(), the loop exits immediately. + /// No action needed if SetUp clears SR. + + /// After erasePage sets STRT, clear it (simulates erase complete). + static void clearAfterErase(uint32_t volatile& cr, uint32_t volatile& sr, uint32_t strtBit) + { + cr &= ~strtBit; + sr = 0U; // BSY=0, no errors + } +}; + +// ============================================================================ +// Fake message RAM for FDCAN (solves 64-bit pointer truncation) +// ============================================================================ + +/// Provides a message RAM region that can be addressed via uint32_t offsets. +/// Instead of using absolute addresses (which get truncated on x86_64), +/// the tests should set SRAMCAN_BASE to 0 and use relative offsets into +/// this array. The production code does: `base + offset` then casts to +/// `uint32_t*`. If base is the actual array address (as uintptr_t cast to +/// uint32_t), it gets truncated. The fix: define SRAMCAN_BASE as 0 and +/// override getInstanceRamBase() to return the real pointer. +/// +/// However, since getInstanceRamBase is a static function inside the .cpp, +/// we can't easily override it. The simplest approach: on 64-bit host, +/// accept that message RAM tests will segfault and skip them with a guard. +/// +/// For a complete fix, the production code should use uintptr_t for RAM +/// addresses, which is an API change requiring upstream approval. + +#if UINTPTR_MAX > UINT32_MAX +#define FAKE_MSG_RAM_64BIT_HOST 1 +#else +#define FAKE_MSG_RAM_64BIT_HOST 0 +#endif diff --git a/platforms/stm32/bsp/bspCan/test/src/can/FdCanDeviceTest.cpp b/platforms/stm32/bsp/bspCan/test/src/can/FdCanDeviceTest.cpp new file mode 100644 index 00000000000..5fea5c6b99a --- /dev/null +++ b/platforms/stm32/bsp/bspCan/test/src/can/FdCanDeviceTest.cpp @@ -0,0 +1,3657 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// Test-only hardware fakes - must be defined before any STM32 header inclusion. + +#include +#include + +// Provide __IO as volatile (same as CMSIS) +#ifndef __IO +#define __IO volatile +#endif + +// --- Fake GPIO_TypeDef (matches STM32G4 layout) --- +typedef struct +{ + __IO uint32_t MODER; + __IO uint32_t OTYPER; + __IO uint32_t OSPEEDR; + __IO uint32_t PUPDR; + __IO uint32_t IDR; + __IO uint32_t ODR; + __IO uint32_t BSRR; + __IO uint32_t LCKR; + __IO uint32_t AFR[2]; + __IO uint32_t BRR; +} GPIO_TypeDef; + +// --- Fake RCC_TypeDef (matches STM32G4 layout) --- +typedef struct +{ + __IO uint32_t CR; + __IO uint32_t ICSCR; + __IO uint32_t CFGR; + __IO uint32_t PLLCFGR; + uint32_t RESERVED0; + uint32_t RESERVED1; + __IO uint32_t CIER; + __IO uint32_t CIFR; + __IO uint32_t CICR; + uint32_t RESERVED2; + __IO uint32_t AHB1RSTR; + __IO uint32_t AHB2RSTR; + __IO uint32_t AHB3RSTR; + uint32_t RESERVED3; + __IO uint32_t APB1RSTR1; + __IO uint32_t APB1RSTR2; + __IO uint32_t APB2RSTR; + uint32_t RESERVED4; + __IO uint32_t AHB1ENR; + __IO uint32_t AHB2ENR; + __IO uint32_t AHB3ENR; + uint32_t RESERVED5; + __IO uint32_t APB1ENR1; + __IO uint32_t APB1ENR2; + __IO uint32_t APB2ENR; + uint32_t RESERVED6; + __IO uint32_t AHB1SMENR; + __IO uint32_t AHB2SMENR; + __IO uint32_t AHB3SMENR; + uint32_t RESERVED7; + __IO uint32_t APB1SMENR1; + __IO uint32_t APB1SMENR2; + __IO uint32_t APB2SMENR; + uint32_t RESERVED8; + __IO uint32_t CCIPR; + uint32_t RESERVED9; + __IO uint32_t BDCR; + __IO uint32_t CSR; + __IO uint32_t CRRCR; + __IO uint32_t CCIPR2; +} RCC_TypeDef; + +// --- Fake FDCAN_GlobalTypeDef (matches STM32G4 layout) --- +typedef struct +{ + __IO uint32_t CREL; + __IO uint32_t ENDN; + uint32_t RESERVED1; + __IO uint32_t DBTP; + __IO uint32_t TEST; + __IO uint32_t RWD; + __IO uint32_t CCCR; + __IO uint32_t NBTP; + __IO uint32_t TSCC; + __IO uint32_t TSCV; + __IO uint32_t TOCC; + __IO uint32_t TOCV; + uint32_t RESERVED2[4]; + __IO uint32_t ECR; + __IO uint32_t PSR; + __IO uint32_t TDCR; + uint32_t RESERVED3; + __IO uint32_t IR; + __IO uint32_t IE; + __IO uint32_t ILS; + __IO uint32_t ILE; + uint32_t RESERVED4[8]; + __IO uint32_t RXGFC; + __IO uint32_t XIDAM; + __IO uint32_t HPMS; + uint32_t RESERVED5; + __IO uint32_t RXF0S; + __IO uint32_t RXF0A; + __IO uint32_t RXF1S; + __IO uint32_t RXF1A; + uint32_t RESERVED6[8]; + __IO uint32_t TXBC; + __IO uint32_t TXFQS; + __IO uint32_t TXBRP; + __IO uint32_t TXBAR; + __IO uint32_t TXBCR; + __IO uint32_t TXBTO; + __IO uint32_t TXBCF; + __IO uint32_t TXBTIE; + __IO uint32_t TXBCIE; + __IO uint32_t TXEFS; + __IO uint32_t TXEFA; +} FDCAN_GlobalTypeDef; + +// --- Static fake peripherals --- +static RCC_TypeDef fakeRcc; +static FDCAN_GlobalTypeDef fakeFdcan; +static GPIO_TypeDef fakeTxGpio; +static GPIO_TypeDef fakeRxGpio; + +// Fake message RAM (848 bytes = 212 words per FDCAN instance) +static uint32_t fakeMessageRam[212]; + +// --- Override hardware macros to point at our fakes --- +#define RCC (&fakeRcc) +#define FDCAN1 (&fakeFdcan) +#define FDCAN1_BASE (reinterpret_cast(&fakeFdcan)) +#define SRAMCAN_BASE (reinterpret_cast(&fakeMessageRam[0])) +#define PERIPH_BASE 0x40000000UL +#define APB1PERIPH_BASE PERIPH_BASE + +// --- FDCAN register bit definitions (from stm32g474xx.h) --- +#define FDCAN_CCCR_INIT_Pos (0U) +#define FDCAN_CCCR_INIT (0x1UL << FDCAN_CCCR_INIT_Pos) +#define FDCAN_CCCR_CCE_Pos (1U) +#define FDCAN_CCCR_CCE (0x1UL << FDCAN_CCCR_CCE_Pos) +#define FDCAN_CCCR_FDOE_Pos (8U) +#define FDCAN_CCCR_FDOE (0x1UL << FDCAN_CCCR_FDOE_Pos) +#define FDCAN_CCCR_BRSE_Pos (9U) +#define FDCAN_CCCR_BRSE (0x1UL << FDCAN_CCCR_BRSE_Pos) + +#define FDCAN_NBTP_NTSEG2_Pos (0U) +#define FDCAN_NBTP_NTSEG1_Pos (8U) +#define FDCAN_NBTP_NBRP_Pos (16U) +#define FDCAN_NBTP_NSJW_Pos (25U) + +#define FDCAN_ECR_TEC_Pos (0U) +#define FDCAN_ECR_REC_Pos (8U) + +#define FDCAN_PSR_BO_Pos (7U) +#define FDCAN_PSR_BO (0x1UL << FDCAN_PSR_BO_Pos) + +#define FDCAN_IR_RF0N_Pos (0U) +#define FDCAN_IR_RF0N (0x1UL << FDCAN_IR_RF0N_Pos) +#define FDCAN_IR_RF0F_Pos (1U) +#define FDCAN_IR_RF0F (0x1UL << FDCAN_IR_RF0F_Pos) +#define FDCAN_IR_RF0L_Pos (2U) +#define FDCAN_IR_RF0L (0x1UL << FDCAN_IR_RF0L_Pos) +#define FDCAN_IR_TC_Pos (7U) +#define FDCAN_IR_TC (0x1UL << FDCAN_IR_TC_Pos) + +#define FDCAN_IE_RF0NE_Pos (0U) +#define FDCAN_IE_RF0NE (0x1UL << FDCAN_IE_RF0NE_Pos) +#define FDCAN_IE_TCE_Pos (7U) +#define FDCAN_IE_TCE (0x1UL << FDCAN_IE_TCE_Pos) +#define FDCAN_IE_TEFNE_Pos (12U) +#define FDCAN_IE_TEFNE (0x1UL << FDCAN_IE_TEFNE_Pos) + +#define FDCAN_IR_TEFN_Pos (12U) +#define FDCAN_IR_TEFN (0x1UL << FDCAN_IR_TEFN_Pos) + +#define FDCAN_TXEFS_EFFL_Pos (0U) +#define FDCAN_TXEFS_EFFL (0x7UL << FDCAN_TXEFS_EFFL_Pos) +#define FDCAN_TXEFS_EFGI_Pos (8U) +#define FDCAN_TXEFS_EFGI (0x3UL << FDCAN_TXEFS_EFGI_Pos) + +#define FDCAN_DBTP_DSJW_Pos (0U) +#define FDCAN_DBTP_DTSEG2_Pos (4U) +#define FDCAN_DBTP_DTSEG1_Pos (8U) +#define FDCAN_DBTP_DBRP_Pos (16U) +#define FDCAN_DBTP_TDC_Pos (23U) +#define FDCAN_DBTP_TDC (0x1UL << FDCAN_DBTP_TDC_Pos) + +#define FDCAN_TDCR_TDCO_Pos (8U) + +#define FDCAN_ILS_SMSG_Pos (2U) +#define FDCAN_ILS_SMSG (0x1UL << FDCAN_ILS_SMSG_Pos) + +#define FDCAN_ILE_EINT0_Pos (0U) +#define FDCAN_ILE_EINT0 (0x1UL << FDCAN_ILE_EINT0_Pos) +#define FDCAN_ILE_EINT1_Pos (1U) +#define FDCAN_ILE_EINT1 (0x1UL << FDCAN_ILE_EINT1_Pos) + +#define FDCAN_RXGFC_ANFE_Pos (2U) +#define FDCAN_RXGFC_ANFS_Pos (4U) +#define FDCAN_RXGFC_LSS_Pos (16U) +#define FDCAN_RXGFC_LSE_Pos (20U) + +#define FDCAN_RXF0S_F0FL_Pos (0U) +#define FDCAN_RXF0S_F0FL (0xFUL << FDCAN_RXF0S_F0FL_Pos) +#define FDCAN_RXF0S_F0GI_Pos (8U) +#define FDCAN_RXF0S_F0GI (0x3UL << FDCAN_RXF0S_F0GI_Pos) + +#define FDCAN_TXFQS_TFFL_Pos (0U) +#define FDCAN_TXFQS_TFFL (0x7UL << FDCAN_TXFQS_TFFL_Pos) +#define FDCAN_TXFQS_TFQPI_Pos (16U) +#define FDCAN_TXFQS_TFQPI (0x3UL << FDCAN_TXFQS_TFQPI_Pos) + +#define RCC_APB1ENR1_FDCANEN_Pos (25U) +#define RCC_APB1ENR1_FDCANEN (0x1UL << RCC_APB1ENR1_FDCANEN_Pos) + +// Prevent the real mcu.h from being included (it would pull in stm32g474xx.h) +#define MCU_MCU_H +#define MCU_TYPEDEFS_H + +// Provide the CANFrame include path directly +#include + +// Now include the driver header - it will see our faked types +#include + +// Include the implementation directly so it compiles with our fakes. +// The getInstanceRamBase() function compares against FDCAN1 which is now &fakeFdcan. +#include + +#include + +// Message RAM offset constants (must match FdCanDevice.cpp). +static constexpr uint32_t MSG_RAM_STD_FILTER_OFFSET = 0x000U; +static constexpr uint32_t MSG_RAM_RX_FIFO0_OFFSET = 0x0B0U; +static constexpr uint32_t MSG_RAM_TX_BUFFER_OFFSET = 0x278U; // STM32G4 specific + +class FdCanDeviceTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Zero all fake peripherals and message RAM + memset(&fakeRcc, 0, sizeof(fakeRcc)); + memset(&fakeFdcan, 0, sizeof(fakeFdcan)); + memset(&fakeTxGpio, 0, sizeof(fakeTxGpio)); + memset(&fakeRxGpio, 0, sizeof(fakeRxGpio)); + memset(fakeMessageRam, 0, sizeof(fakeMessageRam)); + + // The CCCR.INIT bit: after setting INIT, the hardware immediately + // reflects it. In our fake we simulate this by pre-setting the bit + // in the write path (the driver busy-waits until INIT is set). + // We handle this by setting INIT in CCCR before construction so + // enterInitMode's while-loop terminates immediately. + } + + bios::FdCanDevice::Config makeDefaultConfig() + { + bios::FdCanDevice::Config cfg{}; + cfg.baseAddress = &fakeFdcan; + cfg.prescaler = 4U; // BRP = prescaler - 1 = 3 + cfg.nts1 = 13U; // NTSEG1 + cfg.nts2 = 2U; // NTSEG2 + cfg.nsjw = 1U; // NSJW + cfg.rxGpioPort = &fakeRxGpio; + cfg.rxPin = 11U; // PA11 (high pin, tests AFR[1] path) + cfg.rxAf = 9U; // AF9 + cfg.txGpioPort = &fakeTxGpio; + cfg.txPin = 5U; // PB5 (low pin, tests AFR[0] path) + cfg.txAf = 9U; // AF9 + return cfg; + } + + // Helper: simulate hardware behavior where INIT bit reflects immediately + void simulateInitBitReflection() + { + // The driver sets INIT, then busy-waits. Since our fake register + // reflects the write immediately (same memory), the loop exits. + // No extra action needed for stack-based volatile registers. + } + + // Helper: put device into initialized + started state + std::unique_ptr makeInitedDevice() + { + auto cfg = makeDefaultConfig(); + auto dev = std::make_unique(cfg); + dev->init(); + return dev; + } + + std::unique_ptr makeStartedDevice() + { + auto dev = makeInitedDevice(); + dev->start(); + return dev; + } + + // Helper: place a frame in RX FIFO0 message RAM at given index + // Element spacing is 72 bytes (18 words) - must match RX_ELEMENT_SIZE + // in FdCanDevice.cpp. + void + placeRxFrame(uint8_t fifoIndex, uint32_t canId, bool extended, uint8_t dlc, uint8_t const* data) + { + uint32_t* rxBuf = reinterpret_cast( + reinterpret_cast(fakeMessageRam) + MSG_RAM_RX_FIFO0_OFFSET + + (fifoIndex * 72U)); + + // Word 0: ID + if (extended) + { + rxBuf[0] = (canId & 0x1FFFFFFFU) | (1U << 30U); // XTD bit + } + else + { + rxBuf[0] = ((canId & 0x7FFU) << 18U); + } + + // Word 1: DLC + rxBuf[1] = (static_cast(dlc) << 16U); + + // Words 2-3: Data + if (data != nullptr) + { + rxBuf[2] = static_cast(data[0]) | (static_cast(data[1]) << 8U) + | (static_cast(data[2]) << 16U) + | (static_cast(data[3]) << 24U); + rxBuf[3] = static_cast(data[4]) | (static_cast(data[5]) << 8U) + | (static_cast(data[6]) << 16U) + | (static_cast(data[7]) << 24U); + } + } + + // Helper: set RX FIFO0 fill level and get index + void setRxFifoStatus(uint8_t fillLevel, uint8_t getIndex) + { + fakeFdcan.RXF0S = (static_cast(fillLevel) << FDCAN_RXF0S_F0FL_Pos) + | (static_cast(getIndex) << FDCAN_RXF0S_F0GI_Pos); + } + + // Helper: set TX FIFO free level and put index + void setTxFifoStatus(uint8_t freeLevel, uint8_t putIndex) + { + fakeFdcan.TXFQS = (static_cast(freeLevel) << FDCAN_TXFQS_TFFL_Pos) + | (static_cast(putIndex) << FDCAN_TXFQS_TFQPI_Pos); + } + + // Helper: read TX buffer element from message RAM + // Element spacing is 72 bytes (18 words) - must match TX_ELEMENT_SIZE + // in FdCanDevice.cpp. + uint32_t const* getTxBuffer(uint8_t index) + { + return reinterpret_cast( + reinterpret_cast(fakeMessageRam) + MSG_RAM_TX_BUFFER_OFFSET + (index * 72U)); + } + + // Helper: read standard filter element from message RAM + uint32_t getStdFilter(uint8_t index) + { + uint32_t const* filterRam = reinterpret_cast( + reinterpret_cast(fakeMessageRam) + MSG_RAM_STD_FILTER_OFFSET); + return filterRam[index]; + } +}; + +TEST_F(FdCanDeviceTest, initEnablesPeripheralClock) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + + EXPECT_EQ(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); +} + +TEST_F(FdCanDeviceTest, initSelectsPclk1KernelClock) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // CCIPR[25:24] should be 10b = PCLK1 + uint32_t fdcanSel = (fakeRcc.CCIPR >> 24U) & 3U; + EXPECT_EQ(fdcanSel, 2U); +} + +TEST_F(FdCanDeviceTest, initConfiguresGpioTxAlternateFunction) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // TX pin = 5 (low register AFR[0]), AF9 + uint32_t txModer = (fakeTxGpio.MODER >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txModer, 2U); // Alternate function mode + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (cfg.txPin * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); + + // Very high speed + uint32_t txSpeed = (fakeTxGpio.OSPEEDR >> (cfg.txPin * 2U)) & 3U; + EXPECT_EQ(txSpeed, 3U); +} + +TEST_F(FdCanDeviceTest, initConfiguresGpioRxAlternateFunctionHighPin) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // RX pin = 11 (high register AFR[1]), AF9 + uint32_t rxModer = (fakeRxGpio.MODER >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(rxModer, 2U); // Alternate function mode + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((cfg.rxPin - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); + + // Pull-up for RX + uint32_t rxPupdr = (fakeRxGpio.PUPDR >> (cfg.rxPin * 2U)) & 3U; + EXPECT_EQ(rxPupdr, 1U); +} + +TEST_F(FdCanDeviceTest, initConfiguresGpioRxLowPin) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 4U; // Low pin to test AFR[0] path + cfg.rxAf = 7U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[0] >> (cfg.rxPin * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 7U); +} + +TEST_F(FdCanDeviceTest, initConfiguresGpioTxHighPin) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 12U; + cfg.txAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[1] >> ((cfg.txPin - 8U) * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); +} + +TEST_F(FdCanDeviceTest, initEntersInitMode) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // After init(), INIT bit should still be set (init mode stays until start()) + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + // CCE should be set (configuration change enabled) + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_CCE, 0U); +} + +TEST_F(FdCanDeviceTest, initDisablesFdAndBrs) +{ + auto cfg = makeDefaultConfig(); + // Pre-set FDOE and BRSE to verify init clears them + fakeFdcan.CCCR = FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE; + bios::FdCanDevice dev(cfg); + dev.init(); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_FDOE, 0U); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_BRSE, 0U); +} + +TEST_F(FdCanDeviceTest, initConfiguresBitTiming) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbtp = fakeFdcan.NBTP; + uint32_t nsjw = (nbtp >> FDCAN_NBTP_NSJW_Pos) & 0x7FU; + uint32_t nbrp = (nbtp >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + uint32_t nts1 = (nbtp >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU; + uint32_t nts2 = (nbtp >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU; + + EXPECT_EQ(nsjw, cfg.nsjw); + EXPECT_EQ(nbrp, cfg.prescaler - 1U); // prescaler is encoded as (prescaler-1) + EXPECT_EQ(nts1, cfg.nts1); + EXPECT_EQ(nts2, cfg.nts2); +} + +TEST_F(FdCanDeviceTest, initConfiguresMessageRam) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // RXGFC should have LSS=0, LSE=0 initially (accept-all replaces it) + // TXBC should be 0 (FIFO mode) + EXPECT_EQ(fakeFdcan.TXBC, 0U); +} + +TEST_F(FdCanDeviceTest, initConfiguresAcceptAllFilter) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // ANFS=0 (accept non-matching std into FIFO0), ANFE=0 (accept non-matching ext into FIFO0) + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfs, 0U); + EXPECT_EQ(anfe, 0U); +} + +TEST_F(FdCanDeviceTest, initSetsInitializedFlag) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + // Before init, start should do nothing (tested in startWithoutInitDoesNothing) + dev.init(); + // After init, start should work - verified indirectly via start() tests +} + +TEST_F(FdCanDeviceTest, doubleInitSafe) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // Second init should not crash + dev.init(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, startEnablesRxFifoInterrupt) +{ + auto dev = makeInitedDevice(); + dev->start(); + // start() enables only RF0NE (RX FIFO 0 new element). TCE is managed + // per-TX by transmit(frame, true) and disabled by transmitISR(). + EXPECT_EQ(fakeFdcan.IE, FDCAN_IE_RF0NE); +} + +TEST_F(FdCanDeviceTest, startSetsILS) +{ + auto dev = makeInitedDevice(); + dev->start(); + // All interrupts routed to line 0 (ILS=0) + EXPECT_EQ(fakeFdcan.ILS, 0U); +} + +TEST_F(FdCanDeviceTest, startEnablesILE) +{ + auto dev = makeInitedDevice(); + dev->start(); + // Only EINT0 enabled (all interrupts on line 0) + EXPECT_NE(fakeFdcan.ILE & FDCAN_ILE_EINT0, 0U); +} + +TEST_F(FdCanDeviceTest, startSetsTXBTIE) +{ + auto dev = makeInitedDevice(); + dev->start(); + // All 3 TX buffers enabled + EXPECT_EQ(fakeFdcan.TXBTIE, 0x7U); +} + +TEST_F(FdCanDeviceTest, startLeavesInitMode) +{ + auto dev = makeInitedDevice(); + dev->start(); + // INIT bit should be cleared + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, startWithoutInitDoesNothing) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + // Do NOT call init() + dev.start(); + // IE should remain 0 - start() returned early + EXPECT_EQ(fakeFdcan.IE, 0U); + EXPECT_EQ(fakeFdcan.ILS, 0U); + EXPECT_EQ(fakeFdcan.ILE, 0U); +} + +TEST_F(FdCanDeviceTest, stopDisablesInterrupts) +{ + auto dev = makeStartedDevice(); + dev->stop(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, stopEntersInitMode) +{ + auto dev = makeStartedDevice(); + dev->stop(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, transmitReturnsTrueOnSuccess) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); // 3 free slots, put index 0 + + uint8_t data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + ::can::CANFrame frame(0x100, data, 8U); + + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, transmitReturnsFalseWhenFifoFull) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(0U, 0U); // 0 free slots + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 8U); + + EXPECT_FALSE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, transmitSetsCorrectStandardId) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x123, data, 8U); + dev->transmit(frame); + + uint32_t const* txBuf = getTxBuffer(0); + // Standard ID: shifted left by 18, no XTD bit + EXPECT_EQ(txBuf[0], (0x123U << 18U)); +} + +TEST_F(FdCanDeviceTest, transmitSetsExtendedId) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + // Extended ID has bit 31 set (0x80000000) + uint32_t extId = 0x80000000U | 0x12345U; + ::can::CANFrame frame(extId, data, 8U); + dev->transmit(frame); + + uint32_t const* txBuf = getTxBuffer(0); + // Extended: raw 29-bit ID in bits [28:0], XTD bit at [30] + EXPECT_EQ(txBuf[0], (0x12345U) | (1U << 30U)); +} + +TEST_F(FdCanDeviceTest, transmitSetsCorrectDlc) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 5U); + dev->transmit(frame); + + uint32_t const* txBuf = getTxBuffer(0); + uint8_t dlc = static_cast((txBuf[1] >> 16U) & 0xFU); + EXPECT_EQ(dlc, 5U); +} + +TEST_F(FdCanDeviceTest, transmitCopiesPayloadBytes) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + ::can::CANFrame frame(0x100, data, 8U); + dev->transmit(frame); + + uint32_t const* txBuf = getTxBuffer(0); + // Word 2: bytes 0-3 in little-endian order + EXPECT_EQ(txBuf[2], 0x04030201U); + // Word 3: bytes 4-7 + EXPECT_EQ(txBuf[3], 0x08070605U); +} + +TEST_F(FdCanDeviceTest, transmitSetsRequestBit) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 1U); // put index = 1 + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 8U); + dev->transmit(frame); + + // TXBAR bit 1 should be set + EXPECT_EQ(fakeFdcan.TXBAR, (1U << 1U)); +} + +TEST_F(FdCanDeviceTest, transmitUsesCorrectPutIndex) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(2U, 2U); // put index = 2 + + uint8_t data[8] = {0xAA}; + ::can::CANFrame frame(0x200, data, 1U); + dev->transmit(frame); + + // Data should be written at TX buffer index 2 + uint32_t const* txBuf = getTxBuffer(2); + EXPECT_EQ(txBuf[0], (0x200U << 18U)); + EXPECT_EQ(fakeFdcan.TXBAR, (1U << 2U)); +} + +TEST_F(FdCanDeviceTest, transmitMultipleFramesUseDifferentBuffers) +{ + auto dev = makeStartedDevice(); + + uint8_t data1[8] = {0x11}; + uint8_t data2[8] = {0x22}; + + // First frame at put index 0 + setTxFifoStatus(3U, 0U); + ::can::CANFrame frame1(0x100, data1, 1U); + dev->transmit(frame1); + + // Second frame at put index 1 + setTxFifoStatus(2U, 1U); + ::can::CANFrame frame2(0x200, data2, 1U); + dev->transmit(frame2); + + uint32_t const* buf0 = getTxBuffer(0); + uint32_t const* buf1 = getTxBuffer(1); + EXPECT_EQ(buf0[0], (0x100U << 18U)); + EXPECT_EQ(buf1[0], (0x200U << 18U)); +} + +TEST_F(FdCanDeviceTest, transmitSingleFrame) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(1U, 0U); + + uint8_t data[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE}; + ::can::CANFrame frame(0x7FF, data, 8U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t const* txBuf = getTxBuffer(0); + EXPECT_EQ(txBuf[0], (0x7FFU << 18U)); + EXPECT_EQ(static_cast((txBuf[1] >> 16U) & 0xFU), 8U); + EXPECT_EQ(txBuf[2], 0xEFBEADDEU); + EXPECT_EQ(txBuf[3], 0xBEBAFECAU); +} + +TEST_F(FdCanDeviceTest, transmitWithZeroPayload) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t const* txBuf = getTxBuffer(0); + uint8_t dlc = static_cast((txBuf[1] >> 16U) & 0xFU); + EXPECT_EQ(dlc, 0U); +} + +TEST_F(FdCanDeviceTest, transmitWithMaxPayload) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8}; + ::can::CANFrame frame(0x100, data, 8U); + EXPECT_TRUE(dev->transmit(frame)); + + uint32_t const* txBuf = getTxBuffer(0); + uint8_t dlc = static_cast((txBuf[1] >> 16U) & 0xFU); + EXPECT_EQ(dlc, 8U); + EXPECT_EQ(txBuf[2], 0xFCFDFEFFU); + EXPECT_EQ(txBuf[3], 0xF8F9FAFBU); +} + +TEST_F(FdCanDeviceTest, receiveISRDrainsFifo) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 1U); +} + +TEST_F(FdCanDeviceTest, receiveISRExtractsStandardId) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x321, false, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x321U); +} + +TEST_F(FdCanDeviceTest, receiveISRExtractsExtendedId) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x1ABCDU, true, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), 1U); + // Extended IDs have bit 31 set in the CANFrame representation + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x80000000U | 0x1ABCDU); +} + +TEST_F(FdCanDeviceTest, receiveISRExtractsDlc) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 5, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxFrame(0).getPayloadLength(), 5U); +} + +TEST_F(FdCanDeviceTest, receiveISRExtractsPayloadBytes) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + uint8_t const* payload = dev->getRxFrame(0).getPayload(); + EXPECT_EQ(payload[0], 0xAAU); + EXPECT_EQ(payload[1], 0xBBU); + EXPECT_EQ(payload[2], 0xCCU); + EXPECT_EQ(payload[3], 0xDDU); + EXPECT_EQ(payload[4], 0xEEU); + EXPECT_EQ(payload[5], 0xFFU); + EXPECT_EQ(payload[6], 0x11U); + EXPECT_EQ(payload[7], 0x22U); +} + +TEST_F(FdCanDeviceTest, receiveISRAcknowledgesFrame) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + // RXF0A should have been written with the get index (0) + EXPECT_EQ(fakeFdcan.RXF0A, 0U); +} + +TEST_F(FdCanDeviceTest, receiveISRReturnsFrameCount) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + // Place 2 frames (fill level = 2, both at index 0 since fake doesn't auto-advance) + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(2U, 0U); + + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 2U); +} + +TEST_F(FdCanDeviceTest, receiveISRDropsWhenQueueFull) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + + // Fill the software RX queue to capacity (32 frames) + for (uint32_t i = 0U; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, static_cast(0x100 + i), false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); + + // Now try to receive one more - should be acknowledged but dropped + placeRxFrame(0, 0x999, false, 8, data); + setRxFifoStatus(1U, 0U); + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 0U); + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); +} + +TEST_F(FdCanDeviceTest, receiveISRWithNullFilterAcceptsAll) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x7FF, false, 8, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 1U); +} + +TEST_F(FdCanDeviceTest, receiveISRWithFilterRejectsUnmatched) +{ + auto dev = makeStartedDevice(); + + // Create a filter bit field where only ID 0x100 is accepted + uint8_t filter[256] = {}; + filter[0x100 / 8U] |= (1U << (0x100 % 8U)); + + // Place a frame with ID 0x200 (not in filter) + uint8_t data[8] = {}; + placeRxFrame(0, 0x200, false, 8, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(filter); + EXPECT_EQ(received, 0U); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, receiveISRWithFilterAcceptsMatched) +{ + auto dev = makeStartedDevice(); + + uint8_t filter[256] = {}; + filter[0x100 / 8U] |= (1U << (0x100 % 8U)); + + uint8_t data[8] = {0x42}; + placeRxFrame(0, 0x100, false, 1, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(filter); + EXPECT_EQ(received, 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); +} + +TEST_F(FdCanDeviceTest, receiveISRSnapshotsFillLevel) +{ + auto dev = makeStartedDevice(); + + // Set fill level to 2 - the ISR should drain exactly 2, not re-read F0FL + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(2U, 0U); + + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 2U); +} + +TEST_F(FdCanDeviceTest, receiveISRClearsInterruptFlags) +{ + auto dev = makeStartedDevice(); + + // Pre-set interrupt flags + fakeFdcan.IR = FDCAN_IR_RF0N | FDCAN_IR_RF0F | FDCAN_IR_RF0L; + + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + // IR should have RF0N|RF0F|RF0L written (write-1-to-clear) + // In our fake, the last write to IR is the clear value + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_RF0N | FDCAN_IR_RF0F | FDCAN_IR_RF0L); +} + +TEST_F(FdCanDeviceTest, receiveISRWithEmptyFifo) +{ + auto dev = makeStartedDevice(); + setRxFifoStatus(0U, 0U); // F0FL = 0 + + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 0U); +} + +TEST_F(FdCanDeviceTest, getRxCountReturnsZeroInitially) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + EXPECT_EQ(dev.getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, getRxFrameReturnsCorrectFrame) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {0xDE, 0xAD}; + placeRxFrame(0, 0x123, false, 2, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + auto const& frame = dev->getRxFrame(0); + EXPECT_EQ(frame.getId(), 0x123U); + EXPECT_EQ(frame.getPayloadLength(), 2U); + EXPECT_EQ(frame.getPayload()[0], 0xDEU); + EXPECT_EQ(frame.getPayload()[1], 0xADU); +} + +TEST_F(FdCanDeviceTest, getRxCountAfterReceive) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(FdCanDeviceTest, clearRxQueueResetsCount) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + EXPECT_EQ(dev->getRxCount(), 1U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, rxQueueWrapsAround) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill queue to capacity + for (uint32_t i = 0U; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); + + // Clear and receive more - should wrap around + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + // Receive 5 more (these wrap into the beginning of the buffer) + for (uint32_t i = 0U; i < 5U; i++) + { + placeRxFrame(0, 0x500U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 5U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x500U); + EXPECT_EQ(dev->getRxFrame(4).getId(), 0x504U); +} + +TEST_F(FdCanDeviceTest, rxQueueCapacity) { EXPECT_EQ(bios::FdCanDevice::RX_QUEUE_SIZE, 32U); } + +TEST_F(FdCanDeviceTest, disableRxInterruptClearsRF0NE) +{ + auto dev = makeStartedDevice(); + // After start, RF0NE should be set + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + + dev->disableRxInterrupt(); + // start() only enabled RF0NE, so IE is now empty + EXPECT_EQ(fakeFdcan.IE, 0U); +} + +TEST_F(FdCanDeviceTest, enableRxInterruptSetsRF0NE) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + + dev->enableRxInterrupt(); + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, transmitISRClearsTCFlag) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + // Only the TC flag is cleared (write-1-to-clear) + EXPECT_NE(fakeFdcan.IR & FDCAN_IR_TC, 0U); +} + +TEST_F(FdCanDeviceTest, transmitISRWithNoPendingTx) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + // Should not crash + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +// NOTE: transmitISR() does not drain the TX Event FIFO - it only disables TCE +// and clears the TC flag (matching the S32K FlexCAN transmitISR pattern). + +TEST_F(FdCanDeviceTest, transmitISRDoesNotDrainTxEventFifo) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + fakeFdcan.TXEFA = 0xDEADBEEFU; // sentinel - should NOT be written + + dev->transmitISR(); + + // TXEFA should be untouched (no drain) + EXPECT_EQ(fakeFdcan.TXEFA, 0xDEADBEEFU); + // TC flag still cleared + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, isBusOffReturnsTrueWhenBOSet) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = FDCAN_PSR_BO; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, isBusOffReturnsFalseNormally) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = 0U; + EXPECT_FALSE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, getTxErrorCounterReadsECR) +{ + auto dev = makeStartedDevice(); + // TEC is in ECR[7:0] + fakeFdcan.ECR = 42U; + EXPECT_EQ(dev->getTxErrorCounter(), 42U); +} + +TEST_F(FdCanDeviceTest, getTxErrorCounterMaxValue) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 0xFFU; // max TEC + EXPECT_EQ(dev->getTxErrorCounter(), 255U); +} + +TEST_F(FdCanDeviceTest, getRxErrorCounterReadsECR) +{ + auto dev = makeStartedDevice(); + // REC is in ECR[14:8] + fakeFdcan.ECR = (96U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 96U); +} + +TEST_F(FdCanDeviceTest, getRxErrorCounterMaxValue) +{ + auto dev = makeStartedDevice(); + // REC max is 127 (7 bits) + fakeFdcan.ECR = (0x7FU << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 127U); +} + +TEST_F(FdCanDeviceTest, errorCountersBothReadable) +{ + auto dev = makeStartedDevice(); + // TEC = 100, REC = 50 + fakeFdcan.ECR = 100U | (50U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 100U); + EXPECT_EQ(dev->getRxErrorCounter(), 50U); +} + +TEST_F(FdCanDeviceTest, configureAcceptAllFilterSetsANFS0ANFE0) +{ + auto dev = makeInitedDevice(); + // Set non-zero first to verify it gets overwritten + fakeFdcan.RXGFC = 0xFFFFFFFFU; + dev->configureAcceptAllFilter(); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfs, 0U); + EXPECT_EQ(anfe, 0U); +} + +TEST_F(FdCanDeviceTest, configureFilterListRejectsNonMatching) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100, 0x200}; + dev->configureFilterList(idList, 2U); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfs, 2U); // Reject non-matching standard + EXPECT_EQ(anfe, 2U); // Reject non-matching extended +} + +TEST_F(FdCanDeviceTest, configureFilterListSetsLSSCount) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100, 0x200, 0x300}; + dev->configureFilterList(idList, 3U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 3U); +} + +TEST_F(FdCanDeviceTest, configureFilterListWritesFilterElements) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100, 0x2AB}; + dev->configureFilterList(idList, 2U); + + // Filter element format: SFT(2=classic)<<30 | SFEC(1)<<27 | SFID1<<16 | SFID2(mask) + uint32_t f0 = getStdFilter(0); + EXPECT_EQ(f0, (2U << 30U) | (1U << 27U) | (0x100U << 16U) | 0x7FFU); + + uint32_t f1 = getStdFilter(1); + EXPECT_EQ(f1, (2U << 30U) | (1U << 27U) | (0x2ABU << 16U) | 0x7FFU); +} + +TEST_F(FdCanDeviceTest, configureFilterListCapsAt28) +{ + auto dev = makeInitedDevice(); + + // Create 30 IDs (exceeds 28 max) + uint32_t idList[30]; + for (uint32_t i = 0; i < 30; i++) + { + idList[i] = 0x100U + i; + } + dev->configureFilterList(idList, 30U); + + // Only 28 elements should be written; element 28 and 29 should be zero + uint32_t f27 = getStdFilter(27); + EXPECT_NE(f27, 0U); // element 27 should exist + + // Element at index 28 should NOT have been written (stays 0 from memset) + uint32_t f28 = getStdFilter(28); + EXPECT_EQ(f28, 0U); +} + +TEST_F(FdCanDeviceTest, configureFilterListAcceptsConfiguredIds) +{ + // This is more of an integration test: configure filter, then verify + // the RXGFC is set to reject non-matching but LSS covers our list + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100, 0x200, 0x300, 0x400, 0x500}; + dev->configureFilterList(idList, 5U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 5U); + + // Verify each filter element + for (uint8_t i = 0; i < 5; i++) + { + uint32_t f = getStdFilter(i); + uint32_t sfid = (f >> 16U) & 0x7FFU; + EXPECT_EQ(sfid, idList[i]); + } +} + +TEST_F(FdCanDeviceTest, configureBitTimingWritesNBTP) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 8U; + cfg.nts1 = 63U; + cfg.nts2 = 15U; + cfg.nsjw = 7U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbtp = fakeFdcan.NBTP; + EXPECT_NE(nbtp, 0U); +} + +TEST_F(FdCanDeviceTest, prescalerEncodedCorrectly) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 10U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbrp = (fakeFdcan.NBTP >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + EXPECT_EQ(nbrp, 9U); // prescaler - 1 +} + +TEST_F(FdCanDeviceTest, tseg1Encoded) +{ + auto cfg = makeDefaultConfig(); + cfg.nts1 = 47U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts1 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU; + EXPECT_EQ(nts1, 47U); +} + +TEST_F(FdCanDeviceTest, tseg2Encoded) +{ + auto cfg = makeDefaultConfig(); + cfg.nts2 = 5U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts2 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU; + EXPECT_EQ(nts2, 5U); +} + +TEST_F(FdCanDeviceTest, sjwEncoded) +{ + auto cfg = makeDefaultConfig(); + cfg.nsjw = 3U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nsjw = (fakeFdcan.NBTP >> FDCAN_NBTP_NSJW_Pos) & 0x7FU; + EXPECT_EQ(nsjw, 3U); +} + +TEST_F(FdCanDeviceTest, bitTimingAllFieldsPackedCorrectly) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 2U; // BRP=1 + cfg.nts1 = 10U; + cfg.nts2 = 3U; + cfg.nsjw = 2U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t expected = (2U << FDCAN_NBTP_NSJW_Pos) | (1U << FDCAN_NBTP_NBRP_Pos) // prescaler - 1 + | (10U << FDCAN_NBTP_NTSEG1_Pos) | (3U << FDCAN_NBTP_NTSEG2_Pos); + EXPECT_EQ(fakeFdcan.NBTP, expected); +} + +TEST_F(FdCanDeviceTest, constructorZerosRxQueue) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + EXPECT_EQ(dev.getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, multipleReceiveCycles) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0x01}; + + // Receive 3 frames + for (uint32_t i = 0; i < 3; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 3U); + + // Verify all 3 frames + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + EXPECT_EQ(dev->getRxFrame(1).getId(), 0x101U); + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x102U); + + // Clear and receive more + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + placeRxFrame(0, 0x200, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(FdCanDeviceTest, stopThenRestartSequence) +{ + auto dev = makeStartedDevice(); + + // Stop + dev->stop(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + + // Re-start + dev->start(); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + EXPECT_EQ(fakeFdcan.IE, FDCAN_IE_RF0NE); +} + +TEST_F(FdCanDeviceTest, transmitAfterStopAndRestart) +{ + auto dev = makeStartedDevice(); + + dev->stop(); + dev->start(); + + setTxFifoStatus(3U, 0U); + uint8_t data[8] = {0x42}; + ::can::CANFrame frame(0x100, data, 1U); + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, filterBitFieldEdgeCases) +{ + auto dev = makeStartedDevice(); + + // Test ID 0 (first bit of first byte) + uint8_t filter[256] = {}; + filter[0] = 0x01U; // Accept ID 0 + + uint8_t data[8] = {}; + placeRxFrame(0, 0, false, 1, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(filter); + EXPECT_EQ(received, 1U); +} + +TEST_F(FdCanDeviceTest, filterBitFieldHighId) +{ + auto dev = makeStartedDevice(); + + // Test ID 0x7FF (max standard ID) + uint8_t filter[256] = {}; + filter[0x7FF / 8U] |= (1U << (0x7FF % 8U)); + + uint8_t data[8] = {}; + placeRxFrame(0, 0x7FF, false, 1, data); + setRxFifoStatus(1U, 0U); + + uint8_t received = dev->receiveISR(filter); + EXPECT_EQ(received, 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x7FFU); +} + +TEST_F(FdCanDeviceTest, rxQueueFullThenPartialDrain) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to capacity + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + + // Read some frames + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + EXPECT_EQ(dev->getRxFrame(31).getId(), 0x11FU); + + // Clear all and verify empty + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, extendedIdFullRange) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + // Test with maximum extended ID + uint32_t maxExtId = 0x1FFFFFFFU; + placeRxFrame(0, maxExtId, true, 8, data); + setRxFifoStatus(1U, 0U); + + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x80000000U | maxExtId); +} + +TEST_F(FdCanDeviceTest, transmitExtendedIdFullRange) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + uint32_t extId = 0x80000000U | 0x1FFFFFFFU; + ::can::CANFrame frame(extId, data, 0U); + dev->transmit(frame); + + uint32_t const* txBuf = getTxBuffer(0); + EXPECT_EQ(txBuf[0], 0x1FFFFFFFU | (1U << 30U)); +} + +TEST_F(FdCanDeviceTest, disableEnableRxInterruptIdempotent) +{ + auto dev = makeStartedDevice(); + + dev->disableRxInterrupt(); + dev->disableRxInterrupt(); // double disable should be safe + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + + dev->enableRxInterrupt(); + dev->enableRxInterrupt(); // double enable should be safe + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, isBusOffWithOtherBitsSet) +{ + auto dev = makeStartedDevice(); + // Set BO along with other PSR bits - should still detect bus-off + fakeFdcan.PSR = 0xFFFFU; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, errorCountersWithBothFieldsNonZero) +{ + auto dev = makeStartedDevice(); + // TEC=200, REC=100 + fakeFdcan.ECR = 200U | (100U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 200U); + EXPECT_EQ(dev->getRxErrorCounter(), 100U); +} + +TEST_F(FdCanDeviceTest, errorCountersZero) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 0U; + EXPECT_EQ(dev->getTxErrorCounter(), 0U); + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(FdCanDeviceTest, receiveISRMultipleFramesDifferentIds) +{ + auto dev = makeStartedDevice(); + + // Simulate 3 frames in FIFO (all at index 0 since our fake doesn't auto-advance) + uint8_t data1[8] = {0x01}; + uint8_t data2[8] = {0x02}; + uint8_t data3[8] = {0x03}; + + // First batch + placeRxFrame(0, 0x100, false, 1, data1); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + placeRxFrame(0, 0x200, false, 1, data2); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + placeRxFrame(0, 0x300, false, 1, data3); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getPayload()[0], 0x01U); + EXPECT_EQ(dev->getRxFrame(1).getPayload()[0], 0x02U); + EXPECT_EQ(dev->getRxFrame(2).getPayload()[0], 0x03U); +} + +TEST_F(FdCanDeviceTest, configureFilterListEmptyList) +{ + auto dev = makeInitedDevice(); + + // Zero-length filter list + dev->configureFilterList(nullptr, 0U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 0U); + + // ANFS and ANFE should both be 2 (reject) + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfs, 2U); + EXPECT_EQ(anfe, 2U); +} + +TEST_F(FdCanDeviceTest, configureFilterListSingleId) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x7FF}; + dev->configureFilterList(idList, 1U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 1U); + + uint32_t f0 = getStdFilter(0); + EXPECT_EQ(f0, (2U << 30U) | (1U << 27U) | (0x7FFU << 16U) | 0x7FFU); +} + +TEST_F(FdCanDeviceTest, getRxFrameIndexWraps) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill half the queue + for (uint32_t i = 0; i < 16; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + // Clear (advances head to 16) + dev->clearRxQueue(); + + // Fill past the end of the array (head=16, fill 20 more -> wraps around) + for (uint32_t i = 0; i < 20; i++) + { + placeRxFrame(0, 0x200U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 20U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(19).getId(), 0x213U); +} + +TEST_F(FdCanDeviceTest, initWithPrescaler1) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; // BRP = 0 + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbrp = (fakeFdcan.NBTP >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + EXPECT_EQ(nbrp, 0U); +} + +TEST_F(FdCanDeviceTest, initWithPrescaler512) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 512U; // BRP = 511 (max 9-bit field) + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbrp = (fakeFdcan.NBTP >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + EXPECT_EQ(nbrp, 511U); +} + +TEST_F(FdCanDeviceTest, initWithMaxTseg1) +{ + auto cfg = makeDefaultConfig(); + cfg.nts1 = 255U; // max 8-bit field + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts1 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU; + EXPECT_EQ(nts1, 255U); +} + +TEST_F(FdCanDeviceTest, initWithMaxTseg2) +{ + auto cfg = makeDefaultConfig(); + cfg.nts2 = 127U; // max 7-bit field + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts2 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU; + EXPECT_EQ(nts2, 127U); +} + +TEST_F(FdCanDeviceTest, initWithMaxSjw) +{ + auto cfg = makeDefaultConfig(); + cfg.nsjw = 127U; // max 7-bit field + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nsjw = (fakeFdcan.NBTP >> FDCAN_NBTP_NSJW_Pos) & 0x7FU; + EXPECT_EQ(nsjw, 127U); +} + +TEST_F(FdCanDeviceTest, initGpioTxPin0) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 0U; + cfg.txAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (0U * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); + uint32_t txModer = (fakeTxGpio.MODER >> (0U * 2U)) & 3U; + EXPECT_EQ(txModer, 2U); +} + +TEST_F(FdCanDeviceTest, initGpioTxPin7) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 7U; + cfg.txAf = 11U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[0] >> (7U * 4U)) & 0xFU; + EXPECT_EQ(txAf, 11U); +} + +TEST_F(FdCanDeviceTest, initGpioTxPin8) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 8U; + cfg.txAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[1] >> ((8U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); +} + +TEST_F(FdCanDeviceTest, initGpioTxPin15) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 15U; + cfg.txAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txAf = (fakeTxGpio.AFR[1] >> ((15U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(txAf, 9U); +} + +TEST_F(FdCanDeviceTest, initGpioRxPin0) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 0U; + cfg.rxAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[0] >> (0U * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); + uint32_t rxPupdr = (fakeRxGpio.PUPDR >> (0U * 2U)) & 3U; + EXPECT_EQ(rxPupdr, 1U); +} + +TEST_F(FdCanDeviceTest, initGpioRxPin7) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 7U; + cfg.rxAf = 12U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[0] >> (7U * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 12U); +} + +TEST_F(FdCanDeviceTest, initGpioRxPin8) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 8U; + cfg.rxAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((8U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); +} + +TEST_F(FdCanDeviceTest, initGpioRxPin15) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 15U; + cfg.rxAf = 9U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxAf = (fakeRxGpio.AFR[1] >> ((15U - 8U) * 4U)) & 0xFU; + EXPECT_EQ(rxAf, 9U); +} + +TEST_F(FdCanDeviceTest, initCCESetAfterInit) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // CCE must be set for configuration change + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_CCE, 0U); +} + +TEST_F(FdCanDeviceTest, doubleInitDoesNotBreakBitTiming) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 6U; + cfg.nts1 = 20U; + cfg.nts2 = 4U; + cfg.nsjw = 2U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbtpFirst = fakeFdcan.NBTP; + dev.init(); + EXPECT_EQ(fakeFdcan.NBTP, nbtpFirst); +} + +TEST_F(FdCanDeviceTest, doubleInitPreservesGpioConfig) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txModerFirst = fakeTxGpio.MODER; + uint32_t rxModerFirst = fakeRxGpio.MODER; + dev.init(); + EXPECT_EQ(fakeTxGpio.MODER, txModerFirst); + EXPECT_EQ(fakeRxGpio.MODER, rxModerFirst); +} + +TEST_F(FdCanDeviceTest, initClockEnableBitPreserved) +{ + // Pre-set some other APB1ENR1 bits - init should not clear them + fakeRcc.APB1ENR1 = 0x00000001U; + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // FDCANEN should be set AND the pre-existing bit preserved + EXPECT_NE(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); + EXPECT_NE(fakeRcc.APB1ENR1 & 0x00000001U, 0U); +} + +TEST_F(FdCanDeviceTest, initWithAllBitTimingZero) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + cfg.nts1 = 0U; + cfg.nts2 = 0U; + cfg.nsjw = 0U; + bios::FdCanDevice dev(cfg); + dev.init(); + + // NBTP should be 0 (prescaler-1=0, all others 0) + EXPECT_EQ(fakeFdcan.NBTP, 0U); +} + +TEST_F(FdCanDeviceTest, initTxGpioSpeedIsVeryHigh) +{ + auto cfg = makeDefaultConfig(); + cfg.txPin = 3U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t txSpeed = (fakeTxGpio.OSPEEDR >> (3U * 2U)) & 3U; + EXPECT_EQ(txSpeed, 3U); // Very high speed +} + +TEST_F(FdCanDeviceTest, initRxGpioPullUpEnabled) +{ + auto cfg = makeDefaultConfig(); + cfg.rxPin = 6U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t rxPupdr = (fakeRxGpio.PUPDR >> (6U * 2U)) & 3U; + EXPECT_EQ(rxPupdr, 1U); // Pull-up +} + +TEST_F(FdCanDeviceTest, startWithoutInitLeavesINITUntouched) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + // INIT starts at 0 (not initialized) + fakeFdcan.CCCR = 0U; + dev.start(); + // start() returned early - CCCR unchanged + EXPECT_EQ(fakeFdcan.CCCR, 0U); +} + +TEST_F(FdCanDeviceTest, startWithoutInitLeavesTXBTIEZero) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.start(); + EXPECT_EQ(fakeFdcan.TXBTIE, 0U); +} + +TEST_F(FdCanDeviceTest, doubleStartDoesNotCrash) +{ + auto dev = makeInitedDevice(); + dev->start(); + dev->start(); // second start + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, doubleStartIEPreserved) +{ + auto dev = makeInitedDevice(); + dev->start(); + uint32_t ieFirst = fakeFdcan.IE; + dev->start(); + EXPECT_EQ(fakeFdcan.IE, ieFirst); +} + +TEST_F(FdCanDeviceTest, stopWithoutStartSafe) +{ + auto dev = makeInitedDevice(); + // init was called but not start - stop should not crash + dev->stop(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, stopClearsRF0NE) +{ + auto dev = makeStartedDevice(); + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + dev->stop(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, stopClearsTCE) +{ + auto dev = makeStartedDevice(); + dev->stop(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, stopThenStartIERestored) +{ + auto dev = makeStartedDevice(); + dev->stop(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + dev->start(); + EXPECT_EQ(fakeFdcan.IE, FDCAN_IE_RF0NE); +} + +TEST_F(FdCanDeviceTest, stopThenStartTXBTIERestored) +{ + auto dev = makeStartedDevice(); + dev->stop(); + dev->start(); + EXPECT_EQ(fakeFdcan.TXBTIE, 0x7U); +} + +TEST_F(FdCanDeviceTest, stopThenStartILERestored) +{ + auto dev = makeStartedDevice(); + dev->stop(); + dev->start(); + EXPECT_NE(fakeFdcan.ILE & FDCAN_ILE_EINT0, 0U); +} + +TEST_F(FdCanDeviceTest, multipleStopStartCycles) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 5; i++) + { + dev->stop(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + dev->start(); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + } +} + +TEST_F(FdCanDeviceTest, startLeavesINITClearedEvenIfCCCRHasOtherBits) +{ + auto dev = makeInitedDevice(); + // Pre-set some bits in CCCR besides INIT + fakeFdcan.CCCR |= (1U << 4U); // some random bit + dev->start(); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, startSetsILSToZero) +{ + auto dev = makeInitedDevice(); + // Pre-set ILS to non-zero + fakeFdcan.ILS = 0xFFFFFFFFU; + dev->start(); + EXPECT_EQ(fakeFdcan.ILS, 0U); +} + +TEST_F(FdCanDeviceTest, startSetsOnlyEINT0) +{ + auto dev = makeInitedDevice(); + dev->start(); + // Only EINT0 should be enabled, not EINT1 + EXPECT_NE(fakeFdcan.ILE & FDCAN_ILE_EINT0, 0U); + // ILE should be exactly EINT0 + EXPECT_EQ(fakeFdcan.ILE, FDCAN_ILE_EINT0); +} + +TEST_F(FdCanDeviceTest, stopDoesNotClearILE) +{ + auto dev = makeStartedDevice(); + dev->stop(); + // stop() only clears specific IE bits and enters init mode + // ILE is not explicitly cleared by stop() + // (verify the actual behavior) + // After stop, INIT should be set + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, stopDoesNotClearTXBTIE) +{ + auto dev = makeStartedDevice(); + EXPECT_EQ(fakeFdcan.TXBTIE, 0x7U); + dev->stop(); + // stop() does not explicitly clear TXBTIE + EXPECT_EQ(fakeFdcan.TXBTIE, 0x7U); +} + +TEST_F(FdCanDeviceTest, startAfterStopClearsINIT) +{ + auto dev = makeStartedDevice(); + dev->stop(); + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); + dev->start(); + EXPECT_EQ(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, initDoesNotLeaveInitMode) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // After init, INIT bit should still be set + EXPECT_NE(fakeFdcan.CCCR & FDCAN_CCCR_INIT, 0U); +} + +TEST_F(FdCanDeviceTest, startThenStopThenStartAgainIECorrect) +{ + auto dev = makeStartedDevice(); + EXPECT_EQ(fakeFdcan.IE, FDCAN_IE_RF0NE); + dev->stop(); + // stop() clears RF0NE and TCE + dev->start(); + EXPECT_EQ(fakeFdcan.IE, FDCAN_IE_RF0NE); +} + +TEST_F(FdCanDeviceTest, enableRxInterruptAfterStartPreservesOtherIEBits) +{ + auto dev = makeStartedDevice(); + // Enable TCE manually so there is another IE bit to preserve + fakeFdcan.IE |= FDCAN_IE_TCE; + + dev->disableRxInterrupt(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + // TCE should still be set + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_TCE, 0U); + + dev->enableRxInterrupt(); + // Both RF0NE and TCE should be set + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, disableRxInterruptPreservesTCE) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IE |= FDCAN_IE_TCE; + dev->disableRxInterrupt(); + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, disableRxInterruptMultipleTimes) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + dev->disableRxInterrupt(); + dev->disableRxInterrupt(); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, enableRxInterruptMultipleTimes) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + dev->enableRxInterrupt(); + dev->enableRxInterrupt(); + dev->enableRxInterrupt(); + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, IERegisterBitMaskRF0NE) +{ + auto dev = makeStartedDevice(); + // Verify RF0NE bit is at position 0 + EXPECT_EQ(FDCAN_IE_RF0NE, (1U << 0U)); +} + +TEST_F(FdCanDeviceTest, IERegisterBitMaskTCE) +{ + // Verify TCE bit is at position 7 + EXPECT_EQ(FDCAN_IE_TCE, (1U << 7U)); +} + +TEST_F(FdCanDeviceTest, IERegisterBitMaskTEFNE) +{ + // Verify TEFNE bit is at position 12 + EXPECT_EQ(FDCAN_IE_TEFNE, (1U << 12U)); +} + +TEST_F(FdCanDeviceTest, ILSZeroAfterStart) +{ + auto dev = makeStartedDevice(); + // All interrupts routed to line 0 + EXPECT_EQ(fakeFdcan.ILS, 0U); +} + +TEST_F(FdCanDeviceTest, ILSPreSetIsOverwritten) +{ + auto dev = makeInitedDevice(); + fakeFdcan.ILS = 0xFFFFFFFFU; + dev->start(); + EXPECT_EQ(fakeFdcan.ILS, 0U); +} + +TEST_F(FdCanDeviceTest, ILEOnlyEINT0Enabled) +{ + auto dev = makeStartedDevice(); + EXPECT_EQ(fakeFdcan.ILE, FDCAN_ILE_EINT0); +} + +TEST_F(FdCanDeviceTest, ILEPreSetIsOverwritten) +{ + auto dev = makeInitedDevice(); + fakeFdcan.ILE = FDCAN_ILE_EINT0 | FDCAN_ILE_EINT1; + dev->start(); + EXPECT_EQ(fakeFdcan.ILE, FDCAN_ILE_EINT0); +} + +TEST_F(FdCanDeviceTest, TXBTIEAllThreeBuffers) +{ + auto dev = makeStartedDevice(); + // Bits 0, 1, 2 should all be set + EXPECT_NE(fakeFdcan.TXBTIE & (1U << 0U), 0U); + EXPECT_NE(fakeFdcan.TXBTIE & (1U << 1U), 0U); + EXPECT_NE(fakeFdcan.TXBTIE & (1U << 2U), 0U); +} + +TEST_F(FdCanDeviceTest, TXBTIENoExtraBitsSet) +{ + auto dev = makeStartedDevice(); + // Only bits 0-2 should be set + EXPECT_EQ(fakeFdcan.TXBTIE & ~0x7U, 0U); +} + +TEST_F(FdCanDeviceTest, disableEnableRxInterruptCyclePreservesIE) +{ + auto dev = makeStartedDevice(); + uint32_t originalIE = fakeFdcan.IE; + + dev->disableRxInterrupt(); + dev->enableRxInterrupt(); + + EXPECT_EQ(fakeFdcan.IE, originalIE); +} + +TEST_F(FdCanDeviceTest, IEAfterStopHasRF0NECleared) +{ + auto dev = makeStartedDevice(); + dev->stop(); + // stop() clears RF0NE (and TCE) + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, ILSBitPositions) +{ + // SMSG is at position 2 + EXPECT_EQ(FDCAN_ILS_SMSG, (1U << 2U)); +} + +TEST_F(FdCanDeviceTest, ILEBitPositions) +{ + EXPECT_EQ(FDCAN_ILE_EINT0, (1U << 0U)); + EXPECT_EQ(FDCAN_ILE_EINT1, (1U << 1U)); +} + +TEST_F(FdCanDeviceTest, enableRxInterruptDoesNotSetTCE) +{ + auto dev = makeStartedDevice(); + dev->disableRxInterrupt(); + dev->enableRxInterrupt(); + // enableRxInterrupt only sets RF0NE, not TCE + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, disableRxInterruptDoesNotAffectILE) +{ + auto dev = makeStartedDevice(); + uint32_t ileBefore = fakeFdcan.ILE; + dev->disableRxInterrupt(); + EXPECT_EQ(fakeFdcan.ILE, ileBefore); +} + +TEST_F(FdCanDeviceTest, disableRxInterruptDoesNotAffectILS) +{ + auto dev = makeStartedDevice(); + uint32_t ilsBefore = fakeFdcan.ILS; + dev->disableRxInterrupt(); + EXPECT_EQ(fakeFdcan.ILS, ilsBefore); +} + +TEST_F(FdCanDeviceTest, acceptAllFilterSetsLSSZero) +{ + auto dev = makeInitedDevice(); + dev->configureAcceptAllFilter(); + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 0U); +} + +TEST_F(FdCanDeviceTest, acceptAllFilterSetsLSEZero) +{ + auto dev = makeInitedDevice(); + dev->configureAcceptAllFilter(); + uint32_t lse = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSE_Pos) & 0xFU; + EXPECT_EQ(lse, 0U); +} + +TEST_F(FdCanDeviceTest, acceptAllFilterClearsRejectBits) +{ + auto dev = makeInitedDevice(); + fakeFdcan.RXGFC = 0xFFFFFFFFU; + dev->configureAcceptAllFilter(); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfs, 0U); + EXPECT_EQ(anfe, 0U); +} + +TEST_F(FdCanDeviceTest, filterListWith1IdWritesOneElement) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x555}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + EXPECT_NE(f0, 0U); + // Element 1 should be 0 (only 1 configured) + uint32_t f1 = getStdFilter(1); + EXPECT_EQ(f1, 0U); +} + +TEST_F(FdCanDeviceTest, filterListWith28IdsAllWritten) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[28]; + for (uint32_t i = 0; i < 28; i++) + { + idList[i] = i + 1U; + } + dev->configureFilterList(idList, 28U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 28U); + + // Verify all 28 elements are non-zero + for (uint8_t i = 0; i < 28; i++) + { + EXPECT_NE(getStdFilter(i), 0U); + } +} + +TEST_F(FdCanDeviceTest, filterListWith0IdsLSSIsZero) +{ + auto dev = makeInitedDevice(); + dev->configureFilterList(nullptr, 0U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 0U); +} + +TEST_F(FdCanDeviceTest, filterListANFSRejectBit) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + EXPECT_EQ(anfs, 2U); +} + +TEST_F(FdCanDeviceTest, filterListANFERejectBit) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + uint32_t anfe = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFE_Pos) & 3U; + EXPECT_EQ(anfe, 2U); +} + +TEST_F(FdCanDeviceTest, filterElementSFTIsClassicFilter) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sft = (f0 >> 30U) & 3U; + EXPECT_EQ(sft, 2U); // Classic filter (ID + mask) +} + +TEST_F(FdCanDeviceTest, filterElementSFECBitIsStoreInFIFO0) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfec = (f0 >> 27U) & 7U; + EXPECT_EQ(sfec, 1U); // Store in RX FIFO 0 +} + +TEST_F(FdCanDeviceTest, filterElementSFID1MatchesId) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x3AB}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid1 = (f0 >> 16U) & 0x7FFU; + EXPECT_EQ(sfid1, 0x3ABU); +} + +TEST_F(FdCanDeviceTest, filterElementSFID2IsExactMatchMask) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x3AB}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid2 = f0 & 0x7FFU; + EXPECT_EQ(sfid2, 0x7FFU); // SFID2 is the mask (all 11 bits must match) +} + +TEST_F(FdCanDeviceTest, filterListIdMaskedTo11Bits) +{ + auto dev = makeInitedDevice(); + + // Pass an ID with bits above 10 set - should be masked to 11 bits + uint32_t idList[] = {0xFFF}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid1 = (f0 >> 16U) & 0x7FFU; + EXPECT_EQ(sfid1, 0x7FFU); // Masked to 11 bits +} + +TEST_F(FdCanDeviceTest, filterListMultipleElementsCorrectOrder) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x001, 0x010, 0x100, 0x200, 0x7FF}; + dev->configureFilterList(idList, 5U); + + for (uint8_t i = 0; i < 5; i++) + { + uint32_t f = getStdFilter(i); + uint32_t sfid = (f >> 16U) & 0x7FFU; + EXPECT_EQ(sfid, idList[i]); + } +} + +TEST_F(FdCanDeviceTest, filterListOverwritesPreviousConfig) +{ + auto dev = makeInitedDevice(); + + uint32_t idList1[] = {0x100, 0x200, 0x300}; + dev->configureFilterList(idList1, 3U); + + uint32_t idList2[] = {0x400}; + dev->configureFilterList(idList2, 1U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid1 = (f0 >> 16U) & 0x7FFU; + EXPECT_EQ(sfid1, 0x400U); +} + +TEST_F(FdCanDeviceTest, acceptAllThenFilterList) +{ + auto dev = makeInitedDevice(); + dev->configureAcceptAllFilter(); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + EXPECT_EQ(anfs, 0U); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + EXPECT_EQ(anfs, 2U); +} + +TEST_F(FdCanDeviceTest, filterListThenAcceptAll) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100}; + dev->configureFilterList(idList, 1U); + + uint32_t anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + EXPECT_EQ(anfs, 2U); + + dev->configureAcceptAllFilter(); + anfs = (fakeFdcan.RXGFC >> FDCAN_RXGFC_ANFS_Pos) & 3U; + EXPECT_EQ(anfs, 0U); +} + +TEST_F(FdCanDeviceTest, filterListWith5IdsHasCorrectLSS) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x001, 0x002, 0x003, 0x004, 0x005}; + dev->configureFilterList(idList, 5U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 5U); +} + +TEST_F(FdCanDeviceTest, filterListWith10IdsHasCorrectLSS) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[10]; + for (uint32_t i = 0; i < 10; i++) + { + idList[i] = 0x100U + i; + } + dev->configureFilterList(idList, 10U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 10U); +} + +TEST_F(FdCanDeviceTest, filterListWith28IdsLSSIs28) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[28]; + for (uint32_t i = 0; i < 28; i++) + { + idList[i] = 0x100U + i; + } + dev->configureFilterList(idList, 28U); + + uint32_t lss = (fakeFdcan.RXGFC >> FDCAN_RXGFC_LSS_Pos) & 0x1FU; + EXPECT_EQ(lss, 28U); +} + +TEST_F(FdCanDeviceTest, filterListIdZero) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x000}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid1 = (f0 >> 16U) & 0x7FFU; + uint32_t sfid2 = f0 & 0x7FFU; + EXPECT_EQ(sfid1, 0U); + EXPECT_EQ(sfid2, 0x7FFU); // SFID2 is the mask, not the ID +} + +TEST_F(FdCanDeviceTest, filterListIdMaxStandard) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x7FF}; + dev->configureFilterList(idList, 1U); + + uint32_t f0 = getStdFilter(0); + uint32_t sfid1 = (f0 >> 16U) & 0x7FFU; + EXPECT_EQ(sfid1, 0x7FFU); +} + +TEST_F(FdCanDeviceTest, filterListElement27IsLast) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[28]; + for (uint32_t i = 0; i < 28; i++) + { + idList[i] = 0x100U + i; + } + dev->configureFilterList(idList, 28U); + + uint32_t f27 = getStdFilter(27); + uint32_t sfid1 = (f27 >> 16U) & 0x7FFU; + EXPECT_EQ(sfid1, 0x100U + 27U); +} + +TEST_F(FdCanDeviceTest, filterListRXGFCFullWord) +{ + auto dev = makeInitedDevice(); + + uint32_t idList[] = {0x100, 0x200}; + dev->configureFilterList(idList, 2U); + + uint32_t expected + = (2U << FDCAN_RXGFC_ANFS_Pos) | (2U << FDCAN_RXGFC_ANFE_Pos) | (2U << FDCAN_RXGFC_LSS_Pos); + EXPECT_EQ(fakeFdcan.RXGFC, expected); +} + +TEST_F(FdCanDeviceTest, busOffWithBOBitOnly) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = FDCAN_PSR_BO; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, notBusOffWithZeroPSR) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = 0U; + EXPECT_FALSE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, notBusOffWithOtherBitsButNotBO) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = 0x0000007FU; // bits 0-6 set, but not bit 7 (BO) + EXPECT_FALSE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, busOffWithAllPSRBitsSet) +{ + auto dev = makeStartedDevice(); + fakeFdcan.PSR = 0xFFFFFFFFU; + EXPECT_TRUE(dev->isBusOff()); +} + +TEST_F(FdCanDeviceTest, txErrorCounterZero) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 0U; + EXPECT_EQ(dev->getTxErrorCounter(), 0U); +} + +TEST_F(FdCanDeviceTest, txErrorCounter128) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 128U; + EXPECT_EQ(dev->getTxErrorCounter(), 128U); +} + +TEST_F(FdCanDeviceTest, txErrorCounter255) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 255U; + EXPECT_EQ(dev->getTxErrorCounter(), 255U); +} + +TEST_F(FdCanDeviceTest, rxErrorCounterZero) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 0U; + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(FdCanDeviceTest, rxErrorCounter64) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = (64U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 64U); +} + +TEST_F(FdCanDeviceTest, rxErrorCounter127) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = (127U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 127U); +} + +TEST_F(FdCanDeviceTest, txErrorCounterNotAffectedByREC) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 0U | (127U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 0U); +} + +TEST_F(FdCanDeviceTest, rxErrorCounterNotAffectedByTEC) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 255U | (0U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getRxErrorCounter(), 0U); +} + +TEST_F(FdCanDeviceTest, bothErrorCountersIndependent) +{ + auto dev = makeStartedDevice(); + fakeFdcan.ECR = 42U | (99U << FDCAN_ECR_REC_Pos); + EXPECT_EQ(dev->getTxErrorCounter(), 42U); + EXPECT_EQ(dev->getRxErrorCounter(), 99U); +} + +TEST_F(FdCanDeviceTest, PSRBOPositionCorrect) { EXPECT_EQ(FDCAN_PSR_BO, (1U << 7U)); } + +TEST_F(FdCanDeviceTest, ECRFieldPositionsCorrect) +{ + EXPECT_EQ(FDCAN_ECR_TEC_Pos, 0U); + EXPECT_EQ(FDCAN_ECR_REC_Pos, 8U); +} + +TEST_F(FdCanDeviceTest, getRxCountEmptyAfterConstruction) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + EXPECT_EQ(dev.getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, clearRxQueueOnEmpty) +{ + auto dev = makeStartedDevice(); + EXPECT_EQ(dev->getRxCount(), 0U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, clearRxQueueDoubleClear) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), 1U); + + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, clearRxQueueAfterPartialRead) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Add 5 frames + for (uint32_t i = 0; i < 5; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 5U); + + // Read a frame (does not consume it) + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x102U); + + // Clear all + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, getRxCountAfterMultipleReceives) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint32_t i = 0; i < 10; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 10U); +} + +TEST_F(FdCanDeviceTest, getRxFrameWrappingAtBoundary) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to exactly RX_QUEUE_SIZE + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); + + // Clear + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + + // Receive 5 more - these wrap around + for (uint32_t i = 0; i < 5; i++) + { + placeRxFrame(0, 0x200U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 5U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(4).getId(), 0x204U); +} + +TEST_F(FdCanDeviceTest, queueHeadAdvancesOnClear) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Add 10 frames + for (uint32_t i = 0; i < 10; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + dev->clearRxQueue(); + + // Add 5 more - should start from new head position + for (uint32_t i = 0; i < 5; i++) + { + placeRxFrame(0, 0x200U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 5U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(FdCanDeviceTest, multipleClearCycles) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (int cycle = 0; cycle < 10; cycle++) + { + placeRxFrame(0, static_cast(0x100 + cycle), false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), 1U); + EXPECT_EQ(dev->getRxFrame(0).getId(), static_cast(0x100 + cycle)); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + } +} + +TEST_F(FdCanDeviceTest, getRxFrameIndex0) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {0xAA}; + placeRxFrame(0, 0x100, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); +} + +TEST_F(FdCanDeviceTest, getRxFrameLastIndex) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + + EXPECT_EQ( + dev->getRxFrame(bios::FdCanDevice::RX_QUEUE_SIZE - 1).getId(), + 0x100U + bios::FdCanDevice::RX_QUEUE_SIZE - 1); +} + +TEST_F(FdCanDeviceTest, rxQueueDropsWhenFullAndContinuesAcknowledging) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to capacity + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + + // Try one more - should return 0 (dropped) but still ack + placeRxFrame(0, 0x999, false, 1, data); + setRxFifoStatus(1U, 0U); + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 0U); + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); +} + +TEST_F(FdCanDeviceTest, clearThenFillToCapacityAgain) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill to capacity + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); + + dev->clearRxQueue(); + + // Fill again + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x200U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(FdCanDeviceTest, getRxCountIncrementsByOne) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint32_t i = 0; i < 5; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxCount(), i + 1U); + } +} + +TEST_F(FdCanDeviceTest, clearRxQueueAfterSingleFrame) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + placeRxFrame(0, 0x100, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); +} + +TEST_F(FdCanDeviceTest, getRxFrameAfterClearAndRefill) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // First fill + placeRxFrame(0, 0x100, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x100U); + + // Clear + dev->clearRxQueue(); + + // Refill + placeRxFrame(0, 0x200, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); +} + +TEST_F(FdCanDeviceTest, queueWrapsCorrectlyAt31To0) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + // Fill 31 frames, clear + for (uint32_t i = 0; i < 31; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + dev->clearRxQueue(); + + // Now head is at 31. Add 3 more - should wrap from 31 to 0, 1 + for (uint32_t i = 0; i < 3; i++) + { + placeRxFrame(0, 0x200U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 3U); + EXPECT_EQ(dev->getRxFrame(0).getId(), 0x200U); + EXPECT_EQ(dev->getRxFrame(1).getId(), 0x201U); + EXPECT_EQ(dev->getRxFrame(2).getId(), 0x202U); +} + +TEST_F(FdCanDeviceTest, rxQueueSizeIs32) { EXPECT_EQ(bios::FdCanDevice::RX_QUEUE_SIZE, 32U); } + +TEST_F(FdCanDeviceTest, getRxCountAfterExactlyFullQueue) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (uint32_t i = 0; i < bios::FdCanDevice::RX_QUEUE_SIZE; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), bios::FdCanDevice::RX_QUEUE_SIZE); +} + +TEST_F(FdCanDeviceTest, receiveAfterClearRxQueueWorks) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + placeRxFrame(0, 0x100, false, 8, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + dev->clearRxQueue(); + + placeRxFrame(0, 0x200, false, 8, data); + setRxFifoStatus(1U, 0U); + uint8_t received = dev->receiveISR(nullptr); + EXPECT_EQ(received, 1U); + EXPECT_EQ(dev->getRxCount(), 1U); +} + +TEST_F(FdCanDeviceTest, clearRxQueueRepeatedlySafe) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 100; i++) + { + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + } +} + +TEST_F(FdCanDeviceTest, fillClearFillClearPattern) +{ + auto dev = makeStartedDevice(); + uint8_t data[8] = {}; + + for (int round = 0; round < 5; round++) + { + for (uint32_t i = 0; i < 8; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + EXPECT_EQ(dev->getRxCount(), 8U); + dev->clearRxQueue(); + EXPECT_EQ(dev->getRxCount(), 0U); + } +} + +TEST_F(FdCanDeviceTest, getRxFramePayloadCorrectAfterWrap) +{ + auto dev = makeStartedDevice(); + + // Fill 30 frames and clear + uint8_t data[8] = {}; + for (uint32_t i = 0; i < 30; i++) + { + placeRxFrame(0, 0x100U + i, false, 1, data); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + } + dev->clearRxQueue(); + + // Now add a frame with specific payload - wraps into beginning + uint8_t payload[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE}; + placeRxFrame(0, 0x500, false, 8, payload); + setRxFifoStatus(1U, 0U); + dev->receiveISR(nullptr); + + auto const& frame = dev->getRxFrame(0); + EXPECT_EQ(frame.getId(), 0x500U); + EXPECT_EQ(frame.getPayloadLength(), 8U); + EXPECT_EQ(frame.getPayload()[0], 0xDEU); + EXPECT_EQ(frame.getPayload()[7], 0xBEU); +} + +TEST_F(FdCanDeviceTest, txFifoFreeLevel0ReturnsFalse) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(0U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_FALSE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, txFifoFreeLevel1ReturnsTrue) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(1U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, txFifoFreeLevel2ReturnsTrue) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(2U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, txFifoFreeLevel3ReturnsTrue) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, txFifoPutIndex0) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + dev->transmit(frame); + + EXPECT_EQ(fakeFdcan.TXBAR, (1U << 0U)); +} + +TEST_F(FdCanDeviceTest, txFifoPutIndex1) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 1U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + dev->transmit(frame); + + EXPECT_EQ(fakeFdcan.TXBAR, (1U << 1U)); +} + +TEST_F(FdCanDeviceTest, txFifoPutIndex2) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 2U); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + dev->transmit(frame); + + EXPECT_EQ(fakeFdcan.TXBAR, (1U << 2U)); +} + +TEST_F(FdCanDeviceTest, txFifoFullThenFreeReturnsTrue) +{ + auto dev = makeStartedDevice(); + + // First: FIFO full + setTxFifoStatus(0U, 0U); + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_FALSE(dev->transmit(frame)); + + // Now: FIFO has space + setTxFifoStatus(1U, 0U); + EXPECT_TRUE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, txFQSFieldPositions) +{ + EXPECT_EQ(FDCAN_TXFQS_TFFL_Pos, 0U); + EXPECT_EQ(FDCAN_TXFQS_TFQPI_Pos, 16U); +} + +TEST_F(FdCanDeviceTest, txFifoChecksOnlyTFFL) +{ + auto dev = makeStartedDevice(); + // TFFL = 0 but other fields non-zero + fakeFdcan.TXFQS = (2U << FDCAN_TXFQS_TFQPI_Pos); + // TFFL is 0, so transmit should fail + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + EXPECT_FALSE(dev->transmit(frame)); +} + +TEST_F(FdCanDeviceTest, transmitDoesNotModifyTXFQS) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + uint32_t txfqsBefore = fakeFdcan.TXFQS; + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + dev->transmit(frame); + + EXPECT_EQ(fakeFdcan.TXFQS, txfqsBefore); +} + +TEST_F(FdCanDeviceTest, transmitSetsTXBAROnly) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(3U, 0U); + + fakeFdcan.TXBAR = 0U; + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + dev->transmit(frame); + + EXPECT_EQ(fakeFdcan.TXBAR, 1U); +} + +TEST_F(FdCanDeviceTest, transmitTXBCIsZeroForFifoMode) +{ + auto dev = makeStartedDevice(); + EXPECT_EQ(fakeFdcan.TXBC, 0U); +} + +TEST_F(FdCanDeviceTest, txFifoSequentialPutIndices) +{ + auto dev = makeStartedDevice(); + + uint8_t data[8] = {}; + ::can::CANFrame frame(0x100, data, 0U); + + for (uint8_t i = 0; i < 3; i++) + { + setTxFifoStatus(3U - i, i); + dev->transmit(frame); + EXPECT_NE(fakeFdcan.TXBAR & (1U << i), 0U); + } +} + +TEST_F(FdCanDeviceTest, transmitWithFullFifoDoesNotWriteMessageRam) +{ + auto dev = makeStartedDevice(); + setTxFifoStatus(0U, 0U); // Full + + // Zero out TXBAR + fakeFdcan.TXBAR = 0U; + + uint8_t data[8] = {0xFF}; + ::can::CANFrame frame(0x100, data, 1U); + EXPECT_FALSE(dev->transmit(frame)); + + // TXBAR should not be written + EXPECT_EQ(fakeFdcan.TXBAR, 0U); +} + +TEST_F(FdCanDeviceTest, transmitISREmptyFifoDoesNotWriteTXEFA) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + fakeFdcan.TXEFA = 0x12345678U; // Sentinel + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.TXEFA, 0x12345678U); +} + +TEST_F(FdCanDeviceTest, transmitISRMultipleCallsEmptyFifo) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 5; i++) + { + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); + } +} + +TEST_F(FdCanDeviceTest, transmitISRIRWriteIsTC) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, transmitISRDoesNotAffectIEWhenTCEClear) +{ + // transmitISR() clears TCE in IE; with TCE already clear, IE is unchanged + auto dev = makeStartedDevice(); + uint32_t ieBefore = fakeFdcan.IE; + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.IE, ieBefore); +} + +TEST_F(FdCanDeviceTest, transmitISRDoesNotAffectILE) +{ + auto dev = makeStartedDevice(); + uint32_t ileBefore = fakeFdcan.ILE; + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.ILE, ileBefore); +} + +TEST_F(FdCanDeviceTest, transmitISRDoesNotAffectILS) +{ + auto dev = makeStartedDevice(); + uint32_t ilsBefore = fakeFdcan.ILS; + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.ILS, ilsBefore); +} + +TEST_F(FdCanDeviceTest, transmitISRDoesNotAffectCCCR) +{ + auto dev = makeStartedDevice(); + uint32_t cccrBefore = fakeFdcan.CCCR; + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.CCCR, cccrBefore); +} + +TEST_F(FdCanDeviceTest, transmitISRDoesNotAffectTXBTIE) +{ + auto dev = makeStartedDevice(); + uint32_t txbtieBefore = fakeFdcan.TXBTIE; + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.TXBTIE, txbtieBefore); +} + +TEST_F(FdCanDeviceTest, transmitISRPreExistingIRBitsOverwritten) +{ + auto dev = makeStartedDevice(); + // Pre-set IR with some bits + fakeFdcan.IR = 0xFFFFFFFFU; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + // The last write to IR is the clear pattern + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, transmitISRCalledBeforeAnyTransmit) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + // Should be safe even if no transmit was ever done + dev->transmitISR(); + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, transmitISRTEFNBitPosition) { EXPECT_EQ(FDCAN_IR_TEFN, (1U << 12U)); } + +TEST_F(FdCanDeviceTest, transmitISRTCBitPosition) { EXPECT_EQ(FDCAN_IR_TC, (1U << 7U)); } + +TEST_F(FdCanDeviceTest, transmitISRTXEFSFieldPositions) +{ + EXPECT_EQ(FDCAN_TXEFS_EFFL_Pos, 0U); + EXPECT_EQ(FDCAN_TXEFS_EFGI_Pos, 8U); +} + +TEST_F(FdCanDeviceTest, transmitISRSequentialCallsAllClearFlags) +{ + auto dev = makeStartedDevice(); + for (int i = 0; i < 10; i++) + { + fakeFdcan.IR = 0U; + fakeFdcan.TXEFS = 0U; + dev->transmitISR(); + } + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, nbtpPrescaler1FieldValue0) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbrp = (fakeFdcan.NBTP >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + EXPECT_EQ(nbrp, 0U); +} + +TEST_F(FdCanDeviceTest, nbtpPrescaler256FieldValue255) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 256U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbrp = (fakeFdcan.NBTP >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU; + EXPECT_EQ(nbrp, 255U); +} + +TEST_F(FdCanDeviceTest, nbtpTseg1Is0) +{ + auto cfg = makeDefaultConfig(); + cfg.nts1 = 0U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts1 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU; + EXPECT_EQ(nts1, 0U); +} + +TEST_F(FdCanDeviceTest, nbtpTseg1Is128) +{ + auto cfg = makeDefaultConfig(); + cfg.nts1 = 128U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts1 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU; + EXPECT_EQ(nts1, 128U); +} + +TEST_F(FdCanDeviceTest, nbtpTseg2Is0) +{ + auto cfg = makeDefaultConfig(); + cfg.nts2 = 0U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts2 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU; + EXPECT_EQ(nts2, 0U); +} + +TEST_F(FdCanDeviceTest, nbtpTseg2Is64) +{ + auto cfg = makeDefaultConfig(); + cfg.nts2 = 64U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nts2 = (fakeFdcan.NBTP >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU; + EXPECT_EQ(nts2, 64U); +} + +TEST_F(FdCanDeviceTest, nbtpSjwIs0) +{ + auto cfg = makeDefaultConfig(); + cfg.nsjw = 0U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nsjw = (fakeFdcan.NBTP >> FDCAN_NBTP_NSJW_Pos) & 0x7FU; + EXPECT_EQ(nsjw, 0U); +} + +TEST_F(FdCanDeviceTest, nbtpSjwIs64) +{ + auto cfg = makeDefaultConfig(); + cfg.nsjw = 64U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nsjw = (fakeFdcan.NBTP >> FDCAN_NBTP_NSJW_Pos) & 0x7FU; + EXPECT_EQ(nsjw, 64U); +} + +TEST_F(FdCanDeviceTest, nbtpFieldPositions) +{ + EXPECT_EQ(FDCAN_NBTP_NTSEG2_Pos, 0U); + EXPECT_EQ(FDCAN_NBTP_NTSEG1_Pos, 8U); + EXPECT_EQ(FDCAN_NBTP_NBRP_Pos, 16U); + EXPECT_EQ(FDCAN_NBTP_NSJW_Pos, 25U); +} + +TEST_F(FdCanDeviceTest, nbtpFieldIsolation500kbps) +{ + // Typical 500kbps: prescaler=4, tseg1=13, tseg2=2, sjw=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 4U; + cfg.nts1 = 13U; + cfg.nts2 = 2U; + cfg.nsjw = 1U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t expected = (1U << FDCAN_NBTP_NSJW_Pos) | (3U << FDCAN_NBTP_NBRP_Pos) + | (13U << FDCAN_NBTP_NTSEG1_Pos) | (2U << FDCAN_NBTP_NTSEG2_Pos); + EXPECT_EQ(fakeFdcan.NBTP, expected); +} + +TEST_F(FdCanDeviceTest, nbtpFieldIsolation250kbps) +{ + // Typical 250kbps: prescaler=8, tseg1=13, tseg2=2, sjw=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 8U; + cfg.nts1 = 13U; + cfg.nts2 = 2U; + cfg.nsjw = 1U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t expected = (1U << FDCAN_NBTP_NSJW_Pos) | (7U << FDCAN_NBTP_NBRP_Pos) + | (13U << FDCAN_NBTP_NTSEG1_Pos) | (2U << FDCAN_NBTP_NTSEG2_Pos); + EXPECT_EQ(fakeFdcan.NBTP, expected); +} + +TEST_F(FdCanDeviceTest, nbtpFieldIsolation1Mbps) +{ + // Typical 1Mbps: prescaler=2, tseg1=13, tseg2=2, sjw=1 + auto cfg = makeDefaultConfig(); + cfg.prescaler = 2U; + cfg.nts1 = 13U; + cfg.nts2 = 2U; + cfg.nsjw = 1U; + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t expected = (1U << FDCAN_NBTP_NSJW_Pos) | (1U << FDCAN_NBTP_NBRP_Pos) + | (13U << FDCAN_NBTP_NTSEG1_Pos) | (2U << FDCAN_NBTP_NTSEG2_Pos); + EXPECT_EQ(fakeFdcan.NBTP, expected); +} + +TEST_F(FdCanDeviceTest, nbtpNoOverlapBetweenFields) +{ + // Set all fields to max and verify no bit overlap + auto cfg = makeDefaultConfig(); + cfg.prescaler = 512U; // BRP = 511 = 0x1FF (9 bits at pos 16) + cfg.nts1 = 255U; // 8 bits at pos 8 + cfg.nts2 = 127U; // 7 bits at pos 0 + cfg.nsjw = 127U; // 7 bits at pos 25 + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t nbtp = fakeFdcan.NBTP; + EXPECT_EQ((nbtp >> FDCAN_NBTP_NTSEG2_Pos) & 0x7FU, 127U); + EXPECT_EQ((nbtp >> FDCAN_NBTP_NTSEG1_Pos) & 0xFFU, 255U); + EXPECT_EQ((nbtp >> FDCAN_NBTP_NBRP_Pos) & 0x1FFU, 511U); + EXPECT_EQ((nbtp >> FDCAN_NBTP_NSJW_Pos) & 0x7FU, 127U); +} + +TEST_F(FdCanDeviceTest, nbtpAllFieldsMinimal) +{ + auto cfg = makeDefaultConfig(); + cfg.prescaler = 1U; + cfg.nts1 = 0U; + cfg.nts2 = 0U; + cfg.nsjw = 0U; + bios::FdCanDevice dev(cfg); + dev.init(); + + EXPECT_EQ(fakeFdcan.NBTP, 0U); +} + +TEST_F(FdCanDeviceTest, clockEnableBitPosition) +{ + EXPECT_EQ(RCC_APB1ENR1_FDCANEN_Pos, 25U); + EXPECT_EQ(RCC_APB1ENR1_FDCANEN, (1U << 25U)); +} + +TEST_F(FdCanDeviceTest, initEnablesFDCANClockInAPB1ENR1) +{ + fakeRcc.APB1ENR1 = 0U; + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); +} + +TEST_F(FdCanDeviceTest, initPreservesOtherAPB1ENR1Bits) +{ + fakeRcc.APB1ENR1 = 0x0000FFFFU; + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + // Original bits preserved + EXPECT_NE(fakeRcc.APB1ENR1 & 0x0000FFFFU, 0U); + // FDCANEN also set + EXPECT_NE(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); +} + +TEST_F(FdCanDeviceTest, initSetsClockSelectPCLK1) +{ + fakeRcc.CCIPR = 0U; + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t fdcanSel = (fakeRcc.CCIPR >> 24U) & 3U; + EXPECT_EQ(fdcanSel, 2U); // PCLK1 +} + +TEST_F(FdCanDeviceTest, initClockSelectClearsOldValue) +{ + // Pre-set clock select to HSE (00) with other bits + fakeRcc.CCIPR = (3U << 24U); // was 11b + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + uint32_t fdcanSel = (fakeRcc.CCIPR >> 24U) & 3U; + EXPECT_EQ(fdcanSel, 2U); // Should be 10b = PCLK1 +} + +TEST_F(FdCanDeviceTest, initClockSelectPreservesOtherCCIPRBits) +{ + fakeRcc.CCIPR = 0x00FFFFFFU; // bits 0-23 set + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // Lower 24 bits should still be set + EXPECT_EQ(fakeRcc.CCIPR & 0x00FFFFFFU, 0x00FFFFFFu); + // Clock select should be PCLK1 + uint32_t fdcanSel = (fakeRcc.CCIPR >> 24U) & 3U; + EXPECT_EQ(fdcanSel, 2U); +} + +TEST_F(FdCanDeviceTest, doubleInitDoesNotDoubleSetClock) +{ + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + uint32_t apb1After1 = fakeRcc.APB1ENR1; + dev.init(); + // OR-ing the same bit twice is idempotent + EXPECT_EQ(fakeRcc.APB1ENR1, apb1After1); +} + +TEST_F(FdCanDeviceTest, initClockSelectBits24And25) +{ + fakeRcc.CCIPR = 0U; + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // Bit 25 should be set, bit 24 should be clear (10b) + EXPECT_NE(fakeRcc.CCIPR & (1U << 25U), 0U); + EXPECT_EQ(fakeRcc.CCIPR & (1U << 24U), 0U); +} + +TEST_F(FdCanDeviceTest, initEnablesClockBeforeGPIO) +{ + // Verify clock is enabled (if clock wasn't enabled, GPIO writes would have no effect + // on real hardware - but we can verify the clock bit is set) + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + EXPECT_NE(fakeRcc.APB1ENR1 & RCC_APB1ENR1_FDCANEN, 0U); +} + +TEST_F(FdCanDeviceTest, initCCIPRUpperBitsUnaffected) +{ + fakeRcc.CCIPR = 0xFC000000U; // bits 26-31 set + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg); + dev.init(); + + // Bits 26-31 should still be set + EXPECT_EQ(fakeRcc.CCIPR & 0xFC000000U, 0xFC000000U); +} + +TEST_F(FdCanDeviceTest, transmitISRInvokesCallbackDelegate) +{ + bool callbackFired = false; + auto callback = ::etl::delegate::create([&callbackFired]() { callbackFired = true; }); + + auto cfg = makeDefaultConfig(); + bios::FdCanDevice dev(cfg, callback); + fakeFdcan.CCCR |= FDCAN_CCCR_INIT; + dev.init(); + dev.start(); + fakeFdcan.TXEFS = 0U; + + dev.transmitISR(); + EXPECT_TRUE(callbackFired); +} + +TEST_F(FdCanDeviceTest, transmitISRWithoutDelegateDoesNotCrash) +{ + // Construct without callback - existing API, should still work + auto dev = makeStartedDevice(); + fakeFdcan.TXEFS = 0U; + + dev->transmitISR(); // Must not crash + EXPECT_EQ(fakeFdcan.IR, FDCAN_IR_TC); +} + +TEST_F(FdCanDeviceTest, transmitWithInterruptEnablesTCE) +{ + auto dev = makeStartedDevice(); + // Clear IE to known state (start() may have set it) + fakeFdcan.IE = FDCAN_IE_RF0NE; // Only RX enabled, no TCE + // TX FIFO has space + fakeFdcan.TXFQS = 0x3U; // TFFL=3 + + ::can::CANFrame frame(0x100U, nullptr, 0U); + bool ok = dev->transmit(frame, true); + EXPECT_TRUE(ok); + // TCE should now be set + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, transmitWithoutInterruptDoesNotEnableTCE) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IE = FDCAN_IE_RF0NE; // Only RX, no TCE + fakeFdcan.TXFQS = 0x3U; + + ::can::CANFrame frame(0x100U, nullptr, 0U); + bool ok = dev->transmit(frame, false); + EXPECT_TRUE(ok); + // TCE should NOT be set + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} + +TEST_F(FdCanDeviceTest, transmitISRDisablesTCE) +{ + auto dev = makeStartedDevice(); + fakeFdcan.IE = FDCAN_IE_RF0NE | FDCAN_IE_TCE; // Both enabled + fakeFdcan.TXEFS = 0U; + + dev->transmitISR(); + // TCE should be cleared after ISR (match S32K disableTransmitInterrupt) + EXPECT_EQ(fakeFdcan.IE & FDCAN_IE_TCE, 0U); + // RF0NE should still be set + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); +} + +TEST_F(FdCanDeviceTest, receiveISRKeepsRF0NEEnabled) +{ + auto dev = makeStartedDevice(); + // Enable RF0NE + fakeFdcan.IE = FDCAN_IE_RF0NE | FDCAN_IE_TCE; + // Put one frame in RX FIFO + fakeFdcan.RXF0S = (1U << FDCAN_RXF0S_F0FL_Pos); // F0FL=1 + fakeFdcan.IR = FDCAN_IR_RF0N; + + // Place a valid frame in message RAM at RX FIFO0 index 0 + uint8_t data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + placeRxFrame(0, 0x100, false, 8, data); + + dev->receiveISR(nullptr); + + // receiveISR does NOT touch IE - RF0NE disable (if needed) is the + // responsibility of the CanSystem ISR trampoline, because disabling + // here could permanently block RX if the dispatch is dedup-dropped. + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_RF0NE, 0U); + // TCE should be unaffected + EXPECT_NE(fakeFdcan.IE & FDCAN_IE_TCE, 0U); +} diff --git a/platforms/stm32/bsp/bxCanTransceiver/CMakeLists.txt b/platforms/stm32/bsp/bxCanTransceiver/CMakeLists.txt new file mode 100644 index 00000000000..bf2d9028e6d --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/CMakeLists.txt @@ -0,0 +1,21 @@ +add_library(bxCanTransceiver src/can/transceiver/bxcan/BxCanTransceiver.cpp) + +if (BUILD_EXECUTABLE STREQUAL "unitTest") + target_include_directories(bxCanTransceiver PUBLIC include + test/mock/include) + + target_link_libraries( + bxCanTransceiver + PUBLIC asyncMockImpl + bsp + cpp2can + etl + bspIo + lifecycle + gmock) +else () + target_include_directories(bxCanTransceiver PUBLIC include) + + target_link_libraries(bxCanTransceiver PUBLIC async bspCan lifecycle + cpp2can) +endif () diff --git a/platforms/stm32/bsp/bxCanTransceiver/doc/index.rst b/platforms/stm32/bsp/bxCanTransceiver/doc/index.rst new file mode 100644 index 00000000000..11d899d4605 --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/doc/index.rst @@ -0,0 +1,45 @@ +.. + ******************************************************************************* + Copyright (c) 2026 An Dao + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +bxCanTransceiver +================ + +Overview +-------- + +The ``bxCanTransceiver`` module implements the OpenBSW +``AbstractCANTransceiver`` interface for the STM32F4 bxCAN peripheral +(classic CAN, 500 kbps). It wraps ``BxCanDevice`` (from ``bspCan``) and adds +lifecycle management, async integration, ISR dispatch and bus-off recovery. + +``init()`` initialises the hardware and moves the transceiver from CLOSED to +INITIALIZED. ``open()`` starts the device (re-initialising it first when +called from CLOSED), schedules the cyclic bus-off poll and moves to OPEN. +``close()`` stops the device, clears the TX queue and returns to CLOSED from +any state; ``shutdown()`` delegates to ``close()``. ``mute()`` and +``unmute()`` toggle between OPEN and MUTED. + +TX: ``write(frame)`` transmits fire-and-forget and notifies registered sent +listeners synchronously. ``write(frame, listener)`` queues the job in a +3-entry TX queue; the listener callback runs in task context (via +``async::execute``) after the TX interrupt, which also sends the next queued +frame. When the hardware mailboxes or the TX queue are full, +``CAN_ERR_TX_HW_QUEUE_FULL`` is returned and an overrun counter increments. + +RX: ``receiveInterrupt()`` is called from the CAN RX ISR and drains the +hardware FIFO into the device's software queue (accept-all; per-listener +filtering happens later). ``receiveTask()`` runs in task context, notifies +the registered frame listeners, clears the software queue and re-enables the +RX interrupt. + +Bus-off recovery: ``cyclicTask()`` polls the bus-off flag every 10 ms, moving +OPEN to MUTED on bus-off and back to OPEN once the bus recovers, unless the +user had explicitly called ``mute()``. diff --git a/platforms/stm32/bsp/bxCanTransceiver/include/can/transceiver/bxcan/BxCanTransceiver.h b/platforms/stm32/bsp/bxCanTransceiver/include/can/transceiver/bxcan/BxCanTransceiver.h new file mode 100644 index 00000000000..6f699030458 --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/include/can/transceiver/bxcan/BxCanTransceiver.h @@ -0,0 +1,105 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace bios +{ + +/** + * CAN transceiver for STM32 bxCAN peripheral. + * + * Wraps BxCanDevice to implement the AbstractCANTransceiver interface. + * Operates in classic CAN mode at 500 kbps on STM32F4 family devices. + * + * \see AbstractCANTransceiver + * \see BxCanDevice + */ +class BxCanTransceiver : public ::can::AbstractCANTransceiver +{ +public: + BxCanTransceiver( + ::async::ContextType context, uint8_t busId, BxCanDevice::Config const& devConfig); + + ErrorCode init() override; + ErrorCode open() override; + ErrorCode open(::can::CANFrame const& frame) override; + ErrorCode close() override; + void shutdown() override; + ErrorCode mute() override; + ErrorCode unmute() override; + + /// Fire-and-forget transmit. Calls notifySentListeners() synchronously. + ErrorCode write(::can::CANFrame const& frame) override; + + /// Transmit with deferred callback. Queues {listener, frame} into fTxQueue. + /// canFrameSent() fires from task context after TX ISR, NOT from write(). + ErrorCode write(::can::CANFrame const& frame, ::can::ICANFrameSentListener& listener) override; + + uint32_t getBaudrate() const override; + uint16_t getHwQueueTimeout() const override; + + /// Number of TX frames dropped due to HW queue full or TX listener queue full. + uint32_t getOverrunCount() const { return fOverrunCount; } + + static uint8_t receiveInterrupt(uint8_t transceiverIndex); + static void transmitInterrupt(uint8_t transceiverIndex); + static void disableRxInterrupt(uint8_t transceiverIndex); + static void enableRxInterrupt(uint8_t transceiverIndex); + + void cyclicTask(); + void receiveTask(); + + /// Underlying bxCAN hardware device. Public for test access. + BxCanDevice fDevice; + +private: + /// TX job waiting for its deferred listener callback. + struct TxJobWithCallback + { + TxJobWithCallback(::can::ICANFrameSentListener& listener, ::can::CANFrame const& frame) + : _listener(listener), _frame(frame) + {} + + ::can::ICANFrameSentListener& _listener; + ::can::CANFrame _frame; + }; + + static uint32_t const TX_QUEUE_CAPACITY = 3U; + using TxQueue = ::etl::deque; + + /// Called from TX ISR - defers to task context via async::execute. + void canFrameSentCallback(); + + /// Runs in task context - pops TX queue, calls listener, sends next frame. + void canFrameSentAsyncCallback(); + + void notifyRegisteredSentListener(::can::CANFrame const& frame) { notifySentListeners(frame); } + + static BxCanTransceiver* fpTransceivers[3]; + + ::async::ContextType fContext; + ::async::TimeoutType fCyclicTimeout; + ::async::Function _cyclicTaskRunner; + ::async::Function _canFrameSent; + TxQueue fTxQueue; + uint32_t fOverrunCount; + bool fMuted; +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bxCanTransceiver/module.spec b/platforms/stm32/bsp/bxCanTransceiver/module.spec new file mode 100644 index 00000000000..50ed87e068b --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/module.spec @@ -0,0 +1,2 @@ +maturity: raw +oss: true diff --git a/platforms/stm32/bsp/bxCanTransceiver/src/can/transceiver/bxcan/BxCanTransceiver.cpp b/platforms/stm32/bsp/bxCanTransceiver/src/can/transceiver/bxcan/BxCanTransceiver.cpp new file mode 100644 index 00000000000..28f390591e8 --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/src/can/transceiver/bxcan/BxCanTransceiver.cpp @@ -0,0 +1,310 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +#include + +namespace bios +{ + +BxCanTransceiver* BxCanTransceiver::fpTransceivers[3] = {nullptr, nullptr, nullptr}; + +BxCanTransceiver::BxCanTransceiver( + ::async::ContextType context, uint8_t busId, BxCanDevice::Config const& devConfig) +: AbstractCANTransceiver(busId) +, fDevice(devConfig) +, fContext(context) +, fCyclicTimeout() +, _cyclicTaskRunner( + ::async::Function::CallType::create(*this)) +, _canFrameSent(::async::Function::CallType:: + create(*this)) +, fTxQueue() +, fOverrunCount(0U) +, fMuted(false) +{ + if (busId < 3U) + { + fpTransceivers[busId] = this; + } +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::init() +{ + if (getState() != State::CLOSED) + { + return ErrorCode::CAN_ERR_ILLEGAL_STATE; + } + + if (!fDevice.init()) + { + return ErrorCode::CAN_ERR_INIT_FAILED; + } + setState(State::INITIALIZED); + return ErrorCode::CAN_ERR_OK; +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::open() +{ + State const state = getState(); + if (state != State::INITIALIZED && state != State::CLOSED) + { + return ErrorCode::CAN_ERR_ILLEGAL_STATE; + } + + if (state == State::CLOSED) + { + if (!fDevice.init()) + { + return ErrorCode::CAN_ERR_INIT_FAILED; + } + } + + if (!fDevice.start()) + { + return ErrorCode::CAN_ERR_ILLEGAL_STATE; + } + setState(State::OPEN); + fMuted = false; + + // Schedule periodic bus-off polling. + ::async::scheduleAtFixedRate( + fContext, _cyclicTaskRunner, fCyclicTimeout, 10U, ::async::TimeUnit::MILLISECONDS); + + return ErrorCode::CAN_ERR_OK; +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::open(::can::CANFrame const& /* frame */) +{ + // Wake-up frame not supported on bxCAN + return open(); +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::close() +{ + if (getState() == State::CLOSED) + { + return ErrorCode::CAN_ERR_OK; + } + + fCyclicTimeout.cancel(); + fDevice.stop(); + fTxQueue.clear(); + setState(State::CLOSED); + return ErrorCode::CAN_ERR_OK; +} + +void BxCanTransceiver::shutdown() { close(); } + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::mute() +{ + if (getState() != State::OPEN) + { + return ErrorCode::CAN_ERR_ILLEGAL_STATE; + } + + fMuted = true; + fTxQueue.clear(); + setState(State::MUTED); + return ErrorCode::CAN_ERR_OK; +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::unmute() +{ + if (getState() != State::MUTED) + { + return ErrorCode::CAN_ERR_ILLEGAL_STATE; + } + + fMuted = false; + setState(State::OPEN); + return ErrorCode::CAN_ERR_OK; +} + +::can::ICanTransceiver::ErrorCode BxCanTransceiver::write(::can::CANFrame const& frame) +{ + if (getState() != State::OPEN || fMuted) + { + return ErrorCode::CAN_ERR_TX_OFFLINE; + } + + if (!fDevice.transmit(frame)) + { + fOverrunCount++; + return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL; + } + + notifySentListeners(frame); + return ErrorCode::CAN_ERR_OK; +} + +::can::ICanTransceiver::ErrorCode +BxCanTransceiver::write(::can::CANFrame const& frame, ::can::ICANFrameSentListener& listener) +{ + if (getState() != State::OPEN || fMuted) + { + return ErrorCode::CAN_ERR_TX_OFFLINE; + } + + if (fTxQueue.full()) + { + fOverrunCount++; + notifyRegisteredSentListener(frame); + return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL; + } + + bool const wasEmpty = fTxQueue.empty(); + fTxQueue.emplace_back(listener, frame); + + if (!wasEmpty) + { + // Not the first in queue - will be sent from the TX ISR chain + return ErrorCode::CAN_ERR_OK; + } + + // First in queue - transmit now + if (!fDevice.transmit(frame)) + { + fTxQueue.pop_front(); + fOverrunCount++; + notifyRegisteredSentListener(frame); + return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL; + } + + // Wait for TX ISR -> canFrameSentCallback() -> canFrameSentAsyncCallback() + return ErrorCode::CAN_ERR_OK; +} + +uint32_t BxCanTransceiver::getBaudrate() const { return 500000U; } + +uint16_t BxCanTransceiver::getHwQueueTimeout() const { return 10U; } + +uint8_t BxCanTransceiver::receiveInterrupt(uint8_t transceiverIndex) +{ + if (transceiverIndex < 3U && fpTransceivers[transceiverIndex] != nullptr) + { + // Accept all frames into the software queue - per-listener filtering + // is done by notifyListeners() in receiveTask(). + return fpTransceivers[transceiverIndex]->fDevice.receiveISR(nullptr); + } + return 0U; +} + +void BxCanTransceiver::transmitInterrupt(uint8_t transceiverIndex) +{ + if (transceiverIndex < 3U && fpTransceivers[transceiverIndex] != nullptr) + { + BxCanTransceiver* self = fpTransceivers[transceiverIndex]; + self->fDevice.transmitISR(); + + if (!self->fTxQueue.empty()) + { + self->canFrameSentCallback(); + } + } +} + +void BxCanTransceiver::cyclicTask() +{ + // Check bus-off state + if (fDevice.isBusOff()) + { + if (getState() == State::OPEN) + { + setState(State::MUTED); + } + } + else if (getState() == State::MUTED && !fMuted) + { + setState(State::OPEN); + } +} + +void BxCanTransceiver::disableRxInterrupt(uint8_t transceiverIndex) +{ + if (transceiverIndex < 3U && fpTransceivers[transceiverIndex] != nullptr) + { + fpTransceivers[transceiverIndex]->fDevice.disableRxInterrupt(); + } +} + +void BxCanTransceiver::enableRxInterrupt(uint8_t transceiverIndex) +{ + if (transceiverIndex < 3U && fpTransceivers[transceiverIndex] != nullptr) + { + fpTransceivers[transceiverIndex]->fDevice.enableRxInterrupt(); + } +} + +void BxCanTransceiver::receiveTask() +{ + uint8_t count = fDevice.getRxCount(); + for (uint8_t i = 0U; i < count; i++) + { + notifyListeners(fDevice.getRxFrame(i)); + } + fDevice.clearRxQueue(); + + // Re-enable RX FIFO interrupt after draining queue + fDevice.enableRxInterrupt(); +} + +void BxCanTransceiver::canFrameSentCallback() { ::async::execute(fContext, _canFrameSent); } + +void BxCanTransceiver::canFrameSentAsyncCallback() +{ + if (!fTxQueue.empty()) + { + // If transceiver is no longer OPEN (bus-off, muted, closed), drop + // all queued TX jobs without calling listeners. + if (getState() != State::OPEN) + { + fTxQueue.clear(); + return; + } + + TxJobWithCallback& job = fTxQueue.front(); + ::can::CANFrame const& frame = job._frame; + ::can::ICANFrameSentListener& listener = job._listener; + fTxQueue.pop_front(); + + bool sendAgain = false; + if (!fTxQueue.empty()) + { + if (getState() == State::OPEN) + { + sendAgain = true; + } + else + { + fTxQueue.clear(); + } + } + + listener.canFrameSent(frame); + notifyRegisteredSentListener(frame); + + if (sendAgain) + { + ::can::CANFrame const& nextFrame = fTxQueue.front()._frame; + if (fDevice.transmit(nextFrame)) + { + // Wait for next TX ISR + return; + } + // HW queue full - no ISR will retrigger, clear remaining + fTxQueue.clear(); + notifyRegisteredSentListener(nextFrame); + } + } +} + +} // namespace bios diff --git a/platforms/stm32/bsp/bxCanTransceiver/test/CMakeLists.txt b/platforms/stm32/bsp/bxCanTransceiver/test/CMakeLists.txt new file mode 100644 index 00000000000..e73c320b832 --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/test/CMakeLists.txt @@ -0,0 +1,15 @@ +add_executable(BxCanTransceiverTest src/can/BxCanTransceiverTest.cpp) + +target_link_libraries( + BxCanTransceiverTest + PRIVATE asyncMockImpl + bsp + bxCanTransceiver + cpp2can + bspIo + lifecycle + bspMock + gmock) + +gtest_discover_tests(BxCanTransceiverTest PROPERTIES LABELS + "BxCanTransceiverTest") diff --git a/platforms/stm32/bsp/bxCanTransceiver/test/mock/include/can/BxCanDevice.h b/platforms/stm32/bsp/bxCanTransceiver/test/mock/include/can/BxCanDevice.h new file mode 100644 index 00000000000..7718745836e --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/test/mock/include/can/BxCanDevice.h @@ -0,0 +1,66 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#pragma once + +#include +#include + +#include + +namespace bios +{ + +// GMock replacement for the register-level BxCanDevice. +class BxCanDevice +{ +public: + struct Config + { + uint32_t baseAddress; + uint32_t prescaler; + uint32_t bs1; + uint32_t bs2; + uint32_t sjw; + uint32_t rxGpioPort; + uint8_t rxPin; + uint8_t rxAf; + uint32_t txGpioPort; + uint8_t txPin; + uint8_t txAf; + }; + + static constexpr uint32_t RX_QUEUE_SIZE = 32U; + + explicit BxCanDevice(Config const& /* config */) + { + ON_CALL(*this, init()).WillByDefault(::testing::Return(true)); + ON_CALL(*this, start()).WillByDefault(::testing::Return(true)); + } + + MOCK_METHOD(bool, init, ()); + MOCK_METHOD(bool, start, ()); + MOCK_METHOD(void, stop, ()); + MOCK_METHOD(bool, transmit, (::can::CANFrame const& frame)); + MOCK_METHOD(uint8_t, receiveISR, (uint8_t const* filterBitField)); + MOCK_METHOD(void, transmitISR, ()); + MOCK_METHOD(bool, isBusOff, (), (const)); + MOCK_METHOD(uint8_t, getTxErrorCounter, (), (const)); + MOCK_METHOD(uint8_t, getRxErrorCounter, (), (const)); + MOCK_METHOD(void, configureAcceptAllFilter, ()); + MOCK_METHOD(void, configureFilterList, (uint32_t const* idList, uint8_t count)); + MOCK_METHOD(::can::CANFrame const&, getRxFrame, (uint8_t index), (const)); + MOCK_METHOD(uint8_t, getRxCount, (), (const)); + MOCK_METHOD(void, clearRxQueue, ()); + MOCK_METHOD(void, disableRxInterrupt, ()); + MOCK_METHOD(void, enableRxInterrupt, ()); +}; + +} // namespace bios diff --git a/platforms/stm32/bsp/bxCanTransceiver/test/src/can/BxCanTransceiverTest.cpp b/platforms/stm32/bsp/bxCanTransceiver/test/src/can/BxCanTransceiverTest.cpp new file mode 100644 index 00000000000..d1447938d39 --- /dev/null +++ b/platforms/stm32/bsp/bxCanTransceiver/test/src/can/BxCanTransceiverTest.cpp @@ -0,0 +1,943 @@ +/******************************************************************************** + * Copyright (c) 2026 An Dao + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "can/transceiver/bxcan/BxCanTransceiver.h" + +#include "async/AsyncMock.h" +#include "bsp/timer/SystemTimerMock.h" +#include "can/canframes/ICANFrameSentListener.h" + +#include +#include + +namespace +{ +using namespace ::can; +using namespace ::testing; +using namespace ::bios; + +class MockCANFrameSentListener : public ::can::ICANFrameSentListener +{ +public: + MOCK_METHOD(void, canFrameSent, (::can::CANFrame const&), (override)); +}; + +class BxCanTransceiverTest : public Test +{ +public: + ::async::AsyncMock fAsyncMock; + ::async::ContextType fAsyncContext = 0; + uint8_t fBusId = 0; + BxCanDevice::Config fDevConfig{}; +}; + +TEST_F(BxCanTransceiverTest, initFromClosed) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.init()); +} + +TEST_F(BxCanTransceiverTest, initTwiceFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.init()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, bxt.init()); +} + +TEST_F(BxCanTransceiverTest, receiveInterruptInvalidIndex) +{ + EXPECT_EQ(0U, BxCanTransceiver::receiveInterrupt(3)); +} + +TEST_F(BxCanTransceiverTest, writeFromClosedFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, bxt.write(frame)); +} + +TEST_F(BxCanTransceiverTest, writeWithListenerFromClosedFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + CANFrame frame; + MockCANFrameSentListener listener; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, bxt.write(frame, listener)); +} + +TEST_F(BxCanTransceiverTest, closeFromClosedReturnsOk) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.close()); +} + +TEST_F(BxCanTransceiverTest, muteFromClosedFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, bxt.mute()); +} + +TEST_F(BxCanTransceiverTest, unmuteFromClosedFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, bxt.unmute()); +} + +TEST_F(BxCanTransceiverTest, openFromClosedWithoutInitFails) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + // CLOSED -> open() should either re-init or fail depending on impl. + // The contract says CLOSED->open() re-inits (see impl). So this tests + // that open() from CLOSED is allowed (re-init path). + EXPECT_CALL(bxt.fDevice, init()).Times(AnyNumber()); + EXPECT_CALL(bxt.fDevice, start()).Times(AnyNumber()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.open()); +} + +class InitedBxCanTransceiverTest : public BxCanTransceiverTest +{ +public: + InitedBxCanTransceiverTest() : fBxt(fAsyncContext, fBusId, fDevConfig) + { + EXPECT_CALL(fBxt.fDevice, init()).Times(AnyNumber()); + EXPECT_CALL(fBxt.fDevice, start()).Times(AnyNumber()); + EXPECT_CALL(fBxt.fDevice, stop()).Times(AnyNumber()); + EXPECT_CALL(fAsyncMock, execute(fAsyncContext, _)) + .Times(AnyNumber()) + .WillRepeatedly([](auto, auto& runnable) { runnable.execute(); }); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.init()); + } + + BxCanTransceiver fBxt; +}; + +TEST_F(InitedBxCanTransceiverTest, open) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); +} + +TEST_F(InitedBxCanTransceiverTest, openTwiceFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.open()); +} + +TEST_F(InitedBxCanTransceiverTest, closeFromOpen) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); +} + +TEST_F(InitedBxCanTransceiverTest, closeFromInitializedReturnsOk) +{ + EXPECT_CALL(fBxt.fDevice, stop()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); +} + +TEST_F(InitedBxCanTransceiverTest, muteFromOpen) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); +} + +TEST_F(InitedBxCanTransceiverTest, muteFromInitializedFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.mute()); +} + +TEST_F(InitedBxCanTransceiverTest, unmuteFromMuted) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.unmute()); +} + +TEST_F(InitedBxCanTransceiverTest, unmuteFromOpenFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.unmute()); +} + +TEST_F(InitedBxCanTransceiverTest, writeWhenOpen) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWhenMutedFails) +{ + CANFrame frame; + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWhenFifoFull) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(false)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, getBaudrate) { EXPECT_EQ(500000U, fBxt.getBaudrate()); } + +TEST_F(InitedBxCanTransceiverTest, getHwQueueTimeout) { EXPECT_EQ(10U, fBxt.getHwQueueTimeout()); } + +TEST_F(InitedBxCanTransceiverTest, receiveTask) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, getRxCount()).WillOnce(Return(0)); + EXPECT_CALL(fBxt.fDevice, clearRxQueue()).Times(1); + + fBxt.receiveTask(); +} + +TEST_F(InitedBxCanTransceiverTest, cyclicTaskBusOff) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + EXPECT_CALL(fBxt.fDevice, isBusOff()).WillOnce(Return(true)); + fBxt.cyclicTask(); + + // After bus-off, write should fail because state is MUTED + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, cyclicTaskBusRecovery) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Go to bus-off + EXPECT_CALL(fBxt.fDevice, isBusOff()).WillOnce(Return(true)).WillOnce(Return(false)); + + fBxt.cyclicTask(); // bus-off -> MUTED + fBxt.cyclicTask(); // bus-on -> OPEN (auto-recovery, not user mute) + + // Write should work again + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, shutdown) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + fBxt.shutdown(); +} + +TEST_F(InitedBxCanTransceiverTest, receiveInterrupt) +{ + EXPECT_CALL(fBxt.fDevice, receiveISR(_)).WillOnce(Return(0)); + BxCanTransceiver::receiveInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, transmitInterrupt) +{ + EXPECT_CALL(fBxt.fDevice, transmitISR()); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, writeWithListenerReturnsOkWhenOpen) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWithListenerWhenMutedFails) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWithListenerWhenFifoFullReturnsQueueFull) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(false)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWithListenerCallbackFromTransmitInterrupt) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // The listener should be called when transmitInterrupt fires + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, txQueueFillsToCapacity) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Queue capacity is 3 - fill it up without draining + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // 4th write should fail because queue is full + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, txQueueDrainAndRefill) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(listener, canFrameSent(_)).Times(AnyNumber()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Fill queue + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // Drain one via TX ISR callback + EXPECT_CALL(fBxt.fDevice, transmitISR()); + BxCanTransceiver::transmitInterrupt(fBusId); + + // Now one slot is free + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackSingleFrame) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackTwoFrames) +{ + CANFrame frame1; + CANFrame frame2; + MockCANFrameSentListener listener1; + MockCANFrameSentListener listener2; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame1, listener1)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame2, listener2)); + + // First TX ISR: listener1 fires + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener1, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); + + // Second TX ISR: listener2 fires + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener2, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackThreeFramesFifoOrder) +{ + CANFrame frame; + MockCANFrameSentListener listener1; + MockCANFrameSentListener listener2; + MockCANFrameSentListener listener3; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener1)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener2)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener3)); + + InSequence seq; + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener1, canFrameSent(_)); + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener2, canFrameSent(_)); + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener3, canFrameSent(_)); + + BxCanTransceiver::transmitInterrupt(fBusId); + BxCanTransceiver::transmitInterrupt(fBusId); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackEmptyQueue) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // TX ISR with nothing queued - should not crash + EXPECT_CALL(fBxt.fDevice, transmitISR()); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackAbortedWhenMuted) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // Mute before TX ISR fires + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + + // TX ISR should still call transmitISR but listener is NOT called (muted) + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(0); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackWithFireAndForgetWrite) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); + + // TX ISR fires - no listener was registered, no crash + EXPECT_CALL(fBxt.fDevice, transmitISR()); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackSameListenerTwice) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + EXPECT_CALL(fBxt.fDevice, transmitISR()).Times(2); + EXPECT_CALL(listener, canFrameSent(_)).Times(2); + + BxCanTransceiver::transmitInterrupt(fBusId); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, canFrameSentCallbackMixedWriteStyles) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Fire-and-forget write + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); + // Write with listener + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // TX ISR fires for the listener-based write + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, receiveInterruptPassesNullFilter) +{ + EXPECT_CALL(fBxt.fDevice, receiveISR(nullptr)).WillOnce(Return(1)); + uint8_t count = BxCanTransceiver::receiveInterrupt(fBusId); + EXPECT_EQ(1U, count); +} + +TEST_F(InitedBxCanTransceiverTest, receiveInterruptUnregisteredIndexReturnsZero) +{ + // Index 2 was never registered (only index 0 was) + EXPECT_EQ(0U, BxCanTransceiver::receiveInterrupt(2)); +} + +TEST_F(InitedBxCanTransceiverTest, receiveTaskWithFramesNotifiesListeners) +{ + CANFrame frame1; + CANFrame frame2; + + EXPECT_CALL(fBxt.fDevice, getRxCount()).WillOnce(Return(2)); + EXPECT_CALL(fBxt.fDevice, getRxFrame(0)).WillOnce(ReturnRef(frame1)); + EXPECT_CALL(fBxt.fDevice, getRxFrame(1)).WillOnce(ReturnRef(frame2)); + EXPECT_CALL(fBxt.fDevice, clearRxQueue()).Times(1); + EXPECT_CALL(fBxt.fDevice, enableRxInterrupt()).Times(1); + + fBxt.receiveTask(); +} + +TEST_F(InitedBxCanTransceiverTest, receiveTaskReenablesInterrupt) +{ + EXPECT_CALL(fBxt.fDevice, getRxCount()).WillOnce(Return(0)); + EXPECT_CALL(fBxt.fDevice, clearRxQueue()).Times(1); + EXPECT_CALL(fBxt.fDevice, enableRxInterrupt()).Times(1); + + fBxt.receiveTask(); +} + +TEST_F(InitedBxCanTransceiverTest, writeFireAndForgetNotifiesRegisteredSentListeners) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // notifySentListeners is called synchronously by write(frame) + // No registered sent listeners by default, so it just doesn't crash + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, writeFailureDoesNotNotifySentListeners) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(false)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // HW queue full - no notification expected + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, docanWriteThenTxIsr) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // Simulates: DoCAN sets _sendPending after write() returns, + // then TX ISR fires, canFrameSent() clears _sendPending + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, docanConsecutiveMultiFrameSend) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(fBxt.fDevice, transmitISR()).Times(3); + EXPECT_CALL(listener, canFrameSent(_)).Times(3); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Simulate DoCAN sending 3 consecutive frames + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + BxCanTransceiver::transmitInterrupt(fBusId); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + BxCanTransceiver::transmitInterrupt(fBusId); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, openWithFrameDelegatesToOpen) +{ + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open(frame)); + // Second open should fail, proving state transitioned + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.open()); +} + +TEST_F(InitedBxCanTransceiverTest, openFromClosedReinitsDevice) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); + + // Re-open from CLOSED should call init + start + EXPECT_CALL(fBxt.fDevice, init()).Times(1); + EXPECT_CALL(fBxt.fDevice, start()).Times(1); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); +} + +TEST_F(InitedBxCanTransceiverTest, closeFromMutedReturnsOk) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); +} + +TEST_F(InitedBxCanTransceiverTest, closeIsIdempotent) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); +} + +TEST_F(InitedBxCanTransceiverTest, muteTwiceFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.mute()); +} + +TEST_F(InitedBxCanTransceiverTest, unmuteFromInitializedFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.unmute()); +} + +TEST_F(InitedBxCanTransceiverTest, getBusIdReturnsConfiguredValue) +{ + EXPECT_EQ(fBusId, fBxt.getBusId()); +} + +TEST_F(InitedBxCanTransceiverTest, getStateReflectsLifecycle) +{ + EXPECT_EQ(ICanTransceiver::State::INITIALIZED, fBxt.getState()); + + fBxt.open(); + EXPECT_EQ(ICanTransceiver::State::OPEN, fBxt.getState()); + + fBxt.mute(); + EXPECT_EQ(ICanTransceiver::State::MUTED, fBxt.getState()); + + fBxt.unmute(); + EXPECT_EQ(ICanTransceiver::State::OPEN, fBxt.getState()); + + fBxt.close(); + EXPECT_EQ(ICanTransceiver::State::CLOSED, fBxt.getState()); +} + +TEST_F(InitedBxCanTransceiverTest, disableRxInterruptDelegatesToDevice) +{ + EXPECT_CALL(fBxt.fDevice, disableRxInterrupt()).Times(1); + BxCanTransceiver::disableRxInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, writeFromInitializedReturnsTxOffline) +{ + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, writeWithListenerFromInitializedReturnsTxOffline) +{ + CANFrame frame; + MockCANFrameSentListener listener; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame, listener)); +} + +TEST_F(InitedBxCanTransceiverTest, openFromMutedFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.open()); +} + +TEST_F(InitedBxCanTransceiverTest, initFromOpenFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.init()); +} + +TEST_F(InitedBxCanTransceiverTest, initFromMutedFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.init()); +} + +TEST_F(InitedBxCanTransceiverTest, writeAfterCloseReturnsTxOffline) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.close()); + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, muteFromMutedFails) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE, fBxt.mute()); +} + +TEST_F(InitedBxCanTransceiverTest, unmuteRestoresWriteCapability) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.unmute()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, shutdownFromInitialized) +{ + fBxt.shutdown(); + EXPECT_EQ(ICanTransceiver::State::CLOSED, fBxt.getState()); +} + +TEST_F(BxCanTransceiverTest, fullLifecycle) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + + EXPECT_CALL(bxt.fDevice, init()).Times(AnyNumber()); + EXPECT_CALL(bxt.fDevice, start()).Times(AnyNumber()); + EXPECT_CALL(bxt.fDevice, stop()).Times(AnyNumber()); + + EXPECT_EQ(ICanTransceiver::State::CLOSED, bxt.getState()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.init()); + EXPECT_EQ(ICanTransceiver::State::INITIALIZED, bxt.getState()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.open()); + EXPECT_EQ(ICanTransceiver::State::OPEN, bxt.getState()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.mute()); + EXPECT_EQ(ICanTransceiver::State::MUTED, bxt.getState()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.close()); + EXPECT_EQ(ICanTransceiver::State::CLOSED, bxt.getState()); +} + +TEST_F(BxCanTransceiverTest, reopenAfterShutdown) +{ + BxCanTransceiver bxt(fAsyncContext, fBusId, fDevConfig); + + EXPECT_CALL(bxt.fDevice, init()).Times(AnyNumber()); + EXPECT_CALL(bxt.fDevice, start()).Times(AnyNumber()); + EXPECT_CALL(bxt.fDevice, stop()).Times(AnyNumber()); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.init()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.open()); + bxt.shutdown(); + EXPECT_EQ(ICanTransceiver::State::CLOSED, bxt.getState()); + + // Re-open from CLOSED + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, bxt.open()); + EXPECT_EQ(ICanTransceiver::State::OPEN, bxt.getState()); +} + +TEST_F(InitedBxCanTransceiverTest, busOffDuringPendingTxDropsCallback) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // Bus goes off before TX ISR + EXPECT_CALL(fBxt.fDevice, isBusOff()).WillOnce(Return(true)); + fBxt.cyclicTask(); // transitions to MUTED + + // TX ISR fires after bus-off - listener should NOT be called + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(0); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +TEST_F(InitedBxCanTransceiverTest, busOffRecoveryResumesTx) +{ + CANFrame frame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillRepeatedly(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // Bus-off -> MUTED + EXPECT_CALL(fBxt.fDevice, isBusOff()).WillOnce(Return(true)).WillOnce(Return(false)); + fBxt.cyclicTask(); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); + + // Bus-on -> OPEN + fBxt.cyclicTask(); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, concurrentRxTxSameCycle) +{ + CANFrame rxFrame; + CANFrame txFrame; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // TX + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(txFrame)); + + // RX in same cycle + EXPECT_CALL(fBxt.fDevice, getRxCount()).WillOnce(Return(1)); + EXPECT_CALL(fBxt.fDevice, getRxFrame(0)).WillOnce(ReturnRef(rxFrame)); + EXPECT_CALL(fBxt.fDevice, clearRxQueue()).Times(1); + EXPECT_CALL(fBxt.fDevice, enableRxInterrupt()).Times(1); + + fBxt.receiveTask(); +} + +TEST_F(InitedBxCanTransceiverTest, txIsrAndReceiveTaskInterleave) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // RX task runs + EXPECT_CALL(fBxt.fDevice, getRxCount()).WillOnce(Return(0)); + EXPECT_CALL(fBxt.fDevice, clearRxQueue()).Times(1); + EXPECT_CALL(fBxt.fDevice, enableRxInterrupt()).Times(1); + fBxt.receiveTask(); + + // TX ISR fires after receive task completed + EXPECT_CALL(fBxt.fDevice, transmitISR()); + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + BxCanTransceiver::transmitInterrupt(fBusId); +} + +class ManualAsyncBxCanTransceiverTest : public BxCanTransceiverTest +{ +public: + ManualAsyncBxCanTransceiverTest() : fBxt(fAsyncContext, fBusId, fDevConfig) + { + EXPECT_CALL(fBxt.fDevice, init()).Times(AnyNumber()); + EXPECT_CALL(fBxt.fDevice, start()).Times(AnyNumber()); + EXPECT_CALL(fBxt.fDevice, stop()).Times(AnyNumber()); + + // Capture the runnable instead of auto-executing + EXPECT_CALL(fAsyncMock, execute(fAsyncContext, _)) + .Times(AnyNumber()) + .WillRepeatedly([this](auto, auto& runnable) { fCapturedRunnable = &runnable; }); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.init()); + } + + void executeDeferred() + { + if (fCapturedRunnable != nullptr) + { + fCapturedRunnable->execute(); + fCapturedRunnable = nullptr; + } + } + + BxCanTransceiver fBxt; + ::async::RunnableType* fCapturedRunnable = nullptr; +}; + +TEST_F(ManualAsyncBxCanTransceiverTest, deferredCallbackNotCalledUntilAsyncFires) +{ + CANFrame frame; + MockCANFrameSentListener listener; + + EXPECT_CALL(fBxt.fDevice, transmit(_)).WillOnce(Return(true)); + + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.write(frame, listener)); + + // TX ISR fires - defers to async context + EXPECT_CALL(fBxt.fDevice, transmitISR()); + BxCanTransceiver::transmitInterrupt(fBusId); + + // Listener is called when async executes + EXPECT_CALL(listener, canFrameSent(_)).Times(1); + executeDeferred(); +} + +TEST_F(InitedBxCanTransceiverTest, cyclicTaskUserMuteNoAutoRecovery) +{ + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.open()); + + // User mutes manually + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_OK, fBxt.mute()); + + // Bus is not off, but fMuted is true - cyclicTask should NOT unmute + EXPECT_CALL(fBxt.fDevice, isBusOff()).WillOnce(Return(false)); + fBxt.cyclicTask(); + + // Should still be MUTED because user muted (fMuted = true) + CANFrame frame; + EXPECT_EQ(ICanTransceiver::ErrorCode::CAN_ERR_TX_OFFLINE, fBxt.write(frame)); +} + +TEST_F(InitedBxCanTransceiverTest, enableRxInterruptDelegatesToDevice) +{ + EXPECT_CALL(fBxt.fDevice, enableRxInterrupt()).Times(1); + BxCanTransceiver::enableRxInterrupt(fBusId); +} + +TEST_F(BxCanTransceiverTest, disableRxInterruptInvalidIndexSafe) +{ + BxCanTransceiver::disableRxInterrupt(3); +} + +TEST_F(BxCanTransceiverTest, enableRxInterruptInvalidIndexSafe) +{ + BxCanTransceiver::enableRxInterrupt(3); +} + +TEST_F(BxCanTransceiverTest, transmitInterruptInvalidIndexSafe) +{ + BxCanTransceiver::transmitInterrupt(3); +} + +} // namespace