adriendesp commented on code in PR #12425: URL: https://github.com/apache/nuttx/pull/12425#discussion_r1620274266
########## arch/arm/src/xmc4/xmc4_vadc.c: ########## @@ -0,0 +1,576 @@ +/**************************************************************************** + * arch/arm/src/xmc4/xmc4_vadc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + * May include some logic from sample code provided by Infineon: + * + * Copyright (C) 2011-2015 Infineon Technologies AG. All rights reserved. + * + * Infineon Technologies AG (Infineon) is supplying this software for use + * with Infineon's microcontrollers. This file can be freely distributed + * within development tools that are supporting such microcontrollers. + * + * THIS SOFTWARE IS PROVIDED AS IS. NO WARRANTIES, WHETHER EXPRESS, + * IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS + * SOFTWARE. INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR + * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <errno.h> +#include <assert.h> + +#include <arch/xmc4/chip.h> + +#include "arm_internal.h" +#include "hardware/xmc4_scu.h" +#include "xmc4_vadc.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static vadc_group_t *const g_xmc_vadc_group_array[XMC_VADC_MAXIMUM_NUM_GROUPS] = { + (vadc_group_t *)VADC_G0, + (vadc_group_t *)VADC_G1, + (vadc_group_t *)VADC_G2, + (vadc_group_t *)VADC_G3 + }; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xmc4_vadc_global_enable + * + * Description: + * Ungate the clock to the VADC module (if applicable) and bring the VADC + * module out of reset state. + * Called in xmc4_vadc_global_initialize. + * + ****************************************************************************/ + +void xmc4_vadc_global_enable(void) +{ + #ifdef XMC4_SCU_GATING + /* Check if VADC is gated */ + + if ((getreg32(XMC4_SCU_CGATSTAT0) & SCU_CGAT0_VADC) == 1) + { + /* Disable VADC gating */ + + putreg32(SCU_CGAT0_VADC, XMC4_SCU_CGATCLR0); + } + + /* Set bit in PRCLR0 to de-assert VADC peripheral reset */ + + putreg32(SCU_PR0_VADCRS, XMC4_SCU_PRCLR0); + #else + + /* Set bit in PRCLR0 to de-assert VADC peripheral reset */ + + putreg32(SCU_PR0_VADCRS, XMC4_SCU_PRCLR0); + #endif +} + +/**************************************************************************** + * Name: xmc4_vadc_global_disable + * + * Description: + * Gate the clock to the VADC module (if applicable) and put the VADC + * module into the reset state + * + ****************************************************************************/ + +void xmc4_vadc_global_disable(void) +{ + /* Set bit in PRSET0 to assert VADC peripheral reset */ + + putreg32(SCU_PR0_VADCRS, XMC4_SCU_PRSET0); + + #ifdef XMC4_SCU_GATING + /* Check if VADC is ungated */ + + if ((getreg32(XMC4_SCU_CGATSTAT0) & SCU_CGAT0_VADC) == 0) + { + /* Enable VADC gating */ + + putreg32(SCU_CGAT0_VADC, XMC4_SCU_CGATSET0); + } + #endif +} + +/**************************************************************************** + * Name: xmc4_vadc_global_initialize + * + * Description: + * Initializes the VADC global module with the given configuration structure. + * It initializes global input classes, boundaries , result resources. + * Configures GLOBICLASS,GLOBBOUND,GLOBRCR registers. + * It also configures the global analog and digital clock dividers + * by setting GLOBCFG register. + * + ****************************************************************************/ + +void xmc4_vadc_global_initialize(const vadc_global_config_t *config) +{ + /* Enable the VADC module */ + + xmc4_vadc_global_enable(); + + VADC->CLC = (uint32_t)(config->clc); + + /* Clock configuration, use DIVWC (write control) to write register */ + + VADC->GLOBCFG = (uint32_t)(config->globcfg | (uint32_t)(VADC_GLOBCFG_DIVWC_MASK)); + + /* Global input class 0 configuration */ + + VADC->GLOBICLASS[0] = (uint32_t)(config->class0.iclass); + + /* Global input class 1 configuration */ + + VADC->GLOBICLASS[1] = (uint32_t)(config->class1.iclass); + + /* Global result generation configuration */ + + VADC->GLOBRCR = (uint32_t)(config->globrcr); + + /* Set global boundaries values */ + + VADC->GLOBBOUND = (uint32_t)(config->globbound); +} + +/**************************************************************************** + * Name: xmc4_vadc_group_initialize + * + * Description: + * Initializes the VADC group module with the associated + * configuration structure pointed by config. It initializes group conversion + * class, arbiter configuration, boundary configuration by setting + * GxICLASS,GxARBCFG,GxBOUND, registers. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_initialize(vadc_group_t *const group_ptr, const vadc_group_config_t *config) +{ + if (!xmc_vadc_check_group_ptr(group_ptr)) + { + return -EINVAL; + } + + /* Configures the group-specific input classes, + * each channel is assigned to a class in GxCHCTRy + */ + + group_ptr->ICLASS[0] = config->class0.iclass; + group_ptr->ICLASS[1] = config->class1.iclass; + + /* Configures the group arbitration behavior */ + + group_ptr->ARBCFG = config->g_arbcfg; + + /* Configures the group-specific boundaries */ + + group_ptr->BOUND = config->g_bound; + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_group_set_powermode + * + * Description: + * Configures the power mode of a VADC group. For a VADC group to + * actually convert an analog signal, its analog converter must be turned on. + * Configure the register bit field GxARBCFG.ANONC + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_set_powermode(vadc_group_t *const group_ptr, const vadc_group_powermode_t power_mode) +{ + if (!xmc_vadc_check_group_ptr(group_ptr) || (power_mode > XMC_VADC_GROUP_POWERMODE_NORMAL)) + { + return -EINVAL; + } + + uint32_t arbcfg = group_ptr->ARBCFG; + + arbcfg &= ~((uint32_t)VADC_GxARBCFG_ANONC_MASK); + arbcfg |= (uint32_t)power_mode; + + group_ptr->ARBCFG = arbcfg; + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_global_start_calibration + * + * Description: + * Start the calibration process and loops until all active groups + * finish calibration. Call xmc4_vadc_global_enable and + * xmc4_vadc_global_initialize before calibration. + * Configures the register bit field GLOBCFG.SUCAL. + * + ****************************************************************************/ + +void xmc4_vadc_global_start_calibration(void) +{ + vadc_group_t * group_ptr; + + /* Start Calibration */ + + VADC->GLOBCFG |= (uint32_t) VADC_GLOBCFG_SUCAL_MASK; + + /* Loop until all groups to finish calibration */ + + for (int i = 0; i < XMC_VADC_MAXIMUM_NUM_GROUPS; i++) + { + group_ptr = g_xmc_vadc_group_array[i]; + + /* Check if group is active */ + + if ((group_ptr->ARBCFG) & (uint32_t)(VADC_GxARBCFG_ANONS_MASK)) + { + /* Loop until it finish calibration */ + + while ((group_ptr->ARBCFG) & (uint32_t)VADC_GxARBCFG_CAL_MASK) + { + /* NOP */ + } + } + } +} + +/**************************************************************************** + * Name: xmc4_vadc_group_background_enable_arbitrationslot + * + * Description: + * Enables arbitration slot of the Background request source to + * participate in the arbitration round. Even if a load event occurs the + * Background channel can only be converted when the arbiter comes to the + * Background slot. Thus this must be enabled if any conversion need to take + * place. + * Configure the register bit field GxARBPR.ASEN2. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_background_enable_arbitrationslot(vadc_group_t *const group_ptr) +{ + if (!xmc_vadc_check_group_ptr(group_ptr)) + { + return -EINVAL; + } + + group_ptr->ARBPR |= (uint32_t)VADC_GxARBPR_ASEN2_MASK; + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_group_background_disable_arbitrationslot + * + * Description: + * Disables arbitration slot of the Background request source to + * participate in the arbitration round. Even if a load event occurs the + * Background channel can only be converted when the arbiter comes to the + * Background slot. Thus this must be enabled if any conversion need to take + * place. + * Configure the register bit field GxARBPR.ASEN2. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_background_disable_arbitrationslot(vadc_group_t *const group_ptr) +{ + if (!xmc_vadc_check_group_ptr(group_ptr)) + { + return -EINVAL; + } + + group_ptr->ARBPR &= ~((uint32_t)VADC_GxARBPR_ASEN2_MASK); + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_global_background_initialize + * + * Description: + * Initializes the Background scan functional block. The BACKGROUND + * SCAN request source functional block converts channels of all VADC groups + * that have not been assigned as a priority channel (priority channels can be + * converted only by queue and scan). Related arbitration slot must be + * disabled to configure background request, then re-enabled. + * + ****************************************************************************/ + +void xmc4_vadc_global_background_initialize(const vadc_background_config_t *config) +{ + uint32_t reg; + uint32_t conv_start_mask; + + /* Disable background request source to change its parameters */ + + for (int i = 0; i < XMC_VADC_MAXIMUM_NUM_GROUPS; i++) + { + xmc4_vadc_group_background_disable_arbitrationslot((vadc_group_t *)g_xmc_vadc_group_array[i]); + } + + /* Set start mode */ + + conv_start_mask = (uint32_t) 0; + if (XMC_VADC_STARTMODE_WFS != (vadc_startmode_t)config->conv_start_mode) + { + conv_start_mask = (uint32_t)VADC_GxARBPR_CSM2_MASK; + } + + /* Configures GxARBPR register for each group */ + + for (int i = 0; i < XMC_VADC_MAXIMUM_NUM_GROUPS; i++) + { + reg = g_xmc_vadc_group_array[i]->ARBPR; + + /* Program the priority of the request source : Background Scan is source 2 */ + + reg &= ~(uint32_t)(VADC_GxARBPR_PRIO2_MASK); + reg |= (uint32_t)((uint32_t)config->req_src_priority << VADC_GxARBPR_PRIO2_SHIFT); + + /* Program the start mode */ + + reg |= conv_start_mask; + + g_xmc_vadc_group_array[i]->ARBPR = reg; + } + + /* program Background Request Source Control register, use XT and GT write control bitfields */ + + VADC->BRSCTRL = (uint32_t)(config->asctrl | (uint32_t)VADC_BRSCTRL_XTWC_MASK | (uint32_t)VADC_BRSCTRL_GTWC_MASK); + + /* program Background Request Source Mode register */ + + VADC->BRSMR = (uint32_t)((config->asmr) | (uint32_t)((uint32_t)XMC_VADC_GATEMODE_IGNORE << VADC_BRSMR_ENGT_SHIFT)); + if (XMC_VADC_STARTMODE_CNR == (vadc_startmode_t)(config->conv_start_mode)) + { + VADC->BRSMR |= (uint32_t)VADC_BRSMR_RPTDIS_MASK; + } + + /* Re enable request source */ + + for (int i = 0; i < XMC_VADC_MAXIMUM_NUM_GROUPS; i++) + { + xmc4_vadc_group_background_enable_arbitrationslot((vadc_group_t *)g_xmc_vadc_group_array[i]); + } +} + +/**************************************************************************** + * Name: xmc4_vadc_group_channel_initialize + * + * Description: + * Initializes the ADC channel for conversion. Must be called after + * request source initialization for each channel to enable their conversion. + * Configures registers GxCHCTRy and boundary flag GxBFL, GxBFLC and GxCHASS. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_channel_initialize(vadc_group_t *const group_ptr, const uint32_t ch_num, + const vadc_channel_config_t *config) +{ + if (!xmc_vadc_check_group_ptr(group_ptr) || (ch_num > XMC_VADC_NUM_CHANNELS_PER_GROUP)) + { + return -EINVAL; + } + + uint32_t prio = (uint32_t)config->channel_priority; + + /* Set channel priority, channel_priority must be 0 for background channel */ + + uint32_t ch_assign = group_ptr->CHASS; + ch_assign &= ~((uint32_t)((uint32_t)1 << ch_num)); + ch_assign |= (uint32_t)(prio << ch_num); + group_ptr->CHASS = ch_assign; + + /* Alias channel, can replace CH0 and CH1 with another channel number. */ + + if (config->alias_channel >= (int32_t)0) + { + uint32_t mask = (uint32_t)0; + if ((uint32_t)1 == ch_num) + { + mask = VADC_GxALIAS_ALIAS1_SHIFT; + group_ptr->ALIAS &= ~(uint32_t)(VADC_GxALIAS_ALIAS1_MASK); + } + else if ((uint32_t)0 == ch_num) + { + mask = VADC_GxALIAS_ALIAS0_SHIFT; + group_ptr->ALIAS &= ~(uint32_t)(VADC_GxALIAS_ALIAS0_MASK); + } + + group_ptr->ALIAS |= (uint32_t)(config->alias_channel << mask); + } + + /* Set channel boundaries flag */ + + group_ptr->BFL |= config->bfl; + #if (XMC_VADC_BOUNDARY_FLAG_SELECT == 1U) + group_ptr->BFLC |= config->bflc; + #endif + + /* Program the CHCTR register */ + + group_ptr->CHCTR[ch_num] = config->chctr; + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_global_background_add_channel_to_sequence + * + * Description: + * Adds a channel to the background scan sequence. The pending + * register are updated only after a new load event occured. + * Configures the register bit fields of BRSSEL. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_global_background_add_channel_to_sequence(const uint32_t grp_num, const uint32_t ch_num) +{ + if ((grp_num > XMC_VADC_MAXIMUM_NUM_GROUPS) || (ch_num > XMC_VADC_NUM_CHANNELS_PER_GROUP)) + { + return -EINVAL; + } + + VADC->BRSSEL[grp_num] |= (uint32_t)((uint32_t)1 << ch_num); + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_global_background_enable_autoscan + * + * Description: + * Enables continuous conversion mode (autoscan). Once all channels + * belonging to a Background request source have been converted, a new load + * event occurs. + * Configures the register bit field BRSMR.SCAN. + * + ****************************************************************************/ + +void xmc4_vadc_global_background_enable_autoscan(void) +{ + VADC->BRSMR |= (uint32_t)VADC_BRSMR_SCAN_MASK; +} + +/**************************************************************************** + * Name: xmc4_vadc_global_background_start_conversion + * + * Description: + * Generates conversion request (Software initiated conversion). + * The background scan must been init. + * Configures the register bit field BRSMR.LDEV. + * + ****************************************************************************/ + +void xmc4_vadc_global_background_start_conversion(void) +{ + VADC->BRSMR |= (uint32_t)VADC_BRSMR_LDEV_MASK; +} + +/**************************************************************************** + * Name: xmc4_vadc_group_get_result + * + * Description: + * Returns the result of the conversion in the given group result register. + * Get the register bit field GxRES.RESULT. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_get_result(vadc_group_t *const group_ptr, const uint32_t res_reg, uint16_t *result_ptr) +{ + if (!xmc_vadc_check_group_ptr(group_ptr) || (res_reg > XMC_VADC_NUM_RESULT_REGISTERS)) + { + return -EINVAL; + } + + *result_ptr = ((uint16_t)group_ptr->RES[res_reg]); + + return OK; +} + +/**************************************************************************** + * Name: xmc4_vadc_group_channel_get_result + * + * Description: + * Returns the result of the conversion of the given group channel. + * Get the register bit field GxRES.RESULT. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_vadc_group_get_channel_result(vadc_group_t *const group_ptr, const uint32_t ch_num, uint16_t *result_ptr) +{ + if (!xmc_vadc_check_group_ptr(group_ptr) || (ch_num > XMC_VADC_NUM_CHANNELS_PER_GROUP)) + { + return -EINVAL; + } + + uint8_t resreg = (uint8_t)((group_ptr->CHCTR[ch_num] & (uint32_t)VADC_GxCHCTR_RESREG_MASK) >> VADC_GxCHCTR_RESREG_SHIFT); Review Comment: I first get acces to the result register number store in CHCTR[19:16] and I shift it back to get it rigth aligned. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
