如何避免.bss变量转化成.data段变量

发现在一个.c文件中有一个初始化为非0的全局变量或静态变量,会使这整个文件中定义的全局变量或静态变量都由.bss段转化为.data段。 .data段的变量会在mcu boot阶段的clib会对这些变量做初始化,.bss段可以透过keilc的config如下图控制是否要跳过clib的初始化为0(目前我们的配置是把IRAM配置为不要初始化) 这样的话,我们的芯片在suspend或sleep之后,由于MCU做了power gating,resume起来后MCU重新上电,会重新从MCU boot那边开始跑,.data段的变量就无法保持suspend或sleep之前的值了,又被初始化成定义时候的值了,而.bss段就不会被初始化,可以保持之前的值。 在我们目前usb产品的应用中,一般变量都是要保持suspend/sleep之前的值,所以不能产生有.data段的变量 为了不产生.data段变量,我们要注意: - 全局变量在定义的时候不能做初始化。 - 不要使用静态的局部变量。 //错误示例: U8 g_byGlobalVar = 5; //正确示例: U8 g_byGlobalVar; void InitGlobalVars(void) { if(reset_status==RESET_FROM_POWER_ON) g_byGlobalVar=5; //InitGlobalVars()函数中做初始化 }

2023-09-06 · 1 min

Cortex-M3权威指南

Reference 《Cortex-M3权威指南》 《ARMv7-M Architecture Reference Manual》 《Cortex-M3 Technical Reference Manual》 Chapter1 介绍 Cortex-M3处理器(CM3)采用ARMv7-M架构,它包括所有的16位Thumb指令集和基本的32位Thumb-2指令集架构,Cortex-M3处理器不能执行ARM指令集。 CM3的出现,还在ARM处理器中破天荒地支持了“非对齐数据访问支持”。 Chapter2 CM3概览 2.2 Registers CM3有R0-R15,16个registers。R13作为堆栈指针SP。SP有两个,但在同一时刻只能有一个可以看到,这也就是所谓的“banked”寄存器。 绝大多数16位Thumb指令只能访问R0-R7,而32位Thumb-2指令可以访问所有寄存器。 Cortex-M3拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个。 主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程) 进程堆栈指针(PSP):由用户的应用程序代码使用。 R14 LR:当调用一个子程序时,由R14存储返回地址。 R15 PC: 指向当前的程序地址。如果修改它的值,就能改变程序的执行流。 2.3 操作模式和特权级别 两种操作模式:handler mode(异常服务程序代码),thread mode(应用程序代码)。 两种特权级别:特权级,用户级。 在CM3运行主应用程序时(线程模式),既可以使用特权级,也可以使用用户级;但是异常服务例程必须在特权级下执行。复位后,处理器默认进入线程模式,特权极访问。 用户级的程序不能简简单单地试图改写CONTROL寄存器就回到特权级,它必须先“申诉”:执行一条系统调用指令(SVC)。这会触发SVC异常,然后由异常服务例程(通常是操作系统的一部分)接管,如果批准了进入,则异常服务例程修改CONTROL寄存器,才能在用户级的线程模式下重新进入特权级。 2.5 存储器映射 总体来说,Cortex-M3支持4GB存储空间,如图2.6所示地被划分成若干区域。 从图中可见,不像其它的ARM架构,它们的存储器映射由半导体厂家说了算,Cortex-M3预先定义好了“粗线条的”存储器映射。 2.6 总线接口 2.9 中断和异常 11种系统异常+5个保留档位+240个外部中断。 编号 类型 优先级 简介 0 N/A N/A 没有异常在运行 1 复位 -3(最高) 复位 2 NMI -2 不可屏蔽中断(来自外部NMI输入脚) 3 硬(hard) fault -1 所有被disable的fault,都将“上访”成硬fault 4 MemManage fault 可编程 存储器管理fault,MPU访问犯规以及访问非法位置 5 总线fault 可编程 总线错误(预取流产(Abort)或数据流产) 6 用法(usage)Fault 可编程 由于程序错误导致的异常 7-10 保留 N/A N/A 11 SVCall 可编程 系统服务调用 12 调试监视器 可编程 调试监视器(断点,数据观察点,或者是外部调试请求 13 保留 N/A N/A 14 PendSV 可编程 为系统设备而设的“可悬挂请求”(pendable request) 15 SysTick 可编程 系统滴答定时器 16-255 IRQ #0~239 可编程 外中断#0~#239 2....

2023-09-06 · 2 min

DFU(Device Firmware Upgrade)

2. Overview 四个阶段: Enumeration device告知host具备的能力。通过Run-Time Descriptor中增加的DFU class-interface descriptor和functional descriptor实现。 Reconfiguration host和device同意初始固件升级。host会发送一次USB reset,设备会exports DFU descriptors出来。 Transfer Manifestation device告知设备完成升级,host会再次发送USB reset, 重新枚举设备,运行新固件。 总体流程: 3. Requests bRequest分别从DFU_DETACH: 0 ~ DFU_ABORT: 6 4. Enumeration Phase 4.1 Run-Time Descriptor Set 支持DFU的设备,在run-time时需要额外增加两个描述符: A single DFU class interface descriptor A single functional descriptor 因此Configuration descriptor的bNumInterfaces域需要加1。 Run-time DFU Interface Descriptor DFU Functional Descriptor static void PrepareDFUFunDesc(DFUFunDesc_t *pDFUFunDesc) { pDFUFunDesc->bLength = sizeof(DFUFunDesc_t); pDFUFunDesc->bDescriptorType = 0x21; pDFUFunDesc->bmAttributes = g_DFUVar.bmAttributes; /// BIT0 | BIT1 | BIT2 | BIT3 pDFUFunDesc->wDetachTimeOut = 200; pDFUFunDesc->wTransferSize = g_DFUVar....

2023-08-15 · 2 min

linux usb driver

USB function driver f_loopback.c USB composite driver zero.c usb_composite_driver struct usb_composite_driver { const char *name; // "zero" const struct usb_device_descriptor *dev; // device_desc struct usb_gadget_strings **strings; // dev_strings enum usb_device_speed max_speed; // USB_SPEED_SUPER unsigned needs_serial:1; int (*bind)(struct usb_composite_dev *cdev); // zero_bind int (*unbind)(struct usb_composite_dev *); // zero_unbind void (*disconnect)(struct usb_composite_dev *); /* global suspend hooks */ void (*suspend)(struct usb_composite_dev *); // zero_suspend void (*resume)(struct usb_composite_dev *); // zero_resume struct usb_gadget_driver gadget_driver; // composite_driver_template }; 提供usb_configuration usb_device_descriptor...

2023-06-15 · 2 min

usb spec

Questions USB-IF Others USB标准名称变更: USB 1.0 -> USB 2.0 Low-Speed USB 1.1 -> USB 2.0 Full-Speed USB 2.0 -> USB 2.0 High-Speed USB 3.0 -> USB 3.1 Gen1 -> USB 3.2 Gen1 USB 3.1 -> USB 3.1 Gen2 -> USB 3.2 Gen2 × 1 USB 3.2 -> USB 3.2 Gen2 × 2 USB OTG中增加了一种MINI USB接头,使用5条线,比标准USB多一条身份识别线。 USB协议规定,设备在未配置前,可以从Vbus最多获取100mA电流,配置之后,最多可以获得500mA电流。Vbus是5V的电压。 枚举就是从设备读取各种描述符信息。 Control transfer:低速8字节,高速64字节,全速8/16/32/64字节。 Isochronous Transfer:全速1023字节,高速1024字节,低速不支持。 Interrupt Transfer:低速上限8字节,全速上限64字节,高速上限1024字节。 Bulk transfer:高速512字节,全速8/16/32/64字节,低速不支持。 Chapter3 Background USB 接口可用于连接多达 127 种外设。...

2023-06-15 · 3 min

risc-v Lookup

CSRs 参考riscv-privileged-20211203.pdf sstatus SPP: 在进入S mode之前hart处于什么mode。 用户态trap进入S mode,SPP被设置为0,其他情况为1。 如果SPP为0,执行SRET后,返回U mode。如果SPP为1,执行SRET后,返回S mode。随后SPP置0。 SIE: 1开启/0关闭 S mode的所有中断 in S mode。 在U mode时,SIE被忽略,S mode 的中断都是打开的。 SPIE: 当trap进入S mode,SIE会置0禁止S mode所有中断,SIE的旧值会保存到SPIE中。 执行SRET后,SIE被设置为SPIE中之前保存的旧值,SPIE置1。 stvec Supervisor Trap Vector Base Address Register, 保存S mode异常/中断的跳转地址。 MODE为0,直接跳转到BASE;MODE为1,跳转到BASE + cause * 4。 在linux entry.S中的做法为直接设置stvec为handle_exception地址,地址的后两位肯定是4bytes对齐的,所以为00。跳转到handle_exception后,分开处理中断、系统调用、异常。根据异常cause再跳转到不同的异常处理函数。 SIP SIE Supervisor Interrupt pending/enable Registers SIP中断挂起(待处理的中断)和SIE中断使能。每一位代表的中断与scause中的为每个中断分配的异常码一致。 当sstatus.SIE=1, SIP[x]=1, SIE[x]=1,表示系统能够处理某个中断。 SIP中有的位是只读的,不能通过直接写0来清除: SEIP is read-only in sip, and is set and cleared by the execution environment, typically through a platform-specific interrupt controller....

2023-05-26 · 1 min

Spi Subsystem

1. SPI协议介绍 CPOL:表示SPICLK的初始电平,0为低电平,1为高电平 CPHA:表示相位,即第一个还是第二个时钟沿采样数据,0为第一个时钟沿,1为第二个时钟沿 CPOL CPHA 模式 含义 0 0 0 SPICLK初始电平为低电平,在第一个时钟沿采样数据 0 1 1 SPICLK初始电平为低电平,在第二个时钟沿采样数据 1 0 2 SPICLK初始电平为高电平,在第一个时钟沿采样数据 1 1 3 SPICLK初始电平为高电平,在第二个时钟沿采样数据 我们常用的是模式0和模式3,因为它们都是在上升沿采样数据,不用去在乎时钟的初始电平是什么,只要在上升沿采集数据就行。 2. SPI driver 2.2 spi_controller include/linux/spi.h 2.3 spi_device include/linux/spi.h 2.4 spi_transfer、spi_message 在SPI子系统中,用spi_transfer结构体描述一个传输,用spi_message管理整个传输。可以构造多个spi_transfer结构体,把它们放入一个spi_message里面。 SPI传输时,发出N个字节,就可以同时得到N个字节。 即使只想读N个字节,也必须发出N个字节:可以发出0xff 即使只想发出N个字节,也会读到N个字节:可以忽略读到的数据。 3. SPI 设备树处理 SPI Master 必须的属性如下: address-cells:这个SPI Master下的SPI设备,需要多少个cell来表述它的片选引脚 size-cells:必须设置为0 compatible:根据它找到SPI Master驱动 可选的属性如下: cs-gpios:SPI Master可以使用多个GPIO当做片选,可以在这个属性列出那些GPIO num-cs:片选引脚总数 SPI Device 必须的属性如下: compatible:根据它找到SPI Device驱动 reg:用来表示它使用哪个片选引脚 spi-max-frequency:必选,该SPI设备支持的最大SPI时钟 可选的属性如下: spi-cpol:这是一个空属性(没有值),表示CPOL为1,即平时SPI时钟为低电平 spi-cpha:这是一个空属性(没有值),表示CPHA为1),即在时钟的第2个边沿采样数据 spi-cs-high:这是一个空属性(没有值),表示片选引脚高电平有效 spi-3wire:这是一个空属性(没有值),表示使用SPI 三线模式 spi-lsb-first:这是一个空属性(没有值),表示使用SPI传输数据时先传输最低位(LSB) spi-tx-bus-width:表示有几条MOSI引脚;没有这个属性时默认只有1条MOSI引脚 spi-rx-bus-width:表示有几条MISO引脚;没有这个属性时默认只有1条MISO引脚 spi-rx-delay-us:单位是毫秒,表示每次读传输后要延时多久 spi-tx-delay-us:单位是毫秒,表示每次写传输后要延时多久 示例:...

2023-05-22 · 2 min

Rust

1.2 Even Better TOML,支持 .toml 文件完整特性 Error Lens, 更好的获得错误展示 One Dark Pro, 非常好看的 VSCode 主题 CodeLLDB, Debugger 程序 1.3 Cargo cargo new hello_world tree cargo run is equal to cargo build + ./target/debug/world_hello 默认的是debug模式,编译器不会做任何的优化,编译速度快,运行慢。 高性能模式,生产发布模式: cargo run --release cargo build --release cargo check 检查编译能否通过 cargo.toml 项目数据描述文件 cargo.lock 项目依赖详细清单 在cargo.toml中定义依赖的三种方式: [dependencies] rand = "0.3" hammer = { version = "0.5.0"} color = { git = "https://github.com/bjz/color-rs" } geometry = { path = "crates/geometry" } 2....

2023-05-20 · 3 min

Linux Driver Common Essentials

NOT indexed include <asm/xxx.h> 先找arch/xxx/include/xxx.h,没有的话就找/include/asm-generic/xxx.h 从dts中获取regs地址并映射到virtual address: linux5.10: void __iomem *devm_platform_get_and_ioremap_resource(struct platform_device *pdev, unsigned int index, struct resource **res) linux5.4: void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index) 相当于platform_get_resource + devm_request_mem_region + devm_ioremap linux链表相关操作: #define list_entry(ptr, type, member) \ /// list_entry作用和container_of相同 container_of(ptr, type, member) container_of(ptr, type, member) // ptr:表示结构体中member的地址h(已知的) // type:表示结构体类型 struct xxx // member:表示结构体中的成员 yyy // 返回结构体的首地址 /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor....

2023-05-19 · 1 min

uCore_Chapter3 多道程序与分时多任务

分时多任务系统与抢占式调度 RISC-V架构中断 以内核所在的 S 特权级为例,中断屏蔽相应的 CSR 有 sstatus 和 sie 。sstatus 的 sie 为 S 特权级的中断使能,能够同时控制三种中断,如果将其清零则会将它们全部屏蔽。即使 sstatus.sie 置 1 ,还要看 sie 这个 CSR,它的三个字段 ssie/stie/seie 分别控制 S 特权级的软件中断、时钟中断和外部中断的中断使能。 当 Trap 发生时,sstatus.sie 会被保存在 sstatus.spie 字段中,同时 sstatus.sie 置零,这也就在 Trap 处理的过程中屏蔽了所有 S 特权级的中断; 当 Trap 处理完毕 sret 的时候, sstatus.sie 会恢复到 sstatus.spie 内的值。 也就是说,如果不去手动设置 sstatus CSR ,在只考虑 S 特权级中断的情况下,是不会出现 嵌套中断 (Nested Interrupt) 的。 嵌套中断可以分为两部分:在处理一个中断的过程中又被同特权级/高特权级中断所打断。默认情况下硬件会避免前一部分,也可以通过手动设置来允许前一部分的存在;而从上面介绍的规则可以知道,后一部分则是无论如何设置都不可避免的。 时钟中断与计时器 计数器保存在一个 64 位的 CSR mtime 另外一个 64 位的 CSR mtimecmp 的作用是:一旦计数器 mtime 的值超过了 mtimecmp,就会触发一次时钟中断。这使得我们可以方便的通过设置 mtimecmp 的值来决定下一次时钟中断何时触发。...

2023-05-17 · 2 min