1169|0

34

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

小熊派BearPi-Pico H2821星闪开发板测评(三)——ADC与DMA测试 [复制链接]

ADC采样测试

对于H2821,GPIO02和GPIO03可复用为模拟电压输入,因此将这两个引脚接入电位器用于ADC采样测试。

 

代码实现:

#include "pinctrl.h"
#include "gpio.h"
#include "adc.h"
#include "adc_porting.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"
#include "pm_pmu.h"

#define ADC_TASK_STACK_SIZE               0x1000
#define ADC_TASK_PRIO                     (osPriority_t)(17)
#define ADC_AUTO_SAMPLE_TEST_TIMES        1000

#define GAFE_SAMPLE_VALUE_SIGN_BIT        17
#define ADC_REFERENCE_VOLTAGE_MV          1500
#define ADC_REF_VOL_DIFFERENCE_MULT       2
#define ADC_TICK2VOL_REF_VOLTAGE_MV       (ADC_REFERENCE_VOLTAGE_MV * ADC_REF_VOL_DIFFERENCE_MULT)


static void adc_set_io(uint8_t channel)
{
    pin_t adc_pin[] = {S_MGPIO2, S_MGPIO3, S_MGPIO4, S_MGPIO5, S_MGPIO28, S_MGPIO29, S_MGPIO30, S_MGPIO31};

    uapi_pin_set_mode(adc_pin[channel], PIN_MODE_0);
    uapi_gpio_set_dir(adc_pin[channel], GPIO_DIRECTION_INPUT);
    uapi_pin_set_pull(adc_pin[channel], PIN_PULL_NONE);
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
    uapi_pin_set_ie(adc_pin[channel], PIN_IE_1);
#endif
}


static void *adc_task(const char *arg)
{
    UNUSED(arg);

    uapi_pmu_control(PMU_CONTROL_MICLDO_POWER, PMU_CONTROL_POWER_ON);
    uapi_pmu_ldo_set_voltage(PMU_LDO_ID_MICLDO, PMU_MICLDO_VSET_1V5);  //在MLDO脚产生一个1.5V的电压便以测试
    osal_printk("start adc sample test\n");
    uapi_adc_init(ADC_CLOCK_NONE);
    adc_set_io(GADC_CHANNEL_0);
    uapi_adc_open_channel(GADC_CHANNEL_0);  //GPIO02
    uapi_adc_power_en(AFE_GADC_MODE, true);
    adc_calibration(AFE_GADC_MODE, true, true, true);

    while (1)
    {
        int gadc_value = 0;
        gadc_value =  uapi_adc_auto_sample(GADC_CHANNEL_0);
        osal_printk("gadc: %dmv\n\n", (gadc_value * ADC_TICK2VOL_REF_VOLTAGE_MV) >> GAFE_SAMPLE_VALUE_SIGN_BIT);
        osDelay(2000);
    }
    return NULL;
}

static void adc_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "ADCTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = ADC_TASK_STACK_SIZE;
    attr.priority = ADC_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)adc_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the adc_entry. */
app_run(adc_entry);

其中

uapi_pmu_control用于使能LDO

uapi_pmu_ldo_set_voltage用于使MIC_LDO引脚产生一个指定的电压(可以产生标准的1.1V,1.3V,1.5V,1.8V,2.0V,2.2V,2.5V,2.8V电压)用于测试

 

得到串口输出

可见在电位器的控制下,电压逐渐升高

特别的,当电压高于1.5V时,ADC的值将不再变化,观察ADC值的计算方法,发现

gadc = gadc_value * ADC_TICK2VOL_REF_VOLTAGE_MV) >> GAFE_SAMPLE_VALUE_SIGN_BIT

其中

gadc_value为ADC接口测量值

ADC_TICK2VOL_REF_VOLTAGE_MV为基准值,宏定义为3000

GAFE_SAMPLE_VALUE_SIGN_BIT为右移位数,宏定义为17

虽然这个表达式并不能看出芯片对ADC电压的限制,但实际电路应该是对ADC输入做了限制,因为就算我调整了基准电压值,最大有效输入电压仍为1.5V

除此之外,对比万用表测量输入电压和ADC采样得到的值,ADC采样结果相较万用表小了大约50mV,因此实际程序运行时可能需要多加注意并进行修正

 

为了实现多路ADC采样,需要在主函数循环部分的每次采样前都打开采样通道

 

若没有在循环部分中打开采样通道,两路ADC采样的结果都将取决于编号较大的模拟采样通道(比如GPIO02的模拟采样通道是AIN0,GPIO03的模拟采样通道是AIN1,如果不打开采样通道就进行采样,AIN0和AIN1的采样结果都将取决于AIN1)。当然,对于单个ADC采样而言,在循环体中是否打开采样通道是无所谓的,仅需在初始化时打开即可。

代码实现:

#include "pinctrl.h"
#include "gpio.h"
#include "adc.h"
#include "adc_porting.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"
#include "pm_pmu.h"

#define ADC_TASK_STACK_SIZE               0x1000
#define ADC_TASK_PRIO                     (osPriority_t)(17)
#define ADC_AUTO_SAMPLE_TEST_TIMES        1000

#define GAFE_SAMPLE_VALUE_SIGN_BIT        17
#define ADC_REFERENCE_VOLTAGE_MV          1500
#define ADC_REF_VOL_DIFFERENCE_MULT       2
#define ADC_TICK2VOL_REF_VOLTAGE_MV       (ADC_REFERENCE_VOLTAGE_MV * ADC_REF_VOL_DIFFERENCE_MULT)


static void adc_set_io(uint8_t channel)
{
    pin_t adc_pin[] = {S_MGPIO2, S_MGPIO3, S_MGPIO4, S_MGPIO5, S_MGPIO28, S_MGPIO29, S_MGPIO30, S_MGPIO31};
    uapi_pin_set_mode(adc_pin[channel], PIN_MODE_0);
    uapi_gpio_set_dir(adc_pin[channel], GPIO_DIRECTION_INPUT);
    uapi_pin_set_pull(adc_pin[channel], PIN_PULL_NONE);
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
    uapi_pin_set_ie(adc_pin[channel], PIN_IE_1);
#endif
}


static void *adc_task(const char *arg)
{
    UNUSED(arg);

    uapi_pmu_control(PMU_CONTROL_MICLDO_POWER, PMU_CONTROL_POWER_ON);
    uapi_pmu_ldo_set_voltage(PMU_LDO_ID_MICLDO, PMU_MICLDO_VSET_1V5);  //在MLDO脚产生一个1.5V的电压便以测试
    osal_printk("start adc sample test\n");
    uapi_adc_init(ADC_CLOCK_NONE);
    adc_set_io(GADC_CHANNEL_0);
    adc_set_io(GADC_CHANNEL_1);
    uapi_adc_open_channel(GADC_CHANNEL_0);  //GPIO02
    uapi_adc_open_channel(GADC_CHANNEL_1);  //GPIO03
    uapi_adc_power_en(AFE_GADC_MODE, true);
    adc_calibration(AFE_GADC_MODE, true, true, true);

    while (1)
    {
        int gadc_value1 = 0;
        int gadc_value2 = 0;
        uapi_adc_open_channel(GADC_CHANNEL_0);  //GPIO02
        gadc_value1 =  uapi_adc_auto_sample(GADC_CHANNEL_0);
        uapi_adc_open_channel(GADC_CHANNEL_1);  //GPIO03
        gadc_value2 = uapi_adc_auto_sample(GADC_CHANNEL_1);
        osal_printk("gadc1: %dmv\n\n", (gadc_value1 * ADC_TICK2VOL_REF_VOLTAGE_MV) >> GAFE_SAMPLE_VALUE_SIGN_BIT);
        osal_printk("gadc2: %dmv\n\n", (gadc_value2 * ADC_TICK2VOL_REF_VOLTAGE_MV) >> GAFE_SAMPLE_VALUE_SIGN_BIT);
        osDelay(2000);
    }
    return NULL;
}

static void adc_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "ADCTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = ADC_TASK_STACK_SIZE;
    attr.priority = ADC_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)adc_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the adc_entry. */
app_run(adc_entry);

输出结果:

 

DMA内存访问测试

DAM用于内存数据的搬运,从而减少CPU的负担

代码实现如下:

#include "securec.h"
#include "common_def.h"
#include "dma.h"
#include "hal_dma.h"
#include "dma_porting.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define DMA_TRANSFER_WORD_NUM       32
#define DMA_TRANSFER_PRIORITY       0
#define DMA_TRANSFER_WIDTH          2

#define DMA_TASK_STACK_SIZE         0x1000
#define DMA_TASK_DURATION_MS        500
#define DMA_TASK_PRIO               (osPriority_t)(17)

static uint32_t g_app_dma_src_data[DMA_TRANSFER_WORD_NUM] = { 0 };
static uint32_t g_app_dma_desc_data[DMA_TRANSFER_WORD_NUM] = { 0 };
static uint8_t g_dma_trans_done = 0;

static void app_dma_trans_done_callback(uint8_t int_type, uint8_t channel, uintptr_t arg)
{
    unused(arg);
    unused(channel);
    switch (int_type) {
        case HAL_DMA_INTERRUPT_TFR:
            g_dma_trans_done = 1;
            break;
        case HAL_DMA_INTERRUPT_BLOCK:
            g_dma_trans_done = 1;
            break;
        case HAL_DMA_INTERRUPT_ERR:
            osal_printk("DMA transfer error.\r\n");
            break;
        default:
            break;
    }
}

static void *dma_task(const char *arg)
{
    unused(arg);
    /* DMA init. */
    dma_port_clock_enable();
    uapi_dma_init();
    uapi_dma_open();

#if defined(CONFIG_DMA_MEMORY_LLI_TRANSFER_MODE)
    dma_channel_t dma_channel = DMA_CHANNEL_NONE;
    dma_channel = uapi_dma_get_lli_channel(0, HAL_DMA_HANDSHAKING_MAX_NUM);
#endif

    for (uint32_t i = 0; i < DMA_TRANSFER_WORD_NUM; i++) {
        g_app_dma_src_data[i] = i;
    }
    memset_s(g_app_dma_desc_data, DMA_TRANSFER_WORD_NUM, 0, DMA_TRANSFER_WORD_NUM);

    dma_ch_user_memory_config_t transfer_config = { 0 };
    transfer_config.src = (uint32_t)(uintptr_t)g_app_dma_src_data;
    transfer_config.dest = (uint32_t)(uintptr_t)g_app_dma_desc_data;
    transfer_config.transfer_num = DMA_TRANSFER_WORD_NUM;
    transfer_config.priority = DMA_TRANSFER_PRIORITY;
    transfer_config.width = DMA_TRANSFER_WIDTH;

    while (1) {
        osDelay(DMA_TASK_DURATION_MS);
        g_dma_trans_done = 0;
#if defined(CONFIG_DMA_MEMORY_LLI_TRANSFER_MODE)
        osal_printk("dma config link list item of memory to memory start!\r\n");
        if (uapi_dma_transfer_memory_lli(dma_channel, &transfer_config, app_dma_trans_done_callback) == ERRCODE_SUCC) {
            osal_printk("dma config link list item of memory to memory succ!\r\n");
        }
        osal_printk("dma enable lli memory transfer start!\r\n");
        if (uapi_dma_enable_lli(dma_channel, app_dma_trans_done_callback, (uintptr_t)NULL) == ERRCODE_SUCC) {
            osal_printk("dma enable lli memory transfer succ!\r\n");
        }
        while (!g_dma_trans_done) {}
        if (uapi_dma_end_transfer(dma_channel) == ERRCODE_SUCC) {
            osal_printk("dma channel transfer finish!\r\n");
        }
#else
        osal_printk("dma single memory transfer start!\r\n");
        if (uapi_dma_transfer_memory_single(&transfer_config, app_dma_trans_done_callback,
                                            (uintptr_t)NULL) == ERRCODE_SUCC) {
            osal_printk("dma single memory transfer succ!\r\n");
        }
        while (!g_dma_trans_done) {}
        osal_printk("dma checking transfer from 0x%08x to 0x%08x...\r\n", transfer_config.src, transfer_config.dest);
        if (memcmp((void *)transfer_config.src, (void *)transfer_config.dest, transfer_config.transfer_num) == 0) {
            osal_printk("dma memory copy test succ, length = %d block\r\n", transfer_config.transfer_num);
        }
#endif
    }

    return NULL;
}

static void dma_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "DmaTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = DMA_TASK_STACK_SIZE;
    attr.priority = DMA_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)dma_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the dma_entry. */
app_run(dma_entry);

结果显示:

   

此帖出自无线连接论坛
点赞 关注
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表