feat add adc/dac for xishutong-arm32 board

This commit is contained in:
Liu_Weichao 2023-12-29 10:25:12 +08:00
parent a590eacebb
commit 616aa90d25
8 changed files with 828 additions and 0 deletions

View File

@ -1,3 +1,19 @@
menuconfig BSP_USING_ADC
bool "Using ADC device"
default n
select RESOURCES_ADC
if BSP_USING_ADC
source "$BSP_DIR/third_party_driver/adc/Kconfig"
endif
menuconfig BSP_USING_DAC
bool "Using DAC device"
default n
select RESOURCES_DAC
if BSP_USING_DAC
source "$BSP_DIR/third_party_driver/dac/Kconfig"
endif
menuconfig BSP_USING_UART
bool "Using UART device"
default y

View File

@ -4,6 +4,14 @@ ifeq ($(CONFIG_BSP_USING_UART),y)
SRC_DIR += usart
endif
ifeq ($(CONFIG_BSP_USING_ADC),y)
SRC_DIR += adc
endif
ifeq ($(CONFIG_BSP_USING_DAC),y)
SRC_DIR += dac
endif
ifeq ($(CONFIG_BSP_USING_GPIO),y)
SRC_DIR += gpio
endif

View File

@ -0,0 +1,13 @@
if BSP_USING_ADC
config ADC1_BUS_NAME
string "adc 1 bus name"
default "adc1"
config ADC1_DRIVER_NAME
string "adc 1 driver name"
default "adc1_drv"
config ADC1_DEVICE_NAME
string "adc 1 bus device name"
default "adc1_dev"
endif

View File

@ -0,0 +1,3 @@
SRC_FILES := connect_adc.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,370 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_adc.c
* @brief support to register ADC pointer and function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-12-29
*/
#include <connect_adc.h>
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* The clock source of ADC. */
#define ADC_CLK_SYS_CLK (1U)
#define ADC_CLK_PLLH (2U)
#define ADC_CLK_PLLA (3U)
/*
* Selects a clock source according to the application requirements.
* PCLK4 is the clock for digital interface.
* PCLK2 is the clock for analog circuit.
* PCLK4 and PCLK2 are synchronous when the clock source is PLL.
* PCLK4 : PCLK2 = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4.
* PCLK2 is in range [1MHz, 60MHz].
* If the system clock is selected as the ADC clock, macro 'ADC_ADC_CLK' can only be defined as 'CLK_PERIPHCLK_PCLK'.
* If PLLH is selected as the ADC clock, macro 'ADC_ADC_CLK' can be defined as 'CLK_PERIPHCLK_PLLx'(x=Q, R).
* If PLLA is selected as the ADC clock, macro 'ADC_ADC_CLK' can be defined as 'CLK_PERIPHCLK_PLLXx'(x=P, Q, R).
*/
#define ADC_CLK_SEL (ADC_CLK_SYS_CLK)
#if (ADC_CLK_SEL == ADC_CLK_SYS_CLK)
#define ADC_CLK (CLK_PERIPHCLK_PCLK)
#elif (ADC_CLK_SEL == ADC_CLK_PLLH)
#define ADC_CLK (CLK_PERIPHCLK_PLLQ)
#elif (ADC_CLK_SEL == ADC_CLK_PLLA)
#define ADC_CLK (CLK_PERIPHCLK_PLLXP)
#else
#error "The clock source your selected does not exist!!!"
#endif
/* ADC unit instance for this example. */
#define ADC_UNIT (CM_ADC1)
#define ADC_PERIPH_CLK (FCG3_PERIPH_ADC1)
/* Selects ADC channels that needed. */
#define ADC_CH_POTENTIOMETER (ADC_CH3)
#define ADC_CH (ADC_CH_POTENTIOMETER)
#define ADC_CH_PORT (GPIO_PORT_A)
#define ADC_CH_PIN (GPIO_PIN_03)
/* ADC sequence to be used. */
#define ADC_SEQ (ADC_SEQ_A)
/* Flag of conversion end. */
#define ADC_EOC_FLAG (ADC_FLAG_EOCA)
/* ADC reference voltage. The voltage of pin VREFH. */
#define ADC_VREF (3.3F)
/* ADC accuracy(according to the resolution of ADC). */
#define ADC_ACCURACY (1UL << 12U)
/* Calculate the voltage(mV). */
#define ADC_CAL_VOL(adcVal) (uint16_t)((((float32_t)(adcVal) * ADC_VREF) / ((float32_t)ADC_ACCURACY)) * 1000.F)
/* Timeout value. */
#define ADC_TIMEOUT_VAL (1000U)
/**
* @brief Set specified ADC pin to analog mode.
* @param None
* @retval None
*/
static void AdcSetPinAnalogMode(void)
{
stc_gpio_init_t stcGpioInit;
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG;
(void)GPIO_Init(ADC_CH_PORT, ADC_CH_PIN, &stcGpioInit);
}
/**
* @brief Configures ADC clock.
* @param None
* @retval None
*/
static void AdcClockConfig(void)
{
#if (ADC_CLK_SEL == ADC_CLK_SYS_CLK)
/*
* 1. Configures the clock divider of PCLK2 and PCLK4 here or in the function of configuring the system clock.
* In this example, the system clock is MRC@8MHz.
* PCLK4 is the digital interface clock, and PCLK2 is the analog circuit clock.
* Make sure that PCLK2 and PCLK4 meet the following conditions:
* PCLK4 : PCLK2 = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4.
* PCLK2 is in range [1MHz, 60MHz].
*/
CLK_SetClockDiv((CLK_BUS_PCLK2 | CLK_BUS_PCLK4), (CLK_PCLK2_DIV8 | CLK_PCLK4_DIV2));
#elif (ADC_CLK_SEL == ADC_CLK_PLLH)
/*
* 1. Configures PLLH and the divider of PLLHx(x=Q, R).
* PLLHx(x=Q, R) is used as both the digital interface clock and the analog circuit clock.
* PLLHx(x=Q, R) must be in range [1MHz, 60MHz] for ADC use.
* The input source of PLLH is XTAL(8MHz).
*/
stc_clock_pll_init_t stcPLLHInit;
stc_clock_xtal_init_t stcXtalInit;
/* Configures XTAL. PLLH input source is XTAL. */
(void)CLK_XtalStructInit(&stcXtalInit);
stcXtalInit.u8State = CLK_XTAL_ON;
stcXtalInit.u8Drv = CLK_XTAL_DRV_ULOW;
stcXtalInit.u8Mode = CLK_XTAL_MD_OSC;
stcXtalInit.u8StableTime = CLK_XTAL_STB_499US;
(void)CLK_XtalInit(&stcXtalInit);
(void)CLK_PLLStructInit(&stcPLLHInit);
/*
* PLLHx(x=Q, R) = ((PLL_source / PLLM) * PLLN) / PLLx
* PLLHQ = (8 / 1) * 80 /16 = 40MHz
* PLLHR = (8 / 1) * 80 /16 = 40MHz
*/
stcPLLHInit.u8PLLState = CLK_PLL_ON;
stcPLLHInit.PLLCFGR = 0UL;
stcPLLHInit.PLLCFGR_f.PLLM = (1UL - 1UL);
stcPLLHInit.PLLCFGR_f.PLLN = (80UL - 1UL);
stcPLLHInit.PLLCFGR_f.PLLP = (4UL - 1UL);
stcPLLHInit.PLLCFGR_f.PLLQ = (16UL - 1UL);
stcPLLHInit.PLLCFGR_f.PLLR = (16UL - 1UL);
/* stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL; */
(void)CLK_PLLInit(&stcPLLHInit);
#elif (ADC_CLK_SEL == ADC_CLK_PLLA)
/*
* 1. Configures PLLA and the divider of PLLAx(x=P, Q, R).
* PLLAx(x=P, Q, R) is used as both the digital interface clock and the analog circuit clock.
* PLLAx(x=P, Q, R) must be in range [1MHz, 60MHz] for ADC use.
* The input source of PLLA is HRC(16MHz).
*/
stc_clock_pllx_init_t stcPLLAInit;
/* Enable HRC(16MHz) for PLLA. */
CLK_HrcCmd(ENABLE);
/* Specify the input source of PLLA. NOTE!!! PLLA and PLLH use the same input source. */
CLK_SetPLLSrc(CLK_PLL_SRC_HRC);
/* PLLA configuration */
(void)CLK_PLLxStructInit(&stcPLLAInit);
/*
* PLLAx(x=P, Q, R) = ((PLL_source / PLLM) * PLLN) / PLLx
* PLLAP = (16 / 2) * 40 / 8 = 40MHz
* PLLAQ = (16 / 2) * 40 / 10 = 32MHz
* PLLAR = (16 / 2) * 40 / 16 = 20MHz
*/
stcPLLAInit.u8PLLState = CLK_PLLX_ON;
stcPLLAInit.PLLCFGR = 0UL;
stcPLLAInit.PLLCFGR_f.PLLM = (2UL - 1UL);
stcPLLAInit.PLLCFGR_f.PLLN = (40UL - 1UL);
stcPLLAInit.PLLCFGR_f.PLLR = (8UL - 1UL);
stcPLLAInit.PLLCFGR_f.PLLQ = (10UL - 1UL);
stcPLLAInit.PLLCFGR_f.PLLP = (16UL - 1UL);
(void)CLK_PLLxInit(&stcPLLAInit);
#endif
/* 2. Specifies the clock source of ADC. */
CLK_SetPeriClockSrc(ADC_CLK);
}
/**
* @brief Initializes ADC.
* @param None
* @retval None
*/
static void AdcInitConfig(void)
{
stc_adc_init_t stcAdcInit;
/* 1. Enable ADC peripheral clock. */
FCG_Fcg3PeriphClockCmd(ADC_PERIPH_CLK, ENABLE);
/* 2. Modify the default value depends on the application. Not needed here. */
(void)ADC_StructInit(&stcAdcInit);
/* 3. Initializes ADC. */
(void)ADC_Init(ADC_UNIT, &stcAdcInit);
/* 4. ADC channel configuration. */
/* 4.1 Set the ADC pin to analog input mode. */
AdcSetPinAnalogMode();
/* 4.2 Enable ADC channels. Call ADC_ChCmd() again to enable more channels if needed. */
ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CH, ENABLE);
/* 5. Conversion data average calculation function, if needed.
Call ADC_ConvDataAverageChCmd() again to enable more average channels if needed. */
ADC_ConvDataAverageConfig(ADC_UNIT, ADC_AVG_CNT8);
ADC_ConvDataAverageChCmd(ADC_UNIT, ADC_CH, ENABLE);
}
/**
* @brief Use ADC in polling mode.
* @param None
* @retval uint16_t u16AdcValue
*/
static uint16_t AdcPolling(void)
{
uint16_t u16AdcValue = 0;
int32_t iRet = LL_ERR;
__IO uint32_t u32TimeCount = 0UL;
/* Can ONLY start sequence A conversion.
Sequence B needs hardware trigger to start conversion. */
ADC_Start(ADC_UNIT);
do {
if (ADC_GetStatus(ADC_UNIT, ADC_EOC_FLAG) == SET) {
ADC_ClearStatus(ADC_UNIT, ADC_EOC_FLAG);
iRet = LL_OK;
break;
}
} while (u32TimeCount++ < ADC_TIMEOUT_VAL);
if (iRet == LL_OK) {
/* Get any ADC value of sequence A channel that needed. */
u16AdcValue = ADC_GetValue(ADC_UNIT, ADC_CH);
KPrintf("The ADC value of potentiometer is %u, voltage is %u mV\r\n",
u16AdcValue, ADC_CAL_VOL(u16AdcValue));
} else {
ADC_Stop(ADC_UNIT);
KPrintf("ADC exception.\r\n");
}
return ADC_CAL_VOL(u16AdcValue);
}
static uint32 AdcOpen(void *dev)
{
x_err_t ret = EOK;
struct AdcHardwareDevice* adc_dev = (struct AdcHardwareDevice*)dev;
AdcClockConfig();
AdcInitConfig();
return ret;
}
static uint32 AdcClose(void *dev)
{
struct AdcHardwareDevice* adc_dev = (struct AdcHardwareDevice*)dev;
CM_ADC_TypeDef *ADCx= (CM_ADC_TypeDef *)adc_dev->private_data;
ADC_Stop(ADC_UNIT);
ADC_DeInit(ADCx);
return EOK;
}
static uint32 AdcRead(void *dev, struct BusBlockReadParam *read_param)
{
*(uint16 *)read_param->buffer = AdcPolling();
read_param->read_length = 2;
return EOK;
}
static uint32 AdcDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
x_err_t ret = EOK;
uint8 adc_channel;
struct AdcDriver *adc_drv = (struct AdcDriver *)drv;
struct AdcHardwareDevice *adc_dev = (struct AdcHardwareDevice *)adc_drv->driver.owner_bus->owner_haldev;
struct HwAdc *adc_cfg = (struct HwAdc *)adc_dev->haldev.private_data;
switch (configure_info->configure_cmd)
{
case OPE_CFG:
adc_cfg->adc_channel = *(uint8 *)configure_info->private_data;
if (adc_cfg->adc_channel != 1) {
KPrintf("AdcDrvConfigure set adc channel(1) %u error!", adc_cfg->adc_channel);
adc_cfg->adc_channel = 1;
ret = ERROR;
}
break;
default:
break;
}
return ret;
}
static const struct AdcDevDone dev_done =
{
AdcOpen,
AdcClose,
NONE,
AdcRead,
};
int HwAdcInit(void)
{
x_err_t ret = EOK;
#ifdef BSP_USING_ADC
static struct AdcBus adc1_bus;
static struct AdcDriver adc1_drv;
static struct AdcHardwareDevice adc1_dev;
static struct HwAdc adc1_cfg;
adc1_drv.configure = AdcDrvConfigure;
ret = AdcBusInit(&adc1_bus, ADC1_BUS_NAME);
if (ret != EOK) {
KPrintf("ADC1 bus init error %d\n", ret);
return ERROR;
}
ret = AdcDriverInit(&adc1_drv, ADC1_DRIVER_NAME);
if (ret != EOK) {
KPrintf("ADC1 driver init error %d\n", ret);
return ERROR;
}
ret = AdcDriverAttachToBus(ADC1_DRIVER_NAME, ADC1_BUS_NAME);
if (ret != EOK) {
KPrintf("ADC1 driver attach error %d\n", ret);
return ERROR;
}
adc1_dev.adc_dev_done = &dev_done;
adc1_cfg.ADCx = CM_ADC1;
adc1_cfg.adc_channel = 1;
ret = AdcDeviceRegister(&adc1_dev, (void *)&adc1_cfg, ADC1_DEVICE_NAME);
if (ret != EOK) {
KPrintf("ADC1 device register error %d\n", ret);
return ERROR;
}
ret = AdcDeviceAttachToBus(ADC1_DEVICE_NAME, ADC1_BUS_NAME);
if (ret != EOK) {
KPrintf("ADC1 device register error %d\n", ret);
return ERROR;
}
#endif
return ret;
}

View File

@ -0,0 +1,17 @@
if BSP_USING_DAC
config DAC_BUS_NAME
string "dac bus name"
default "dac"
config DAC_DRIVER_NAME
string "dac driver name"
default "dac_drv"
config DAC_DEVICE_NAME
string "dac bus device name"
default "dac_dev"
config DAC_GPIO_NUM
int "dac gpio pin num(only support 4 or 5)"
default "4"
endif

View File

@ -0,0 +1,3 @@
SRC_FILES := connect_dac.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,398 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_dac.c
* @brief support to register DAC pointer and function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-12-29
*/
#include <connect_dac.h>
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
#define DAC_UNIT1_PORT (GPIO_PORT_A)
#define DAC_UNIT1_CHN1_PIN (GPIO_PIN_04)
#define VREFH (3.3F)
#define DAC_CHN1 (0U)
#define DAC_CHN2 (1U)
#define DAC_DATA_ALIGN_12b_R (0U)
#define DAC_DATA_ALIGN_12b_L (1U)
#define SUPPORT_AMP
#define SUPPORT_ADP
#define SINGLE_WAVE_DAC_CHN (DAC_CHN1)
#define DAC_DATA_ALIGN (DAC_DATA_ALIGN_12b_L)
#define SINE_DOT_NUMBER (4096U)
#define SINE_NEGATIVE_TO_POSITVE (1.0F)
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
typedef enum {
DAC_Unit1,
DAC_Unit2,
DAC_Unit_Max,
}en_dac_unit_t;
typedef enum {
E_Dac_Single,
E_Dac_Dual,
}en_dac_cvt_t;
typedef struct {
CM_DAC_TypeDef *pUnit;
en_dac_cvt_t enCvtType;
uint16_t u16Ch;
} stc_dac_handle_t;
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
static stc_dac_handle_t m_stcDACHandle[DAC_Unit_Max] = {0};
static uint32_t gu32SinTable[SINE_DOT_NUMBER];
static stc_dac_handle_t *pSingleDac;
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @brief MAU Initialization
* @param None
* @retval None
*/
static void MauInit(void)
{
/* Enable MAU peripheral clock. */
FCG_Fcg0PeriphClockCmd(PWC_FCG0_MAU, ENABLE);
}
/**
* @brief MAU De-Initialization
* @param None
* @retval None
*/
static void MauDeinit(void)
{
/* Enable MAU peripheral clock. */
FCG_Fcg0PeriphClockCmd(PWC_FCG0_MAU, DISABLE);
}
/**
* @brief Sin table Initialization
* @param [in] pSinTable sin table
* @param [in] u32count number of pSinTable items
* @retval None
*/
static void SinTableInit(uint32_t pSinTable[], uint32_t u32count)
{
uint32_t i;
uint32_t u32AngAvg = (uint32_t)(float32_t)((float32_t)((float32_t)MAU_SIN_ANGIDX_TOTAL / (float32_t)u32count) + 0.5);
float32_t fSin;
for (i = 0U; i < u32count; i++) {
fSin = (((float32_t)MAU_Sin(CM_MAU, (uint16_t)(u32AngAvg * i))
/ (float32_t)MAU_SIN_Q15_SCALAR + SINE_NEGATIVE_TO_POSITVE) / VREFH) *
(float32_t)DAC_DATAREG_VALUE_MAX + 0.5F;
#if (DAC_DATA_ALIGN == DAC_DATA_ALIGN_12b_L)
{
pSinTable[i] = (uint32_t)fSin << 4;
}
#else
{
pSinTable[i] = (uint32_t)fSin;
}
#endif
}
}
/**
* @brief Enable DAC peripheral clock
* @param [in] enUnit The selected DAC unit
* @retval None
*/
static void DacPClkEnable(en_dac_unit_t enUnit)
{
uint32_t u32PClk;
switch (enUnit) {
case DAC_Unit1:
u32PClk = PWC_FCG3_DAC1;
break;
case DAC_Unit2:
u32PClk = PWC_FCG3_DAC2;
break;
default:
u32PClk = PWC_FCG3_DAC1 | PWC_FCG3_DAC2;
break;
}
/* Enable DAC peripheral clock. */
FCG_Fcg3PeriphClockCmd(u32PClk, ENABLE);
}
/**
* @brief Init DAC single channel
* @param [in] enUnit The selected DAC unit
* @retval A pointer of DAC handler
*/
static stc_dac_handle_t *DacSingleConversionInit(en_dac_unit_t enUnit)
{
uint8_t u8Port;
uint16_t u16Pin;
stc_dac_handle_t *pDac;
if (enUnit == DAC_Unit1) {
pDac = &m_stcDACHandle[DAC_Unit1];
pDac->pUnit = CM_DAC1;
} else {
pDac = &m_stcDACHandle[DAC_Unit2];
pDac->pUnit = CM_DAC2;
}
DacPClkEnable(enUnit);
pDac->enCvtType = E_Dac_Single;
#if (SINGLE_WAVE_DAC_CHN == DAC_CHN1)
pDac->u16Ch = DAC_CH1;
#else
pDac->u16Ch = DAC_CH2;
#endif
/* Init DAC by default value: source from data register and output enabled*/
DAC_DeInit(pDac->pUnit);
stc_dac_init_t stInit;
(void)DAC_StructInit(&stInit);
(void)DAC_Init(pDac->pUnit, pDac->u16Ch, &stInit);
#if (DAC_DATA_ALIGN == DAC_DATA_ALIGN_12b_L)
DAC_DataRegAlignConfig(pDac->pUnit, DAC_DATA_ALIGN_L);
#else
DAC_DataRegAlignConfig(pDac->pUnit, DAC_DATA_ALIGN_R);
#endif
/* Set DAC pin attribute to analog */
if (enUnit == DAC_Unit1) {
u8Port = DAC_UNIT1_PORT;
#if (SINGLE_WAVE_DAC_CHN == DAC_CHN1)
u16Pin = DAC_UNIT1_CHN1_PIN;
#endif
}
stc_gpio_init_t stcGpioInit;
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG;
(void)GPIO_Init(u8Port, u16Pin, &stcGpioInit);
#ifdef SUPPORT_ADP
/* Set ADC first */
/* Enable ADC peripheral clock. */
FCG_Fcg3PeriphClockCmd(PWC_FCG3_ADC1 | PWC_FCG3_ADC2 | PWC_FCG3_ADC3, ENABLE);
if (CM_ADC1->STR == 0U) {
if (CM_ADC2->STR == 0U) {
if (CM_ADC3->STR == 0U) {
DAC_ADCPrioConfig(pDac->pUnit, DAC_ADP_SELECT_ALL, ENABLE);
DAC_ADCPrioCmd(pDac->pUnit, ENABLE);
}
}
}
#endif
return pDac;
}
/**
* @brief Start single DAC conversions
* @param [in] pDac A pointer of DAC handler
* @retval None
*/
static void DacStartSingleConversion(const stc_dac_handle_t *pDac)
{
/* Enalbe AMP */
#ifdef SUPPORT_AMP
(void)DAC_AMPCmd(pDac->pUnit, pDac->u16Ch, ENABLE);
#endif
(void)DAC_Start(pDac->pUnit, pDac->u16Ch);
#ifdef SUPPORT_AMP
/* delay 3us before setting data*/
DDL_DelayMS(1U);
#endif
}
/**
* @brief Convert data by single DAC channel
* @param [in] pDac A pointer of DAC handler
* @param [in] pDataTable The data table to be converted
* @param [in] u32count Number of data table items
* @retval None
*/
__STATIC_INLINE void DacSetSingleConversionData(const stc_dac_handle_t *pDac, uint32_t const pDataTable[], uint32_t u32count)
{
uint32_t i = 0U;
for (i = 0U; i < u32count; i++) {
#ifdef SUPPORT_ADP
uint32_t u32TryCount = 100U;
while (u32TryCount != 0U) {
u32TryCount--;
if (SET != DAC_GetChConvertState(pDac->pUnit, pDac->u16Ch)) {
break;
}
}
#endif
DAC_SetChData(pDac->pUnit, pDac->u16Ch, (uint16_t)pDataTable[i]);
}
}
/**
* @brief stop DAC conversion
* @param [in] pDac A pointer of DAC handler
* @retval None
*/
static void DAC_StopConversion(const stc_dac_handle_t *pDac)
{
if (NULL == pDac) {
DAC_DeInit(CM_DAC1);
DAC_DeInit(CM_DAC2);
} else if (pDac->enCvtType != E_Dac_Dual) {
(void)DAC_Stop(pDac->pUnit, pDac->u16Ch);
} else {
DAC_StopDualCh(pDac->pUnit);
}
}
static uint32 DacOpen(void *dev)
{
struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev;
/* Init MAU for generating sine data*/
MauInit();
/* Init sine data table */
SinTableInit(gu32SinTable, SINE_DOT_NUMBER);
/* Init single DAC */
pSingleDac = DacSingleConversionInit(DAC_Unit1);
return EOK;
}
static uint32 DacClose(void *dev)
{
struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev;
CM_DAC_TypeDef *DACx = (CM_DAC_TypeDef *)dac_dev->private_data;
DAC_StopConversion(pSingleDac);
DAC_DeInit(DACx);
MauDeinit();
memset(gu32SinTable, 0 , sizeof(gu32SinTable));
return EOK;
}
static uint32 DacWrite(void *dev, struct BusBlockWriteParam *write_param)
{
struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev;
struct HwDac *dac_cfg = (struct HwDac *)dac_dev->haldev.private_data;
for (int i = 0; i < dac_cfg->digital_data; i ++) {
DacStartSingleConversion(pSingleDac);
DacSetSingleConversionData(pSingleDac, &gu32SinTable[i], 1U);
if (i > SINE_DOT_NUMBER) {
i = 0;
}
}
return EOK;
}
static uint32 DacDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
x_err_t ret = EOK;
struct DacDriver *dac_drv = (struct DacDriver *)drv;
struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dac_drv->driver.owner_bus->owner_haldev;
struct HwDac *dac_cfg = (struct HwDac *)dac_dev->haldev.private_data;
switch (configure_info->configure_cmd)
{
case OPE_CFG:
dac_cfg->digital_data = *(uint16 *)configure_info->private_data;
break;
default:
break;
}
return ret;
}
static const struct DacDevDone dev_done =
{
DacOpen,
DacClose,
DacWrite,
NONE,
};
int HwDacInit(void)
{
x_err_t ret = EOK;
#ifdef BSP_USING_DAC
static struct DacBus dac_bus;
static struct DacDriver dac_drv;
static struct DacHardwareDevice dac_dev;
static struct HwDac dac_cfg;
dac_drv.configure = DacDrvConfigure;
ret = DacBusInit(&dac_bus, DAC_BUS_NAME);
if (ret != EOK) {
KPrintf("DAC bus init error %d\n", ret);
return ERROR;
}
ret = DacDriverInit(&dac_drv, DAC_DRIVER_NAME);
if (ret != EOK) {
KPrintf("DAC driver init error %d\n", ret);
return ERROR;
}
ret = DacDriverAttachToBus(DAC_DRIVER_NAME, DAC_BUS_NAME);
if (ret != EOK) {
KPrintf("DAC driver attach error %d\n", ret);
return ERROR;
}
dac_dev.dac_dev_done = &dev_done;
dac_cfg.DACx = CM_DAC1;
dac_cfg.digital_data = 0;
ret = DacDeviceRegister(&dac_dev, (void *)&dac_cfg, DAC_DEVICE_NAME);
if (ret != EOK) {
KPrintf("DAC device register error %d\n", ret);
return ERROR;
}
ret = DacDeviceAttachToBus(DAC_DEVICE_NAME, DAC_BUS_NAME);
if (ret != EOK) {
KPrintf("DAC device register error %d\n", ret);
return ERROR;
}
#endif
return ret;
}