Mini2440 driver qitan-LED driver and test (dynamic loading)

Source: Internet
Author: User

My blog: http://blog.csdn.net/muyang_ren

Function: The Development Board dynamically loads the LED driver module and passes the test program.

System: Ubuntu 14.04

Driver cross-compilation kernel: linux-2.6.32.2 // build cross-Compilation

Development Board: mini2440 (128 M nandflash) // for how to download Linux to the Development Board, click. For Linux rootfs, select rootfs_rtm_2440.img (Disk Directory: image/Linux/RTM)

Tools required for development: NFS network file minicom Vim

Linux File directory:/opt/friendlyarm/mini2440/linux-2.6.32.2

Self-driving Directory:/home/lianghuiyong/my2440drivers

Note: I have cropped the LED driver in the kernel of my Development Board, including some drivers to be written later. It is very easy to crop the kernel. After the make menuconfig menu, the corresponding driver space is blank.


We recommend a good Vim plug-in: ma6174, because I am using NFS network mounting and using a router to access the Internet. When you don't want to use a router, when using a wireless network, I still want to use NFS network to mount files. The others are not changed. I just want to modify the network cable. The network cable we access is usually arranged by B. Remember what the teacher said, if you only connect to the LAN and do not access the Internet, you only need to select a route for one end of the network cable and B route for the other end. Just connect the Development Board to your computer.


(1) Analysis of LED principles

It's shameful to steal pictures. I am still stealing pictures. Forgive me...

We can know that one end of the LED is directly followed by the pins on the chip. How does the other end receive a resistor? If there is no resistance to reduce the pressure, the current will be connected, so the LED resistance, the chip is estimated glorious. To light up the led, the current at the end of the resistor cannot be changed, and the current at the end of the resistor is high. If the LED is not bright, it is because the end of the chip also provides a high level, to light up the LED, you only need to set the Chip Control Register corresponding to the chip to output, and write the data register to 0. 0 is low, the current passes through, and the LED lights up!


(2) Code
Driver Module:

/*************************************** * *********************************> File Name: lhy_led.c> author: Liang huiyong> mail:> created time: monday, September 29, 2014, 50 seconds ******************************** **************************************** /// in the linux-2.6.32.2/ARCH/ARM/mach-s3c2410/include/Mach directory # include <Mach/regs-gpio.h> // macro definition related to gpio # include <Mach/hardware. h> // s3c2410_gpio_cfgpin // G such as s3c2410_gpio_setpin Pio Function Definition // under the linux-2.6.32.2/include/Linux directory # include <Linux/miscdevice. h> // register the miscdevide struct member variable # include <Linux/delay. h> // This should be a latency function # include <Linux/kernel. h> // kernel, needless to say # include <Linux/module. h> // define the driver to load and unmount the function # include <Linux/init. h> // initialize the header file # include <Linux/mm. h> # include <Linux/Fs. h> // register the file_operations struct variable # include <Linux/types. h> # include <Linux/moduleparam. h> # include <Linux/slab. h> # include <Linux/errno. h> # InCl Ude <Linux/IOCTL. h> # include <Linux/cdev. h> # include <Linux/string. h> # include <Linux/list. h> # include <Linux/PCI. h> # include <Linux/gpio. h> // gpio port definition file (Virtual Address) // under the linux-2.6.32.2/ARCH/ARM/include/ASM directory # include <ASM/IRQ. h> # include <ASM/uaccess. h> # include <ASM/atomic. h> # include <ASM/unistd. h> # define device_name "LEDs" static unsigned long led_table [] = {s3c2410_gpb (5), // In the gpio-nrs.h (is gpio. h contains the header file) defines the virtual address s3c2410_gp B (6), s3c2410_gpb (7), s3c2410_gpb (8),}; static unsigned int led_cfg_table [] = {s3c2410_gpio_output, // defines the header file s3c2410_gpio_output, s3c2410_gpio_output, s3c2410_gpio_output,}; static int sbc2440_leds_ioctl (struct inode * inode, struct file * file, unsigned int cmd, unsigned long Arg) {Switch (CMD) {Case 0: Case 1: if (Arg> 4) {return-einval;} s3c2410_gpio_setpin (led_table [Arg],! CMD); Return 0; default: Return-einval;} // file structure static struct file_operations dev_fops = {. owner = this_module, // this_module prevents being uninstalled during use. IOCTL = sbc2440_leds_ioctl ,//. IOCTL points to the sbc2440_leds_ioctl function}; // The static struct miscdevice MISC = {. minor = misc_dynamic_minor, // dynamically allocates the device number (driver number ). name = device_name, // The device_name defined by the driver name. foPs = & dev_fops, // file operation pointer pointing to dev_fops address}; // module loading and initializing function static int _ ini T dev_init (void) {int ret; int I; printk (kern_alert "Hello, mini2440 LED is installed! \ N "); for (I = 0; I <4; I ++) {// configure the LED pin function. led_table [I] is the LED virtual address defined above; // led_cfg_table [I] sets the led status for the previously defined function (output) s3c2410_gpio_cfgpin (led_table [I], led_cfg_table [I]); // The value 0 indicates the low level, LED light s3c2410_gpio_setpin (led_table [I], 0);} ret = misc_register (& MISC); printk (device_name "\ t lianghuiyong-LEDs \ n"); return ret ;} static void _ exit dev_exit (void) {printk (kern_alert "good-bye, mini2440 LED is removed! \ N "); misc_deregister (& MISC);} module_init (dev_init); module_exit (dev_exit); module_license (" GPL "); // GPL module_author (" lianghuiyong. Inc. ");



Driver makefile

PWD = $(shell pwd)KDIR =/opt/FriendlyARM/mini2440/linux-2.6.32.2/obj-m:= LHY_led.oall:$(MAKE) -C $(KDIR) M=$(PWD) CONFIG_DEBUG_SECTION_MISMATCH=yclean:rm -rf *.o *~core.depend. *.cmd *.ko *.mod.c .tmp_versionsrm -rf *.order Module.*insmod:insmod LHY_led.kormmod:rmmod LHY_ledactive:echo -e "$(MAKE) \n"$(MAKE) -C $(KDIR) M=$(PWD)



Test Module:

/*************************************** * *********************************> File Name: ledceshi. c> author: Liang huiyong> mail:> created time: on Sunday 1, October 02, 2014 ******************************** **************************************** /# include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <sys/IOCTL. h> int main (INT argc, char ** argv) {int on; int led_on; int FD;/* Check two parameters. If not, exit */If (argc! = 3 | sscanf (argv [1], "% d", & led_on )! = 1 | sscanf (argv [2], "% d", & on )! = 1 | on <0 | on> 1 | led_on <0 | led_on> 3) {fprintf (stderr, "Usage: LEDs led_on 0 | 1 \ n "); exit (1);} FD = open ("/dev/leds0 ", 0); If (FD <0) {FD = open ("/dev/LEDs", 0);} If (FD <0) {perror ("open device LEDs"); exit (1 );} /* use IOCTL to call the input led_on and on controls led */IOCTL (FD, on, led_on); close (FD); Return 0 ;}



The test file used the official MAKEFILE file to make, but the Development Board encountered a syntax error: Word unexpected (expecting ") error. Use GCC directly.

Command: Arm-Linux-gcc-G ledceshi. C (file c)-O ledceshi (generated executable file name)


Operation on the Development Board (this is not a hacker ......)



(3) function call notes (1) s3c2410_gpb (5)

Macro definition in the header file

#define S3C2410_GPB(_nr)(S3C2410_GPIO_B_START + (_nr))S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),#define S3C2410_GPIO_NEXT(__gpio) ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)#define S3C2410_GPIO_B_NR(32)S3C2410_GPIO_A_START = 0,

We only use the macro definition of s3c2410_gpb (_ nR). How is this virtual address counted? Macro definitions (the first line) and equations (the second line) are easy to understand,

What about s3c2410_gpio_next (s3c2410_gpio_a?

S3c2410_gpio_next (s3c2410_gpio_a) = s3c2410_gpio_a_start (0) + s3c2410_gpio_a_nr (32) + config_cloud_gpio_space + 0,

What is the value of config_initi_gpio_space? According

#if CONFIG_S3C_GPIO_SPACE != 0#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment#endif

It can be seen that the virtual address can be discussed only when config_initi_gpio_space is set to 0. When we look back, we will know that s3c2410_gpb (_ nR) = 32 + _ Nr.

Conclusion: s3c2410_gpn (_ nR), n is a, B, c, d, etc., and s3c2410_gpn (_ nR) = n × 32 + _ nR (when a, n is 0, when B is 1, C is 2 .......)


(2) s3c2410_gpio_cfgpin (led_table [I], led_cfg_table [I]); the function uses the real parameters of s3c2410_gpb (5) and s3c2410_gpio_output.

The specific definition of this function:

Definition used by gpio-nrs.h --- s3c2410_gpio_bankb

Regs-gpio.h --- s3c2410_gpio_output, s3c2410_gpio_bankb, s3c24xx_gpio_base (x), s3c2410_gpio_offset (PIN)

--- S3c2410_gpio_base (PIN)

Void s3c2410_gpio_cfgpin (unsigned int pin, unsigned int function) // according to the above calculation, we can see pin = 37. function can be defined according to macro # define s3c2410_gpio_output (0xfffffff1) {void _ iomem * base = s3c24xx_gpio_base (PIN); // # define s3c24xx_gpio_base (x) s3c2410_gpio_base (X)/* s3c24xx_gpio_base (PIN) calculation of :( the following definition is in/linux-2.6.32.2/ARCH/ARM/mach-s3c2410/include/Mach/map. linux-2.6.32.2/ARCH/ARM/plat-s3c24xx/include/plat/map. linux-2.6. 32.2/ARCH/ARM/plat-s3c/include/plat/Map-base.h) # define s3c2410_gpio_base (PIN )&~ 31)> 1) + s3c24xx_va_gpio) # define s3c24xx_va_gpio (s3c24xx_pa_gpio-s3c24xx_pa_uart) + s3c24xx_va_uart) # define kernel s3c2410_pa_uart # define s3c24xx_va_uart initi_va_uart # define kernel (0x56000000) # define s3c2410_pa_uart (0x50000000) # define initi_va_uart initi_addr (0x01000000) # define cloud_addr (x) (cloud_addr_base + (x) # define cloud_addr_base (0xf4 000000) s3c24xx_gpio_base (PIN) = s3c2410_gpio_base (x) = (PIN )&~ 31)> 1) + s3c24xx_va_gpio) = (PIN )&~ 31)> 1) + (s3c24xx_pa_gpio-s3c24xx_pa_uart) + s3c24xx_va_uart) = (PIN )&~ 31)> 1) + (0x56000000-0x50000000) + initi_va_uart) = (PIN )&~ 31)> 1) + (0x56000000-0x50000000) + (Fig + (0x01000000) = (PIN )&~ 31)> 1) + (0x56000000-0x50000000) + (0xf4000000) + (0x01000000) = (PIN )&~ 31)> 1) + (0xfb000000) = 0xfb000010 // (PIN )&~ 31)> 1) operation: (PIN )&~ 31) = 100000, shifts one digit to the Right = 10000, that is, hexadecimal 0x10. // The base variable stores the virtual address 0xfb000010 */unsigned long mask; unsigned long con; unsigned long flags; If (PIN <s3c2410_gpio_bankb) {// # define s3c2410_gpio_bankb (32*1), starting with the GPB virtual address, // if it is true, the pin points to the GPA, otherwise, point to the address other than GPA mask = 1 <s3c2410_gpio_offset (PIN); // # define s3c2410_gpio_offset (PIN) & 31), (PIN) & 31) that is, clearing the number above the sixth (inclusive)} else {mask = 3 <s3c2410_gpio_offset (PIN) * 2; // s3c2410_gpio_offset (37) = (37)) & 31) * 2 = 00101*2 = 10, mask = 3 <10} // based on my understanding of the above if statement, 1 and 3 represent the initial status of the register control bit, respectively. s3c2410_gpio_offset (PIN) * 2 and s3c2410_gpio_offset (PIN) // only obtain the specific bit of the control register, then, 1 <s3c2410_gpio_offset (PIN) and 3 <s3c2410_gpio_offset (PIN) * 2 assign a certain control bit of the register to the initial state, 1 and 3, s3c2410_gpio_offset (PIN), and s3c2410_gpio_offset (PIN) * 2; it is mainly because only one/bit of the control status bit of GBA is enough (two functions), while other registers need two (four functions. Switch (function) {Case s3c2410_gpio_leave: // whether the last base (virtual) address is mask = 0; function = 0; break; Case s3c2410_gpio_input: Case s3c2410_gpio_output: Case s3c2410_gpio_sfn2: case when: if (PIN <s3c2410_gpio_bankb) {// This if function is the same as the one analyzed above-= 1; Function & = 1; function <= s3c2410_gpio_offset (PIN );} else {// The GPB pin belongs to the following function & = 3; // obtain the last two digits of the function, and the remaining digits are cleared. Function = 0xfffffff1, and the following = 01 function <= s3c2410_gpio_offset (PIN) * 2; // The above if analysis shows function = 01 <10}/* modify the specified register wwith irqs off */local_irq_save (flags); // Guanzhong disconnection, the interrupt flag is stored in flags and defined in <ASM/system. h> in the file, con = _ raw_readl (base + 0x00); // The base is the pointer variable above. The base address 0xfb000010 is stored. The function definition is not found, con should be the value of the read control register. Con & = ~ Mask; // The number of corresponding con bits [10, 11] is set to zero ,~ Mask = ~ (3 <10) con | = function; // set the corresponding number of con bits [10, 11] to the last two digits of function 01, function = 01 <10 _ raw_writel (con, base + 0x00); // write the changed con to the Register local_irq_restore (flags); // enable register interruption}
S3c2410_gpio_setpin (led_table [I], 0); functions and s3c2410_gpio_cfgpin (led_table [I], led_cfg_table [I]); otherwise, we will not analyze them.

Steal the virtual address ing diagram of a netizen (so this figure makes sense, O (Taobao _ blank) O Haha ~)



Error notes (2.6.32.2 kernel ):

1./home/nfsshare/root_qtopia/drive/led/mini2440_leds.c: 29: Error: 's3c2410 _ gpb5 'undeclared here (not in a function)

Solution: this is because of kernel version issues, the gpio-nrs.h definition and manual examples use a different: s3c2410_gpb5 changed to s3c2410_gpb (5)


2./home/lianghuiyong/my2440drivers/led/lhy_led.c: 40: Error: 's3c2410 _ gpb5_outp 'undeclared here (not in a function)

Solution: For the same reason, you can see under the arch/ARM/mach-s3c2410/include/Mach/regs-gpio.h File

47 rows # define s3c2410_gpio_output (0xfffffff1)

Change the value of s3c2410_gpb5_outp to s3c2410_gpio_output.


3. Error: 'misc' undeclared (first use in this function)

Error: Variable 'dev _ fops 'has initializer but incomplete type

Error: Unknown field 'owner' specified in initializer
I did not pay attention to this. I wrote the wrong code: file_operations is wrong, MISC is also written up and down inconsistent, and misc_dynamic_minor is missing a letter.


4. Line 1: syntax error: Word unexpected (expecting ")") Error

Compile with GCC directly

Command: Arm-Linux-gcc-G ledceshi. C (file c)-O ledceshi (generated executable file name)


Mini2440 driver qitan-LED driver and test (dynamic loading)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.