2022-09-06 12:48:16 +08:00
|
|
|
/*
|
2023-08-15 18:41:20 +08:00
|
|
|
* Copyright (c) 2021-2023 HPMicro
|
2022-09-06 12:48:16 +08:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*/
|
|
|
|
#include <rtthread.h>
|
|
|
|
|
|
|
|
#ifdef BSP_USING_ADC
|
|
|
|
#include <rtdevice.h>
|
|
|
|
#include "board.h"
|
|
|
|
#include "drv_adc.h"
|
|
|
|
#ifdef BSP_USING_ADC12
|
|
|
|
#include "hpm_adc12_drv.h"
|
|
|
|
#endif
|
|
|
|
#ifdef BSP_USING_ADC16
|
|
|
|
#include "hpm_adc16_drv.h"
|
|
|
|
#endif
|
|
|
|
#include "hpm_sysctl_drv.h"
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
bool enabled;
|
|
|
|
} adc_channel_state_t;
|
|
|
|
|
2022-09-06 12:48:16 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
char *adc_name;
|
|
|
|
struct rt_adc_device hpm_adc_device;
|
2023-08-15 18:41:20 +08:00
|
|
|
bool is_adc12;
|
|
|
|
bool adc_enabled;
|
|
|
|
uint32_t adc_base;
|
|
|
|
adc_channel_state_t chn_state[16];
|
2022-09-06 12:48:16 +08:00
|
|
|
}hpm_rtt_adc;
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
static uint32_t hpm_adc_init_clock(struct rt_adc_device *device);
|
|
|
|
|
|
|
|
static rt_err_t hpm_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled);
|
|
|
|
static rt_err_t hpm_get_adc_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value);
|
|
|
|
static rt_uint8_t hpm_get_resolution(struct rt_adc_device *device);
|
|
|
|
static rt_int16_t hpm_get_vref(struct rt_adc_device *device);
|
|
|
|
|
|
|
|
|
|
|
|
static const struct rt_adc_ops hpm_adc_ops =
|
|
|
|
{
|
|
|
|
.enabled = hpm_adc_enabled,
|
|
|
|
.convert = hpm_get_adc_value,
|
|
|
|
.get_resolution = hpm_get_resolution,
|
|
|
|
.get_vref = hpm_get_vref,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-09-06 12:48:16 +08:00
|
|
|
static hpm_rtt_adc hpm_adc_config_tbl[] =
|
|
|
|
{
|
|
|
|
#ifdef BSP_USING_ADC0
|
|
|
|
{
|
|
|
|
.adc_name = "adc0",
|
|
|
|
#ifdef BSP_USING_ADC12
|
2023-08-15 18:41:20 +08:00
|
|
|
.is_adc12 = true,
|
|
|
|
#else
|
|
|
|
.is_adc12 = false,
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
.adc_base = (uint32_t)HPM_ADC0,
|
2022-09-06 12:48:16 +08:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BSP_USING_ADC1
|
|
|
|
{
|
|
|
|
.adc_name = "adc1",
|
|
|
|
#ifdef BSP_USING_ADC12
|
2023-08-15 18:41:20 +08:00
|
|
|
.is_adc12 = true,
|
|
|
|
#else
|
|
|
|
.is_adc12 = false,
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
.adc_base = (uint32_t)HPM_ADC1,
|
2022-09-06 12:48:16 +08:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BSP_USING_ADC2
|
|
|
|
{
|
|
|
|
.adc_name = "adc2",
|
|
|
|
#ifdef BSP_USING_ADC12
|
2023-08-15 18:41:20 +08:00
|
|
|
.is_adc12 = true,
|
|
|
|
#else
|
|
|
|
.is_adc12 = false,
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
.adc_base = (uint32_t)HPM_ADC2,
|
2022-09-06 12:48:16 +08:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BSP_USING_ADC3
|
|
|
|
{
|
|
|
|
.adc_name = "adc3",
|
2023-08-15 18:41:20 +08:00
|
|
|
.is_adc12 = false,
|
|
|
|
.adc_base = (uint32_t)HPM_ADC3,
|
2022-09-06 12:48:16 +08:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static uint8_t adc_nums = sizeof(hpm_adc_config_tbl) / sizeof(hpm_rtt_adc);
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
|
|
|
|
static uint32_t hpm_adc_init_clock(struct rt_adc_device *device)
|
|
|
|
{
|
|
|
|
hpm_rtt_adc *hpm_adc;
|
|
|
|
uint32_t clock_freq = 0;
|
|
|
|
RT_ASSERT(device != RT_NULL);
|
|
|
|
hpm_adc = (hpm_rtt_adc *)device->parent.user_data;
|
|
|
|
|
|
|
|
#if defined(ADC12_SOC_MAX_CH_NUM)
|
|
|
|
if (hpm_adc->is_adc12)
|
|
|
|
{
|
|
|
|
clock_freq = board_init_adc12_clock((ADC12_Type*)hpm_adc->adc_base);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
clock_freq = board_init_adc16_clock((ADC16_Type*)hpm_adc->adc_base);
|
|
|
|
}
|
|
|
|
return clock_freq;
|
|
|
|
}
|
|
|
|
|
2022-09-06 12:48:16 +08:00
|
|
|
static rt_err_t init_adc_config(hpm_rtt_adc *adc)
|
|
|
|
{
|
|
|
|
hpm_stat_t ret;
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
if (adc->is_adc12) {
|
|
|
|
#ifdef BSP_USING_ADC12
|
|
|
|
adc12_config_t cfg;
|
|
|
|
adc12_get_default_config(&cfg);
|
|
|
|
cfg.res = adc12_res_12_bits;
|
|
|
|
cfg.conv_mode = adc12_conv_mode_oneshot;
|
|
|
|
cfg.adc_ahb_en = true;
|
|
|
|
cfg.adc_clk_div = 3;
|
|
|
|
ret = adc12_init((ADC12_Type *)adc->adc_base, &cfg);
|
|
|
|
if (ret != status_success) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
} else {
|
2022-09-06 12:48:16 +08:00
|
|
|
#ifdef BSP_USING_ADC16
|
2023-08-15 18:41:20 +08:00
|
|
|
adc16_config_t cfg;
|
2022-09-06 12:48:16 +08:00
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
adc16_get_default_config(&cfg);
|
|
|
|
cfg.conv_mode = adc16_conv_mode_oneshot;
|
|
|
|
cfg.res = adc16_res_16_bits;
|
|
|
|
cfg.adc_clk_div = 4;
|
|
|
|
cfg.sel_sync_ahb = true;
|
|
|
|
cfg.adc_ahb_en = true;
|
|
|
|
cfg.wait_dis = 0;
|
|
|
|
ret = adc16_init((ADC16_Type *)adc->adc_base, &cfg);
|
|
|
|
if (ret != status_success) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
static rt_err_t init_channel_config(hpm_rtt_adc *adc, uint16_t channel)
|
2022-09-06 12:48:16 +08:00
|
|
|
{
|
|
|
|
hpm_stat_t ret;
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
if (adc->is_adc12) {
|
|
|
|
#ifdef BSP_USING_ADC12
|
|
|
|
adc12_channel_config_t ch_cfg;
|
2022-09-06 12:48:16 +08:00
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
adc12_get_channel_default_config(&ch_cfg);
|
|
|
|
ch_cfg.ch = adc->channel;
|
|
|
|
ch_cfg.diff_sel = adc12_sample_signal_single_ended;
|
|
|
|
ch_cfg.sample_cycle = 20;
|
2022-09-06 12:48:16 +08:00
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
ret = adc12_init_channel((ADC12_Type *)adc->adc_base, &ch_cfg);
|
|
|
|
if (ret != status_success) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
2022-09-06 12:48:16 +08:00
|
|
|
#ifdef BSP_USING_ADC16
|
2023-08-15 18:41:20 +08:00
|
|
|
adc16_channel_config_t ch_cfg;
|
2022-09-06 12:48:16 +08:00
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
adc16_get_channel_default_config(&ch_cfg);
|
|
|
|
ch_cfg.ch = channel;
|
|
|
|
ch_cfg.sample_cycle = 20;
|
|
|
|
ret = adc16_init_channel((ADC16_Type *)adc->adc_base, &ch_cfg);
|
|
|
|
if (ret != status_success) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
static rt_err_t hpm_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
|
2022-09-06 12:48:16 +08:00
|
|
|
{
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_rtt_adc *hpm_adc;
|
2022-09-06 12:48:16 +08:00
|
|
|
rt_err_t ret;
|
|
|
|
|
|
|
|
RT_ASSERT(device != RT_NULL);
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_adc = (hpm_rtt_adc *)device->parent.user_data;
|
|
|
|
if (enabled == RT_TRUE) {
|
|
|
|
if (!hpm_adc->chn_state[channel].enabled)
|
|
|
|
{
|
|
|
|
if (!hpm_adc->adc_enabled)
|
|
|
|
{
|
|
|
|
(void)hpm_adc_init_clock(device);
|
|
|
|
ret = init_adc_config(hpm_adc);
|
|
|
|
if (ret != RT_EOK) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
|
|
|
hpm_adc->adc_enabled = true;
|
|
|
|
}
|
|
|
|
hpm_adc->chn_state[channel].enabled = true;
|
|
|
|
|
|
|
|
ret = init_channel_config(hpm_adc, channel);
|
|
|
|
if (ret != RT_EOK) {
|
|
|
|
return RT_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
}
|
2023-08-15 18:41:20 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Since the ADC channel cannot be truly disabled, do nothing here */
|
2022-09-06 12:48:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
static rt_err_t hpm_get_adc_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
|
2022-09-06 12:48:16 +08:00
|
|
|
{
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_rtt_adc *hpm_adc;
|
2022-09-06 12:48:16 +08:00
|
|
|
rt_err_t ret;
|
|
|
|
rt_uint16_t val;
|
|
|
|
|
|
|
|
RT_ASSERT(device != RT_NULL);
|
|
|
|
RT_ASSERT(value != RT_NULL);
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_adc = (hpm_rtt_adc *)device->parent.user_data;
|
|
|
|
uint32_t adc_chn = (uint16_t)channel;
|
|
|
|
if (hpm_adc->is_adc12) {
|
2022-09-06 12:48:16 +08:00
|
|
|
#ifdef BSP_USING_ADC12
|
2023-08-15 18:41:20 +08:00
|
|
|
adc12_get_oneshot_result((ADC12_Type *)hpm_adc->adc_base, adc_chn, &val);
|
|
|
|
*value = val;
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
} else {
|
2022-09-06 12:48:16 +08:00
|
|
|
#ifdef BSP_USING_ADC16
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_stat_t status = adc16_get_oneshot_result((ADC16_Type *)hpm_adc->adc_base, adc_chn, &val);
|
|
|
|
*value = val;
|
|
|
|
// rt_kprintf("%s, status=%d\n", __func__, status);
|
2022-09-06 12:48:16 +08:00
|
|
|
#endif
|
2023-08-15 18:41:20 +08:00
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
static rt_uint8_t hpm_get_resolution(struct rt_adc_device *device)
|
2022-09-06 12:48:16 +08:00
|
|
|
{
|
2023-08-15 18:41:20 +08:00
|
|
|
hpm_rtt_adc *hpm_adc;
|
|
|
|
|
|
|
|
RT_ASSERT(device != RT_NULL);
|
|
|
|
hpm_adc = (hpm_rtt_adc *)device->parent.user_data;
|
|
|
|
if (hpm_adc->is_adc12) {
|
|
|
|
return 12;
|
|
|
|
} else {
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static rt_int16_t hpm_get_vref(struct rt_adc_device *device)
|
|
|
|
{
|
|
|
|
return -RT_EIO;
|
|
|
|
}
|
2022-09-06 12:48:16 +08:00
|
|
|
|
|
|
|
int rt_hw_adc_init(void)
|
|
|
|
{
|
|
|
|
rt_err_t ret = RT_EOK;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < adc_nums; i++) {
|
2023-08-15 18:41:20 +08:00
|
|
|
ret = rt_hw_adc_register(&hpm_adc_config_tbl[i].hpm_adc_device,
|
|
|
|
hpm_adc_config_tbl[i].adc_name,
|
|
|
|
&hpm_adc_ops,
|
|
|
|
&hpm_adc_config_tbl[i]);
|
2022-09-06 12:48:16 +08:00
|
|
|
if (ret != RT_EOK) {
|
2023-08-15 18:41:20 +08:00
|
|
|
ret = RT_ERROR;
|
2022-09-06 12:48:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
INIT_BOARD_EXPORT(rt_hw_adc_init);
|
|
|
|
|
2023-08-15 18:41:20 +08:00
|
|
|
#endif /* BSP_USING_ADC */
|