mini2440 ADC adjustable resistor driver development source code (miscellaneous device driver framework)

Publisher:SereneMeadow7Latest update time:2024-06-20 Source: elecfansKeywords:mini2440  ADC Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

/*********************************************************/

/****s3c2440 ADC adjustable resistor driver development source code (miscellaneous device driver framework)****/

/********************************************************/

#include

#include

#include

#define DEVICE_NAME "adc_driver" /*Device name*/

static void __iomem *adc_base; /*Defines a memory address used to save virtual mapping*/
static struct clk *adc_clk; /*Save the ADC clock obtained from the platform clock queue*/


DECLARE_MUTEX(ADC_LOCK); /*Declare and initialize a semaphore ADC_LOCK for mutually exclusive access to ADC resources*/
static DECLARE_WAIT_QUEUE_HEAD(adc_waitq); /*Define and initialize a waiting queue adc_waitq for blocking access to ADC resources*/


static volatile int ev_adc = 0; ///*Used to identify whether the data after AD conversion can be read, 0 means it cannot be read*/
static int adc_data; /*Used to save the read AD converted value, which is read in the ADC interrupt*/

/*ADC interrupt service program, this service program mainly reads the AD converted value from the ADC data register*/
static irqreturn_t adc_irq(int irq, void *dev_id)
{
/*Ensures that the application reads the AD converted value once here,
avoiding multiple interruptions and multiple readings of the AD converted value after the application reads once*/
if(!ev_adc)
{
/*The read AD converted value is saved in the global variable adc_data. S3C2410_ADCDAT0 is defined in regs-adc.h.
Why is it necessary to AND the previous 0x3ff here? It's very simple, because the AD converted data is saved in bits 0-9 of ADCDAT0,
so after ANDing with 0x3ff (i.e.: 1111111111), the data of bits 0-9 is obtained, and the remaining bits are all 0*/
adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff;
ev_adc = 1; //Set the readable flag to 1 and wake up the waiting queue
wake_up_interruptible(&adc_waitq);
}
return IRQ_HANDLED;
}

/*ADC device driver open interface function*/
static int adc_open(struct inode *inode, struct file *file)
{
int ret;

/*Request ADC interrupt service. Here we use the shared interrupt: IRQF_SHARED. Why do we use the shared interrupt? Because
this interrupt number is also used in the touch screen driver. The interrupt service program is: adc_irq is implemented below. IRQ_ADC is the interrupt number of ADC. Note:
The last parameter of the interrupt request function must not be NULL, otherwise the interrupt request will fail. If this parameter is not used in the interrupt service program
, just give a random value. I will give 1 here*/
ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, 1);
if (ret)
{
/*Error handling*/
printk(KERN_ERR "IRQ%d error %dn", IRQ_ADC, ret);
return -EINVAL;
}

return 0;
}


/*Set ADC control register and start AD conversion*/
static void start_adc(void)
{
unsigned int tmp;

tmp = (1 << 14) | (255 << 6) | (0 << 3);/* 0 1 00000011 000 0 0 0 */
writel(tmp, adc_base + S3C2410_ADCCON); /*AD prescaler enabled, analog input channel set to AIN0*/

tmp = readl(adc_base + S3C2410_ADCCON);
tmp = tmp | (1 << 0); /* 0 1 00000011 000 0 0 1 */
writel(tmp, adc_base + S3C2410_ADCCON); /*AD conversion starts*/
}


/*ADC device driver read interface function*/
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
/*Try to get the semaphore (ie: lock)*/
if (down_trylock(&ADC_LOCK))
{
return -EBUSY;
}

if(!ev_adc)/*Indicates that there is no AD converted data yet, and it cannot be read*/
{
if(filp->f_flags & O_NONBLOCK) //If the application uses non-blocking reading, an error will be returned
{
return -EAGAIN;
}
else/*Read in blocking mode*/
{
start_adc(); /*Set the ADC control register and start AD conversion*/
wait_event_interruptible(adc_waitq, ev_adc); /*Put the waiting queue to sleep*/
}
}
/*Getting here means that there is AD converted data, so the flag is cleared to 0 for the next reading*/
ev_adc = 0;
/*Send the read AD converted value to the upper application*/
copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));
up(&ADC_LOCK); /*Release the acquired semaphore (ie: unlock)*/

return sizeof(adc_data);
}


/*ADC device driver shutdown interface function*/
static int adc_release(struct inode *inode, struct file *filp)
{
return 0;
}


/*Related operations of character devices*/
static struct file_operations adc_fops =
{
.owner = THIS_MODULE,
.open = adc_open,
.read = adc_read,
.release = adc_release,
};

/*misc device structure implementation*/
static struct miscdevice adc_miscdev =
{
.minor = MISC_DYNAMIC_MINOR, /*minor device number, defined in miscdevice.h, 255*/
.name = DEVICE_NAME, /* device name*/
.fops = &adc_fops, /* ADC device file operation*/
};


static int __init adc_init(void)
{
int ret;
/*Get the ADC clock from the platform clock queue. Why do we need to get this clock here? Because the conversion frequency of the ADC is related to the clock.
Some system clocks are defined in arch/arm/plat-s3c24xx /s3c2410-clock.c*/
adc_clk = clk_get(NULL, "adc");
if (!adc_clk)
{
/*Error handling*/
printk(KERN_ERR "failed to find adc clock sourcen");
return -ENOENT;
}

/*After the clock is acquired, it must be enabled before it can be used. clk_enable is defined in arch/arm/plat-s3c/clock.c*/
clk_enable(adc_clk);

/*Map the IO space occupied by the ADC IO port to the virtual address of the memory. ioremap is defined in io.h.
Note: IO space can only be used after mapping. The operation of virtual address in the future is the operation of IO space. S3C2410_PA_ADC
is the base address of ADC controller, defined in mach-s3c2410/include/mach/map.h. 0x20 is the length of virtual address*/
adc_base = ioremap(S3C2410_PA_ADC, 0x20);
if (adc_base == NULL)
{

printk(KERN_ERR "Failed to remap register blockn"); /*Error handling*/
ret = -EINVAL;
goto err_noclk;
}

/*Register ADC as misc device, misc_register is defined in miscdevice.h. The adc_miscdev structure definition
and internal interface functions are described in step ②. MISC_DYNAMIC_MINOR is the minor device number, defined in miscdevice.h*/
ret = misc_register(&adc_miscdev);
if (ret)
{
/*Error handling*/
printk(KERN_ERR "cannot register miscdev on minor=%d (%d)n",
MISC_DYNAMIC_MINOR, ret);
goto err_nomap;
}

printk(DEVICE_NAME " initialized!n");

return 0;
//The following is the jump point of the error handling above
err_noclk:
clk_disable(adc_clk);
clk_put(adc_clk);

err_nomap:
iounmap(adc_base);

return ret;
}

static void __exit adc_exit(void)
{
free_irq(IRQ_ADC, 1);/*Release interrupt*/
iounmap(adc_base);/*Release virtual address mapping space*/

if (adc_clk)/*Shield and destroy clock*/
{
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}

misc_deregister(&adc_miscdev);/*Cancel misc device*/
}

/*The exported semaphore ADC_LOCK is used in the touch screen driver, because the touch screen driver and ADC driver share
93. Related registers. In order to avoid resource competition, semaphores are used to ensure mutual exclusive access to resources*/
//EXPORT_SYMBOL(ADC_LOCK);
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("youshaohui 2012.10.31 in ruanjianyuan");
MODULE_DESCRIPTION("s3c2440 ADC Driver");

//=======================================================================

The application test code is developed as follows:

//=======================================================================


#include

#define MYADC "/dev/adc_driver"

void Delay_MS( unsigned int time)  //50 ns
{
unsigned int i,j;

for ( i=0; i {
for(j=0;j<30000;j++)
{

}
}
}
//adc可调电阻
int main(void)
{
int fd;
int i=0;
unsigned int value = -1;
char buf[30]={0};

fd = open(MYADC,O_RDWR,0666);
if (fd < 0)
{
perror("open device adc_driver errorn");
exit(1);
}
printf("open /dev/adc_driver success!n");


while(1)
{
read(fd,&value,4);

printf("result value=%dn",value);

Delay_MS(1000);
}

if(close(fd)<0)
{
perror("close errorn");
exit(1);
}

return 0;
}


Keywords:mini2440  ADC Reference address:mini2440 ADC adjustable resistor driver development source code (miscellaneous device driver framework)

Previous article:Summary and analysis of IIC timing problems in mini2440 debugging
Next article:3 ways to compile the driver into the kernel (using mini2440 key as an example)

Recommended ReadingLatest update time:2024-11-23 04:47

mini2440 simple nandflash driver code record (2.6.32.2 kernel)
#include linux/module.h #include linux/types.h #include linux/init.h #include linux/kernel.h #include linux/string.h #include linux/ioport.h #include linux/platform_device.h #include linux/delay.h #include linux/err.h #include linux/slab.h #include linux/clk.h #include linux/cpufreq.h   #include linux/mtd/
[Microcontroller]
Running bare metal programs on mini2440
Are you still foolishly using this method to run bare metal programs? The development board is started with norflash, and the led.bin bare metal program is burned into nandflash through the supervivi auxiliary software in norflash, and then run it? This method is time-consuming, and everything in nandflash will be e
[Microcontroller]
ADC signal-to-noise ratio analysis and high-speed and high-resolution ADC circuit
Source: China IC Technology Market In military fields such as radar and navigation, due to the wide signal bandwidth (sometimes may be higher than 10MHz), the sampling rate of the ADC is required to be higher than 30MSPS and the resolution is greater than 10 bits. At present, high-speed and high-resolution ADC devices
[Analog Electronics]
LED driver analysis of mini2440
I have been watching LDD3 for a while, and have practiced most of the routines in it. Now onto the real driver learning. Starting from the driver provided by Friendly Arm mini2440, analyze some basic drivers to improve your understanding of drivers and improve your programming capabilities. Let's start with the analys
[Microcontroller]
Solution to abnormal data reading of STM8 ADC
I did a project to measure voltage and current of stm8, and found that when the adc channel was connected to VCC through a 10k resistor, the ADC data output was only more than 200. Logically, the 10-bit adc should output more than 1000. Since the data output of the adc is 16 bits, I suspected that the number of data b
[Microcontroller]
Solution to abnormal data reading of STM8 ADC
What is the difference between the number of ADC bits and ENOB of an oscilloscope? What is the impact on the measurement?
The number of ADC bits in an oscilloscope is one of the most scrutinized specifications. As a result, many engineers tend to use this as the only specification to determine the quality of an oscilloscope. While this is a very important specification, the number of ADC bits can be greatly compromised if the rest of the
[Test Measurement]
Vertical resolution of digital oscilloscopes
Vertical resolution concept The first step in measuring analog signals with a digital oscilloscope is to use an ADC (analog-to-digital converter) to convert the analog signal received by the probe into a digital signal. The resolution of the ADC digital-to-analog conversion chip directly determines the sampling accura
[Test Measurement]
Vertical resolution of digital oscilloscopes
24-bit analog-to-digital converter AD7713 and its applications
    Abstract: The article introduces in detail the pin definitions, internal control word definitions, hardware interfaces and usage precautions of AD's 24-bit analog-to-digital converter AD7713. It lists interface examples and programming methods between AD7713 and 8031 ​​microcontrollers, and also gives detailed in
[Analog Electronics]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号