blob: f7024024461fb802f45072f784029e9205cd7f8b [file] [log] [blame]
/**********************************************************************************************
* 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_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 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. Initializes group conversion
* class, arbiter configuration, boundary configuration by setting
* GxICLASS,GxARBCFG,GxBOUND, registers.
*
* Returned Value:
* Zero (OK) is returned on success; A negative 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 on.
* Configure the register bit field GxARBCFG.ANONC
*
* Returned Value:
* Zero (OK) is returned on success; A negative 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_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 negative 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 negative 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(g_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_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_vadc_group_array[i]->ARBPR = reg;
}
/* Program BackgroundRequestSourceControl 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(g_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 negative 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 negative 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)(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 negative 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 negative 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);
*result_ptr = (uint16_t)(group_ptr->RES[resreg]);
return OK;
}