Zhengdian Atom embedded linux driver development – LED driver development

In the previous note, the character device driver development steps were explained in detail, and the development of the first character device driver was completed using a virtual chrdevbase device as an example. This chapter begins writing the first real Linux character device driver. There is an LED light on the Zhengdian Atomic STM32MP157 development board. In this chapter, we will learn how to write an LED light driver under Linux.

LED light driving principle under Linux

Any peripheral driver under Linux must eventually configure the corresponding hardware registers. Therefore, the LED light driver ultimately configures the IO port of the STM32MP157. Different from the bare metal experiment, writing the driver under Linux must comply with the Linux driver framework. LED0 on the development board is connected to the PI0 pin of STM32MP157, so the focus is to write the STM32MP157 pin control driver under Linux.

Address mapping

First, let’s briefly understand MMU.The full name of MMU is Memory.
Manage Unit, also known as memory management unit
. In older versions of Linux, the processor was required to have an MMU, but now the Linux kernel already supports MMU-less processors. The main functions completed by MMU are as follows:

  1. Complete the mapping of virtual space to physical space.
  2. Memory protection, setting memory access permissions, and setting buffer characteristics of virtual storage space.

The mapping from virtual space to physical space is also called address mapping. First understand the two address concepts: virtual address (VA, Virtual Address) and physical address (PA, Physical Address). For 32-bit processors, the virtual address range is 2^32=4GB. There is 1GB of DDR3 on the development board. This 1GB of memory is physical memory, which can be mapped through MMU to the entire 4GB virtual space, as shown in the figure below:
Memory mapping
When the Linux kernel starts, it will initialize the MMU and set up the memory mapping. After setting up, the CPU will access virtual addresses. For example, the physical address of the port mode register GPIOI_MODER of the PI0 pin of the STM32MP157 is 0x5000A000. The MMU is turned on and the memory mapping is set up, so data cannot be written directly to the address 0x5000A000. You must get the virtual address corresponding to the physical address 0x5000A000 in the Linux system, which is covered here To convert between physical memory and virtual memory, two functions are required: ioremap and iounmap.

ioremap function

The ioremap function is used to obtain the virtual address space corresponding to the specified physical address space and is defined in the arch/arm/include/asm/io.h file. The function is defined as follows:

void __iomem *ioremap(resource_size_t res_cookie, size_t size);

There are two parameters in total, and the function actually calls arch_ioremap_caller and has a return value:

  • res_cookie: The physical starting address to be mapped.
  • size: The size of the mapped memory space.
  • Return value: __iomem type pointer, pointing to the first address of the mapped virtual space.

iounmap function

When uninstalling the driver, you need to use the iounmap function to release the mapping done by the ioremap function. The iounmap function prototype is as follows:

void iounmap (volatile void __iomem *addr);

There is only one parameter, which is the first address of the virtual address space to be unmapped.

I/O memory access function

I/O is input/output. Two concepts are involved here: I/O ports and I/O memory. When external registers or memory are mapped into IO space, they are called I/O ports. When external registers or memory are mapped into memory space, it is called I/O memory. For the ARM system, there is only I/O memory (can be directly understood as memory). After using the ioremap function to map the physical address of the register to a virtual address, you can directly access these addresses through pointers, but the Linux kernel does not recommend it.
To do so, it isrecommended to use a set of operation functions to read and write mapped memory.

Read operation function

The three functions readb, readw and readl correspond to 8bit, 16bit and 32bit read operations respectively. The parameter addr is to read and write the memory address, and the return value is the read data.

u8 readb(const volatile void __iomem *addr)
u16 readw(const volatile void __iomem *addr)
u32 readl(const volatile void __iomem *addr)

Write operation function

The three functions writeb, writew and writel correspond to 8bit, 16bit and 32bit write operations respectively. The parameter value is the value to be written, and addr is the address to be written.

void writeb(u8 value, volatile void __iomem *addr)
void writew(u16 value, volatile void __iomem *addr)
void writel(u32 value, volatile void __iomem *addr)

Hardware schematic analysis

There is an LED0 in the STM32MP157 development class of Zhengdian Atom, as shown in the figure below:
LED schematic
It can be seen that LED0 is connected to PI0. When PI0 outputs a low level, LED0 will turn on and light up. When PI0 outputs a high level, LED0 will not turn on, so LED0 will not light up.

Experimental program writing

LED light driver

First, define some macros that are convenient for operation, such as device number, device name, and LED on/off status macros; then you need to define register macro definitions; define the mapped register address pointer, which is of type __iomem*;

Then define the led_switch function to operate the LED status through the readl and writel functions; then define the led_unmap function, which is iounmap to cancel the mapping of each register;

The read, open and release of the device can just return 0, and there is no operation; the write function needs to copy the data, and then use the received message to determine the specific operation, and call led_switch to change the LED state; then file_operations will Encapsulate several device operation functions;

The last is the init function, in which the LED needs to be configured by configuring the register: first, read the physical register mapped virtual address through ioremap, then configure the register, Finally, register_chrdev needs to be registered as the character device LED; Registration failure needs to be recycled, which can be done through led_unmap;

Finally, there is the exit function, which is to directly unmap led_unmap and then log out unregister_chrdev;

Finally, just add module_init and module_exit, license and author, and finally indicate that this driver is an intree module driver.

Write a test APP

It is the most basic open, close and write operations.

First determine whether argc is 3, then pass the device name argv[1] into your own char* filename, and then int fd receives the opened device through open. If fd<0 means that it is not open, just return -1; then read The data is passed into databuf[0], which is also a self-defined unsigned char array with a size of 1, passed in through atoi(argv[2]); finally call write to write int retvalue; close the file and also call close to pass retvalue.

Run the test

Compile driver module and test APP

The driver simply writes a Makefile and sets obj-m to led.o. Then make can get the “led.ko” driver module file.

The test APP is compiled and generated through the following command:

arm-none-linux-gnueabihf-gcc ledApp.c -o ledApp

Run the test

Copy the two files generated by compilation to rootfs/lib/modules/5.4.31, then restart the development board, enter lib/modules/5.4.31 and load the driver:

depmod //You need to run this command when loading the driver for the first time
modprobe led //Load driver

After success, create the “/dev/led” device node:

mknod /dev/led.c 200 0

Then test the driver through ledAPP:

./ledApp /dev/led 1 //Turn on the LED light
./ledApp /dev/led 0 //Turn off the LED light

If successful, you can then uninstall the driver:

rmmod led.ko

Summary

This article mainly uses Linux address mapping to map the physical register address to the virtual memory, and then uses the character device operation method to operate the LED on and off. The main thing here is to learn how to configure registers. Just read the manual and take note of it.

syntaxbug.com © 2021 All Rights Reserved.