点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达Linux内核配置系统的组成 Linux内核源码很多,有上千条配置选项,配置相当复杂。为了更好选择自己想要的功能配置,linux内核源码组织了一个配置系统;配置系统包括三部分:Makefile:负责整体的配置编译Kconfig:配置选项的来源配置菜单这个配置系统就是执行make menuconfig显示的图形化界面:内核Kconfig文件 Kconfig层级关系内核配置选项的源文件是 Kconfig文件;主选项的配置源文件是:arch/$(ARCH)/Kconfig文件;主Kconfig文件调用其他目录的Kconfig文件,其他目...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达为什么会有很多人每天加班,还是解决不了bug?有人一天解决,有人一周解决,有人解决不了,这就是彼此之间的差距。找到问题,才是解决问题的第一步很多人在遇到bug时,第一反应就是着急解决问题,想着能规避就规避,但殊不知,你连问题在哪都不知道。找到问题在哪,是解决bug的第一步也是最重要的。通常来说主要就是跟代码,但很多人跟代码,都喜欢只跟表面,稍微深一点都不愿意继续跟了。也许不是代码问题,但通过跟代码,你也能排除一些可能性。除了代码上,很多人...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达本篇讲解如何使用gdbserver对目标开发板上的程序进行远程调试。安装 GDBSERVER 首先在开发板上安装 gdbserver:apt install gdbservergdbserver 用法 gdbserver用法描述:Usage: gdbserver [OPTIONS] COMM PROG [ARGS ...] gdbserver [OPTIONS] --attach COMM PID gdbserver [OPTIONS] --multi COMMCOMM may either be a tty device (for serial debugging),HOST:PORT to listen for a TCP connection...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达很多人想知道,我实际的工作内容,那就简单列举一下过去一年我的工作内容吧。我的岗位JD 关于我岗位职责的官方描述,是这样的:1、负责自研SOC芯片固件开发、驱动原型的开发和仿真验证2、负责自研SOC芯片系统级的相关功能验证验证以及性能分析实际上,我的工作内容,也基本上跟岗位描述差不多。过去一年的工作 流片前的验证工作:CPU benchmark测试L2 Cache、L2 预取器等L2相关验证cjtag、pmu验证bring up相关工作:opensbi:uart、pmu驱动开发uboot相关:clock、rese...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达内核延时函数接口 延时的函数有delay和sleep两种类型:delay接口void ndelay(unsigned long nsecs);//纳秒延时void udelay(unsigned long usecs);//微妙延时void mdelay(unsigned long msecs);//毫秒延时sleep接口void msleep(unsigned int msecs);//毫秒级延时long msleep_interruptible(unsigned int msecs);//毫秒级延时,可被信号打断void ssleep(unsigned int seconds);//秒级延时delay和sleep的区别delay型延时:忙等待,占用CPU资源,延迟过...
成为码农后,我们好像都被贴上了标签。这个标签叫“高薪”。似乎只有高薪,才能算是一个合格的程序员。这么看的话,让大家失望了...小A是做底层开发的,一次聚会和做应用开发的同学小B聊了会。小B:你工作咋样,做底层开发应该学到了很多底层技术吧小A:工作还行,确实学到了很多,技术上有些积累了小B:真羡慕你啊,能学到技术,不像我只能写业务代码没啥积累。诶我最近涨工资了,15k,还有几个月年终奖,你呢?小A:还没过万,年终奖...没有小B:这......小A:那你还想学技术转底层开发吗小B:......某天,小A遇到做外包的同学小C。小C:你是不知...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达本篇讲解使用GDB调试Linux应用程序,以下以 hellowld.c 为例介绍 GDB 的调试入门:编写代码 #include <stdio.h>int main(int argc, char **argv){ int i; int result = 0; if(1 >= argc) { printf("Helloworld.\n"); } printf("Hello World %s!\n",argv[1]); for(i = 1; i <= 100; i++) { result += i; } printf("result = %d\n", result...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达本篇讲解Linux应用程序发生Segmentation fault段错误时,如何利用core dump文件定位错误。核心转储 在 Linux 系统中,常将“主内存”称为核心(core),而核心映像(core image) 就是 “进程”(process)执行当时的内存内容。当进程发生错误或收到“信号”(signal) 而终止执行时,系统会将核心映像写入一个文件,以作为调试之用,这就是所谓的核心转储(core dump)。当在一个程序崩溃时,系统会在指定目录下生成一个core文件,我们就可以通过 core文件来对造成程序崩贵的原...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达0、看到了这个注释,心凉了一半1、阅读源码的人,心里一定的崩溃的2、这个flag大概是魔法值吧3、这个程序媛的联系方式我要了4、“前人栽树,后人乘凉”5、好奇心迫使我要试试6、还记得虾米吗?要再见了7、据说,合格的程序员必须要会写注释8、写这个注释的人,老家在外太空吗?9、注意:代码没有Bug10、佛祖镇楼,效果增值十来源:程序员最幽默版权归原作者所有,如有侵权,请联系删除。end往期推荐
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达大家好,我是Vincent。我第一次听到cache这个概念,是在大学的计算机组成原理这门课上。由于太理论太低层,学得不咋样,考完试后就完全忘记了。但我万万没想到,当时刚工作,我居然就要用到cache的知识。。前言 事情其实是这样的,当时领导交给我一个perf硬件性能监视的任务,在使用perf的过程中,输入命令perf list,我看到了以下信息:我的任务就要让这些cache事件能够正常计数,但关键是,我根本不知道这些misses、loads是什么意思。我只知道它们都是cache,但这几...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达有不少做应用开发的同学,考虑技术深度的问题,会走向驱动岗位。但就在这过程,有可能走错了,你以为你做的是驱动开发,实际还是应用开发。就像这位粉丝的描述,他说他在做用户态驱动开发,我没太理解,我问他什么叫用户态驱动开发,他回答:应用层api到系统调用之间的封装,这不还是应用层吗?也就偶尔需要定位一下驱动问题,对驱动有一些了解。可能就是打着驱动的名号,让你觉得这个岗位会涉及驱动,让你产生有机会写驱动的错觉。所以,大家要注意辨别一个岗位到底...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达1、驱动程序分为几类?字符设备驱动块设备驱动网络设备驱动2、字符设备驱动需要实现的接口通常有哪些open、close、read、write、ioctl等接口。3、主设备号与次设备号的作用主设备号和次设备号是用来标识系统中的设备的,主设备号用来标识设备的类型,次设备号用来标识具体的设备,以便系统能够识别出具体的设备。4、交叉编译器的作用在一个平台上生成另一个平台的可执行程序。例如,x86平台上生成arm平台的可执行程序。通常嵌入式系统是基于arm平台,由于arm平台的算...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达到底什么是BSP工程师呢?来看这篇文章吧一、嵌入式系统要明白什么是嵌入式软件工程师,我们先从嵌入式系统(嵌入式设备)说起。维基百科上对嵌入式系统的定义如下:嵌入式系统(Embedded System),是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。通俗的讲,嵌入式系统就是一种具有专一功能的计算机系统。我们身边就有好多嵌入式设备,常见的比如智能手机,数码相机等消费类的电子设备,再比如最近几年兴起的诸如智能音箱、智能电视、扫地机...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达大家好,我是Vincent。大家都知道在linux中操作寄存器,都是驱动去做的。但其实,驱动层、应用层和shell中都是可以操作寄存器的。Linux驱动操作寄存器 首先在设备树里定义一个节点,例如:uart0: serial@10010000 { compatible = "sifive,uart0"; reg = <0x0 0x10010000 0x0 0x1000>; status = "okay";}@符号后面是寄存器的基地址,然后填写compatible和reg属性,status属性设置为okay。reg属性中,第二参数为寄存器基址,与@符号后面的地...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达出了几道题,考了一下做Linux驱动的同事!说下新增驱动的一些基本操作同事:先在设备树里新建一个节点,填写compatible和reg属性,然后在驱动里映射寄存器基址,后续就可以操作寄存器。我:寄存器基址怎么映射?同事:先用platform_get_resource获取IORESOURCE_MEM资源,然后用devm_ioremap_resource将基址映射为虚拟地址。我:probe里还有哪些常规操作?同事:通常一个驱动都会有时钟,所以probe里映射完基址后,通常要进行时钟和复位的操作。调用devm_clk_get获取时...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达大家好,我是Vincent。做Linux驱动工程师也有一段时间了,今天分享一下我曾经入职才知道的一些事情,算是一个菜鸟的经历吧。设备树起初学习Linux驱动,是从最简单的一个.c文件开始。在.c中实现module_init和module_exit这两个函数,然后在module_init的函数里加个printk,输出个hello world。把.c编译成.ko,然后insmod加载驱动,看到有打印,就算成功了。到了后来,我接触到设备树,加载dtb和.ko驱动,看到有打印,又成功了。心想,设备树应该就是这样吧。直到有一天...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达什么是SysRq Linux内核提供了一些与用户空间的通信机制,例如procfs接口和sysfs接口,大部分的这些接口都可以作为获取内核信息的手段。但除了这些接口,内核也提供了专门的调试机制——系统请求键SysRq。SysRq被内核称为“Magic SysRq key”,即“神奇的系统请求键”。简单来说,就是可以通过键盘的按键获取内核的信息,用于调试。相当于是一个快捷键。SysRq内核配置选项 要使用系统请求键SysRq,内核配置选项中必须打开CONFIG_MAGIC_SYSRQCONFIG_MAGIC_SYSRQ=ySysRq...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达前言 前几篇介绍了几种IO模型,今天介绍另一种IO模型——异步IO。相对于前面的几种IO模型,异步IO在提交完IO操作请求后就立即返回,程序不需要等到IO操作完成再去做别的事情,具有非阻塞的特性。当底层把IO操作完成后,可以给提交者发送信号,或者调用注册的回调函数,告知请求提交者IO操作已完成。在信号处理函数或者回调函数中,可以使用异步IO接口来获得IO的完成情况,比如获取读写操作返回的字节数或错误码、读取的数据等。相关接口 struct aiocb结构体struct ai...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达非阻塞IO 在应用程序中,使用open函数打开一个/dev目录下的一个设备文件时,默认是以阻塞的方式打开。所谓阻塞,就是当我们请求的资源不可用时(资源被占用,没有数据到达等等),会使得进程休眠,从现象看就是卡在那里。应用层如果我们希望以非阻塞方式打开设备文件,则应该在open设备文件时,添加一个O_NONBLOCK的flag参数,例如:fd = open("/dev/vser0", O_RDWR | O_NONBLOCK);驱动层应用层以非阻塞方式打开设备文件,则驱动层也要有对应的处理操作才行。应...
点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”福利干货,第一时间送达应用程序如果想要设置/获取驱动层的数据,一般是驱动提供一个ioclt接口,然后应用层调用。因此,学会在驱动中实现ioctl接口是必要的一项技能。ioctl命令编码规则 想要定义一个自己的ioctl命令,必须要遵从ioctl的编码规则。一个ioctl命令由32比特位表示,每个比特位都有不同的含义,不同版本的内核定义可能有些差异,具体参考文档“Documentation/ioctl/ioctl-deconding.txt”.比特位含义31-3000 - 命令不带参数01 - 命令需要把数据写入驱动,写方向10 - 命令需要从驱...
本例子使用zynq7000系列的ps带的两个mac,一个通过mio引出,一个通过emio引出。如下图:由于lwip通常不使用双网口,有部分需要注意修改。有以下注意事项:1 增加宏定义vivado自带的问题,生成的时候少宏定义。xxx_bsp/ps7_cortexa9_0/include/xparameters.h 增加宏定义:#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR 5xxx_bsp/ps7_cortexa9_0/libsrc/lwip202_v1_2/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c 增加宏定义 #define XPAR_GMII2RGMIICON_0N_ETH1_ADDR 6此数据5应与ip核设置为相同2 路由相关设置使能路由,并且由于双网口可...
如果是把SD卡,emmc卡的驱动合并到一起那会有一些识别卡的步骤。看起来不太好理解。单看emmc的驱动就比较好理解。整体分两步。第一步,初始化外设控制器获取参数 HAL_MMC_Init。第二步,根据需求配置emmc时钟速率, 总线位宽等 HAL_MMC_ConfigWideBusOperation。整体流程图如下:1 初始化外设控制器获取参数 HAL_MMC_Init1.1 初始化GPIO(HAL_MMC_MspInit)对外设控制器进行初始化,包括gpio,控制器参数,要使用的dma的配置。1.2 初始化卡(HAL_MMC_InitCard)1.2.1 初始化总线位宽、时钟(1bit线、速度400k以下)(SDMMC_Init)1.2.2 卡时钟输出禁...
iic可以开启时钟拉伸功能,这种功能可以让主机决定什么时候继续发送时钟,此功能作用时会将从机SCL拉低。针对主机多读或者多写的情况(比如主机收10个字节,从机发送5个字节),hal库并未作处理,会导致从机一直拉低SCL。Hal库原来的程序是这样:static voidI2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c){ if(hi2c->XferCount != 0U) {/* Write data to DR */hi2c->Instance->DR = *hi2c->pBuffPtr;/* Increment Buffer pointer */hi2c->pBuffPtr++;/* Update counter */hi2c->XferCount--; }}static voidI2C_SlaveReceive_BTF(I2C_HandleTypeDef...
HAL库里有很多的IIC的库函数,比如HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);HAL_I2C_Master_Transmit_DMA(I2C_Hand...
写的是Zynq 7000系列的,arm有两个核。主要有AMP和SMP两种方式,SMP是两个核运行一个操作系统,跑LINUX的话,使能SMP,资源会自动分配给两个核运行。AMP是两个核独立运行,每个核可以运行操作系统也可以裸机运行。两个CPU的启动方式是CPU0先运行,然后根据需要启动CPU1。ZYNQ会先运行一个fsbl程序,再运行应用程序。因此启动CPU1的工作可以在fsbl中做,也可以在应用程序中做。1 在FSBL中启动CPU1FSBL程序可以在VITIS这个软件中生成。在FSBL中添加以下程序来启动CPU1Xil_Out32(0XFFFFFFF0, CPU1程序地址);dmb(); sev(); //唤醒 CPU1此段程序加在FSBL...
Zynq中存储程序的地方有QSPI Flash,SD卡,EMMC。Zynq的程序分为三部分,上电启动的引导程序(fsbl),FPGA的程序,arm程序。这里以arm程序存储位置为主进行讨论。1 ARM为裸机程序裸机程序比较小,可以将全部程序(fsbl,FPGA的程序,arm程序)一起存储在QSPI Flash,SD卡,EMMC中的任何一个位置。1.1 固化在QSPI FLASH使用JTAG和sdk固化。或者先运行程序,然后通过程序将可执行文件写入到QSPI Flash中,然后将启动方式设置为QSPI Flash启动,下次启动就可以从QSPI Flash启动了。1.2 固化在SD卡通过读卡器将可执行文件复制进SD卡,将启动方式设置为S...
联合体是一种数据结构,其内部的成员共享同一块内存。应用这种方式可以简化多种复杂数据的处理。比如接收一段16进制到的数据,根据帧头不同数据的含义不同需要进行解析;第一个字节为0x01时,后两个字节代表一个含义;第一个字节为0x02时,后四个字节代表另一个含义;第一个字节为0x03时,后3个字节代表另一个含义。首先定义几个结构体。struct test_data1{ uint8_t header; uint16_t data_xxx; ...}__attribute__ ((__packed__));struct test_data2{ uint8_t header; uint32_t data_xxx; ...}__attribute__ ((__packed__));struc...
sysfs是一个特殊的文件系统,可以设备驱动模型之间的层级关系。可以通过这个文件系统来操作设备。有些设备还只能用sysfs来使用。sysfs可以通过读写数据对设备进行具体的操作。ioctl也可以读写数据,但是有些场合还是使用sysfs更合适。sysfs可以在控制台和shell脚本上直接和用户空间进行交互,而ioctl需要编写个c程序才能运行。因此在这方面sysfs更合适。sysfs可以将设备属性直接展示给用户,比如要对一个LED等做一些操作,先查看一下这个led的属性/sys/class/leds/led1# ls
硬实时和软实时的区别就是一个命令从准备执行到实际执行的时间长度的区别。比如要点亮一个LED灯。运行到这个指令的时候有些其他的中断产生,到执行这个命令的时候就产生了一些延迟,有的程序延迟10ms,有的延迟1ms,有的10us。如果需求是最多2ms内必须执行,那10ms的是软实时,1ms和10us的是硬实时。如果需求是最多20us内必须执行,那10ms和1ms的是软实时,10us的是硬实时。所以软硬实时得看具体需求。 操作系统有的说是软实时,有的说是硬实时。是互相相对着说的,linux很多定义为软实时,freertos和RTX之类的rtos被定义为硬实时...
USB是一种主从通信机制,所有互相连接在一起的设备中只有一个主机,其余的都是从机。从机不能主动发起通信,主机轮流对各从机进行访问。USB协议比较复杂,这是因为USB的硬件接口线比较少,要完成很多的功能就只能把协议做的复杂。USB协议里面有个描述符,分为好多个子类(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符、设备限定符描述符)。这些描述符其实就是一个个数据结构,对应程序里的几个结构体。表征USB的状态,在主机询问时,将自身的状态汇报给主机。比如:主机:性别?从机:男主机:身高?从机:180......从机回答的这...