ADC 使用 简介 ROC-RK3576-PC å¼€å‘æ¿ä¸Šçš„ AD 接å£æœ‰ä¸¤ç§ï¼Œåˆ†åˆ«ä¸ºï¼šæ¸©åº¦ä¼ 感器 (Temperature Sensor)ã€é€æ¬¡é€¼è¿‘ADC (Successive Approximation Register) 。其ä¸ï¼š TS-ADC(Temperature Sensor):支æŒä¸ƒé€šé“。 SAR-ADC(Successive Approximation Register):支æŒå…«é€šé“å•ç«¯12ä½çš„SAR- ADC,最大转æ¢é€ŸçŽ‡ä¸º1MSPS,采用20MHzçš„A/D转æ¢å™¨æ—¶é’Ÿã€‚ å†…æ ¸é‡‡ç”¨å·¥ä¸š I/O å系统æ¥æŽ§åˆ¶ ADC,该å系统主è¦ä¸º AD 转æ¢æˆ–者 DA è½¬æ¢ çš„ä¼ æ„Ÿå™¨è®¾è®¡ã€‚ 下é¢ä»¥ SAR-ADC 为例åï¼Œä»‹ç» ADC 的基本é…置方法。 硬件 ROC-RK3576-PC çš„ADC接å£å›¾å¦‚下: DTSé…ç½® é…ç½®DTS节点 ROC-RK3576-PC SAR-ADC çš„ DTS 节点在 "kernel/arch/arm64/boot/dts/rockchip/rk3576.dtsi" 文件ä¸å®šä¹‰ï¼Œå¦‚下所示 : saradc: adc@2ae00000 { compatible = "rockchip,rk3576-saradc", "rockchip,rk3576-saradc"; reg = <0x0 0x2ae00000 0x0 0x10000>; interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>; #io-channel-cells = <1>; clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; clock-names = "saradc", "apb_pclk"; resets = <&cru SRST_P_SARADC>; reset-names = "saradc-apb"; status = "disabled"; }; 用户首先需在 DTS 文件ä¸æ·»åŠ ADC 的资æºæ述: kernel/arch/arm64/boot/dts/rockchip/rk3576-firefly-demo.dtsi : adc_demo: adc_demo{ compatible = "firefly,rk3576-adc"; status = "disabled"; io-channels = <&saradc 4>; }; 在驱动文件ä¸åŒ¹é… DTS 节点 用户驱动å¯å‚考 Firefly adc demo :"kernel/drivers/iio/adc/adc-firefly- demo.c",这是一个侦测风扇状æ€çš„驱动,但实际 ROC-RK3576-PC çš„ SARADC通 é“4 并没有用在风扇ä¸ï¼Œæ‰€ä»¥é©±åŠ¨åªæ˜¯ç¤ºä¾‹ 。 首先在驱动文件ä¸å®šä¹‰ "of_device_id" 结构体数组: static const struct of_device_id firefly_adc_match[] = { { .compatible = "firefly,rk3576-adc" }, {}, }; 然åŽå°†è¯¥ç»“构体数组填充到è¦ä½¿ç”¨ ADC çš„ platform_driver ä¸ï¼š static struct platform_driver firefly_adc_driver = { .probe = firefly_adc_probe, .remove = firefly_adc_remove, .driver = { .name = "firefly_adc", .owner = THIS_MODULE, .of_match_table = firefly_adc_match, }, }; 接ç€åœ¨ firefly_adc_probe ä¸å¯¹ DTS æ‰€æ·»åŠ çš„èµ„æºè¿›è¡Œè§£æžï¼š static int firefly_adc_probe(struct platform_device *pdev) { printk("firefly_adc_probe!\n"); count = 0; chan = iio_channel_get(&(pdev->dev), NULL); if (IS_ERR(chan)) { chan = NULL; printk("%s() have not set adc chan\n", __FUNCTION__); return -1; } fan_insert = false; if (chan) { INIT_DELAYED_WORK(&adc_poll_work, firefly_demo_adc_poll); schedule_delayed_work(&adc_poll_work,1000); } return 0; } 驱动说明 èŽ·å– AD é€šé“ struct iio_channel *chan; #定义 IIO 通é“结构体 chan = iio_channel_get(&pdev->dev, NULL); #èŽ·å– IIO 通é“结构体 注æ„: "iio_channel_get" 通过 probe å‡½æ•°ä¼ è¿›æ¥çš„å‚æ•° pdev èŽ·å– IIO 通é“结构 体,probe 函数如下: static int XXX_probe(struct platform_device *pdev); è¯»å– AD é‡‡é›†åˆ°çš„åŽŸå§‹æ•°æ® int val,ret; ret = iio_read_channel_raw(chan, &val); 调用 iio_read_channel_raw å‡½æ•°è¯»å– AD 采集的原始数æ®å¹¶å˜å…¥ val ä¸ã€‚ 计算采集到的电压 ä½¿ç”¨æ ‡å‡†ç”µåŽ‹å°† AD 转æ¢çš„值转æ¢ä¸ºç”¨æˆ·æ‰€éœ€è¦çš„电压值。其计算公å¼å¦‚下: Vref / (2^n-1) = Vresult / raw 注æ„: Vref ä¸ºæ ‡å‡†ç”µåŽ‹ n 为 AD 转æ¢çš„ä½æ•° Vresult 为用户所需è¦çš„采集电压 raw 为 AD é‡‡é›†çš„åŽŸå§‹æ•°æ® ä¾‹å¦‚ï¼Œæ ‡å‡†ç”µåŽ‹ä¸º 1.8V,AD 采集ä½æ•°ä¸º 12 ä½ï¼ŒAD 采集到的原始数æ®ä¸º 445 ,则: Vresult = (1800mv * 445) / 4095; 接å£è¯´æ˜Ž struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel); åŠŸèƒ½ï¼šèŽ·å– iio 通é“æè¿° å‚数: dev: 使用该通é“的设备æ述指针 consumer_channel: 该设备所使用 çš„ IIO 通é“æ述指针 void iio_channel_release(struct iio_channel *chan); 功能:释放 iio_channel_get 函数获å–åˆ°çš„é€šé“ å‚数: chan:è¦è¢«é‡Šæ”¾çš„通é“æ述指针 int iio_read_channel_raw(struct iio_channel *chan, int *val); åŠŸèƒ½ï¼šè¯»å– chan é€šé“ AD 采集的原始数æ®ã€‚ å‚数: chan:è¦è¯»å–的采集通é“指针 val:å˜æ”¾è¯»å–结果的指针 调试方法 Demo 程åºä½¿ç”¨ 在 "kernel/arch/arm64/boot/dts/rockchip/rk3576-firefly-demo.dtsi" ä¸ä½¿ 能 adc_demo ,将 "disabled" 改为 "okay": adc_demo: adc_demo{ status = "okay"; compatible = "firefly,rk3576-adc"; io-channels = <&saradc 4>; }; ç¼–è¯‘å†…æ ¸ï¼Œçƒ§å½•å†…æ ¸åˆ° ROC-RK3576-PC å¼€å‘æ¿ä¸Šï¼Œç„¶åŽæ’拔风扇时,会打å°å†… æ ¸ log ä¿¡æ¯å¦‚下: [ 73.513351][ T173] Fan insert! raw= 449 Voltage= 197mV [ 75.893182][ T173] Fan out! raw= 4095 Voltage=1800mV 获å–所有 ADC 值 有个便æ·çš„方法å¯ä»¥æŸ¥è¯¢åˆ°æ¯ä¸ª SARADC 的值: cat /sys/bus/iio/devices/iio\:device0/in_voltage*_raw FAQs 为何按上é¢çš„æ¥éª¤ç”³è¯· SARADC,会出现申请报错的情况? 驱动需è¦èŽ·å–ADC通é“æ¥ä½¿ç”¨æ—¶ï¼Œéœ€è¦å¯¹é©±åŠ¨çš„åŠ è½½æ—¶é—´è¿›è¡ŒæŽ§åˆ¶ï¼Œå¿…é¡»è¦åœ¨ saradcåˆå§‹åŒ–之åŽã€‚saradc是使用module_platform_driver()进行平å°è®¾å¤‡é©±åŠ¨ 注册,最终调用的是module_init()ã€‚æ‰€ä»¥ç”¨æˆ·çš„é©±åŠ¨åŠ è½½å‡½æ•°åªéœ€ä½¿ç”¨æ¯” module_init()优先级低的,例如:late_initcall(),就能ä¿è¯é©±åŠ¨çš„åŠ è½½çš„æ—¶ 间比saradcåˆå§‹åŒ–时间晚,å¯é¿å…出错。