如何避免.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

Spi Subsystem

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,因为它们都是在上升沿采样数据,不用去在乎时钟的初始电平是什么,只要在上升沿采集数据就行。 SPI driver spi_controller struct spi_controller { struct device dev; struct list_head list; s16 bus_num; u16 num_chipselect; u16 dma_alignment; u32 mode_bits; u32 buswidth_override_bits; u32 bits_per_word_mask; u32 min_speed_hz; u32 max_speed_hz; u16 flags; bool devm_allocated; union { bool slave; bool target; }; size_t (*max_transfer_size)(struct spi_device *spi); size_t (*max_message_size)(struct spi_device *spi); struct mutex io_mutex; struct mutex add_lock; spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex; bool bus_lock_flag; int (*setup)(struct spi_device *spi); int (*set_cs_timing)(struct spi_device *spi); int (*transfer)(struct spi_device *spi, struct spi_message *mesg); void (*cleanup)(struct spi_device *spi); bool (*can_dma)(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer); struct device *dma_map_dev; struct device *cur_rx_dma_dev; struct device *cur_tx_dma_dev; bool queued; struct kthread_worker *kworker; struct kthread_work pump_messages; spinlock_t queue_lock; struct list_head queue; struct spi_message *cur_msg; struct completion cur_msg_completion; bool cur_msg_incomplete; bool cur_msg_need_completion; bool busy; bool running; bool rt; bool auto_runtime_pm; bool cur_msg_mapped; bool fallback; bool last_cs_mode_high; s8 last_cs[SPI_CS_CNT_MAX]; u32 last_cs_index_mask : SPI_CS_CNT_MAX; struct completion xfer_completion; size_t max_dma_len; int (*optimize_message)(struct spi_message *msg); int (*unoptimize_message)(struct spi_message *msg); int (*prepare_transfer_hardware)(struct spi_controller *ctlr); int (*transfer_one_message)(struct spi_controller *ctlr, struct spi_message *mesg); int (*unprepare_transfer_hardware)(struct spi_controller *ctlr); int (*prepare_message)(struct spi_controller *ctlr, struct spi_message *message); int (*unprepare_message)(struct spi_controller *ctlr, struct spi_message *message); union { int (*slave_abort)(struct spi_controller *ctlr); int (*target_abort)(struct spi_controller *ctlr); }; void (*set_cs)(struct spi_device *spi, bool enable); int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *transfer); void (*handle_err)(struct spi_controller *ctlr, struct spi_message *message); const struct spi_controller_mem_ops *mem_ops; const struct spi_controller_mem_caps *mem_caps; struct gpio_desc **cs_gpiods; bool use_gpio_descriptors; s8 unused_native_cs; s8 max_native_cs; struct spi_statistics __percpu *pcpu_statistics; struct dma_chan *dma_tx; struct dma_chan *dma_rx; void *dummy_rx; void *dummy_tx; int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs); bool ptp_sts_supported; unsigned long irq_flags; bool queue_empty; bool must_async; bool defer_optimize_message; }; list: spi controller global list。...

2023-05-22 · 6 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

Uart Subsystem

Reference https://www.kernel.org/doc/Documentation/serial/driver Introduction 波特率115200,bps每秒传输的bit数。 每一位1/115200秒,传输1byte需要10位(start, data, stop),那么每秒能传11520byte。 115200,8n1。8:data,n:校验位不用,1:停止位。 TTY体系中设备节点的差别 不关心终端是真实的还是虚拟的,都可以通过/dev/tty找到当前终端。 /dev/console 内核的打印信息可以通过cmdline来选择打印到哪个设备。 console=ttyS0 console=tty console=ttyS0时,/dev/console就是ttyS0 console=ttyN时,/dev/console就是/dev/ttyN console=tty时,/dev/console就是前台程序的虚拟终端 console=tty0时,/dev/console就是前台程序的虚拟终端 console有多个取值时,使用最后一个取值来判断。 /dev/tty 和/dev/tty0区别 /dev/tty表示当前进程的控制终端,也就是当前进程与用户交互的终端。 /dev/tty0则是当前所使用虚拟终端的一个别名 Linux串口应用编程 https://digilander.libero.it/robang/rubrica/serial.htm struct termios options; open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY)// O_NOCTTY: 不用作控制终端 O_NDELAY: 使I/O变成非阻塞模式 fcntl(fd, F_SETFL, 0): //读数据时,没有数据则阻塞等待 fcntl(fd, F_SETFL, FNDELAY): //读数据时不等待,没有数据就返回0 /* c_cflag: Control Options */ options.c_cflag |= (CLOCAL | CREAD); // 必须打开 Enable the receiver and set local mode options.c_cflag &= ~CSIZE; /* Mask the character size bits */ options....

2023-05-15 · 3 min

GPIO Subsystem

https://zhuanlan.zhihu.com/p/41942876 push pull推挽输出 推挽输出的最大特点是可以真正能真正的输出高电平和低电平,在两种电平下都具有驱动能力。 open drain开漏输出 open source开集输出 这两种输出的原理和特性基本是类似的,区别在于一个是使用MOS管,其中的"漏"指的就是MOS管的漏极;另一个使用三极管,其中的"集"指的就是MOS三极管的集电极。这两者其实都是和推挽输出相对应的输出模式,由于使用MOS管的情况较多,很多时候就用"开漏输出"这个词代替了开漏输出和开集输出。 开漏、开集输出最主要的特性就是高电平没有驱动能力,需要借助外部上拉电阻才能真正输出高电平。 Kernel doc: General Purpose Input/Output (GPIO) GPIO Driver Interface Controller Drivers: gpio_chip struct gpio_chip 抽象gpio controller。 gpiochip_add_data() or devm_gpiochip_add_data()接口用来注册gpio controller。gpiochip_remove()释放gpio controller。 gpiochip_is_request()在gpio controller driver中用于检测某个gpio是否被其他chip占用,没占用返回NULL,占用返回request时传入的string。 GPIO electrical configuration gpio_chip的.set_config回调用于设置: Debouncing Single-ended modes (open drain/open source) Pull up and pull down resistor enablement 这些属性可以在dts中指定,include/dt-bindings/gpio/gpio.h GPIO_PUSH_PULL GPIO_LINE_OPEN_SOURCE GPIO_OPEN_DRAIN … 可以设置为gpiochip_generic_config()会调用到pinctrl_gpio_set_config()->ops->pin_config_set GPIO drivers providing IRQs gpiod_to_irq(); // 传入gpio_desc,返回gpio的irq number(软件映射的,不是irq hw id) gpio_chip_hwgpio(); gc->to_irq(); rts_gpio_to_irq(); irq_linear_revmap(); Cascaded GPIO irqchips CHAINED CASCADED GPIO IRQCHIPS:挺多soc上是这种做法,打开CONFIG_GPIOLIB_IRQCHIP设置girq->parent_handler。gpio controller注册过程中通过irq_set_chained_handler设置中断处理函数,因此在中断处理函数中需要chained_irq_enter,chained_irq_exit。相当于级联中断处理器的做法。 static irqreturn_t foo_gpio_irq(int irq, void *data) /// 中断处理函数 chained_irq_enter(....

2023-05-12 · 2 min

CMA&DMA

Reserved-memory 参考:http://www.wowotech.net/memory_management/cma.html https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841683/Linux+Reserved+Memory?view=blog /Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt 定义了 no-map 属性的,不会自动映射到虚拟地址,需要自行在 driver 中映射。 // dts reserved: buffer@0x38000000 { no-map; reg = <0x38000000 0x08000000>; }; /* Get reserved memory region from Device-tree */ np = of_parse_phandle(dev->of_node, "memory-region", 0); rc = of_address_to_resource(np, 0, &r); lp->paddr = r.start; lp->vaddr = memremap(r.start, resource_size(&r), MEMREMAP_WB); 定义"shared-dma-pool" 就可以创建 DMA memory pool,使用 DMA engine API 了。of_reserved_mem_device_init 中会帮我们创建映射。(DMA 在 of_reserved_mem_device_init 阶段会进行 memremap 同上,这个 remap 不是直接映射的方式)。 // dts reserved: buffer@0 { compatible = "shared-dma-pool"; no-map; reg = <0x0 0x70000000 0x0 0x10000000>; }; /* Initialize reserved memory resources */ rc = of_reserved_mem_device_init(dev); /* Allocate memory */ dma_set_coherent_mask(dev, 0xFFFFFFFF); lp->vaddr = dma_alloc_coherent(dev, ALLOC_SIZE, &lp->paddr, GFP_KERNEL); log:...

2023-05-10 · 4 min