系统版本:Ubuntu18.04-64
编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)
uboot版本:2018.07 -linux4sam_6.0
板子型号:at91sama5d3x-xplained
MCU型号:sama5d36
在一些特殊应用场景,在板子上电启动阶段就需要优先给IO进行上电,甚至是按照时序输出 ;比如:以前去广东电科院送检,有个检测项是4G模块在上电阶段,就要有RST信号出现1S低脉冲,然后ON/OFF信号200ms低脉冲,为了让4G模块和系统同步进入运行状态;就这么一个不起眼的操作,用单片机系统的厂家很快就解决了,我们使用Linux系统的搞起来有点繁琐,修改uboot,修改内核启动流程的代码。
linux开发相比单片机的主要难度就是无法在线仿真,调试手段打印,或者测量外部电平的变化。
一、查找到芯片初始化代码,理论上初始化完CPU时钟,DDR时钟之后就可以进行外围寄存器操作了;
1.1 调试内核驱动首先要了解芯片是属于哪个平台架构,atmel这款芯片mach-at91;其次就是开发板型号,参考官网开发板,这样可以少做很多无用功。
mach-at91下面有很多不同cpu型号的加载文件,每个里面都有初始化函数,该从哪里选择呢?
首先查看Makefile文件,可以看到里面有很多宏,要是不知道目前是哪个宏生效,可以先编译一次,然后查看这个目录下面有哪些文件编译出了.o文件,就可以说明是哪个宏生效了,我们要修改的是sama5.c;
二、进入sama5.c中查看对应的代码
//初始化函数
static void __init sama5_dt_device_init(void)
{
of_platform_default_populate(NULL, NULL, NULL);
sama5_pm_init();
}
static const char *const sama5_dt_board_compat[] __initconst = {
"atmel,sama5", //SOC厂商信息
NULL
};
DT_MACHINE_START(sama5_dt, "Atmel SAMA5")
/* Maintainer: Atmel */
.init_machine = sama5_dt_device_init,//初始化函数
.dt_compat = sama5_dt_board_compat, //设备树平台信息
MACHINE_END
机器的入口函数都是从DT_MACHINE_START进入,完成后MACHINE_END;
这里根据设备树信息选择对应的初始化,这个文件中还有D2和D4平台的初始化代码;
三、初始化代码主要在sama5_pm_init()里面
linux-at91-linux-4.19-at91\arch\arm\mach-at91\pm.c
void __init sama5_pm_init(void)
{
if (!IS_ENABLED(CONFIG_SOC_SAMA5))
return;
at91_dt_ramc();//RAM初始化
at91_pm_init(NULL);//根据设备树初始化一些节点寄存器
at91_phy_gpio_init(); //自定义添加PHY gpio init
}
给对应的GPIO进行初始化操作,脉冲或者高低电平
static void __init at91_phy_gpio_init(void)
{
ulong phy9031_reset_gpio; //ksz9031 reset
ulong phy8081_reset_gpio; //ksz8081 reset
ulong phy8081_power_gpio; //ksz8081 power
ulong led_gpio; //led
//对应GPIO引脚,和硬件原理图相关
phy9031_reset_gpio = AT91_PIN_PE9;
phy8081_reset_gpio = AT91_PIN_PC31;
phy8081_power_gpio = AT91_PIN_PC18;
led_gpio = AT91_PIN_PB12;
// setup output ,设置为输出模式,默认高电平
gpio_direction_output(phy9031_reset_gpio, 1);
gpio_direction_output(phy8081_reset_gpio, 1);
gpio_direction_output(phy8081_power_gpio, 1);
gpio_direction_output(led_gpio, 1);
//micrel ksz9031 reset gpio,100ms低电平脉冲
gpio_set_value(phy9031_reset_gpio, 1);
mdelay(100);
gpio_set_value(phy9031_reset_gpio, 0);
mdelay(100);
gpio_set_value(phy9031_reset_gpio, 1);
//micrel ksz8081 reset gpio,设置为高电平
gpio_set_value(phy8081_reset_gpio, 1);
//micrel ksz8081 power gpio,设置为低电平
gpio_set_value(phy8081_power_gpio, 0);
//led on,低电平点亮LED
gpio_set_value(led_gpio, 0);
}
更多linux知识点推荐:
[职场吐槽]如何缓解焦虑
[linux kernel] 内核下ksz8081驱动调试
[linux kernel] 内核下ksz9031驱动调试
[linux kernel]内核图形化裁剪配置
[linux kernel]内核移植过程记录
[linux kernel] 内核启动流程梳理
[linux 底层]u-boot EMMC驱动
[linux 底层]u-boot图形化裁剪配置
[Linux 底层]U-boot ksz9031网络驱动调试
[Linux 底层]U-boot调试命令使用技巧
[Linux 底层]U-boot编译移植
[Linux 底层]U-boot烧录脚本介绍SecureCRT
[Linux 底层]bootstrap移植裁剪及编译
[Linux 底层] 平台软件分层介绍
[Linux 驱动] RS485测试程序编写
[Linux 驱动] CAN测试程序编写
推荐阅读:
芯片手册解读 | Linux底层 | 职场吐槽 | C语言视频
关注微信公众号,回复“启动文件”,下载启动文件源代码