#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
The following content is defined in /linux-2.6.32.2/arch/arm/plat-s3c24xx/include/plat/map.h
#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
The following content is defined in /linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/map.h
#define S3C24XX_PA_GPIO S3C2410_PA_GPIO
#define S3C24XX_PA_UART S3C2410_PA_UART
The following content is defined in /linux-2.6.32.2/arch/arm/plat-s3c24xx/include/plat/map.h
#define S3C2410_PA_GPIO (0x56000000)
#define S3C2410_PA_UART (0x50000000)
The following content is defined in linux-2.6.32.2/arch/arm/plat-s3c24xx/include/plat/map.h
#define S3C24XX_VA_UART S3C_VA_UART
The following content is defined in linux-2.6.32.2/arch/arm/plat-s3c/include/plat/map.h
#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */
The following content is defined in linux-2.6.32.2/arch/arm/plat-s3c/include/plat/Map-base.h
#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif
#define S3C_ADDR_BASE (0xF4000000)
Here we have found all the macros that define S3C24XX_GPIO_BASE(x). From here we can see that the file definitions in Linux are scattered, which is also a headache for many beginners.
S3C24XX_VA_GPIO=((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
=((0x56000000 - 0x50000000) + (0xF4000000 + 0x01000000))
= (0x06000000 + 0xF5000000)
= (0xFB000000)
#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */
This sentence shows that the base address of the virtual address is offset by 0x01000000
Explain the following two:
#define S3C_ADDR_BASE (0xF4000000) The first virtual address of all registers
#S3C24XX_VA_GPIO GPIO virtual address first address
The value of S3C2410_GPB(5) is 37 according to the above calculation.
S3C24XX_GPIO_BASE(S3C2410_GPB(5))= S3C24XX_GPIO_BASE(37)
=((((37) & ~31) >> 1) + S3C24XX_VA_GPIO)
=((((37) & ~31) >> 1) + (0xFB000000))= 0xFB000010
So in the end *base = 0xFB000010, this is the virtual address of GPBCON, looking at its manual we know that the physical address of GPBCON is 0X56000010, the virtual address of GPACON is 0xFB000000, looking at its manual we know that the physical address of GPACON is 0X56000000, the following program accesses this virtual address to access the control register to configure the I/O port, at this time someone will ask, I access this virtual address, why can I access the physical address? This is the mapping problem of the virtual address and physical address of the MMU, the problem about this is more complicated, I found an article to introduce this virtual-real mapping relationship, see this article "Realization of Virtual-Real Mapping of Register Addresses under 2410" http://www.linuxidc.com/Linux/2013-01/77977.htm on this site , because the content is more, I will not introduce it here.
One more question
What does ((((pin) & ~31) >> 1) mean? This mainly depends on understanding. As mentioned above, each group of ports is defined as 32. ((pin) & ~31) is equivalent to clearing all the lower five bits to zero, and the range that the fifth bit can represent is exactly 32, which is a bit like matching the size of 32. If the obtained value is shifted right by 5 bits, the obtained value (set as ppvalue) can exactly represent which group of I/O ports it is. Why is it shifted right by 1 bit here? Let's see
The physical addresses of several GPXCON registers.
GPACON 0X56000000
GPBCON 0X56000010
GPCCON 0X56000020
GPDCON 0X56000030
The same goes for the rest. We can see the rule of this I/O port control register. If we shift ppvalue left by four bits and add the GPIO virtual base address, we can get the virtual address of the GPXCON control register. By the way, the mapping between the virtual and real addresses here only differs by an offset.
Analysis: if (pin < S3C2410_GPIO_BANKB)
The definition of S3C2410_GPIO_BANKB is as follows
#define S3C2410_GPIO_BANKA (32*0)
#define S3C2410_GPIO_BANKB (32*1)
#define S3C2410_GPIO_BANKC (32*2)
#define S3C2410_GPIO_BANKD (32*3)
#define S3C2410_GPIO_BANKE (32*4)
#define S3C2410_GPIO_BANKF (32*5)
#define S3C2410_GPIO_BANKG (32*6)
#define S3C2410_GPIO_BANKH (32*7)
Used to determine whether this I/O port is a GPA port. This is to distinguish GPA from other groups of ports, because the operation of the GPA control register is a little different from other ports. Also note that it has no input function. You can get a better understanding by looking at the datasheet.
Analysis: S3C2410_GPIO_OFFSET(pin)
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31) //Use this macro to get the offset
if (pin < S3C2410_GPIO_BANKB) { //Judge whether the I/O port belongs to GPA, mask = 1 << S3C2410_GPIO_OFFSET(pin); //Set the mask code
} else {
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; //Set the mask code
}
Analysis: local_irq_save(flags);
This is used in pairs with local_irq_restore(flags); that appears below to turn off and on interrupts, and store the interrupt flag in flags.
Analysis: __raw_readl(base + 0x00); __raw_writel(con, base + 0x00);
con = __raw_readl(base + 0x00); //Read control register data
con &= ~mask; //mask the corresponding bit
con |= function; //Set the bit to be set
__raw_writel(con, base + 0x00); //Write the changed data back to the control register
The above are two function macros, defined as follows
#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
PS(ZXX): First check whether the pointer a is legal, and then write the value v to the space pointed to by a.
The three types correspond to char, short, and int respectively.
#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
PS(ZXX): First check whether the pointer a is legal, and then read the value of the space pointed to by a.
The three types correspond to char, short, and int respectively
.
5.Analysis s3c2410_gpio_setpin(led_table[i], 0);
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04);
local_irq_restore(flags);
}
With the above analysis of s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]), the above codes are similar. Let's just talk about __raw_readl(base + 0x04);. This is to operate the data register. Looking at the datasheet, you will know that the address value of GPXDAT in each group is 4 greater than the address value of GPXCON.
Summary: This is the end of the LED driver analysis. Although the program is small, it involves a lot of things. It is mainly for beginners to feel confused. It is mainly helpful for beginners. There are several versions of this driver, and the kernel is constantly changing. I also posted another article about the LED driver, but the structure data involved is more complicated than this one. You can find it in my blog. If you understand it, you can still learn a lot.
Previous article:Mini2440 Norflash driver transplantation process
Next article:How to re-burn supervivi on mini2440
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Sandia Labs develops battery failure early warning technology to detect battery failures faster
- Ranking of installed capacity of smart driving suppliers from January to September 2024: Rise of independent manufacturers and strong growth of LiDAR market
- Industry first! Xiaopeng announces P7 car chip crowdfunding is completed: upgraded to Snapdragon 8295, fluency doubled
- P22-009_Butterfly E3106 Cord Board Solution
- Keysight Technologies Helps Samsung Electronics Successfully Validate FiRa® 2.0 Safe Distance Measurement Test Case
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Nexperia ESD Webinar Invitation
- What is the four-wire resistance measurement? What are the advantages?
- msp430 contains ADC12 module program implementation
- This circuit for detecting mobile phones is no longer usable, right?
- STM32 stepper motor trapezoidal acceleration and deceleration program
- What is the way to distinguish whether series resonance is good or bad?
- Improved Snowy Night Christmas Tree Program
- National Geographic China and "Beautiful China - China's Most Beautiful Places Selection Event"
- 2020 is about to pass, and the problems brought by these new technologies are still there
- [2022 Digi-Key Innovation Design Competition] Material Unboxing - ESP32-S2-KALUGA-1