1 /* 2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #ifndef R_ADC_H 8 #define R_ADC_H 9 10 /*********************************************************************************************************************** 11 * Includes 12 **********************************************************************************************************************/ 13 #include <stdlib.h> 14 15 /* Fixed width integer support. */ 16 #include <stdint.h> 17 18 /* bool support */ 19 #include <stdbool.h> 20 #include "bsp_api.h" 21 #include "r_adc_cfg.h" 22 #include "r_adc_api.h" 23 24 /* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ 25 FSP_HEADER 26 27 /*******************************************************************************************************************//** 28 * @addtogroup ADC 29 * @{ 30 **********************************************************************************************************************/ 31 32 /*********************************************************************************************************************** 33 * Macro definitions 34 **********************************************************************************************************************/ 35 36 /* Typical values that can be used to modify the sample states. 37 * The minimum sample state count value is either 6 or 7 depending on the clock ratios. 38 * It is fixed to 7 based on the fact that at the lowest ADC conversion clock supported (1 MHz) 39 * this extra state will lead to at worst a "1 microsecond" increase in conversion time. 40 * At 60 MHz the extra sample state will add 16.7 ns to the conversion time. 41 */ 42 #define ADC_SAMPLE_STATE_COUNT_MIN (7U) 43 #define ADC_SAMPLE_STATE_COUNT_MAX (255U) 44 45 /* Typical values that can be used for the sample and hold counts for the channels 0-2*/ 46 /* Minimum sample and hold states */ 47 #define ADC_SAMPLE_STATE_HOLD_COUNT_MIN (4U) 48 49 /* Default sample and hold states */ 50 #define ADC_SAMPLE_STATE_HOLD_COUNT_DEFAULT (24U) 51 52 /** For ADC Scan configuration adc_channel_cfg_t::scan_mask, adc_channel_cfg_t::scan_mask_group_b, 53 * adc_channel_cfg_t::add_mask and adc_channel_cfg_t::sample_hold_mask. 54 * Use bitwise OR to combine these masks for desired channels and sensors. */ 55 typedef enum e_adc_mask 56 { 57 ADC_MASK_OFF = (0U), ///< No channels selected 58 ADC_MASK_CHANNEL_0 = (1U << 0U), ///< Channel 0 mask 59 ADC_MASK_CHANNEL_1 = (1U << 1U), ///< Channel 1 mask 60 ADC_MASK_CHANNEL_2 = (1U << 2U), ///< Channel 2 mask 61 ADC_MASK_CHANNEL_3 = (1U << 3U), ///< Channel 3 mask 62 ADC_MASK_CHANNEL_4 = (1U << 4U), ///< Channel 4 mask 63 ADC_MASK_CHANNEL_5 = (1U << 5U), ///< Channel 5 mask 64 ADC_MASK_CHANNEL_6 = (1U << 6U), ///< Channel 6 mask 65 ADC_MASK_CHANNEL_7 = (1U << 7U), ///< Channel 7 mask 66 ADC_MASK_CHANNEL_8 = (1U << 8U), ///< Channel 8 mask 67 ADC_MASK_CHANNEL_9 = (1U << 9U), ///< Channel 9 mask 68 ADC_MASK_CHANNEL_10 = (1U << 10U), ///< Channel 10 mask 69 ADC_MASK_CHANNEL_11 = (1U << 11U), ///< Channel 11 mask 70 ADC_MASK_CHANNEL_12 = (1U << 12U), ///< Channel 12 mask 71 ADC_MASK_CHANNEL_13 = (1U << 13U), ///< Channel 13 mask 72 ADC_MASK_CHANNEL_14 = (1U << 14U), ///< Channel 14 mask 73 ADC_MASK_CHANNEL_15 = (1U << 15U), ///< Channel 15 mask 74 ADC_MASK_CHANNEL_16 = (1U << 16U), ///< Channel 16 mask 75 ADC_MASK_CHANNEL_17 = (1U << 17U), ///< Channel 17 mask 76 ADC_MASK_CHANNEL_18 = (1U << 18U), ///< Channel 18 mask 77 ADC_MASK_CHANNEL_19 = (1U << 19U), ///< Channel 19 mask 78 ADC_MASK_CHANNEL_20 = (1U << 20U), ///< Channel 20 mask 79 ADC_MASK_CHANNEL_21 = (1U << 21U), ///< Channel 21 mask 80 ADC_MASK_CHANNEL_22 = (1U << 22U), ///< Channel 22 mask 81 ADC_MASK_CHANNEL_23 = (1U << 23U), ///< Channel 23 mask 82 ADC_MASK_CHANNEL_24 = (1U << 24U), ///< Channel 24 mask 83 ADC_MASK_CHANNEL_25 = (1U << 25U), ///< Channel 25 mask 84 ADC_MASK_CHANNEL_26 = (1U << 26U), ///< Channel 26 mask 85 ADC_MASK_CHANNEL_27 = (1U << 27U), ///< Channel 27 mask 86 ADC_MASK_CHANNEL_28 = (1U << 28U), ///< Channel 28 mask 87 ADC_MASK_TEMPERATURE = (1U << 29UL), ///< Temperature sensor channel mask 88 ADC_MASK_VOLT = (1U << 30UL), ///< Voltage reference channel mask 89 ADC_MASK_SENSORS = (ADC_MASK_TEMPERATURE | ADC_MASK_VOLT), ///< All sensor channel mask 90 } adc_mask_t; 91 92 /** ADC data sample addition and averaging options */ 93 typedef enum e_adc_add 94 { 95 ADC_ADD_OFF = 0, ///< Addition turned off for channels/sensors 96 ADC_ADD_TWO = 1, ///< Add two samples 97 ADC_ADD_THREE = 2, ///< Add three samples 98 ADC_ADD_FOUR = 3, ///< Add four samples 99 ADC_ADD_SIXTEEN = 5, ///< Add sixteen samples 100 ADC_ADD_AVERAGE_TWO = 0x81, ///< Average two samples 101 ADC_ADD_AVERAGE_FOUR = 0x83, ///< Average four samples 102 ADC_ADD_AVERAGE_EIGHT = 0x84, ///< Average eight samples 103 ADC_ADD_AVERAGE_SIXTEEN = 0x85, ///< Add sixteen samples 104 } adc_add_t; 105 106 /** ADC clear after read definitions */ 107 typedef enum e_adc_clear 108 { 109 ADC_CLEAR_AFTER_READ_OFF = 0, ///< Clear after read off 110 ADC_CLEAR_AFTER_READ_ON = 1 ///< Clear after read on 111 } adc_clear_t; 112 113 /* VREF configuration options, not all options are available on all MCUs. If the MCU does not have VREFAMPCNT or 114 * ADHVREFCNT. */ 115 typedef enum e_adc_vref_control 116 { 117 /* Available selections on MCUs with VREFAMPCNT. 118 * Reference Table 32.12 "VREFADC output voltage control list" in the RA2A1 manual R01UH0888EJ0100.*/ 119 120 ADC_VREF_CONTROL_VREFH = 0, ///< VREFAMPCNT reset value. VREFADC Output voltage is Hi-Z 121 ADC_VREF_CONTROL_1_5V_OUTPUT = 25, ///< BGR turn ON. VREFADC Output voltage is 1.5 V 122 ADC_VREF_CONTROL_2_0V_OUTPUT = 29, ///< BGR turn ON. VREFADC Output voltage is 2.0 V 123 ADC_VREF_CONTROL_2_5V_OUTPUT = 31, ///< BGR turn ON. VREFADC Output voltage is 2.5 V 124 125 /* Available selections on MCUs with ADHVREFCNT. 126 * Reference Section 35.2.31 "A/D High-Potential/Low-Potential Reference Voltage Control Register (ADHVREFCNT)" 127 * in the RA4M1 manual R01UH0887EJ0100.*/ 128 129 ADC_VREF_CONTROL_AVCC0_AVSS0 = 0x0, ///< High potential is AVCC0, low potential is AVSS0 130 ADC_VREF_CONTROL_VREFH0_AVSS0 = 0x1, ///< High potential is VREFH0, low potential is AVSS0 131 132 /** High potential is internal reference voltage, low potential is AVSS0. When the high potential is set to the 133 * internal reference voltage, wait 5 us after R_ADC_Open() to start an ADC measurement. */ 134 ADC_VREF_CONTROL_IVREF_AVSS0 = 0x2, 135 ADC_VREF_CONTROL_AVCC0_VREFL0 = 0x10, ///< High potential is AVCC0, low potential is VREFL0 136 ADC_VREF_CONTROL_VREFH0_VREFL0 = 0x11, ///< High potential is VREFH0, low potential is VREFL0 137 138 /** High potential is internal reference voltage, low potential is VREFL0. When the high potential is set to the 139 * internal reference voltage, wait 5 us after R_ADC_Open() to start an ADC measurement. */ 140 ADC_VREF_CONTROL_IVREF_VREFL0 = 0x12, 141 } adc_vref_control_t; 142 143 /** ADC sample state registers */ 144 typedef enum e_adc_sample_state_reg 145 { 146 ADC_SAMPLE_STATE_CHANNEL_0 = 0, ///< Sample state register channel 0 147 ADC_SAMPLE_STATE_CHANNEL_1, ///< Sample state register channel 1 148 ADC_SAMPLE_STATE_CHANNEL_2, ///< Sample state register channel 2 149 ADC_SAMPLE_STATE_CHANNEL_3, ///< Sample state register channel 3 150 ADC_SAMPLE_STATE_CHANNEL_4, ///< Sample state register channel 4 151 ADC_SAMPLE_STATE_CHANNEL_5, ///< Sample state register channel 5 152 ADC_SAMPLE_STATE_CHANNEL_6, ///< Sample state register channel 6 153 ADC_SAMPLE_STATE_CHANNEL_7, ///< Sample state register channel 7 154 ADC_SAMPLE_STATE_CHANNEL_8, ///< Sample state register channel 8 155 ADC_SAMPLE_STATE_CHANNEL_9, ///< Sample state register channel 9 156 ADC_SAMPLE_STATE_CHANNEL_10, ///< Sample state register channel 10 157 ADC_SAMPLE_STATE_CHANNEL_11, ///< Sample state register channel 11 158 ADC_SAMPLE_STATE_CHANNEL_12, ///< Sample state register channel 12 159 ADC_SAMPLE_STATE_CHANNEL_13, ///< Sample state register channel 13 160 ADC_SAMPLE_STATE_CHANNEL_14, ///< Sample state register channel 14 161 ADC_SAMPLE_STATE_CHANNEL_15, ///< Sample state register channel 15 162 ADC_SAMPLE_STATE_CHANNEL_16_TO_31 = -3, ///< Sample state register channel 16 to 31 163 } adc_sample_state_reg_t; 164 165 /** ADC comparison settings */ 166 typedef enum e_adc_compare_cfg 167 { 168 ADC_COMPARE_CFG_EVENT_OUTPUT_OR = 0, 169 ADC_COMPARE_CFG_EVENT_OUTPUT_XOR = 1, 170 ADC_COMPARE_CFG_EVENT_OUTPUT_AND = 2, 171 ADC_COMPARE_CFG_A_ENABLE = R_ADC0_ADCMPCR_CMPAE_Msk | R_ADC0_ADCMPCR_CMPAIE_Msk, 172 ADC_COMPARE_CFG_B_ENABLE = R_ADC0_ADCMPCR_CMPBE_Msk | R_ADC0_ADCMPCR_CMPBIE_Msk, 173 ADC_COMPARE_CFG_WINDOW_ENABLE = R_ADC0_ADCMPCR_WCMPE_Msk, 174 } adc_compare_cfg_t; 175 176 /** ADC Window B channel */ 177 typedef enum e_adc_window_b_channel 178 { 179 ADC_WINDOW_B_CHANNEL_0 = 0, 180 ADC_WINDOW_B_CHANNEL_1, 181 ADC_WINDOW_B_CHANNEL_2, 182 ADC_WINDOW_B_CHANNEL_3, 183 ADC_WINDOW_B_CHANNEL_4, 184 ADC_WINDOW_B_CHANNEL_5, 185 ADC_WINDOW_B_CHANNEL_6, 186 ADC_WINDOW_B_CHANNEL_7, 187 ADC_WINDOW_B_CHANNEL_8, 188 ADC_WINDOW_B_CHANNEL_9, 189 ADC_WINDOW_B_CHANNEL_10, 190 ADC_WINDOW_B_CHANNEL_11, 191 ADC_WINDOW_B_CHANNEL_12, 192 ADC_WINDOW_B_CHANNEL_13, 193 ADC_WINDOW_B_CHANNEL_14, 194 ADC_WINDOW_B_CHANNEL_15, 195 ADC_WINDOW_B_CHANNEL_16, 196 ADC_WINDOW_B_CHANNEL_17, 197 ADC_WINDOW_B_CHANNEL_18, 198 ADC_WINDOW_B_CHANNEL_19, 199 ADC_WINDOW_B_CHANNEL_20, 200 ADC_WINDOW_B_CHANNEL_21, 201 ADC_WINDOW_B_CHANNEL_22, 202 ADC_WINDOW_B_CHANNEL_23, 203 ADC_WINDOW_B_CHANNEL_24, 204 ADC_WINDOW_B_CHANNEL_25, 205 ADC_WINDOW_B_CHANNEL_26, 206 ADC_WINDOW_B_CHANNEL_27, 207 ADC_WINDOW_B_CHANNEL_28, 208 ADC_WINDOW_B_CHANNEL_TEMPERATURE = 32, 209 ADC_WINDOW_B_CHANNEL_VOLT = 33, 210 } adc_window_b_channel_t; 211 212 /** ADC Window B comparison mode */ 213 typedef enum e_adc_window_b_mode 214 { 215 ADC_WINDOW_B_MODE_LESS_THAN_OR_OUTSIDE = 0, 216 ADC_WINDOW_B_MODE_GREATER_THAN_OR_INSIDE = R_ADC0_ADCMPBNSR_CMPLB_Msk, 217 } adc_window_b_mode_t; 218 219 /** ADC action for group A interrupts group B scan. 220 * This enumeration is used to specify the priority between Group A and B in group mode. */ 221 typedef enum e_adc_group_a 222 { 223 ADC_GROUP_A_PRIORITY_OFF = 0, ///< Group A ignored and does not interrupt ongoing group B scan 224 ADC_GROUP_A_GROUP_B_WAIT_FOR_TRIGGER = 1, ///< Group A interrupts Group B(single scan) which restarts at next Group B trigger 225 ADC_GROUP_A_GROUP_B_RESTART_SCAN = 3, ///< Group A interrupts Group B(single scan) which restarts immediately after Group A scan is complete 226 ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN = 0x8001, ///< Group A interrupts Group B(continuous scan) which continues scanning without a new Group B trigger 227 } adc_group_a_t; 228 229 /** ADC double-trigger mode definitions */ 230 typedef enum e_adc_double_trigger 231 { 232 ADC_DOUBLE_TRIGGER_DISABLED = 0, ///< Double-triggering disabled 233 ADC_DOUBLE_TRIGGER_ENABLED = 1, ///< Double-triggering enabled 234 ADC_DOUBLE_TRIGGER_ENABLED_EXTENDED = 2, ///< Double-triggering enabled on both ADC ELC events 235 } adc_double_trigger_t; 236 237 /** ADC Trigger synchronous start source 238 * Note: not all sources are available for all MCUs or channels. See User Manual for more information. */ 239 typedef enum 240 { 241 ADC_START_SOURCE_DISABLED = 0x3F, ///< ELC/GPT Start source disabled (For use with software start) 242 ADC_START_SOURCE_ASYNC_EXTERNAL = 0x00, ///< External Trigger Input 243 ADC_START_SOURCE_ELC_AD0 = 0x09, ///< ELC_AD0 (Converter 0 and Converter 1) 244 ADC_START_SOURCE_ELC_AD1 = 0x0A, ///< ELC_AD1 (Converter 0 and Converter 1) 245 ADC_START_SOURCE_ELC_AD01 = 0x0B, ///< ELC_AD0 and ELC_AD1 (Converter 0) also ELC_AD0 and ELC_AD1 (Converter 1) 246 ADC_START_SOURCE_GPT_A0_A4 = 0x11, ///< GTADTRA0 (Converter 0) and GTADTRA4 (Converter 1) 247 ADC_START_SOURCE_GPT_B0_B4 = 0x12, ///< GTADTRB0 (Converter 0) and GTADTRB4 (Converter 1) 248 ADC_START_SOURCE_GPT_A1_A5 = 0x13, ///< GTADTRA1 (Converter 0) and GTADTRB5 (Converter 1) 249 ADC_START_SOURCE_GPT_B1_B5 = 0x14, ///< GTADTRB1 (Converter 0) and GTADTRB5 (Converter 1) 250 ADC_START_SOURCE_GPT_A2_A6 = 0x15, ///< GTADTRA2 (Converter 0) and GTADTRA6 (Converter 1) 251 ADC_START_SOURCE_GPT_B2_B6 = 0x16, ///< GTADTRB2 (Converter 0) and GTADTRB6 (Converter 1) 252 ADC_START_SOURCE_GPT_A3_A7 = 0x17, ///< GTADTRA3 (Converter 0) and GTADTRA7 (Converter 1) 253 ADC_START_SOURCE_GPT_B3_B7 = 0x18, ///< GTADTRB3 (Converter 0) and GTADTRB7 (Converter 1) 254 ADC_START_SOURCE_GPT_AB0_AB4 = 0x19, ///< GTADTRA/B0 (Converter 0) and GTADTRA/B4 (Converter 1) 255 ADC_START_SOURCE_GPT_AB1_AB5 = 0x1A, ///< GTADTRA/B1 (Converter 0) and GTADTRA/B5 (Converter 1) 256 ADC_START_SOURCE_GPT_AB2_AB6 = 0x1B, ///< GTADTRA/B2 (Converter 0) and GTADTRA/B6 (Converter 1) 257 ADC_START_SOURCE_GPT_AB3_AB7 = 0x1C, ///< GTADTRA/B3 (Converter 0) and GTADTRA/B7 (Converter 1) 258 } adc_start_source_t; 259 260 /** ADC sample state configuration */ 261 typedef struct st_adc_sample_state 262 { 263 adc_sample_state_reg_t reg_id; ///< Sample state register ID 264 uint8_t num_states; ///< Number of sampling states for conversion. Ch16-20/21 use the same value. 265 } adc_sample_state_t; 266 267 /** ADC Window Compare configuration */ 268 typedef struct st_adc_window_cfg 269 { 270 uint32_t compare_mask; ///< Channel mask to compare with Window A 271 uint32_t compare_mode_mask; ///< Per-channel condition mask for Window A 272 adc_compare_cfg_t compare_cfg; ///< Window Compare configuration 273 uint16_t compare_ref_low; ///< Window A lower reference value 274 uint16_t compare_ref_high; ///< Window A upper reference value 275 uint16_t compare_b_ref_low; ///< Window B lower reference value 276 uint16_t compare_b_ref_high; ///< Window A upper reference value 277 adc_window_b_channel_t compare_b_channel; ///< Window B channel 278 adc_window_b_mode_t compare_b_mode; ///< Window B condition setting 279 } adc_window_cfg_t; 280 281 /** Extended configuration structure for ADC. */ 282 typedef struct st_adc_extended_cfg 283 { 284 adc_add_t add_average_count; ///< Add or average samples 285 adc_clear_t clearing; ///< Clear after read 286 adc_start_source_t trigger; ///< Trigger source for ADC 287 adc_start_source_t trigger_group_b; ///< Trigger source for ADC group B; valid only for group mode 288 adc_double_trigger_t double_trigger_mode; ///< Double-trigger mode setting 289 adc_vref_control_t adc_vref_control; ///< VREFADC output voltage control 290 uint8_t enable_adbuf; ///< Enable ADC Ring Buffer, Valid only to use along with DMAC transfer 291 IRQn_Type window_a_irq; ///< IRQ number for Window Compare A interrupts 292 IRQn_Type window_b_irq; ///< IRQ number for Window Compare B interrupts 293 uint8_t window_a_ipl; ///< Priority for Window Compare A interrupts 294 uint8_t window_b_ipl; ///< Priority for Window Compare B interrupts 295 } adc_extended_cfg_t; 296 297 /** ADC channel(s) configuration */ 298 typedef struct st_adc_channel_cfg 299 { 300 uint32_t scan_mask; ///< Channels/bits: bit 0 is ch0; bit 15 is ch15. 301 uint32_t scan_mask_group_b; ///< Valid for group modes. 302 uint32_t add_mask; ///< Valid if add enabled in Open(). 303 adc_window_cfg_t * p_window_cfg; ///< Pointer to Window Compare configuration 304 adc_group_a_t priority_group_a; ///< Valid for group modes. 305 uint8_t sample_hold_mask; ///< Channels/bits 0-2. 306 uint8_t sample_hold_states; ///< Number of states to be used for sample and hold. Affects channels 0-2. 307 } adc_channel_cfg_t; 308 309 /* Sample and hold Channel mask. Sample and hold is only available for channel 0,1,2*/ 310 #define ADC_SAMPLE_HOLD_CHANNELS (0x07U) 311 312 /*********************************************************************************************************************** 313 * Typedef definitions 314 **********************************************************************************************************************/ 315 316 /** ADC instance control block. DO NOT INITIALIZE. Initialized in @ref adc_api_t::open(). */ 317 typedef struct 318 { 319 R_ADC0_Type * p_reg; // Base register for this unit 320 adc_cfg_t const * p_cfg; 321 uint32_t opened; // Boolean to verify that the Unit has been initialized 322 uint32_t initialized; // Initialized status of ADC 323 uint32_t scan_mask; // Scan mask used for Normal scan 324 uint16_t scan_start_adcsr; 325 326 void (* p_callback)(adc_callback_args_t *); // Pointer to callback that is called when an adc_event_t occurs. 327 adc_callback_args_t * p_callback_memory; // Pointer to non-secure memory that can be used to pass arguments to a callback in non-secure memory. 328 329 /* Pointer to context to be passed into callback function */ 330 void const * p_context; 331 } adc_instance_ctrl_t; 332 333 /********************************************************************************************************************** 334 * Exported global variables 335 **********************************************************************************************************************/ 336 337 /** @cond INC_HEADER_DEFS_SEC */ 338 /** Interface Structure for user access */ 339 extern const adc_api_t g_adc_on_adc; 340 341 /** @endcond */ 342 343 /*********************************************************************************************************************** 344 * Public APIs 345 **********************************************************************************************************************/ 346 fsp_err_t R_ADC_Open(adc_ctrl_t * p_ctrl, adc_cfg_t const * const p_cfg); 347 fsp_err_t R_ADC_ScanCfg(adc_ctrl_t * p_ctrl, void const * const p_channel_cfg); 348 fsp_err_t R_ADC_InfoGet(adc_ctrl_t * p_ctrl, adc_info_t * p_adc_info); 349 fsp_err_t R_ADC_ScanStart(adc_ctrl_t * p_ctrl); 350 fsp_err_t R_ADC_ScanGroupStart(adc_ctrl_t * p_ctrl, adc_group_mask_t group_id); 351 fsp_err_t R_ADC_ScanStop(adc_ctrl_t * p_ctrl); 352 fsp_err_t R_ADC_StatusGet(adc_ctrl_t * p_ctrl, adc_status_t * p_status); 353 fsp_err_t R_ADC_Read(adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint16_t * const p_data); 354 fsp_err_t R_ADC_Read32(adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint32_t * const p_data); 355 fsp_err_t R_ADC_SampleStateCountSet(adc_ctrl_t * p_ctrl, adc_sample_state_t * p_sample); 356 fsp_err_t R_ADC_Close(adc_ctrl_t * p_ctrl); 357 fsp_err_t R_ADC_OffsetSet(adc_ctrl_t * const p_ctrl, adc_channel_t const reg_id, int32_t offset); 358 fsp_err_t R_ADC_Calibrate(adc_ctrl_t * const p_ctrl, void const * p_extend); 359 fsp_err_t R_ADC_CallbackSet(adc_ctrl_t * const p_api_ctrl, 360 void ( * p_callback)(adc_callback_args_t *), 361 void const * const p_context, 362 adc_callback_args_t * const p_callback_memory); 363 364 /*******************************************************************************************************************//** 365 * @} (end defgroup ADC) 366 **********************************************************************************************************************/ 367 368 /* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ 369 FSP_FOOTER 370 371 #endif 372