当前位置: 首页 > news >正文

RP2040 C SDK ADC功能使用

RP2040 C SDK ADC功能使用


  • 🌿RP2040 ADC功能说明文档:https://www.raspberrypi.com/documentation/pico-sdk/hardware.html#hardware_adc

📗RP2040 ADC介绍

  • SAR ADC
  • 500 kS/s (Using an independent 48MHz clock)
  • 12 bit (RP2040 8.7 ENOB, RP2350 9.2 ENOB)
  • RP2040 5 input mux:
  • 4 inputs that are available on package pins shared with GPIO[29:26]
  • 1 input is dedicated to the internal temperature sensor
  • 4 element receive sample FIFO。
  • One input dedicated to the internal temperature sensor (see Section 12.4.6)
  • Interrupt generation
  • DMA interface
  • 🍁相关电路:
    在这里插入图片描述

📑RP2040 ADC API相关函数介绍

  • 🌿static inline void adc_select_input(uint input):配置输入通道:0 - 3分别对应GPIO26 - GPIO29。
  • 🌿static inline uint16_t adc_read(void):读取对应通道ADC转换结果。
  • 🌿static inline void adc_set_temp_sensor_enabled(bool enable):内部温度传感器使能位
  • 🌿static inline void adc_gpio_init(uint gpio):配置gpio模式作为ADC模拟输入模式。
  • 🌿static inline void adc_set_round_robin(uint input_mask) :ADC通道选择位:0 - 4bit,值:0 - 1f,分别对应通道0-3,4:内部温度

如果需要配置adc下一个转换通道为3(GPIO29),那么adc_set_round_robin(0x08);等同于adc_select_input(3)效果。

📜ADC通道和输入引脚
  • 用户ADC输入在0-3(GPIO 26-29)上,共用一个ADC模数转换器,在多通道读取轮流读取。内部温度传感器在输入4通道上。
  • CMakeLists.txt配置文件中需要引入adc外设:
# Add the standard library to the build
target_link_libraries(RP2040_ADCpico_stdlibhardware_adc)

📘内部温度读取

/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_ADC.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_ADC.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "hardware/adc.h"
#include "hardware/clocks.h"#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25/* Choose 'C' for Celsius or 'F' for Fahrenheit. */
#define TEMPERATURE_UNITS 'C'static void measure_freqs(void);
/* References for this implementation:* raspberry-pi-pico-c-sdk.pdf, Section '4.1.1. hardware_adc'* pico-examples/adc/adc_console/adc_console.c */
float read_onboard_temperature(const char unit)
{/* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */const float conversionFactor = 3.3f / (1 << 12);float adc = (float)adc_read() * conversionFactor;float tempC = 27.0f - (adc - 0.706f) / 0.001721f;if (unit == 'C'){return tempC;}else if (unit == 'F'){return tempC * 9 / 5 + 32;}return -1.0f;
}int main()
{stdio_init_all();sleep_ms(2500);printf("adc test!\n");set_sys_clock_khz(133000, true); // 325us// GPIO initialisation.gpio_init(BUILTIN_LED);gpio_set_dir(BUILTIN_LED, 1);gpio_pull_up(BUILTIN_LED);adc_init();// 使能温度传感器adc_set_temp_sensor_enabled(true);adc_select_input(4);while (true){// Read the temperature from the onboard temperature sensor.float temperature = read_onboard_temperature(TEMPERATURE_UNITS);printf("Onboard temperature = %.02f %c\n", temperature, TEMPERATURE_UNITS);sleep_ms(1000);gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED// tight_loop_contents();measure_freqs();}return 0;
}static void measure_freqs(void) {uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);printf("pll_sys  = %dkHz\n", f_pll_sys);printf("pll_usb  = %dkHz\n", f_pll_usb);printf("rosc     = %dkHz\n", f_rosc);printf("clk_sys  = %dkHz\n", f_clk_sys);printf("clk_peri = %dkHz\n", f_clk_peri);printf("clk_usb  = %dkHz\n", f_clk_usb);printf("clk_adc  = %dkHz\n", f_clk_adc);printf("clk_rtc  = %dkHz\n", f_clk_rtc);// Can't measure clk_ref / xosc as it is the ref
}

📗ADC单通道读取


/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_ADC.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_ADC.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "hardware/adc.h"
#include "hardware/clocks.h"#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25static void measure_freqs(void);void ADC_Reading(void)
{// 12-bit conversion, assume max value == ADC_VREF == 3.3 Vconst float conversion_factor = 3.3f / (1 << 12);uint16_t result = adc_read();printf("Raw value: 0x%03x, voltage: %f V\n", result, 3 * result * conversion_factor);
}int main()
{stdio_init_all();sleep_ms(2500);printf("adc test!\n");set_sys_clock_khz(133000, true); // 325us// GPIO initialisation.gpio_init(BUILTIN_LED);gpio_set_dir(BUILTIN_LED, 1);gpio_pull_up(BUILTIN_LED);adc_init();// Make sure GPIO is high-impedance, no pullups etcadc_gpio_init(29);// Select ADC input 3 (GPIO29)adc_select_input(3);while (true){
、、sleep_ms(1000);gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED// tight_loop_contents();measure_freqs();ADC_Reading();}return 0;
}static void measure_freqs(void) {uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);printf("pll_sys  = %dkHz\n", f_pll_sys);printf("pll_usb  = %dkHz\n", f_pll_usb);printf("rosc     = %dkHz\n", f_rosc);printf("clk_sys  = %dkHz\n", f_clk_sys);printf("clk_peri = %dkHz\n", f_clk_peri);printf("clk_usb  = %dkHz\n", f_clk_usb);printf("clk_adc  = %dkHz\n", f_clk_adc);printf("clk_rtc  = %dkHz\n", f_clk_rtc);
}

在这里插入图片描述

📒多通道读取方式

由于ADC共用一个ADC模数转换器,在多通道读取时,,需要采用轮流配置通道读取方式。

void ADC_Reading(void)
{// 12-bit conversion, assume max value == ADC_VREF == 3.3 Vconst float conversion_factor = 3.3f / (1 << 12);adc_select_input(2);//设置通道2uint16_t adc_2_raw = adc_read();//读取转换通道转换结果adc_select_input(3);//设置通道3uint16_t adc_3_raw = adc_read();//读取转换通道转换结果printf("Raw1 value: 0x%03x, voltage: %f V\n", adc_2_raw, 3 * adc_2_raw * conversion_factor);printf("Raw2 value: 0x%03x, voltage: %f V\n", adc_3_raw, 3 * adc_3_raw * conversion_factor);
}

📓ADC 通过DMA方式读取

  • 🐛 目前程序有个bug问题:不管设置的dma传输字节大小为DMA_SIZE_8还是DMA_SIZE_16,DMA采样的ADC数据结果都一样。

/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_ADC_DMA.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_ADC_DMA.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "hardware/adc.h"
#include "hardware/dma.h"
#include "hardware/clocks.h"
//#include "hardware/irq.h"
#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25// Channel 0 is GPIO26
#define CAPTURE_CHANNEL 0
#define SAMPLES 10
// Ideally the signal should be bandwidth limited to sample_frequency/2
#define SAMPLING_FREQUENCY 14000 // Sampling frequency in Hzuint16_t sampleBuffer[SAMPLES];
uint16_t streamBuffer[SAMPLES]; // Scaled ADC sample working bufferdma_channel_config cfg;
int dma_chan;// const char src[] = "Hello, world! (from DMA)";
// char dst[count_of(src)];static void measure_freqs(void);void ADC_Reading(void)
{// 12-bit conversion, assume max value == ADC_VREF == 3.3 Vconst float conversion_factor = 3.3f / (1 << 12);adc_select_input(0);//设置通道2uint16_t adc_0_raw = adc_read();//读取转换通道转换结果printf("Raw1 value:%d, voltage: %f V\n", adc_0_raw,adc_0_raw * conversion_factor);}int main()
{stdio_init_all();sleep_ms(2500);printf("adc DMA test!\n");// set_sys_clock_khz(133000, true); // 325us// GPIO initialisation.gpio_init(BUILTIN_LED);gpio_set_dir(BUILTIN_LED, 1);gpio_pull_up(BUILTIN_LED);adc_init();// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.adc_gpio_init(26 + CAPTURE_CHANNEL);//ADC_Reading();//1983//adc_set_round_robin(ADCopen==1 ? 1 : ADCopen==2 ? 3 : ADCopen==3 ? 7 : 15);adc_select_input(CAPTURE_CHANNEL);adc_fifo_setup(true,    // Write each completed conversion to the sample FIFOtrue,    // Enable DMA data request (DREQ)1,       // DREQ (and IRQ) asserted when at least 1 sample presentfalse,   // We won't see the ERR bit because of 8 bit reads; disable.true     // Shift each sample to 8 bits when pushing to FIFO);// Divisor of 0 -> full speed. Free-running capture with the divider is// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`// cycles (div not necessarily an integer). Each conversion takes 96// cycles, so// in general you want a divider of 0 (hold down the button// continuously) or > 95 (take samples less frequently than 96 cycle// intervals). This is all timed by the 48 MHz ADC clock.//adc_set_clkdiv((48000000/SAMPLING_FREQUENCY) - 1);adc_set_clkdiv(0);// Set up the DMA to start transferring data as soon as it appears in FIFO设置DMA,一旦数据出现在FIFO中就开始传输数据dma_chan = dma_claim_unused_channel(true);cfg = dma_channel_get_default_config(dma_chan);//获取给定通道的默认通道配置// Reading from constant address, writing to incrementing byte addresseschannel_config_set_transfer_data_size(&cfg, DMA_SIZE_16);channel_config_set_read_increment(&cfg, false);//因为就一个地址永远地写到同一个位置,目的是循环触发同一个DMA.channel_config_set_write_increment(&cfg, true);//FIFO的地址自增
//新增channel_config_set_irq_quiet(&cfg, true);//在QUIET模式下,通道不会在每个传输块结束时产生irq。channel_config_set_dreq(&cfg, DREQ_ADC); // pace data according to ADCchannel_config_set_chain_to(&cfg, dma_chan);//外设作为传输源,即ADC->DMAchannel_config_set_enable(&cfg, true);//设置DMA通道的配置,包括源地址、目的地址、传输字节数、传输方向、中断等。
//这里设置了源地址为ADC的FIFO,目的地址为streamBuffer,传输字节数为SAMPLES,传输方向为从ADC到streamBuffer,中断为DREQ_ADC。// Pace transfers based on availability of ADC samples// channel_config_set_dreq(&cfg, DREQ_ADC);dma_channel_configure(dma_chan, &cfg,(uint16_t*)sampleBuffer,   // dst 数据存储到目标缓冲区&adc_hw->fifo,  // srcSAMPLES,        // transfer count 传输数量,即采样点数true            // start immediately);
// Everything is ready to go. Tell the control channel to load the first// control block. Everything is automatic from here.dma_start_channel_mask(1u << dma_chan);// 开始传输printf("Starting capture\n");adc_run(true);// Start capturewhile (true){// Read the temperature from the onboard temperature sensor.//  float temperature = read_onboard_temperature(TEMPERATURE_UNITS);//   printf("Onboard temperature = %.02f %c\n", temperature, TEMPERATURE_UNITS);sleep_ms(1000);gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED// tight_loop_contents();measure_freqs();//ADC_Reading();// Wait for DMA to finish (may have already)dma_channel_wait_for_finish_blocking(dma_chan);// Stop and clean out FIFOadc_run(false);adc_fifo_drain();// Copy samples into buffer for approxFFT SAMPLESfor (int i = 0; i < SAMPLES; i++) {streamBuffer[i] = sampleBuffer[i];// streamBuffer[i] = (uint16_t)((sampleBuffer[i]&0x0f)<<8)+(uint16_t)sampleBuffer[i+1] ;printf("%d ",streamBuffer[i]);if (i % 10 == 9)printf("\n");// sleep_ms(100);}sleep_ms(1000);dma_channel_set_trans_count(DREQ_ADC, 10, true);//设置DMA传输的字节数,这里是10个字节,即10个采样点。// Now we have a copy of the samples we can start capture again// dma_channel_configure(dma_chan, &cfg,//                       (uint16_t*)sampleBuffer,   // dst//                       &adc_hw->fifo,  // src//                       SAMPLES,        // transfer count//                       true            // start immediately//                      );// Restart the ADC captureadc_run(true);}return 0;
}static void measure_freqs(void) {uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);printf("pll_sys  = %dkHz\n", f_pll_sys);printf("pll_usb  = %dkHz\n", f_pll_usb);printf("rosc     = %dkHz\n", f_rosc);printf("clk_sys  = %dkHz\n", f_clk_sys);printf("clk_peri = %dkHz\n", f_clk_peri);printf("clk_usb  = %dkHz\n", f_clk_usb);printf("clk_adc  = %dkHz\n", f_clk_adc);printf("clk_rtc  = %dkHz\n", f_clk_rtc);// Can't measure clk_ref / xosc as it is the ref
}

在这里插入图片描述


http://www.mrgr.cn/news/24237.html

相关文章:

  • 如何用ChatGPT创建阅读10W+爆款文章标题
  • 重温学习之C语言学习笔记3
  • 强密码策略+使用jasypt保存用户密码
  • Linux cut命令详解使用:掌握高效文本切割
  • Web3附录
  • [240911] 11 款最佳 Linux 控制台文件管理器 | OpenAI 或将推出每月2000美元的 LLM 订阅服务
  • 网络高级(学习)2024.9.10
  • vscode设置vue标签不换行
  • 善于善行——贵金属回收
  • thinkphp6 事务不起作用了咋回事
  • 手动用梯度下降法和随机梯度下降法实现一元线性回归
  • Windows安装Redis环境
  • LeetCode题练习与总结:矩形面积--223
  • Docker常用操作(基础篇)
  • Nestjs仿小米商城企业级Nodejs RBAC 微服务项目实战视频教程+Docker Swarm K8s云原生分布式部署教程分享
  • Docker部署Doris数据库
  • docker的相关网络问题
  • 关于大模型在产品开发中所面临的问题,利用大模型技术解决很简单!
  • 【编程入门】与7无关的数?
  • 潘多拉的盒子还是阿拉丁的神灯:揭示RAG噪声在大语言模型中的作用