从SD卡启动到点亮LED:在迅为Exynos 4412开发板上玩转原生Linux驱动开发
1. 开发环境搭建与系统启动
对于嵌入式Linux开发者而言,Exynos 4412开发板是一个极具性价比的学习平台。迅为iTOP-4412开发板搭载三星Exynos 4412四核处理器,采用ARM Cortex-A9架构,主频可达1.4GHz,是学习ARM架构和Linux驱动开发的理想选择。
硬件准备清单:
- 迅为iTOP-4412开发板(SCP封装1GB内存版本)
- 32GB SD卡及读卡器
- 5V/2A电源适配器
- USB转串口调试模块
- 网线(可选,用于网络调试)
开发环境配置步骤如下:
SD卡分区规划:
- 使用
fdisk工具创建三个分区:- 1.5GB未格式化分区(存放uboot、内核和设备树)
- 10GB ext4分区(根文件系统)
- 剩余空间FAT32分区(Windows文件交换)
- 使用
交叉编译器选择:
# 下载ARM官方交叉编译器 wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz # 解压并设置环境变量 tar xvf gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz export PATH=$PATH:/path/to/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin- 系统组件烧写:
组件 文件 SD卡扇区 内存地址 U-Boot u-boot-iTOP-4412.bin 1 0x43e00000 设备树 exynos4412.dtb 2048 0x41000000 内核 uImage 4096 0x40007000
使用dd命令烧写示例:
# 烧写U-Boot sudo dd if=u-boot-iTOP-4412.bin of=/dev/sdb seek=1 bs=512 conv=sync # 烧写内核 sudo dd if=uImage of=/dev/sdb seek=4096 bs=512 conv=sync提示:烧写前务必确认SD卡设备路径,错误的设备路径可能导致主机系统数据丢失。
2. GPIO驱动开发实战
Exynos 4412的GPIO控制器通过内存映射寄存器进行控制。在开发板上,LED通常连接在GPX2组引脚上,我们可以通过sysfs接口或编写字符设备驱动来控制。
GPX2寄存器映射:
- GPX2CON:配置寄存器(0x11000C40)
- GPX2DAT:数据寄存器(0x11000C44)
- GPX2PUD:上拉/下拉寄存器(0x11000C48)
通过sysfs操作LED的简单方法:
# 导出GPIO echo 57 > /sys/class/gpio/export # GPX2_1对应Linux GPIO编号57 # 设置为输出 echo "out" > /sys/class/gpio/gpio57/direction # 点亮LED echo 1 > /sys/class/gpio/gpio57/value # 熄灭LED echo 0 > /sys/class/gpio/gpio57/value对于更专业的驱动开发,可以创建字符设备驱动:
#include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #define GPIO_BASE 0x11000000 #define GPX2CON (GPIO_BASE + 0x0C40) #define GPX2DAT (GPIO_BASE + 0x0C44) static void __iomem *gpx2con; static void __iomem *gpx2dat; static int led_open(struct inode *inode, struct file *file) { // 配置GPX2_1为输出 writel((readl(gpx2con) & ~(0xF << 4)) | (0x1 << 4), gpx2con); return 0; } static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char val; if (copy_from_user(&val, buf, 1)) return -EFAULT; // 根据用户输入控制LED if (val == '1') writel(readl(gpx2dat) | (1 << 1), gpx2dat); else if (val == '0') writel(readl(gpx2dat) & ~(1 << 1), gpx2dat); return 1; } static struct file_operations fops = { .open = led_open, .write = led_write, }; static int __init led_init(void) { gpx2con = ioremap(GPX2CON, 4); gpx2dat = ioremap(GPX2DAT, 4); register_chrdev(240, "led_driver", &fops); return 0; } module_init(led_init);编译驱动模块:
arm-none-linux-gnueabihf-gcc -c led_driver.c -o led_driver.o arm-none-linux-gnueabihf-ld -r led_driver.o -o led_driver.ko3. ADC驱动开发与数据采集
Exynos 4412内置10位ADC控制器,支持4通道模拟输入。开发板通常将ADC0连接至可调电阻,适合进行模拟信号采集实验。
ADC关键寄存器:
- ADCCON:控制寄存器(0x126C0000)
- ADCDAT:数据寄存器(0x126C000C)
- ADCMUX:通道选择寄存器(0x126C001C)
通过sysfs读取ADC值:
# 查看可用ADC通道 ls /sys/bus/iio/devices/iio\:device0/ # 读取ADC0值 cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw编写ADC字符设备驱动示例:
#include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #define ADC_BASE 0x126C0000 #define ADCCON (ADC_BASE + 0x00) #define ADCDAT (ADC_BASE + 0x0C) #define ADCMUX (ADC_BASE + 0x1C) static int adc_open(struct inode *inode, struct file *file) { // 配置ADC预分频、使能 writel((1 << 16) | (1 << 14) | (0xFF << 6) | (1 << 0), ADCCON); // 选择通道0 writel(0x0, ADCMUX); return 0; } static ssize_t adc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int value; char str[16]; // 启动转换 writel(readl(ADCCON) | (1 << 0), ADCCON); while (readl(ADCCON) & (1 << 0)); // 等待转换完成 value = readl(ADCDAT) & 0x3FF; // 10位有效数据 sprintf(str, "%d\n", value); return simple_read_from_buffer(buf, count, ppos, str, strlen(str)); } static struct file_operations fops = { .open = adc_open, .read = adc_read, }; static int __init adc_init(void) { register_chrdev(241, "adc_driver", &fops); return 0; } module_init(adc_init);注意:ADC参考电压通常为1.8V,输入信号不应超过此范围,否则可能损坏ADC模块。
4. 系统扩展与网络配置
最小Linux系统搭建完成后,可以通过移植常用工具来增强系统功能。以下是几个实用扩展方案:
常用工具移植方法:
BusyBox配置:
make menuconfig # 选择需要的工具(如ifconfig、ping等网络工具) make && make installDropbear SSH服务器:
./configure --host=arm-none-linux-gnueabihf --prefix=/usr make && make installLighttpd Web服务器:
./configure --host=arm-none-linux-gnueabihf --prefix=/usr make && make install
网络配置示例:
# 配置静态IP ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up route add default gw 192.168.1.1 # 或者使用DHCP udhcpc -i eth0开发板与主机文件传输:
NFS共享:
# 主机端配置 echo "/nfs_root *(rw,sync,no_root_squash)" >> /etc/exports service nfs-kernel-server restart # 开发板挂载 mount -t nfs 192.168.1.2:/nfs_root /mnt -o nolockSCP传输:
scp file.txt root@192.168.1.100:/root/TFTP传输:
tftp -g -r uImage 192.168.1.2
在实际项目中,Exynos 4412的GPIO中断功能也经常用到。通过配置GPIO的中断触发方式和编写中断处理函数,可以实现高效的按键检测等应用。开发过程中,使用/proc/interrupts可以查看系统中断统计信息,帮助调试中断相关的问题。