957 lines
22 KiB
C
957 lines
22 KiB
C
// Copyright 2020-2021 Beken
|
|
//
|
|
// 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 <common/bk_include.h>
|
|
#include <common/bk_compiler.h>
|
|
#include <os/mem.h>
|
|
#include <driver/gpio.h>
|
|
#include "gpio_driver.h"
|
|
#include <os/os.h>
|
|
#include "adc_hal.h"
|
|
#include "adc_statis.h"
|
|
#include "adc_driver.h"
|
|
#include <driver/int.h>
|
|
#include "icu_driver.h"
|
|
#include "power_driver.h"
|
|
#include "clock_driver.h"
|
|
#include <driver/adc.h>
|
|
#include "bk_drv_model.h"
|
|
#include "bk_sys_ctrl.h"
|
|
#include "sys_driver.h"
|
|
#include "iot_adc.h"
|
|
#include "bk_saradc.h"
|
|
#include "common/bk_err.h"
|
|
#include <modules/pm.h>
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
#include "spinlock.h"
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
|
|
static void adc_isr(void) __BK_SECTION(".itcm");
|
|
static bk_err_t adc_read_fifo(void) __BK_SECTION(".itcm");
|
|
bk_err_t bk_adc_stop(void) __BK_SECTION(".itcm");
|
|
|
|
typedef struct
|
|
{
|
|
adc_isr_t callback;
|
|
uint32_t param;
|
|
IotAdcCallback_t iot_callback;
|
|
void * p_iot_context;
|
|
} adc_callback_t;
|
|
|
|
typedef struct {
|
|
adc_hal_t hal;
|
|
uint16_t chan_init_bits;
|
|
} adc_driver_t;
|
|
|
|
typedef struct {
|
|
beken_semaphore_t adc_read_sema;
|
|
beken_mutex_t adc_mutex;
|
|
} adc_dev_t;
|
|
|
|
typedef struct {
|
|
uint16_t *buf;
|
|
/* The size is in unit of uint16_t */
|
|
uint16_t size;
|
|
uint16_t sample_cnt;
|
|
} adc_buf_t;
|
|
|
|
static adc_driver_t s_adc = {0};
|
|
static bool s_adc_driver_is_init = false;
|
|
static adc_dev_t s_adc_dev = {NULL};
|
|
static adc_buf_t s_adc_buf = {0};
|
|
static adc_callback_t s_adc_read_isr = {NULL};
|
|
static adc_statis_t* s_adc_statis = NULL;
|
|
UINT8 g_saradc_flag = 0x0;
|
|
|
|
saradc_calibrate_val saradc_val = {
|
|
#if (CONFIG_SOC_BK7256XX)
|
|
0xD40, 0x1A72 /* 1Volt, 2Volt*/
|
|
#elif (CONFIG_SOC_BK7236XX)
|
|
0x9C7,0x1358 /* 1Volt, 2Volt*/
|
|
#else
|
|
0x55, 0x354
|
|
#endif
|
|
};
|
|
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
static volatile spinlock_t adc_spin_lock = SPIN_LOCK_INIT;
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
|
|
__attribute__((section(".dtcm_sec_data "))) adc_config_t g_adc_cfg = {0};
|
|
|
|
|
|
//TODO - by Frank
|
|
//1. ADC id range confirm
|
|
//2. Add API for ADC saturate mode, hide it for application
|
|
//3. Considering how/when to use cli_done/calib_trig bits?
|
|
//4. adc_hal_init to reset the ADC to default value
|
|
//5. Currently ADC ISR is always enabled once ADC is started, can we provide ADC
|
|
// API that don't need to enable ADC ISR?
|
|
//6. Make adc_buf_t.buf configurable in bk_adc_init() since different application may
|
|
// use different buffer size.
|
|
//7. If necessary, provide ADC API specific for calibration that don't need ADC ISR.
|
|
//8. Hide the difference of ADC RAW data
|
|
//9. Update doc accordingly
|
|
//10. adc_chan_t to adc_chan_t
|
|
|
|
#define ADC_SAMPLE_CNT_DEFAULT 32
|
|
|
|
#define ADC_RETURN_ON_NOT_INIT() do {\
|
|
if (!s_adc_driver_is_init) {\
|
|
ADC_LOGE("adc driver not init\r\n");\
|
|
return BK_ERR_ADC_NOT_INIT;\
|
|
}\
|
|
} while(0)
|
|
|
|
#define ADC_RETURN_ON_INVALID_CHAN(id) do {\
|
|
if (!adc_hal_is_valid_channel(&s_adc.hal, (id))) {\
|
|
ADC_LOGE("ADC id number(%d) is invalid\r\n", (id));\
|
|
return BK_ERR_ADC_INVALID_CHAN;\
|
|
}\
|
|
} while(0)
|
|
|
|
#define ADC_RETURN_ON_INVALID_MODE(mode) do {\
|
|
if ((mode) >= ADC_NONE_MODE) {\
|
|
return BK_ERR_ADC_INVALID_MODE;\
|
|
}\
|
|
} while(0)
|
|
|
|
#define ADC_RETURN_ON_INVALID_SRC_CLK(src_clk) do {\
|
|
if ((src_clk) >= ADC_SCLK_NONE) {\
|
|
return BK_ERR_ADC_INVALID_SCLK_MODE;\
|
|
}\
|
|
} while(0)
|
|
|
|
|
|
static void adc_isr(void);
|
|
static void adc_flush(void);
|
|
|
|
static void adc_init_gpio(adc_chan_t chan)
|
|
{
|
|
if (adc_hal_is_analog_channel(&s_adc.hal, chan))
|
|
return;
|
|
|
|
adc_gpio_map_t adc_map_table[] = ADC_DEV_MAP;
|
|
adc_gpio_map_t *adc_map = &adc_map_table[chan];
|
|
|
|
//TODO optimize it
|
|
if(chan == 0) {
|
|
uint32_t param = PARAM_SARADC_BT_TXSEL_BIT;
|
|
|
|
#if CONFIG_SYSTEM_CTRL
|
|
sys_drv_analog_reg4_bits_or(param);// to do,need remove old interface after all adaption is finished
|
|
#else
|
|
sddev_control(DD_DEV_TYPE_SCTRL, CMD_SCTRL_ANALOG_CTRL4_SET, ¶m);
|
|
#endif
|
|
}
|
|
|
|
gpio_dev_map(adc_map->gpio_id, adc_map->gpio_dev);
|
|
bk_gpio_disable_pull(adc_map->gpio_id);
|
|
bk_gpio_disable_input(adc_map->gpio_id);
|
|
bk_gpio_disable_output(adc_map->gpio_id);
|
|
}
|
|
|
|
static void adc_deinit_gpio(adc_chan_t chan)
|
|
{
|
|
if (adc_hal_is_analog_channel(&s_adc.hal, chan))
|
|
return;
|
|
|
|
adc_gpio_map_t adc_map_table[] = ADC_DEV_MAP;
|
|
adc_gpio_map_t *adc_map = &adc_map_table[chan];
|
|
|
|
gpio_dev_unmap(adc_map->gpio_id);
|
|
}
|
|
|
|
static void adc_enable_block(void)
|
|
{
|
|
#if (!CONFIG_SOC_BK7231N) && (!CONFIG_SOC_BK7256XX)
|
|
//TODO - optimize it after sysctrl driver optimized!
|
|
uint32_t param = BLK_BIT_SARADC;
|
|
sddev_control(DD_DEV_TYPE_SCTRL, CMD_SCTRL_BLK_ENABLE, ¶m);
|
|
#endif
|
|
}
|
|
|
|
static bk_err_t adc_chan_init_common(adc_chan_t chan)
|
|
{
|
|
bk_err_t ret = 0;
|
|
|
|
sys_drv_sadc_pwr_up();
|
|
adc_enable_block();
|
|
adc_hal_init(&s_adc.hal);
|
|
adc_init_gpio(chan);
|
|
adc_hal_sel_channel(&s_adc.hal, chan);
|
|
|
|
s_adc.chan_init_bits |= BIT(chan);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bk_err_t adc_chan_deinit_common(adc_chan_t chan)
|
|
{
|
|
s_adc.chan_init_bits &= ~(BIT(chan));
|
|
|
|
adc_hal_stop_commom(&s_adc.hal);
|
|
sys_drv_sadc_int_disable();
|
|
|
|
adc_flush();
|
|
|
|
sys_drv_sadc_pwr_down();
|
|
adc_deinit_gpio(chan);
|
|
return BK_OK;
|
|
}
|
|
|
|
static bk_err_t adc_read_fifo(void)
|
|
{
|
|
|
|
while(!adc_hal_is_fifo_empty(&s_adc.hal)) {
|
|
ADC_STATIS_INC(s_adc_statis->adc_rx_total_cnt);
|
|
|
|
if(s_adc_buf.sample_cnt < s_adc_buf.size) {
|
|
s_adc_buf.buf[s_adc_buf.sample_cnt++] = adc_hal_get_adc_data(&s_adc.hal);
|
|
|
|
ADC_STATIS_INC(s_adc_statis->adc_rx_succ_cnt);
|
|
} else {
|
|
if((adc_hal_get_mode(&s_adc.hal) == ADC_CONTINUOUS_MODE)) {
|
|
adc_hal_get_adc_data(&s_adc.hal);
|
|
|
|
ADC_STATIS_INC(s_adc_statis->adc_rx_drop_cnt);
|
|
} else {
|
|
//software mode is NOT used!
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
static void adc_flush(void)
|
|
{
|
|
adc_hal_clear_int_status(&s_adc.hal);
|
|
|
|
while(!adc_hal_is_fifo_empty(&s_adc.hal)) {
|
|
adc_hal_get_adc_data(&s_adc.hal);
|
|
}
|
|
}
|
|
|
|
#if CONFIG_SARADC_PM_CB_SUPPORT
|
|
static int adc_restore(uint64_t sleep_time, void *args)
|
|
{
|
|
int ret;
|
|
|
|
ret = bk_adc_set_config(&g_adc_cfg);
|
|
if (BK_OK != ret) {
|
|
return ret;
|
|
}
|
|
|
|
if (g_adc_cfg.is_open) {
|
|
ret = bk_adc_start();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
bk_err_t bk_adc_driver_init(void)
|
|
{
|
|
int ret;
|
|
|
|
if (s_adc_driver_is_init) {
|
|
return BK_OK;
|
|
}
|
|
|
|
os_memset(&s_adc, 0, sizeof(s_adc));
|
|
os_memset(&g_adc_cfg, 0, sizeof(g_adc_cfg));
|
|
|
|
if (s_adc_buf.buf) {
|
|
os_free(s_adc_buf.buf);
|
|
}
|
|
|
|
s_adc_buf.size = CONFIG_ADC_BUF_SIZE;
|
|
s_adc_buf.buf = (uint16_t*)os_zalloc(CONFIG_ADC_BUF_SIZE<<1);
|
|
if (!s_adc_buf.buf) {
|
|
return BK_ERR_NO_MEM;
|
|
}
|
|
|
|
if (!s_adc_dev.adc_mutex) {
|
|
ret = rtos_init_mutex(&s_adc_dev.adc_mutex);
|
|
if (kNoErr != ret) {
|
|
os_free(s_adc_buf.buf);
|
|
return BK_ERR_ADC_INIT_MUTEX;
|
|
}
|
|
}
|
|
|
|
if (!s_adc_dev.adc_read_sema) {
|
|
ret = rtos_init_semaphore(&(s_adc_dev.adc_read_sema), 1);
|
|
if (BK_OK != ret) {
|
|
os_free(s_adc_buf.buf);
|
|
rtos_deinit_mutex(&s_adc_dev.adc_mutex);
|
|
return BK_ERR_ADC_INIT_READ_SEMA;
|
|
}
|
|
}
|
|
|
|
//bk_int_isr_register(INT_SRC_SARADC, adc_isr, NULL);
|
|
|
|
adc_statis_init();
|
|
s_adc_statis = adc_statis_get_statis();
|
|
|
|
g_adc_cfg.clk = DEFAULT_ADC_CLK;
|
|
g_adc_cfg.sample_rate = DEFAULT_ADC_SAMPLE_RATE;
|
|
g_adc_cfg.adc_filter = 0;
|
|
g_adc_cfg.steady_ctrl = DEFAULT_ADC_STEADY_TIME;
|
|
g_adc_cfg.adc_mode = DEFAULT_ADC_MODE;
|
|
g_adc_cfg.chan = ADC_MAX;
|
|
g_adc_cfg.src_clk = DEFAULT_ADC_SCLK;
|
|
g_adc_cfg.saturate_mode = DEFAULT_SATURATE_MODE;
|
|
g_adc_cfg.output_buf = NULL;
|
|
g_adc_cfg.output_buf_len = 0;
|
|
g_adc_cfg.is_open = 0;
|
|
|
|
s_adc_driver_is_init = true;
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_acquire(void)
|
|
{
|
|
ADC_LOGD("acquire\n");
|
|
return rtos_lock_mutex(&s_adc_dev.adc_mutex);
|
|
}
|
|
|
|
bk_err_t bk_adc_release(void)
|
|
{
|
|
ADC_LOGD("release\n");
|
|
return rtos_unlock_mutex(&s_adc_dev.adc_mutex);
|
|
}
|
|
|
|
bk_err_t bk_adc_driver_deinit(void)
|
|
{
|
|
if (!s_adc_driver_is_init)
|
|
return BK_OK;
|
|
|
|
bk_adc_deinit(ADC_1); // Deinit ADC_1 to deinit ADC
|
|
adc_hal_deinit(&s_adc.hal);
|
|
//bk_int_isr_unregister(INT_SRC_SARADC);
|
|
|
|
if (s_adc_dev.adc_mutex)
|
|
rtos_deinit_mutex(&s_adc_dev.adc_mutex);
|
|
|
|
if (s_adc_dev.adc_read_sema)
|
|
rtos_deinit_semaphore(&(s_adc_dev.adc_read_sema));
|
|
|
|
os_free(s_adc_buf.buf);
|
|
s_adc_buf.buf = NULL;
|
|
s_adc_buf.size = 0;
|
|
|
|
os_memset(&g_adc_cfg, 0, sizeof(g_adc_cfg));
|
|
|
|
s_adc_driver_is_init = false;
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_init(adc_chan_t adc_chan)
|
|
{
|
|
#if CONFIG_SARADC_PM_CB_SUPPORT
|
|
pm_cb_conf_t resume_cfg;
|
|
#endif
|
|
|
|
ADC_RETURN_ON_NOT_INIT();
|
|
ADC_RETURN_ON_INVALID_CHAN(adc_chan);
|
|
|
|
#if CONFIG_SARADC_PM_CB_SUPPORT
|
|
resume_cfg.cb = (pm_cb)adc_restore;
|
|
resume_cfg.args = NULL;
|
|
bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_SARADC, NULL, &resume_cfg);
|
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_SADC, PM_POWER_MODULE_STATE_ON);
|
|
#endif
|
|
#if (CONFIG_SARADC_NEED_FLUSH)
|
|
adc_flush();
|
|
#endif
|
|
adc_chan_init_common(adc_chan);
|
|
|
|
bk_int_isr_register(INT_SRC_SARADC, adc_isr, NULL);
|
|
|
|
bk_adc_set_sample_cnt(ADC_SAMPLE_CNT_DEFAULT);
|
|
sys_hal_set_saradc_config();
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_deinit(adc_chan_t chan)
|
|
{
|
|
bk_int_isr_unregister(INT_SRC_SARADC);
|
|
|
|
ADC_RETURN_ON_NOT_INIT();
|
|
ADC_RETURN_ON_INVALID_CHAN(chan);
|
|
|
|
#if CONFIG_SARADC_PM_CB_SUPPORT
|
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_SADC, PM_POWER_MODULE_STATE_OFF);
|
|
bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_SARADC, false, true);
|
|
#endif
|
|
adc_chan_deinit_common(chan);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_start(void)
|
|
{
|
|
if(adc_hal_check_adc_busy(&s_adc.hal))
|
|
return BK_ERR_ADC_BUSY;
|
|
|
|
g_adc_cfg.is_open = 1;
|
|
if (adc_hal_check_adc_enable(&s_adc.hal))
|
|
return BK_OK;
|
|
|
|
adc_hal_start_commom(&s_adc.hal);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_stop(void)
|
|
{
|
|
uint32_t ret = 0;
|
|
|
|
g_adc_cfg.is_open = 0;
|
|
if (!adc_hal_check_adc_enable(&s_adc.hal))
|
|
return BK_OK;
|
|
|
|
s_adc_buf.sample_cnt = 0;
|
|
|
|
sys_drv_sadc_int_disable();
|
|
adc_flush();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bk_err_t adc_block_read(uint32_t timeout)
|
|
{
|
|
adc_flush();
|
|
sys_drv_sadc_int_enable();
|
|
|
|
int ret = rtos_get_semaphore(&(s_adc_dev.adc_read_sema), timeout);
|
|
if(ret != kNoErr)
|
|
return BK_ERR_ADC_GET_READ_SEMA;
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_single_read(uint16_t* data)
|
|
{
|
|
*data = adc_hal_get_adc_data(&s_adc.hal);
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_read_raw(uint16_t* buf, uint32_t size, uint32_t timeout)
|
|
{
|
|
uint32_t ret = 0;
|
|
|
|
//TODO init check
|
|
|
|
if (size > s_adc_buf.size) {
|
|
ADC_LOGE("adc size %d too big\n", size);
|
|
return BK_ERR_ADC_SIZE_TOO_BIG;
|
|
}
|
|
|
|
ret = adc_block_read(timeout);
|
|
if (BK_OK != ret)
|
|
return ret;
|
|
|
|
os_memcpy(buf, s_adc_buf.buf, (size<<1));
|
|
|
|
return ret;
|
|
}
|
|
|
|
bk_err_t bk_adc_register_isr(adc_isr_t isr, uint32_t param)
|
|
{
|
|
ADC_RETURN_ON_NOT_INIT();
|
|
|
|
GLOBAL_INT_DECLARATION();
|
|
GLOBAL_INT_DISABLE();
|
|
s_adc_read_isr.callback = isr;
|
|
s_adc_read_isr.param = param;
|
|
GLOBAL_INT_RESTORE();
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_clk(adc_src_clk_t src_clk, uint32_t clk)
|
|
{
|
|
ADC_RETURN_ON_INVALID_SRC_CLK(src_clk);
|
|
|
|
adc_hal_set_clk(&s_adc.hal, src_clk, clk);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_channel(adc_chan_t adc_chan)
|
|
{
|
|
ADC_RETURN_ON_INVALID_CHAN(adc_chan);
|
|
|
|
adc_hal_sel_channel(&s_adc.hal, adc_chan);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_sample_rate(uint32_t sample_rate)
|
|
{
|
|
adc_hal_set_sample_rate(&s_adc.hal, sample_rate);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_filter(uint32_t filter)
|
|
{
|
|
adc_hal_set_adc_filter(&s_adc.hal, filter);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_steady_time(uint32_t steady_ctrl)
|
|
{
|
|
adc_hal_set_steady_ctrl(&s_adc.hal, steady_ctrl);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_sample_cnt(uint32_t cnt)
|
|
{
|
|
if (cnt == 0) {
|
|
cnt = SOC_ADC_SAMPLE_CNT_MAX;
|
|
}
|
|
|
|
if (cnt > SOC_ADC_SAMPLE_CNT_MAX) {
|
|
ADC_LOGW("sample cnt %d too big, default to %d\n", cnt, SOC_ADC_SAMPLE_CNT_MAX);
|
|
cnt = SOC_ADC_SAMPLE_CNT_MAX;
|
|
}
|
|
|
|
adc_hal_set_fifo_threshold(&s_adc.hal, cnt);
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_set_saturate_mode(adc_saturate_mode_t mode)
|
|
{
|
|
return adc_hal_set_saturate_mode(&s_adc.hal, mode);
|
|
}
|
|
|
|
bk_err_t bk_adc_enable_bypass_clalibration(void)
|
|
{
|
|
adc_hal_enable_bypass_calib(&s_adc.hal);
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_disable_bypass_clalibration(void)
|
|
{
|
|
adc_hal_disable_bypass_calib(&s_adc.hal);
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_get_saturate_mode(adc_saturate_mode_t *mode)
|
|
{
|
|
return BK_OK;
|
|
//return adc_hal_get_sat_ctrl(&s_adc.hal);
|
|
}
|
|
|
|
bk_err_t bk_adc_set_mode(adc_mode_t adc_mode)
|
|
{
|
|
ADC_RETURN_ON_INVALID_MODE(adc_mode);
|
|
|
|
return adc_hal_set_mode(&s_adc.hal, adc_mode);
|
|
}
|
|
|
|
adc_mode_t bk_adc_get_mode(void)
|
|
{
|
|
return adc_hal_get_mode(&s_adc.hal);
|
|
}
|
|
|
|
bk_err_t bk_adc_set_config(adc_config_t *config)
|
|
{
|
|
BK_RETURN_ON_NULL(config);
|
|
ADC_RETURN_ON_INVALID_MODE(config->adc_mode);
|
|
ADC_RETURN_ON_INVALID_SRC_CLK(config->src_clk);
|
|
ADC_RETURN_ON_INVALID_CHAN(config->chan);
|
|
|
|
if (&g_adc_cfg != config) {
|
|
os_memcpy(&g_adc_cfg, config, sizeof(g_adc_cfg));
|
|
}
|
|
|
|
adc_hal_set_clk(&s_adc.hal, config->src_clk, config->clk);
|
|
adc_hal_set_mode(&s_adc.hal, config->adc_mode);
|
|
|
|
adc_hal_set_steady_ctrl(&s_adc.hal, config->steady_ctrl);
|
|
adc_hal_set_saturate_mode(&s_adc.hal, config->saturate_mode);
|
|
|
|
bk_adc_set_channel(config->chan);
|
|
|
|
if(config->adc_mode == ADC_CONTINUOUS_MODE) {
|
|
adc_hal_set_sample_rate(&s_adc.hal, config->sample_rate);
|
|
adc_hal_set_adc_filter(&s_adc.hal, config->adc_filter);
|
|
}
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_get_config(uint32 adc_ch, adc_config_t **config)
|
|
{
|
|
if (adc_ch != g_adc_cfg.chan) {
|
|
return BK_ERR_ADC_CHAN_NOT_INIT;
|
|
}
|
|
*config = &g_adc_cfg;
|
|
return BK_OK;
|
|
}
|
|
|
|
int saradc_hal_is_fifo_empty(void)
|
|
{
|
|
return (!adc_hal_is_fifo_empty(&s_adc.hal));
|
|
}
|
|
|
|
bk_err_t bk_saradc_start_int_disable(void)
|
|
{
|
|
if(adc_hal_check_adc_busy(&s_adc.hal))
|
|
return BK_ERR_ADC_BUSY;
|
|
if (adc_hal_check_adc_enable(&s_adc.hal))
|
|
return BK_OK;
|
|
sys_drv_sadc_int_disable();
|
|
return BK_OK;
|
|
}
|
|
|
|
void saradc_hal_start_enable(void)
|
|
{
|
|
adc_hal_start_commom(&s_adc.hal);
|
|
}
|
|
|
|
uint32_t bk_saradc_read_raw_data(uint32_t timeout)
|
|
{
|
|
uint32_t raw_data = 0;
|
|
raw_data = adc_hal_get_adc_data(&s_adc.hal);
|
|
return raw_data;
|
|
}
|
|
|
|
#if SARADC_AUTOTEST
|
|
bk_err_t bk_saradc_set_config(adc_config_t *config, uint32_t div)
|
|
{
|
|
BK_RETURN_ON_NULL(config);
|
|
ADC_RETURN_ON_INVALID_MODE(config->adc_mode);
|
|
ADC_RETURN_ON_INVALID_SRC_CLK(config->src_clk);
|
|
ADC_RETURN_ON_INVALID_CHAN(config->chan);
|
|
adc_hal_set_div(&s_adc.hal, div);
|
|
adc_hal_set_mode(&s_adc.hal, config->adc_mode);
|
|
adc_hal_set_steady_ctrl(&s_adc.hal, config->steady_ctrl);
|
|
adc_hal_set_saturate_mode(&s_adc.hal, config->saturate_mode);
|
|
if(config->adc_mode == ADC_CONTINUOUS_MODE)
|
|
{
|
|
os_printf("config->sample_rate = %d\r\n",config->sample_rate);
|
|
adc_hal_set_sample_rate(&s_adc.hal, config->sample_rate);
|
|
adc_hal_set_adc_filter(&s_adc.hal, config->adc_filter);
|
|
}
|
|
return BK_OK;
|
|
}
|
|
#endif
|
|
|
|
bk_err_t bk_adc_read(uint16_t* data, uint32_t timeout)
|
|
{
|
|
uint32_t sum = 0;
|
|
int ret = BK_OK;
|
|
UINT32 num;
|
|
|
|
//TODO init check
|
|
|
|
if (s_adc_buf.size == 0)
|
|
return BK_ERR_ADC_NOT_INIT;
|
|
|
|
ret = adc_block_read(timeout);
|
|
if (BK_OK != ret)
|
|
return ret;
|
|
|
|
num = s_adc_buf.size/2 + s_adc_buf.size%2;
|
|
for (uint16_t i = num; i < s_adc_buf.size; i++) {
|
|
sum += s_adc_buf.buf[i];
|
|
}
|
|
|
|
sum = sum / (s_adc_buf.size / 2);
|
|
|
|
#if CONFIG_SARADC_RANGE_DIVIDE
|
|
sum = sum >> 1;
|
|
#endif
|
|
|
|
*data = sum;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void adc_isr(void)
|
|
{
|
|
adc_hal_clear_int_status(&s_adc.hal);
|
|
|
|
ADC_STATIS_INC(s_adc_statis->adc_isr_cnt);
|
|
|
|
adc_read_fifo();
|
|
|
|
if (s_adc_buf.sample_cnt >= s_adc_buf.size) {
|
|
rtos_set_semaphore(&(s_adc_dev.adc_read_sema));
|
|
bk_adc_stop();
|
|
}
|
|
|
|
if (s_adc_read_isr.callback) {
|
|
s_adc_read_isr.callback(s_adc_read_isr.param);
|
|
}
|
|
|
|
if (s_adc_read_isr.iot_callback) {
|
|
s_adc_read_isr.iot_callback(s_adc_buf.buf, s_adc_read_isr.p_iot_context);
|
|
}
|
|
}
|
|
|
|
bk_err_t bk_adc_is_valid_ch(uint32_t ch)
|
|
{
|
|
if (!adc_hal_is_valid_channel(&s_adc.hal, ch))
|
|
{
|
|
ADC_LOGE("ADC id number(%d) is invalid\r\n", (ch));
|
|
return BK_ERR_ADC_INVALID_CHAN;
|
|
}
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_register_isr_iot_callback( void* iot_callback, void * p_iot_context)
|
|
{
|
|
ADC_RETURN_ON_NOT_INIT();
|
|
|
|
GLOBAL_INT_DECLARATION();
|
|
GLOBAL_INT_DISABLE();
|
|
s_adc_read_isr.iot_callback = (IotAdcCallback_t)iot_callback;
|
|
s_adc_read_isr.p_iot_context = p_iot_context;
|
|
GLOBAL_INT_RESTORE();
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_unregister_isr_iot_callback(void)
|
|
{
|
|
ADC_RETURN_ON_NOT_INIT();
|
|
|
|
GLOBAL_INT_DECLARATION();
|
|
GLOBAL_INT_DISABLE();
|
|
s_adc_read_isr.iot_callback = NULL;
|
|
s_adc_read_isr.p_iot_context = NULL;
|
|
GLOBAL_INT_RESTORE();
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_adc_en(void)
|
|
{
|
|
if(adc_hal_check_adc_busy(&s_adc.hal))
|
|
{
|
|
os_printf("adc_start:adc busy\n");
|
|
return BK_ERR_ADC_BUSY;
|
|
}
|
|
|
|
adc_hal_start_commom(&s_adc.hal);
|
|
|
|
int ret = rtos_get_semaphore(&(s_adc_dev.adc_read_sema), 1000);
|
|
if(ret != kNoErr)
|
|
{
|
|
os_printf("adc_start:rtos_get_semaphore fail\n");
|
|
return BK_ERR_ADC_GET_READ_SEMA;
|
|
}
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
void saradc_config_param_init_for_temp(saradc_desc_t* adc_config)
|
|
{
|
|
os_memset(adc_config, 0x00, sizeof(saradc_desc_t));
|
|
adc_config->channel = 1;
|
|
adc_config->current_read_data_cnt = 0;
|
|
adc_config->current_sample_data_cnt = 0;
|
|
adc_config->filter = 0;
|
|
adc_config->has_data = 0;
|
|
adc_config->all_done = 0;
|
|
adc_config->mode = (ADC_CONFIG_MODE_CONTINUE << 0)
|
|
|(ADC_CONFIG_MODE_4CLK_DELAY << 2)
|
|
|(ADC_CONFIG_MODE_SHOULD_OFF);
|
|
adc_config->pre_div = 0x10;
|
|
adc_config->samp_rate = 0x20;
|
|
}
|
|
|
|
float saradc_calculate(UINT16 adc_val)
|
|
{
|
|
float practic_voltage;
|
|
|
|
#if (CONFIG_SOC_BK7256XX)
|
|
adc_val = adc_val * 2;
|
|
/* (adc_val - low) / (practic_voltage - 1Volt) = (high - low) / 1Volt */
|
|
/* practic_voltage = (adc_val - low) / (high - low) + 1Volt */
|
|
if(g_saradc_flag == 0x1)
|
|
{
|
|
practic_voltage = (float)(adc_val - saradc_val.low);
|
|
practic_voltage = (practic_voltage / (float)(saradc_val.high - saradc_val.low)) + 1;
|
|
if(practic_voltage < 0)
|
|
practic_voltage = practic_voltage *(-1.0);
|
|
}
|
|
else
|
|
{
|
|
/* saradc 1.2V = 4096 */
|
|
practic_voltage = ((float)(adc_val * 2) / 4096) * 1.2 * 1000;
|
|
}
|
|
#elif (CONFIG_SOC_BK7236XX)
|
|
/* (adc_val - low) / (practic_voltage - 1Volt) = (high - low) / 1Volt */
|
|
/* practic_voltage = (adc_val - low) / (high - low) + 1Volt */
|
|
practic_voltage = (float)(adc_val - saradc_val.low);
|
|
practic_voltage = (practic_voltage / (float)(saradc_val.high - saradc_val.low)) + 1;
|
|
#elif ( (CFG_SOC_NAME != SOC_BK7271) && (CFG_SOC_NAME != SOC_BK7221U))
|
|
practic_voltage = ((adc_val - saradc_val.low) * 1.8);
|
|
practic_voltage = (practic_voltage / (saradc_val.high - saradc_val.low)) + 0.2;
|
|
#else
|
|
practic_voltage = (adc_val -(saradc_val.low-4096));
|
|
practic_voltage = practic_voltage/(saradc_val.high - (saradc_val.low-4096));
|
|
practic_voltage = 2*practic_voltage;
|
|
#endif
|
|
|
|
if (practic_voltage < 0) {
|
|
practic_voltage = 0.0f;
|
|
}
|
|
|
|
return practic_voltage;
|
|
}
|
|
|
|
float bk_adc_data_calculate(UINT16 adc_val, UINT8 adc_chan)
|
|
{
|
|
float cali_value = 0;
|
|
|
|
if(adc_chan == 0)
|
|
{
|
|
#if (CONFIG_SOC_BK7256XX)
|
|
cali_value = saradc_calculate(adc_val);
|
|
cali_value = cali_value*5/2;
|
|
#elif(CONFIG_SOC_BK7236XX)
|
|
adc_val = adc_val*5/3;
|
|
cali_value = saradc_calculate(adc_val);
|
|
#else
|
|
adc_val = adc_val*5/3;
|
|
cali_value = saradc_calculate(adc_val);
|
|
#endif
|
|
}
|
|
else if(adc_chan == 7 || adc_chan == 8 || adc_chan == 9 || adc_chan == 11)
|
|
{
|
|
ADC_LOGI("adc_chan %d has been used\r\n", adc_chan);
|
|
}
|
|
else
|
|
{
|
|
cali_value = saradc_calculate(adc_val);
|
|
}
|
|
|
|
return cali_value;
|
|
}
|
|
|
|
UINT32 saradc_set_calibrate_val(uint16_t *value, SARADC_MODE mode)
|
|
{
|
|
uint32_t irq_level = rtos_disable_int();
|
|
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
spin_lock(&adc_spin_lock);
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
|
|
if(SARADC_CALIBRATE_LOW == mode)
|
|
{
|
|
saradc_val.low = *value;
|
|
}
|
|
else if(SARADC_CALIBRATE_HIGH == mode)
|
|
{
|
|
saradc_val.high = *value;
|
|
}
|
|
else
|
|
{
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
spin_unlock(&adc_spin_lock);
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
rtos_enable_int(irq_level);
|
|
return SARADC_FAILURE;
|
|
}
|
|
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
spin_unlock(&adc_spin_lock);
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
rtos_enable_int(irq_level);
|
|
return SARADC_SUCCESS;
|
|
}
|
|
|
|
void bk_adc_read_for_ate(uint32_t saradc_num, uint16_t *saradc_buf)
|
|
{
|
|
uint32_t i = 0;
|
|
int irq_level = 0;
|
|
|
|
BK_LOG_ON_ERR(bk_saradc_start_int_disable());
|
|
//saradc enable
|
|
saradc_hal_start_enable();
|
|
//need check saradc fifo empty
|
|
//os_printf("saradc_hal_is_fifo_empty=%x\r\n",saradc_hal_is_fifo_empty());
|
|
//os_printf("sardata_start\r\n");
|
|
irq_level = rtos_disable_int();
|
|
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
spin_lock(&adc_spin_lock);
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
|
|
for(i = 0; i < saradc_num; i++)
|
|
{
|
|
if(saradc_hal_is_fifo_empty())
|
|
{
|
|
saradc_buf[i] = bk_saradc_read_raw_data(1000);
|
|
//saradc_buf[i] = *((volatile unsigned long *) (BASEADDR_SADC+0x4*4));
|
|
}
|
|
else
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
}
|
|
#ifdef CONFIG_FREERTOS_SMP
|
|
spin_unlock(&adc_spin_lock);
|
|
#endif // CONFIG_FREERTOS_SMP
|
|
rtos_enable_int(irq_level);
|
|
}
|
|
|
|
void test_adc_for_ate(adc_chan_t channel, adc_mode_t mode,
|
|
uint32_t pre_div, uint32_t samp_rate,
|
|
uint32_t filter, uint32_t sta_ctrl,
|
|
uint32_t usCount, uint16_t *pDataBuffer)
|
|
{
|
|
adc_config_t config = {0};
|
|
uint32_t adc_clk;
|
|
|
|
adc_clk = 26000000/2/(pre_div + 1);
|
|
BK_LOG_ON_ERR(bk_adc_acquire());
|
|
BK_LOG_ON_ERR(bk_adc_init(channel));
|
|
|
|
config.chan = channel;
|
|
config.adc_mode = mode;
|
|
config.clk = adc_clk;
|
|
config.src_clk = 1;
|
|
config.saturate_mode = 4;
|
|
config.sample_rate = samp_rate;
|
|
config.steady_ctrl= sta_ctrl;
|
|
config.adc_filter = filter;
|
|
|
|
BK_LOG_ON_ERR(bk_adc_set_config(&config));
|
|
BK_LOG_ON_ERR(bk_adc_enable_bypass_clalibration());
|
|
BK_LOG_ON_ERR(bk_adc_start());
|
|
|
|
bk_adc_read_for_ate(usCount, pDataBuffer);
|
|
BK_LOG_ON_ERR(bk_adc_stop());
|
|
BK_LOG_ON_ERR(bk_adc_deinit(channel));
|
|
BK_LOG_ON_ERR(bk_adc_release());
|
|
}
|