Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bsp/k230/.config
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions bsp/k230/board/Kconfig
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 11 additions & 0 deletions bsp/k230/drivers/interdrv/adc/SConscript
Original file line number Diff line number Diff line change
@@ -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 changes: 162 additions & 0 deletions bsp/k230/drivers/interdrv/adc/drv_adc.c
Original file line number Diff line number Diff line change
@@ -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 changes: 65 additions & 0 deletions bsp/k230/drivers/interdrv/adc/drv_adc.h
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions bsp/k230/drivers/utest/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -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']

Expand Down
118 changes: 118 additions & 0 deletions bsp/k230/drivers/utest/test_adc.c
Original file line number Diff line number Diff line change
@@ -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);