Today, the company's second version of the infrared remote control has been improved, and it is also more sensitive when running on Android, gpio simulation of SPI can also work, read the book, corrected the meeting, it is more than when I return to the dormitory. Think about it. There is an ad module on ok6410. After searching for information on the Internet, I found that I could try to find out if I could. Okay, it took me almost an hour. Haha, I finally got it done.
See the code below:
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/device.h> /* device_create()*/ #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <mach/map.h> #include <plat/regs-adc.h> #include <mach/map.h> static void __iomem *base_addr; #define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name)) #define ADCCON __ADCREG(S3C_ADCCON) // ADC control #define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0 #define ADC_START (1 << 0) #define ADC_SIZE 0x1000 #define ADC_MAJOR 240 static int adc_major = ADC_MAJOR; struct adc_dev { struct cdev cdev; unsigned char mem[ADC_SIZE]; }; struct adc_dev *adc_devp; static int adc_init(void) { 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) {printk("$$$$$%s$$$$$\n", __func__); adc_init(); return 0; } static int adc_release(struct inode *inode, struct file *filp) { printk("$$$$$$%s$$$$$\n", __func__); return 0; } static ssize_t adc_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { unsigned int count = size; int ret = 0; printk("$$$$$%s$$$$$\n", __func__); ADCCON |= ADC_START; while(ADCCON & 0x01);//check if Enable_start is low while(!(ADCCON &0x8000)); ret = ADCDAT0 & 0x3ff; count = copy_to_user(buf,(char *)&ret,sizeof(ret)); return sizeof(ret); } static const struct file_operations adc_fops = { .owner = THIS_MODULE, .read = adc_read, .open = adc_open, .release = adc_release, }; static void adc_setup_cdev(struct adc_dev *dev, int index) { int err, devno = MKDEV(adc_major, index); cdev_init(&dev->cdev, &adc_fops); dev->cdev.owner = THIS_MODULE; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding LED%d", err, index); } struct class *myclass; int adc_dev_init(void) { int result; printk("$$$$$$%s$$$$$$\n", __func__); dev_t devno = MKDEV(adc_major, 0); if (adc_major) result = register_chrdev_region(devno, 1, "adc"); else { result = alloc_chrdev_region(&devno, 0, 1, "adc"); adc_major = MAJOR(devno); } if (result < 0) return result; adc_devp = kmalloc(sizeof(struct adc_dev), GFP_KERNEL); if (!adc_devp) { result = - ENOMEM; goto fail_malloc; } memset(adc_devp, 0, sizeof(struct adc_dev)); adc_setup_cdev(adc_devp, 0); myclass = class_create(THIS_MODULE,"test_char"); device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc"); base_addr = ioremap(0x7E00B000,0X20); if(base_addr == NULL) { printk("failed to remap\n"); return -ENOMEM; } return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } void adc_dev_exit(void) { cdev_del(&adc_devp->cdev); kfree(adc_devp); unregister_chrdev_region(MKDEV(adc_major, 0), 1); class_destroy(myclass); device_destroy(myclass,MKDEV(adc_major,0)); iounmap(base_addr); } MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_LICENSE("Dual BSD/GPL"); module_param(adc_major, int, S_IRUGO); module_init(adc_dev_init); module_exit(adc_dev_exit);
The Code was not written by myself. For reference, I removed unnecessary code a little and added some test prints to digest it.
The above code mainly uses the two registers.
Let's take a look at the principle diagram and pins of the AD module.
Its pin is
Let's take a look at these two registers.
ADCCON = (1<<14) | (preScaler<<6) | (0<<3) | (0<<2);
Here 1 <14 is to start the adconversion. Prescaler <6 is the value of the ADC preset 0 x ff, 0 <3 indicates that the ADC channel 0 is the ad module. Then
0 <2 is the normal operation mode.
After the analysis, the control register is the data register.
while(ADCCON & 0x01);//check if Enable_start is low while(!(ADCCON &0x8000)); ret = ADCDAT0 & 0x3ff;
While (adccon & 0x01); judge whether the adconversion is complete. While (! (Adccon & 0x8000); determines whether the adswitch is over.
Ret = adcdat0 & 0x3ff;, the value after normal ADC conversion.
That's it. It's easy? Okay. You can only say that.
Then, makefile:
obj-m :=adc.o
Then create a makemod. The Code is as follows:
make -C /home/eastmoon/work/linux2.6.28/ M=`pwd` modules
Then, you only need source makemod to compile it into buzzer. Ko.
OK, the driver is like this, and then the application
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #define DEVICE "/dev/myadc" int main() { int fp,adc_data,i; int ret; fp = open(DEVICE, O_RDWR); if(fp < 0) { printf("open failed!\n"); return -1; } while(1) { ret = read(fp,&adc_data,sizeof(adc_data)); if(ret<0) { printf("read ADC failed!\n"); return -1; } else { printf("Read ADC value is: %d\n",adc_data); } sleep(1); } close(fp); return 0; }
Then makefile:
CC = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-gcc adcapp:adcapp.o $(CC) -o adcapp adcapp.oadcapp.o:adcapp.c $(CC) -c adcapp.c clean : rm adcapp.o
Finally, it was done on the board. Copy ADC. Ko and adcapp to the SD card and then to the board. Start test:
Init is in. If no error is displayed, everything is OK.
Then the mknod Device File
Okay, the device node is OK, and then the test program is started.
At the beginning, the potentiometer is positioned like this, and then the potentiometer is rotated.
If the rotation range is greater:
End:
OK. The test passed. Tomorrow is Friday, and the weekend is over. The weather is getting hotter and hotter. Continue to work hard. I found that my knowledge system is far from enough, which is quite different from my colleagues. Come on ....