From fe506d515767abf079cbe89692fea8175a2ed845 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 9 Jun 2025 10:27:09 +0800 Subject: [PATCH] bsp: k230: support adc Signed-off-by: Chen Wang --- bsp/k230/.config | 1 + bsp/k230/board/Kconfig | 5 + bsp/k230/drivers/interdrv/adc/SConscript | 11 ++ bsp/k230/drivers/interdrv/adc/drv_adc.c | 162 +++++++++++++++++++++++ bsp/k230/drivers/interdrv/adc/drv_adc.h | 65 +++++++++ bsp/k230/drivers/utest/SConscript | 3 + bsp/k230/drivers/utest/test_adc.c | 118 +++++++++++++++++ 7 files changed, 365 insertions(+) create mode 100644 bsp/k230/drivers/interdrv/adc/SConscript create mode 100644 bsp/k230/drivers/interdrv/adc/drv_adc.c create mode 100644 bsp/k230/drivers/interdrv/adc/drv_adc.h create mode 100644 bsp/k230/drivers/utest/test_adc.c diff --git a/bsp/k230/.config b/bsp/k230/.config index 427b666995..c0107f7912 100644 --- a/bsp/k230/.config +++ b/bsp/k230/.config @@ -1490,6 +1490,7 @@ CONFIG_PKG_ZLIB_VER="latest" # # Drivers Configuration # +# CONFIG_BSP_USING_ADC is not set CONFIG_BSP_USING_HARDLOCK=y CONFIG_BSP_USING_SDIO=y CONFIG_BSP_USING_SDIO0=y diff --git a/bsp/k230/board/Kconfig b/bsp/k230/board/Kconfig index 63fd86b1b0..b9207044b9 100644 --- a/bsp/k230/board/Kconfig +++ b/bsp/k230/board/Kconfig @@ -1,5 +1,10 @@ menu "Drivers Configuration" + config BSP_USING_ADC + bool "Enable ADC" + select RT_USING_ADC + default n + config BSP_USING_HARDLOCK bool "Enable Hard-Lock" default y diff --git a/bsp/k230/drivers/interdrv/adc/SConscript b/bsp/k230/drivers/interdrv/adc/SConscript new file mode 100644 index 0000000000..a1f34e523c --- /dev/null +++ b/bsp/k230/drivers/interdrv/adc/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('ADC', src, depend = ['BSP_USING_ADC'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/k230/drivers/interdrv/adc/drv_adc.c b/bsp/k230/drivers/interdrv/adc/drv_adc.c new file mode 100644 index 0000000000..f3e5eb2028 --- /dev/null +++ b/bsp/k230/drivers/interdrv/adc/drv_adc.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "board.h" +#include "drv_adc.h" + +struct k230_adc adc_dev; + +static int k230_adc_hw_init(struct k230_adc_regs *adc_regs) +{ + rt_uint32_t reg; + + reg = readl(&adc_regs->trim_reg); + reg &= (~(0x1)); + writel(reg, &adc_regs->trim_reg); + + reg = readl(&adc_regs->trim_reg); + reg |= 0x1; + writel(reg, &adc_regs->trim_reg); + + reg = readl(&adc_regs->trim_reg); + reg |= (0x1 << 20); + writel(reg, &adc_regs->trim_reg); + + /* delay 150us */ + rt_hw_us_delay(150); + + reg &= ~(0x1 << 20); + writel(reg, &adc_regs->trim_reg); + + writel(0x0, &adc_regs->mode_reg); + + return RT_EOK; +} + +static int k230_adc_init() +{ + int i; + + adc_dev.adc_regs = (struct k230_adc_regs*)rt_ioremap((void *)ADC_BASE_ADDR, ADC_IO_SIZE); + + for (i = 0; i < ADC_MAX_DMA_CHN; i++) + { + adc_dev.chn[i].chn_num = i; + adc_dev.chn[i].enabled = 0; + } + + k230_adc_hw_init(adc_dev.adc_regs); + + return RT_EOK; +} + +static int k_adc_drv_enabled(struct k230_adc_regs *adc_regs) +{ + rt_uint32_t reg; + + reg = readl(&adc_regs->trim_reg); + reg |= 0x1; + writel(reg, &adc_regs->trim_reg); + + return RT_EOK; +} + +static int k_adc_drv_disabled(struct k230_adc_regs *adc_regs) +{ + rt_uint32_t reg; + + reg = readl(&adc_regs->trim_reg); + reg = reg & (~(0x1)); + writel(reg, &adc_regs->trim_reg); + + return RT_EOK; +} + +rt_err_t k230_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled) +{ + if (channel >= ADC_MAX_CHANNEL) + return -RT_ERROR; + + struct k230_adc *kd_adc = rt_container_of(device, struct k230_adc, dev); + + kd_adc->chn[channel].enabled = 1; + if (enabled) + { + kd_adc->chn[channel].enabled = 1; + } + else + { + kd_adc->chn[channel].enabled = 0; + } + + return RT_EOK; +} + +rt_err_t k230_get_adc_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value) +{ + if (channel >= ADC_MAX_CHANNEL) + return -RT_ERROR; + + struct k230_adc *kd_adc = rt_container_of(device, struct k230_adc, dev); + + if (!kd_adc->chn[channel].enabled) + return -RT_ERROR; + + writel(channel | 0x10, &kd_adc->adc_regs->cfg_reg); + while ((readl(&kd_adc->adc_regs->cfg_reg) & 0x10000) == 0); + *value = readl(&kd_adc->adc_regs->data_reg[channel]); + + return RT_EOK; +} + +static const struct rt_adc_ops k230_adc_ops = +{ + .enabled = k230_adc_enabled, + .convert = k230_get_adc_value, +}; + +int rt_hw_adc_init(void) +{ + k230_adc_init(); + + rt_hw_adc_register(&adc_dev.dev, K230_ADC_NAME, &k230_adc_ops, NULL); + + return RT_EOK; +} +INIT_BOARD_EXPORT(rt_hw_adc_init); diff --git a/bsp/k230/drivers/interdrv/adc/drv_adc.h b/bsp/k230/drivers/interdrv/adc/drv_adc.h new file mode 100644 index 0000000000..474d38e4e9 --- /dev/null +++ b/bsp/k230/drivers/interdrv/adc/drv_adc.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DRV_ADC__ +#define __DRV_ADC__ +#include "board.h" + +#define K230_ADC_NAME "adc" + +#define ADC_MAX_CHANNEL 6 +#define ADC_MAX_DMA_CHN 3 + +struct k230_adc_regs +{ + rt_uint32_t trim_reg; /**< 0x00 */ + rt_uint32_t cfg_reg; /**< 0x04 */ + rt_uint32_t mode_reg; /**< 0x08 */ + rt_uint32_t thsd_reg; /**< 0x0c */ + rt_uint32_t dma_intr_reg; /**< 0x10 */ + rt_uint32_t data_reg[ADC_MAX_CHANNEL]; /**< 0x14~0x28 */ + rt_uint32_t data_dma[ADC_MAX_DMA_CHN]; /**< 0x2c~0x34 */ +}; + +struct k230_adc_chan +{ + rt_uint32_t chn_num; + rt_int8_t enabled; +}; + +struct k230_adc +{ + struct rt_adc_device dev; + struct k230_adc_regs *adc_regs; + struct k230_adc_chan chn[ADC_MAX_CHANNEL]; +}; + +#endif /*__DRV_ADC__*/ \ No newline at end of file diff --git a/bsp/k230/drivers/utest/SConscript b/bsp/k230/drivers/utest/SConscript index e2daadae5a..54a5845c0f 100644 --- a/bsp/k230/drivers/utest/SConscript +++ b/bsp/k230/drivers/utest/SConscript @@ -6,6 +6,9 @@ if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('BSP_UTEST_DRIVERS'): src += ['test_gpio.c'] src += ['test_gpio_irq.c'] + if GetDepend('BSP_USING_ADC'): + src += ['test_adc.c'] + if GetDepend('BSP_USING_TIMERS'): src += ['test_timer.c'] diff --git a/bsp/k230/drivers/utest/test_adc.c b/bsp/k230/drivers/utest/test_adc.c new file mode 100644 index 0000000000..d4df244328 --- /dev/null +++ b/bsp/k230/drivers/utest/test_adc.c @@ -0,0 +1,118 @@ +/* Copyright 2020 Canaan Inc. + * + * Licensed 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. + */ + +#include +#include +#include +#include "../interdrv/adc/drv_adc.h" +#include "utest.h" + +/* + * 测试 ADC 驱动的读操作 + * 1. 查找 ADC 设备。 + * 2. 启用 ADC 设备。 + * 3. 启用每个 ADC 通道并读取其值。 + * 4. 验证读取的值在预期范围内。 + * 5. 禁用每个 ADC 通道并验证读取值为 0。 + * + * 本测试基于 01Studio 开发板,该开发板自带排针,并引出 SoC 的以下 4 个 ADC 通道 + * 板级排针编号 | SoC 的 ADC 通道编号 | 输入电压范围 + * -------------+---------------------+------------- + * 32 | ADC0 | (0 ~ 3.6V) + * 36 | ADC1 | (0 ~ 3.6V) + * 38 | ADC2 | (0 ~ 1.8V) + * 40 | ADC3 | (0 ~ 1.8V) + * SoC 的 ADC 通道默认只支持最大 1.8V 的输入电压,对于 ADC0 和 ADC1 通道,开发板 + * 通过增加功放将最大支持电压提升到 3.6V(而且同样采用了分压机制,导致实际 ADC + * 通道的输入电压只有板级排针电压的一半)。 + * + * 测试时注意连接输入的最大电压不要超过额定值,否则可能会损坏 ADC 通道。 + * + * 另外注意这个adc 只有 12bit,所以读取的值范围是 0 ~ 4095 + * + * 具体测试最大 1.8V 的 ADC 通道(譬如 38/40)时,可以自己通过两个 10K 欧姆的电 + * 阻将模拟输入从 3.3V 分压(将可调电阻调制最大时万用表实测 A 点电压为 1.69V 左右): + * +----------+ +---------------+ + * 3.3V ----| 10K 欧姆 |----| 可调 10K 欧姆 |---- 接地 + * +----------+ +---------------+ + * A + * | + * ADC2/ADC3 + * + * 具体测试最大 3.6V 的 ADC 通道(譬如 32/36)时,可以直接引入 3.3V。 + * +---------------+ + * 3.3V --------------------| 可调 10K 欧姆 |---- 接地 + * +---------------+ + * A + * | + * ADC0/ADC1 + */ +static void test_read(void) +{ + int i; + rt_err_t ret = RT_EOK; + rt_uint32_t value, vol; + rt_adc_device_t adc_dev; + + adc_dev = (rt_adc_device_t)rt_device_find(K230_ADC_NAME); + uassert_not_null(adc_dev); + + ret = rt_adc_enable(adc_dev, 0); + uassert_int_equal(ret, RT_EOK); + + for (i = 0; i < 4; i++) + { + ret = rt_adc_enable(adc_dev, i); + uassert_int_equal(ret, RT_EOK); + + value = rt_adc_read(adc_dev, i); + /* 转换为对应电压值,对应 12 位 ADC 最大值 4095, 内部基准最大电压值 1.8V,数据精度乘以 100 保留 2 位小数 */ + vol = value * 180 / 4095; + if (i == 0 || i == 1) + vol = vol * 2; /* ADC0/ADC1 分压后实际电压是输入电压的二分之一 */ + + LOG_I("ADC chan[%d] read value: %d, calculated voltage is: %d.%02dV\n", + i, value, vol / 100, vol % 100); + } + + for (i = 0; i < ADC_MAX_CHANNEL; i++) + { + ret = rt_adc_disable(adc_dev, i); + uassert_int_equal(ret, RT_EOK); + + value = rt_adc_read(adc_dev, i); + uassert_int_equal(value, 0); + } + + return; +} + +static rt_err_t utest_tc_init(void) +{ + + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(test_read); +} +UTEST_TC_EXPORT(testcase, "adc", utest_tc_init, utest_tc_cleanup, 100); \ No newline at end of file