小熊派BearPi-Pico H2821星闪开发板测评(三)——ADC与DMA测试
<p><strong><span style="font-size:18px;">ADC采样测试</span></strong></p><p>对于H2821,GPIO02和GPIO03可复用为模拟电压输入,因此将这两个引脚接入电位器用于ADC采样测试。</p>
<p style="text-align: center;"> </p>
<p style="text-align: justify;">代码实现:</p>
<pre>
<code>#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, PIN_MODE_0);
uapi_gpio_set_dir(adc_pin, GPIO_DIRECTION_INPUT);
uapi_pin_set_pull(adc_pin, PIN_PULL_NONE);
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
uapi_pin_set_ie(adc_pin, 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);
</code></pre>
<p>其中</p>
<p>uapi_pmu_control用于使能LDO</p>
<p>uapi_pmu_ldo_set_voltage用于使MIC_LDO引脚产生一个指定的电压(可以产生标准的1.1V,1.3V,1.5V,1.8V,2.0V,2.2V,2.5V,2.8V电压)用于测试</p>
<p style="text-align: center;"> </p>
<p>得到串口输出</p>
<p style="text-align: center;"></p>
<p style="text-align: justify;">可见在电位器的控制下,电压逐渐升高</p>
<p style="text-align: justify;"><strong>特别的,当电压高于1.5V时,ADC的值将不再变化,观察ADC值的计算方法,发现</strong></p>
<p style="text-align: center;">gadc = gadc_value * ADC_TICK2VOL_REF_VOLTAGE_MV) >> GAFE_SAMPLE_VALUE_SIGN_BIT</p>
<p style="text-align: justify;">其中</p>
<p style="text-align: justify;">gadc_value为ADC接口测量值</p>
<p style="text-align: justify;">ADC_TICK2VOL_REF_VOLTAGE_MV为基准值,宏定义为3000</p>
<p style="text-align: justify;">GAFE_SAMPLE_VALUE_SIGN_BIT为右移位数,宏定义为17</p>
<p style="text-align: justify;">虽然这个表达式并不能看出芯片对ADC电压的限制,但实际电路应该是对ADC输入做了限制,因为就算我调整了基准电压值,最大有效输入电压仍为1.5V</p>
<p style="text-align: justify;"><strong>除此之外,对比万用表测量输入电压和ADC采样得到的值,ADC采样结果相较万用表小了大约50mV,因此实际程序运行时可能需要多加注意并进行修正</strong></p>
<p style="text-align: justify;"> </p>
<p style="text-align: justify;">为了实现多路ADC采样,需要在主函数循环部分的每次采样前都打开采样通道</p>
<p style="text-align: center;"> </p>
<p style="text-align: justify;">若没有在循环部分中打开采样通道,两路ADC采样的结果都将取决于编号较大的模拟采样通道(比如GPIO02的模拟采样通道是AIN0,GPIO03的模拟采样通道是AIN1,如果不打开采样通道就进行采样,AIN0和AIN1的采样结果都将取决于AIN1)。当然,对于单个ADC采样而言,在循环体中是否打开采样通道是无所谓的,仅需在初始化时打开即可。</p>
<p style="text-align: justify;">代码实现:</p>
<pre>
<code>#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, PIN_MODE_0);
uapi_gpio_set_dir(adc_pin, GPIO_DIRECTION_INPUT);
uapi_pin_set_pull(adc_pin, PIN_PULL_NONE);
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
uapi_pin_set_ie(adc_pin, 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);
</code></pre>
<p style="text-align: justify;">输出结果:</p>
<p style="text-align: center;"> </p>
<p style="text-align: justify;"><strong><span style="font-size:18px;">DMA内存访问测试</span></strong></p>
<p style="text-align: justify;">DAM用于内存数据的搬运,从而减少CPU的负担</p>
<p style="text-align: justify;">代码实现如下:</p>
<pre>
<code>#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 = { 0 };
static uint32_t g_app_dma_desc_data = { 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;
}
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);
</code></pre>
<p style="text-align: justify;">结果显示:</p>
<p style="text-align: center;"> </p>
页:
[1]