summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChen Wang <[email protected]>2025-06-09 10:27:09 +0800
committerRbb666 <[email protected]>2025-06-10 19:23:09 +0800
commitfe506d515767abf079cbe89692fea8175a2ed845 (patch)
tree95fba7684e120e5d4fd083223ba80127e84de917
parent01ca3911ecc34548e45dd3a5f2f04ecbc10582b1 (diff)
bsp: k230: support adc
Signed-off-by: Chen Wang <[email protected]>
-rw-r--r--bsp/k230/.config1
-rw-r--r--bsp/k230/board/Kconfig5
-rw-r--r--bsp/k230/drivers/interdrv/adc/SConscript11
-rw-r--r--bsp/k230/drivers/interdrv/adc/drv_adc.c162
-rw-r--r--bsp/k230/drivers/interdrv/adc/drv_adc.h65
-rw-r--r--bsp/k230/drivers/utest/SConscript3
-rw-r--r--bsp/k230/drivers/utest/test_adc.c118
7 files changed, 365 insertions, 0 deletions
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 <drivers/adc.h>
+#include <ioremap.h>
+#include <rtthread.h>
+#include <rthw.h>
+#include <rtdevice.h>
+#include <riscv_io.h>
+#include <string.h>
+
+#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 <rtthread.h>
+#include <rtdevice.h>
+#include <stdlib.h>
+#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