rt-thread-official/bsp/hc32/libraries/hc32_drivers/drv_dac.c

176 lines
4.2 KiB
C

/*
* Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-05-12 CDT first version
*/
#include <board.h>
#if defined(BSP_USING_DAC1) || defined(BSP_USING_DAC2)
#include <drivers/dac.h>
#include <drv_dac.h>
#include <drv_config.h>
#include "rtdevice.h"
#include "hc32_ll.h"
#include <drv_log.h>
#if defined(HC32F4A0)
#define DAC_CHANNEL_ID_MAX (DAC_CH2 + 1U)
#define DAC_RESOLUTION (12)
#define DAC_LEFT_ALIGNED_DATA_MASK (0xFFF0U)
#define DAC_RIGHT_ALIGNED_DATA_MASK (0xFFFU)
#endif
typedef struct
{
struct rt_dac_device rt_dac;
CM_DAC_TypeDef *instance;
struct dac_dev_init_params init;
} dac_device;
static dac_device _g_dac_dev_array[] =
{
#ifdef BSP_USING_DAC1
{
{0},
CM_DAC1,
DAC1_INIT_PARAMS,
},
#endif
#ifdef BSP_USING_DAC2
{
{0},
CM_DAC2,
DAC2_INIT_PARAMS,
},
#endif
};
static rt_uint16_t _dac_get_channel(rt_uint32_t channel)
{
rt_uint16_t ll_channel = 0;
switch (channel)
{
case 1:
ll_channel = DAC_CH1;
break;
case 2:
ll_channel = DAC_CH2;
break;
default:
RT_ASSERT(0);
break;
}
return ll_channel;
}
static rt_err_t _dac_enabled(struct rt_dac_device *device, rt_uint32_t channel)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(channel <= DAC_CHANNEL_ID_MAX);
CM_DAC_TypeDef *p_ll_instance = device->parent.user_data;
uint16_t ll_channel = _dac_get_channel(channel);
int32_t result = DAC_Start(p_ll_instance, ll_channel);
return (result == LL_OK) ? RT_EOK : -RT_ERROR;
}
static rt_err_t _dac_disabled(struct rt_dac_device *device, rt_uint32_t channel)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(channel <= DAC_CHANNEL_ID_MAX);
CM_DAC_TypeDef *p_ll_instance = device->parent.user_data;
uint16_t ll_channel = _dac_get_channel(channel);
int32_t result = DAC_Stop(p_ll_instance, ll_channel);
return (result == LL_OK) ? RT_EOK : -RT_ERROR;
}
static rt_uint8_t _dac_get_resolution(struct rt_dac_device *device)
{
return DAC_RESOLUTION;
}
static rt_err_t _dac_set_value(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(channel <= DAC_CHANNEL_ID_MAX);
CM_DAC_TypeDef *p_ll_instance = device->parent.user_data;
if (READ_REG16_BIT(p_ll_instance->DACR, DAC_DACR_DPSEL) == DAC_DATA_ALIGN_LEFT)
{
RT_ASSERT(0U == (*value & ~DAC_LEFT_ALIGNED_DATA_MASK));
}
else
{
RT_ASSERT(0U == (*value & ~DAC_RIGHT_ALIGNED_DATA_MASK));
}
uint16_t ll_channel = _dac_get_channel(channel);
DAC_SetChData(p_ll_instance, ll_channel, *value);
return RT_EOK;
}
static const struct rt_dac_ops g_dac_ops =
{
.disabled = _dac_disabled,
.enabled = _dac_enabled,
.convert = _dac_set_value,
.get_resolution = _dac_get_resolution,
};
static void _dac_clock_enable(void)
{
#if defined(BSP_USING_DAC1)
FCG_Fcg3PeriphClockCmd(PWC_FCG3_DAC1, ENABLE);
#endif
#if defined(BSP_USING_DAC2)
FCG_Fcg3PeriphClockCmd(PWC_FCG3_DAC2, ENABLE);
#endif
}
extern rt_err_t rt_hw_board_dac_init(CM_DAC_TypeDef *DACx);
int rt_hw_dac_init(void)
{
int result = RT_EOK;
rt_err_t ret;
int i = 0;
_dac_clock_enable();
uint32_t dev_cnt = sizeof(_g_dac_dev_array) / sizeof(_g_dac_dev_array[0]);
for (; i < dev_cnt; i++)
{
DAC_DeInit(_g_dac_dev_array[i].instance);
rt_hw_board_dac_init(_g_dac_dev_array[i].instance);
ret = rt_hw_dac_register(&_g_dac_dev_array[i].rt_dac, \
(const char *)_g_dac_dev_array[i].init.name, \
&g_dac_ops, (void *)_g_dac_dev_array[i].instance);
if (ret == RT_EOK)
{
LOG_D("%s init success", (const char *)_g_dac_dev_array[i].init.name);
}
else
{
LOG_E("%s register failed", (const char *)_g_dac_dev_array[i].init.name);
result = -RT_ERROR;
}
}
return result;
}
INIT_DEVICE_EXPORT(rt_hw_dac_init);
#endif /* BSP_USING_DAC */