Browse Source

bsp: k230: support adc

Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
Chen Wang 2 weeks ago
parent
commit
fe506d5157

+ 1 - 0
bsp/k230/.config

@@ -1490,6 +1490,7 @@ CONFIG_PKG_ZLIB_VER="latest"
 #
 #
 # Drivers Configuration
 # Drivers Configuration
 #
 #
+# CONFIG_BSP_USING_ADC is not set
 CONFIG_BSP_USING_HARDLOCK=y
 CONFIG_BSP_USING_HARDLOCK=y
 CONFIG_BSP_USING_SDIO=y
 CONFIG_BSP_USING_SDIO=y
 CONFIG_BSP_USING_SDIO0=y
 CONFIG_BSP_USING_SDIO0=y

+ 5 - 0
bsp/k230/board/Kconfig

@@ -1,5 +1,10 @@
 menu "Drivers Configuration"
 menu "Drivers Configuration"
 
 
+    config BSP_USING_ADC
+        bool "Enable ADC"
+        select RT_USING_ADC
+        default n
+
     config BSP_USING_HARDLOCK
     config BSP_USING_HARDLOCK
         bool "Enable Hard-Lock"
         bool "Enable Hard-Lock"
         default y
         default y

+ 11 - 0
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')

+ 162 - 0
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);

+ 65 - 0
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__*/

+ 3 - 0
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.c']
     src += ['test_gpio_irq.c']
     src += ['test_gpio_irq.c']
 
 
+    if GetDepend('BSP_USING_ADC'):
+        src += ['test_adc.c']
+
     if GetDepend('BSP_USING_TIMERS'):
     if GetDepend('BSP_USING_TIMERS'):
         src += ['test_timer.c']
         src += ['test_timer.c']
 
 

+ 118 - 0
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);