本帖最后由 qinyunti 于 2023-6-24 10:39 编辑
f54c020b5b79171138481b8508dd67aa
前言
本篇进行ADC的测试以及音频的采集。
原理图
有6路模拟输入,分别对应
P10.0~P10.5, VREF为模拟参考电压。
ADC模块介绍
参考《Infineon-PSoC_6_MCU_CY8C6xx8_CY8C6xxA_Architecture_Technical_Reference_Manual_(TRM)-AdditionalTechnicalInformation-v08_00-EN.pdf》的Section E: Analog Subsystem
特征
AREF 产生电压参考
由一个带隙参考电路产生的1.2 V电压参考(VREFBG)
来自SRSS块的0.8 V参考
来自外部引脚的外部参考
AREF 产生电流参考
零温度系数IZTAT生成器产生1µA电流。
从SRSS的250 nA参考电流放大4倍得到1µA电流。
- 一个12位逐次逼近寄存器,1-Msps 模数转换器(SAR ADC)。
- 十六个可单独配置的逻辑通道,可以扫描十一个唯一的输入通道。每个通道都具有以下功能:
来自八个专用引脚的输入(八个单端模式或四个差分输入)或内部信号(AMUXBUS或温度传感器)
每个通道可以选择四个可编程采集时间中的一个来设置采集时间
支持单端和差分
支持平均和累加
结果双缓存
- 结果可左对齐,右对齐,16位符号扩展
- 软件,其他外设,引脚触发,单次和连续模式
- 支持2、4、8、16、32、64、128和256个样本(2的幂)的一阶累加
- 参考电压
VDDA和VDDA/2
内部1.2V
外部参考
- 中断
扫描结束
饱和或者超量程
结果溢出
碰撞检测
采集时间
最少需要18个CLK
时钟
来源于SRSS必须为1.8MHz~18MHz之间
时序
配置模拟采集引脚
代码
Adc.c
#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"
#define VPLUS_CHANNEL_0 (P10_0)
/* Conversion factor */
#define MICRO_TO_MILLI_CONV_RATIO (1000u)
/* Acquistion time in nanosecond */
#define ACQUISITION_TIME_NS (116680u)
/* ADC Scan delay in millisecond */
#define ADC_SCAN_DELAY_MS (200u)
/*******************************************************************************
* Enumerated Types
*******************************************************************************/
/* ADC Channel constants*/
enum ADC_CHANNELS
{
CHANNEL_0 = 0,
NUM_CHANNELS
} adc_channel;
/*******************************************************************************
* Global Variables
*******************************************************************************/
/* ADC Object */
cyhal_adc_t adc_obj;
/* ADC Channel 0 Object */
cyhal_adc_channel_t adc_chan_0_obj;
/* Default ADC configuration */
const cyhal_adc_config_t adc_config = {
.continuous_scanning=false, // Continuous Scanning is disabled
.average_count=1, // Average count disabled
.vref=CYHAL_ADC_REF_VDDA, // VREF for Single ended channel set to VDDA
.vneg=CYHAL_ADC_VNEG_VSSA, // VNEG for Single ended channel set to VSSA
.resolution = 12u, // 12-bit resolution
.ext_vref = NC, // No connection
.bypass_pin = NC }; // No connection
/* Asynchronous read complete flag, used in Event Handler */
static bool async_read_complete = true;
#define NUM_SCAN (1000)
#define NUM_CHANNELS (1)
/* Variable to store results from multiple channels during asynchronous read*/
int32_t result_arr[NUM_CHANNELS * NUM_SCAN] = {0};
static void adc_event_handler(void* arg, cyhal_adc_event_t event)
{
if(0u != (event & CYHAL_ADC_ASYNC_READ_COMPLETE))
{
/* Set async read complete flag to true */
async_read_complete = true;
}
}
int adc_init(void)
{
/* Variable to capture return value of functions */
cy_rslt_t result;
/* Initialize ADC. The ADC block which can connect to the channel 0 input pin is selected */
result = cyhal_adc_init(&adc_obj, VPLUS_CHANNEL_0, NULL);
if(result != CY_RSLT_SUCCESS)
{
printf("ADC initialization failed. Error: %ld\n", (long unsigned int)result);
CY_ASSERT(0);
}
/* ADC channel configuration */
const cyhal_adc_channel_config_t channel_config = {
.enable_averaging = false, // Disable averaging for channel
.min_acquisition_ns = ACQUISITION_TIME_NS, // Minimum acquisition time set to 1us
.enabled = true }; // Sample this channel when ADC performs a scan
/* Initialize a channel 0 and configure it to scan the channel 0 input pin in single ended mode. */
result = cyhal_adc_channel_init_diff(&adc_chan_0_obj, &adc_obj, VPLUS_CHANNEL_0,
CYHAL_ADC_VNEG, &channel_config);
if(result != CY_RSLT_SUCCESS)
{
printf("ADC first channel initialization failed. Error: %ld\n", (long unsigned int)result);
CY_ASSERT(0);
}
/* Register a callback to handle asynchronous read completion */
cyhal_adc_register_callback(&adc_obj, &adc_event_handler, result_arr);
/* Subscribe to the async read complete event to process the results */
cyhal_adc_enable_event(&adc_obj, CYHAL_ADC_ASYNC_READ_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true);
printf("ADC is configured in multichannel configuration.\r\n\n");
printf("Channel 0 is configured in single ended mode, connected to the \r\n");
printf("channel 0 input pin. Provide input voltage at the channel 0 input pin \r\n");
return 0;
}
int adc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_t result;
/* Variable to store ADC conversion result from channel 0 */
int32_t adc_result_0 = 0;
/* Clear async read complete flag */
async_read_complete = false;
/* Initiate an asynchronous read operation. The event handler will be called
* when it is complete. */
memset(result_arr,0,sizeof(result_arr));
cyhal_gpio_write_internal(CYBSP_USER_LED,true);
result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);
if(result != CY_RSLT_SUCCESS)
{
printf("ADC async read failed. Error: %ld\n", (long unsigned int)result);
CY_ASSERT(0);
}
while(async_read_complete == false);
cyhal_gpio_write_internal(CYBSP_USER_LED,false);
/*
* Read data from result list, input voltage in the result list is in
* microvolts. Convert it millivolts and print input voltage
*
*/
for(int i=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (long int)adc_result_0);
}
return 0;
}
Adc.h
#ifndef ADC_H
#define ADC_H
int adc_init(void);
int adc_samp(void);
#endif
Main.c调用
adc_init();
adc_samp();
测试
时钟源
时钟源是100Mhz,12分频=8.33M,满足1.8MHz~18MHz之间的要求
默认是按照8M配置
采样时间
采样前后翻转LED用示波器测量时间
int adc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_t result;
/* Variable to store ADC conversion result from channel 0 */
int32_t adc_result_0 = 0;
/* Clear async read complete flag */
async_read_complete = false;
/* Initiate an asynchronous read operation. The event handler will be called
* when it is complete. */
memset(result_arr,0,sizeof(result_arr));
cyhal_gpio_write_internal(CYBSP_USER_LED,true);
result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);
if(result != CY_RSLT_SUCCESS)
{
printf("ADC async read failed. Error: %ld\n", (long unsigned int)result);
CY_ASSERT(0);
}
while(async_read_complete == false);
cyhal_gpio_write_internal(CYBSP_USER_LED,false);
/*
* Read data from result list, input voltage in the result list is in
* microvolts. Convert it millivolts and print input voltage
*
*/
for(int i=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (long int)adc_result_0);
}
return 0;
}
采样1000次,分别设置采样时间为2uS和1uS对比。
#define ACQUISITION_TIME_NS (2000u)
10.28mS
#define ACQUISITION_TIME_NS (1000u)
9.32mS
10.28-9.32=0.96mS 1000次约1mS1次刚好是1uS。
而1000次除去采样时间其他时间为8.32mS,即一次8.32uS。
因为前面设置了时钟为8.33MHz, 从前面时序一节可以看到,除去采样时间,其他转换时间等需要14个CLK,所以需要14/8.33uS=1.7uS. 剩余的8.32-1.7为数据搬运,软件处理等时间。
采样值正确性
1.545V和示波器采集为1.54V差不多是正确的,这里没有高精度的万用表就不对测试精度了,只测试了正确性。
音频采集
一次采集1000次然后串口打印,使用SerialStudio可视化显示
int adc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_t result;
/* Variable to store ADC conversion result from channel 0 */
int32_t adc_result_0 = 0;
/* Clear async read complete flag */
async_read_complete = false;
/* Initiate an asynchronous read operation. The event handler will be called
* when it is complete. */
memset(result_arr,0,sizeof(result_arr));
cyhal_gpio_write_internal(CYBSP_USER_LED,true);
result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);
if(result != CY_RSLT_SUCCESS)
{
printf("ADC async read failed. Error: %ld\n", (long unsigned int)result);
CY_ASSERT(0);
}
while(async_read_complete == false);
cyhal_gpio_write_internal(CYBSP_USER_LED,false);
/*
* Read data from result list, input voltage in the result list is in
* microvolts. Convert it millivolts and print input voltage
*
*/
for(int i=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (long int)adc_result_0);
}
return 0;
}
总结
以上实现了ADC的测试,包括采样率,正确性,并进行了音频的采集,为后续语音识别做了准备。