This post was last edited by qinyunti on 2023-6-24 10:39
f54c020b5b79171138481b8508dd67aa
Preface
This article tests ADC and collects audio.
Schematic
There are 6 analog inputs, corresponding to
P10.0~P10.5, VREF is the analog reference voltage.
ADC Module Introduction
参考《Infineon-PSoC_6_MCU_CY8C6xx8_CY8C6xxA_Architecture_Technical_Reference_Manual_(TRM)-AdditionalTechnicalInformation-v08_00-EN.pdf》的Section E: Analog Subsystem
feature
AREF generates the voltage reference
1.2 V voltage reference (VREFBG) generated by a bandgap reference circuit
0.8 V reference from the SRSS block
External reference from external pin
AREF generates the current reference
The zero temperature coefficient IZTAT generator produces 1A current.
The 250 nA reference current of the SRSS is amplified by 4 times to get a 1A current.
- A 12-bit successive approximation register, 1-Msps analog-to-digital converter (SAR ADC).
- Sixteen individually configurable logic channels can scan eleven unique input channels. Each channel has the following functions:
Inputs from eight dedicated pins (eight single-ended mode or four differential inputs) or internal signals (AMUXBUS or temperature sensor)
Each channel can select one of four programmable acquisition times to set the acquisition time
Supports single-ended and differential
Support averaging and accumulation
Double buffering of results
- The result can be left-aligned, right-aligned, or 16-bit sign-extended
- Software, other peripherals, pin trigger, single and continuous modes
- Supports first-order accumulation of 2, 4, 8, 16, 32, 64, 128, and 256 samples (powers of 2)
- Reference voltage
VDDA and VDDA/2
Internal 1.2V
External References
- Interrupt
Scan End
Saturation or over range
Result overflow
Collision Detection
Collection time
At least 18 CLKs are required
clock
The source is SRSS, which must be between 1.8MHz and 18MHz.
Timing
Configuring analog acquisition pins
Code
Adc.c
#include"cy_pdl.h"
#include"cyhal.h"
#include"cybsp.h"
#include"cy_retarget_io.h"
#defineVPLUS_CHANNEL_0 (P10_0)
/* Conversion factor */
#defineMICRO_TO_MILLI_CONV_RATIO (1000u)
/* Acquistiontime in nanosecond */
#defineACQUISITION_TIME_NS (116680u)
/* ADC Scan delay in millisecond */
#defineADC_SCAN_DELAY_MS (200u)
/*******************************************************************************
* Enumerated Types
*******************************************************************************/
/* ADC Channel constants*/
enumADC_CHANNELS
{
CHANNEL_0= 0,
NUM_CHANNELS
} adc_channel;
/*******************************************************************************
* Global Variables
*******************************************************************************/
/* ADC Object */
cyhal_adc_tadc_obj;
/* ADC Channel 0 Object */
cyhal_adc_channel_tadc_chan_0_obj;
/* Default ADC configuration */
constcyhal_adc_config_tadc_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 */
staticbool async_read_complete = true;
#defineNUM_SCAN (1000)
#defineNUM_CHANNELS (1)
/* Variable to store results from multiple channels during asynchronous read*/
int32_tresult_arr[NUM_CHANNELS * NUM_SCAN] = {0};
staticvoidadc_event_handler(void* arg, cyhal_adc_event_tevent)
{
if(0u != (event & CYHAL_ADC_ASYNC_READ_COMPLETE))
{
/* Set asyncread complete flag to true */
async_read_complete = true;
}
}
intadc_init(void)
{
/* Variable to capture return value of functions */
cy_rslt_tresult;
/* 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", (longunsignedint)result);
CY_ASSERT(0);
}
/* ADC channel configuration */
constcyhal_adc_channel_config_tchannel_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", (longunsignedint)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 asyncread 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 multichannelconfiguration.\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");
return0;
}
intadc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_tresult;
/* Variable to store ADC conversion result from channel 0 */
int32_tadc_result_0 = 0;
/* Clear asyncread 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 asyncread failed. Error: %ld\n", (longunsignedint)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 millivoltsand print input voltage
*
*/
for(inti=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (longint)adc_result_0);
}
return0;
}
Adc.h
#ifndefADC_H
#defineADC_H
intadc_init(void);
intadc_samp(void);
#endif
Main.c calls
adc_init();
adc_samp();
test
Clock Source
The clock source is 100Mhz, divided by 12 = 8.33M, which meets the requirement between 1.8MHz and 18MHz
The default is 8M configuration
Sampling time
Flip the LED before and after sampling and measure the time with an oscilloscope
intadc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_tresult;
/* Variable to store ADC conversion result from channel 0 */
int32_tadc_result_0 = 0;
/* Clear asyncread 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 asyncread failed. Error: %ld\n", (longunsignedint)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 millivoltsand print input voltage
*
*/
for(inti=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (longint)adc_result_0);
}
return0;
}
Sample 1000 times, set the sampling time to 2uS and 1uS respectively for comparison.
#define ACQUISITION_TIME_NS (2000u)
10.28mS
#define ACQUISITION_TIME_NS (1000u)
9.32mS
10.28-9.32=0.96mS 1000 times is about 1mS and 1 time is exactly 1uS.
Excluding the sampling time, the remaining time for 1000 times is 8.32mS, that is, 8.32uS per time.
Because the clock is set to 8.33MHz, from the previous timing section, we can see that excluding the sampling time, other conversion times require 14 CLKs, so 14/8.33uS=1.7uS is required. The remaining 8.32-1.7 is the time for data transfer, software processing, etc.
Sampling value accuracy
1.545V and the oscilloscope acquisition of 1.54V are almost correct. Since we don't have a high-precision multimeter here, we can't test the accuracy, we only test the correctness.
Audio Capture
Collect 1000 times at a time and print them to the serial port, and use SerialStudio to visualize them
intadc_samp(void)
{
/* Variable to capture return value of functions */
cy_rslt_tresult;
/* Variable to store ADC conversion result from channel 0 */
int32_tadc_result_0 = 0;
/* Clear asyncread 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 asyncread failed. Error: %ld\n", (longunsignedint)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 millivoltsand print input voltage
*
*/
for(inti=0; i<NUM_SCAN; i++)
{
adc_result_0 = result_arr / MICRO_TO_MILLI_CONV_RATIO;
printf("/*%4ld*/\r\n", (longint)adc_result_0);
}
return0;
}
Summarize
The above implements the ADC test, including sampling rate and correctness, and collects audio to prepare for subsequent speech recognition.