Share this

Implementation of CAN bus driver under embedded Linux

2026-04-06 07:38:43 · · #1
Abstract: This paper uses the S3C44B0X microprocessor and its SPI interface to extend the CAN bus using the MCP2510 CAN controller. Based on the analysis of the working principle and structure of Linux device drivers, this paper focuses on the design method of CAN device drivers under uClinux, writes the operation routines of the driver, and tests the correctness of the driver. The results show the correctness of the CAN device driver under the embedded operating system uClinux; the successful implementation of the CAN device driver has important guiding significance for extending other device drivers under embedded operating systems. Keywords: CAN; µClinux; S3C44B0X; device driver 1 Introduction Industrial control devices based on embedded system design are subject to various interferences in the industrial control field, such as electromagnetic interference, dust, and weather, which greatly affect the normal operation of the system. In the industrial control field, various devices need to exchange and transmit data frequently, requiring a fieldbus with strong anti-interference, stability, and high transmission rate for communication. This paper adopts the CAN bus, based on the 32-bit S3C44B0X microprocessor in the embedded system, and expands the CAN bus through its SPI interface and MCP2510 CAN controller. An embedded operating system is embedded into the S3C44B0X microprocessor, enabling multi-tasking and a user-friendly graphical interface. Since the S3C44B0X microprocessor lacks a memory management unit (MMU), the uClinux embedded operating system is used. Therefore, the key technology for expanding CAN devices in an embedded system is the implementation of the CAN device driver under the embedded operating system. This paper focuses on solving the problem of CAN bus driver implementation under the embedded operating system. For users, the implementation of the CAN device driver under the embedded operating system shields them from hardware details, allowing them to write their own user programs without worrying about the hardware. Experimental results show that the driver is correct, improves the overall system's anti-interference capability, has good stability, and achieves a maximum transmission rate of 1Mb/s; the hardware's error detection characteristics also enhance the CAN's anti-electromagnetic interference capability. 2 System Hardware Design The system uses the S3C44B0X microprocessor and requires the expansion of the CAN controller. Commonly used CAN controllers include the SJA1000 and MCP2510, both of which support the CAN 2.0B standard. The SJA1000 uses a bus that multiplexes address and data lines, but most embedded processor external buses have separate address and data lines. This means that each operation on the SJA1000 requires writing the address and data twice, and the SJA1000 uses a 5V logic level. Therefore, the MCP2510 controller is used for expansion, with the 82C250 transceiver. The MCP2510 controller features: 1. Supports standard and extended CAN data frame structures (CAN 2.0B); 2. Valid data length of 0 to 8 bytes, supporting remote frames; 3. Programmable baud rate up to 1Mb/s; 4. Two receive buffers with filters, and three transmit buffers; 5. SPI high-speed serial bus, up to 5MHz; 6. Wide voltage range power supply of 3 to 5.5V. The MCP2510 operates at 3.3V and can be directly connected to the I/O port of the S3C44B0X microprocessor. To further improve the system's anti-interference capability, an optical isolator 6N137 can be added between the CAN controller and the transceiver. Its structural principle block diagram is shown in Figure 1: [align=center] Figure 1. S3C44B0X Extended CAN Structure Block Diagram[/align] [align=center] Figure 2. Character Device Registry[/align] 3 Design of CAN Device Driver Linux treats devices as special files for management. To add a device, it must first be registered and its driver added. The device driver is the interface between the operating system kernel and the device hardware, and it hides the hardware details from the application. In Linux, user processes cannot directly operate on physical devices; they must make requests to the kernel through system calls, and the kernel will call the corresponding device driver. Therefore, we first establish the concepts of Linux device management, device driver, device registration, and Linux interrupts. 3.1 Linux Device Management Linux supports a variety of peripheral devices, and the management of these devices is generally referred to as device management. Device management is divided into two parts: one is the upper layer of the driver, which is independent of the device. This part communicates with the device through a specific device driver interface based on input/output requests; the other is the lower layer, which is related to the device and is usually called the device driver. It directly interacts with the hardware and provides a set of access interfaces to the upper layer. To perform read and write operations on devices, Linux device management logically represents physical devices as special files called device files, using file system interfaces and system calls to manage and control them. Linux classifies devices into three categories: block devices, character devices, and network devices. Each type of device has different management and control methods and different drivers, which facilitates system customization. The Linux kernel identifies devices based on device type and device number. Each character device using the same driver has a unique major device number. For CAN devices, the device type and device number are set to 'can' and '125' respectively in the `/vendor/Samsung/44b0/Makefile` file. 3.2 The `file_operations` structure: The specific implementation of device operations in Linux is completed by the device driver. The device driver is loaded into the system through device registration. Linux drivers perform file operations using the `file_operations` structure. This structure is a collection of pointers to file operation functions. In device management, the operation functions pointed to by each member of this structure are the operation routines of the device driver. Writing a driver essentially means writing the functions within this structure. Different devices can be equipped with all or some of these operation functions; unused function pointers are set to NULL. Below is the `file_operations` structure for a CAN device: `Static struct file_operations { write: s3c44b0_mcp2510_write, // Write operation read: s3c44b0_mcp2510_read, // Read operation ioctl: s3c44b0_mcp2510_ioctl, // Operations other than read and write open: s3c44b0_mcp2510_open, // Open device release: s3c44b0_mcp2510_release}; // Close device` Each member of this structure corresponds to a system call. User processes use system calls to invoke their driver interfaces. The system call finds the corresponding device driver through the major device number of the device file, then reads the corresponding function pointer from this data structure, and then transfers control to that function. 3.3 Device Registration In Linux, when a device is installed on the system, it must be registered with the system. The main task of device registration is to load the device driver into the system. Linux manages the registration of different devices (such as character devices and block devices) separately. Each device descriptor includes two pointers: `name` points to the device name string, and `fops` points to the file operation function structure `file_operations`, which contains pointers to the various operation routines of the driver. Figure 2 shows a schematic diagram of the Linux character device registry. The registration function for the CAN character device is the kernel function: `register_chrdev(MAJOR_NR, DEVICE_NAME, &s3c44b0_mcp2510_fops)`; where `DEVICE_NAME` represents the device name, and `s3c44b0_mcp2510_fops` represents a pointer to the `file_operations` structure, i.e., the device driver. 3.4 Linux Interrupt Handling In the Linux system, interrupt handling is part of the system kernel. Therefore, if a device exchanges data with the system via interrupts, the device driver must be part of the system kernel. Device drivers request interrupts using the `request_irq` function and release interrupts using `free_irq`. Since interrupts are not used in this experiment, they will not be discussed in detail here. 3.5 Implementation of CAN Driver 3.5.1 Writing Driver Operation Routine CAN devices are character devices. For CAN bus devices, in addition to sending (using the write method) and receiving (using the read method), it is also necessary to control the baud rate of CAN bus communication, set the working mode, set the ID, etc. Therefore, using ioctl is the most suitable method. The entry function of the CAN driver: `int __init s3c44b0_mcp2510_init(void) { ARMTargetInit(); // Initialize ARM init_MCP2510 (BandRat125kbps); // Initialize CAN controller ret = register_chrdev(MAJOR_NR, DEVICE_NAME, &s3c44b0_mcp2510_fops); } // Register CAN device` The exit function of the CAN driver: `void __exit s3c44b0_mcp2510_exit(void) { unregister_chrdev(MAJOR_NR, DEVICE_NAME); printk("MCP2510 Exit!\n"); }` Write the following routines for each operation of the CAN device driver: 1. ioctl function: `Static int s3c44b0_mcp2510_ioctl` (struct inode * inode, struct file * file, unsigned cmd, unsigned long arg) {switch(cmd) {case SETBAND://Set baud rate MCP2510_SetBandRate(BandRate, TRUE); break; case SETLPBK://Set working mode MCP2510_Write(CLKCTRL, MODE_LOOPBACK|CLK|CLK1); break; case SETID://Set identifier MCP2510_Write_Can_ID(RXF0SIDH, U8 ID, 0); break; case SETFILTER: //Set mask MCP2510_Write_Can_ID(RXM0SIDH, 0x1ff, 0); break; } } 2. open function (open device): static int s3c44b0_mcp2510_open(struct inode * inode, struct file * file) {printk("device open\n"); return 0;} 3. write function (send data): static ssize_t s3c44b0_mcp2510_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) {copy_from_user(&temp, buffer, sizeof(mcpcan_data)); canWrite(temp.id, temp.data, temp.DataLen, temp.IdType, temp.BufNo);} //send data function 4. read function (receive data): static ssize_t s3c44b0_mcp2510_read(struct file *file, char *buffer, size_t count, loff_t *ppos) {Revdata(0x66,datas,0x08); // Data receiving function copy_to_user(buffer,Receivedata.data,0x08); return count;} 3.5.2 Cross-compiling the CAN driver Cross-compiling the driver requires a host machine running Red Hat Linux. For instructions on installing the cross-compilation tools, please refer to the relevant documentation (cross-compilation tools: arm-elf-tools-20030314.sh). The driver can be compiled in two ways: statically compiled into the kernel, or compiled into a module for dynamic loading. Since uClinux does not support dynamic module loading, this section only describes the method of statically compiling the driver into the kernel. To allow the compiler to compile the added driver, relevant files need to be modified. 1. Modify the file /linux-2.4.x/driver/char/Makefile and add the following line: Ifeq((tab key)$(CONFIG_MCP2510),Y) (newline)Obj-y+=akaeled.o Endif // This means that if mcp2510 is configured, then add mcp2510.o to the kernel. 2. Modify linux-2.4.x/driver/char/mem.c, and add the following code to the file: #ifdef CONFIG_MCP2510 (newline) extern void mcp2510_init(); #endif // This file tells the kernel to call the corresponding CAN driver #ifdef CONFIG_MCP2510 (newline) mcp2510_init(); (newline) #endif 3. Modify linux-2.4.x/driver/char/Config.in file, and add the following code to the character field: Bool 'mcp2510 support' CONFIG_MCP2510 This will make the mcp2510 configuration option appear when making menuconfig. 4. Modify /uClinux/vendor/Samsung/44b0/Makefile, and add the following content to the DEVICES section: can, c, 125, 0. This means registering a character device named 'can' in the device list, with a major device number of 125 and a minor device number of 0. In the `make menuconfig` dialog, navigate to Character devices and select "support mcp2510". Under root privileges, execute the following commands to compile the kernel: 1. #make dep; 2. #make lib_only; 3. #make romfs; 4. #make image; 5. #make 4. Testing the CAN Driver 4.1 Writing an Application To verify the correctness of the added driver, write an application CAN2510.C for testing. In the application, use the following function to create a thread to send data: pthread_creat(&id,NULL,(void *)cansend,&sendata); In the cansend() function, use the write() function to call the driver s3c44b0_mcp2510_write() to send data, use the read() function to call the driver s3c44b0_mcp2510_read() to receive data sent from the node, and use printf() to output the data sent from the node to verify whether the received data is correct. 4.2 Compiling the CAN Application There are two methods for compiling the application: one is to compile it within the kernel, which requires writing a Makefile and modifying relevant files, making it relatively cumbersome; the other method is to compile it separately, adding the generated executable file to the bin folder in the uClinux file system's romfs directory, and then recompiling the kernel. This experiment uses the latter. Execution: #arm-elf-gcc –elf2flt can2510.c –o can2510 –lpthread Where arm-elf-gcc is the compiler, the –elf2flt parameter is added because uClinux only supports flat format executable files, -0 optimizes the compilation, and can2510 is the name of the generated executable file. Copy can2510 to the /home/cai/uclinux/romfs/bin directory, recompile the kernel, download the generated image file image.rom or image.ram to the target board, and run can2510 to perform CAN driver testing. 5 Conclusion The innovation of this paper: Based on the analysis of the working principle and structure of Linux device drivers, a CAN bus device driver was independently added to the embedded operating system Linux. Experiments have shown that the CAN bus data transmission under the embedded system is reliable and has strong anti-interference, and has great application value in industrial control. At the same time, the successful implementation of the CAN device driver under the embedded operating system linux provides a good reference for extending the driver of other hardware devices in the embedded system. References [1] Zhang Weigang. Parallel hydraulic hybrid vehicle control system based on CAN bus structure [J]. Microcomputer Information. 2006.2: 1-3 [2] Liu Miao. Embedded system interface design and Linux driver development [M]. Beijing University of Aeronautics and Astronautics Press, 2006.5 [3] RUBINT A, CORBET J. LINUX device driver (second edition) [M]. Translated by Wei Yongming, Luo Gang, and Jiang Jun. China Electric Power Press, 2002 [4] Zhou Ligong, Chen Mingji, and Chen Yu. ARM embedded Linux system construction and driver development examples [M]. Beijing University of Aeronautics and Astronautics Press, 2006.1
Read next

CATDOLL 136CM Jing (Customer Photos)

Height: 136cm Weight: 23.3kg Shoulder Width: 31cm Bust/Waist/Hip: 60/54/68cm Oral Depth: 3-5cm Vaginal Depth: 3-15cm An...

Articles 2026-02-22
CATDOLL 139CM Lucy Silicone Doll

CATDOLL 139CM Lucy Silicone Doll

Articles
2026-02-22
CATDOLL 146CM Mila TPE

CATDOLL 146CM Mila TPE

Articles
2026-02-22
CATDOLL Laura Soft Silicone Head

CATDOLL Laura Soft Silicone Head

Articles
2026-02-22