mini6410 實現 linux adc驅動詳解--muge0913版 .
mini6410 實現 linux adc驅動詳解--muge0913版 .
在嵌入式學習中嵌入式linux驅動佔據著十分重要的地位,它不僅牽扯到操作系統、linux內核知識,同時作為開發者你必須了解面對的硬體體系結構和工作原理。在這本人muge0913對linux ad開發做了詳細的介紹。
此文章僅供技術交流請勿商用。轉載請註明出處:
http://blog.csdn.net/muge0913/article/details/7059241
一、ad轉換器介紹
在這裡我們先從adc的工作原理出發,由淺入深的學習,對於已經掌握adc硬體知識的閱讀者可跳過此部分。
adc的基礎知識我們可直接參考郭天祥老師的教材,免積分下載地址:
http://download.csdn.net/detail/muge0913/3903535
二、ARM中ad轉換器介紹
這裡我們以arm11為例:
①簡介:
.
10-bit/12-bit的CMOSADC(模數轉換器)是一個8通道模擬輸入的回收型設備。5MHz的A / D轉換時鐘,最高轉換率的1MSPS轉換到10-bit/12-bit二進位數字編碼的模擬輸入信號。A / D轉換片上採樣和保持功能。支持省電模式。
②特性:
③配置:如果簡單的驅動ad,只配置ADCCON寄存器即可,如要實現觸摸屏的工能則要其他寄存器
註:在下面代碼中我們由此部分的註釋
三、linux中的adc驅動程序及註釋view plaincopy to clipboardprint?
01.#include
02.#include
03.#include
04.#include
05.#include
06.#include
07.#include
08.#include
09.#include
10.#include
11.#include
12.#include
13.
14.
15.#include
16.#include
17.#include
18.
19.#include
20.#include
21.#include
22.#include
23.static void __iomem * base_addr;
24.static struct clk *adc_clock;
25.
26.
27.#define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name))
28.#define ADCCON __ADCREG(S3C_ADCCON) // ADC control
29.#define ADCTSC __ADCREG(S3C_ADCTSC) // ADC touch screen control
30.#define ADCDLY __ADCREG(S3C_ADCDLY) // ADC start or Interval Delay
31.#define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0
32.#define ADCDAT1 __ADCREG(S3C_ADCDAT1) // ADC conversion data 1
33.#define ADCUPDN __ADCREG(S3C_ADCUPDN) // Stylus Up/Down interrupt status
34.
35.#define PRESCALE_DIS (0 << 14)
36.#define PRESCALE_EN (1 << 14)
37.#define PRSCVL(x) ((x) << 6)
38.#define ADC_INPUT(x) ((x) << 3)
39.#define ADC_START (1 << 0)
40.#define ADC_ENDCVT (1 << 15)
41.
42.#define DEVICE_NAME "adc_dev"
43.static int adc_init()
44.{
45. unsigned int preScaler = 0XFF;
46. ADCCON = (1<<14)|(preScaler<<6)|(0<<3)|(0<<2);
47. ADCCON |= ADC_START;
48. return 0;
49.}
50.static int adc_open(struct inode *inode ,struct file *filp)
51.{
52. adc_init();
53. return 0;
54.}
55.static int adc_release(struct inode *inode,struct file *filp)
56.{
57. return 0;
58.}
59.static ssize_t adc_read(struct file *filp,char __user *buff,size_t size,loff_t *ppos)
60.{
61. ADCCON |= ADC_START;
62. while(ADCCON & 0x01);//check if Enable_start is low
63. while(!(ADCCON &0x8000));/*檢查轉換是否結束*/
64. return (ADCDAT0 & 0x3ff);
65.}
66.
67.static struct file_operations dev_fops =
68.{
69. .owner = THIS_MODULE,
70. .open = adc_open,
71. .release = adc_release,
72. .read = adc_read,
73.};
74.
75.static struct miscdevice misc =
76.{
77. .minor = MISC_DYNAMIC_MINOR,
78. .name = DEVICE_NAME,
79. .fops = &dev_fops,
80.};
81.
82.static int __init dev_init()
83.{
84. int ret;
85.
86.
87. base_addr =ioremap(SAMSUNG_PA_ADC,0X20);//地址映射
88. if(base_addr == NULL)
89. {
90. printk(KERN_ERR"failed to remap\n");
91. return -ENOMEM;
92. }
93.
94. adc_clock = clk_get(NULL,"adc");//激活adc時鐘模塊
95. if(!adc_clock)
96. {
97. printk(KERN_ERR"failed to get adc clock\n");
98. return -ENOENT;
99. }
100. clk_enable(adc_clock);
101.
102.
103. ret = misc_register(&misc);//混雜設備註冊
104. printk("dev_init return ret:%d\n",ret);
105. return ret;
106.}
107.static void __exit dev_exit()
108.{
109. iounmap(base_addr);//取消映射
110.
111. if(adc_clock)//disable adc clock取消adc時鐘
112. {
113. clk_disable(adc_clock);
114. clk_put(adc_clock);
115. adc_clock =NULL;
116. }
117. misc_deregister(&misc);//註銷混雜設備
118.
119.}
120.module_init(dev_init);
121.module_exit(dev_exit);
122.
123.MODULE_LICENSE("GPL");
124.MODULE_AUTHOR("MUGE0913");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void __iomem * base_addr;
static struct clk *adc_clock;
#define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name))
#define ADCCON __ADCREG(S3C_ADCCON) // ADC control
#define ADCTSC __ADCREG(S3C_ADCTSC) // ADC touch screen control
#define ADCDLY __ADCREG(S3C_ADCDLY) // ADC start or Interval Delay
#define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0
#define ADCDAT1 __ADCREG(S3C_ADCDAT1) // ADC conversion data 1
#define ADCUPDN __ADCREG(S3C_ADCUPDN) // Stylus Up/Down interrupt status
#define PRESCALE_DIS (0 << 14)
#define PRESCALE_EN (1 << 14)
#define PRSCVL(x) ((x) << 6)
#define ADC_INPUT(x) ((x) << 3)
#define ADC_START (1 << 0)
#define ADC_ENDCVT (1 << 15)
#define DEVICE_NAME "adc_dev"
static int adc_init()
{
unsigned int preScaler = 0XFF;
ADCCON = (1<<14)|(preScaler<<6)|(0<<3)|(0<<2);
ADCCON |= ADC_START;
return 0;
}
static int adc_open(struct inode *inode ,struct file *filp)
{
adc_init();
return 0;
}
static int adc_release(struct inode *inode,struct file *filp)
{
return 0;
}
static ssize_t adc_read(struct file *filp,char __user *buff,size_t size,loff_t *ppos)
{
ADCCON |= ADC_START;
while(ADCCON & 0x01);//check if Enable_start is low
while(!(ADCCON &0x8000));/*檢查轉換是否結束*/
return (ADCDAT0 & 0x3ff);
}
static struct file_operations dev_fops =
{
.owner = THIS_MODULE,
.open = adc_open,
.release = adc_release,
.read = adc_read,
};
static struct miscdevice misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init()
{
int ret;
base_addr =ioremap(SAMSUNG_PA_ADC,0X20);//地址映射
if(base_addr == NULL)
{
printk(KERN_ERR"failed to remap\n");
return -ENOMEM;
}
adc_clock = clk_get(NULL,"adc");//激活adc時鐘模塊
if(!adc_clock)
{
printk(KERN_ERR"failed to get adc clock\n");
return -ENOENT;
}
clk_enable(adc_clock);
ret = misc_register(&misc);//混雜設備註冊
printk("dev_init return ret:%d\n",ret);
return ret;
}
static void __exit dev_exit()
{
iounmap(base_addr);//取消映射
if(adc_clock)//disable adc clock取消adc時鐘
{
clk_disable(adc_clock);
clk_put(adc_clock);
adc_clock =NULL;
}
misc_deregister(&misc);//註銷混雜設備
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MUGE0913");四、測試程序view plaincopy to clipboardprint?
01.#include
02.#include
03.#include
04.
05.int main()
06.{
07. int fp,adc_data,i;
08. fp = open("/dev/adc_dev",O_RDWR);
09. for(i=0;i<100;i++)
10. {
11. adc_data = read(fp,NULL,0);
12. printf("%d\n",adc_data);
13. sleep(1);
14. }
15. close(fp);
16. return 0;
17.}
#include
#include
#include
int main()
{
int fp,adc_data,i;
fp = open("/dev/adc_dev",O_RDWR);
for(i=0;i<100;i++)
{
adc_data = read(fp,NULL,0);
printf("%d\n",adc_data);
sleep(1);
}
close(fp);
return 0;
}五、運行效果
《解決方案》
學習鳥 謝謝分享 《解決方案》
多路接入如何處理?通道選擇如何處理?不同通道性能要求不同如何配置?