完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
uC-CPU文件夹内容
cpu_def.h :主要是机器字长定义、机器大小端定义 、CPU进入临界区方式宏定义 cpu.h :主要是一些跟移植相关的数据类型重新定义(typedef),宏定义CM3的内部异常号,然后一些CM3内核寄存器的宏定义(非常主要),最后是一些配置宏定义依赖关系出错处理的预处理。 cpu_c.c :主要是位域操作宏定义和函数,然后就是使能、失能特定优先级中断的函数和修改中断优先级的函数。 cpu_a.asm:先导出文件后半部分定义的一些汇编函数,再定义一些汇编函数 ——————————————————————————————— cpu_def.h分析 由于文件里面注释太多,所以仅仅复制相关代码 /* ------------------- CPU机器字长宏定义------------------ */ #define CPU_WORD_SIZE_16 2 /* 16-bit word size = sizeof(CPU_INT16x). */ #define CPU_WORD_SIZE_32 4 /* 32-bit word size = sizeof(CPU_INT32x). */ #define CPU_WORD_SIZE_64 8 /* 64-bit word size = sizeof(CPU_INT64x) [see Note #1a]. */ /* ------------------- CPU大小端定义------------------ */ #define CPU_ENDIAN_TYPE_NONE 0 /* */ #define CPU_ENDIAN_TYPE_BIG 1 /* Big- endian word order (CPU words' most significant ... */ /* ... octet @ lowest mem addr). */ #define CPU_ENDIAN_TYPE_LITTLE 2 /* Little-endian word order (CPU words' least significant ... */ /* ... octet @ lowest mem addr). */ /*CPU定义进入系统临界区的几种方式*/ #define CPU_CRITICAL_METHOD_NONE 0 /* */ #define CPU_CRITICAL_METHOD_INT_DIS_EN 1 /* DIS/EN ints. 直接关中断进入临界区,退出临界区开中断*/ /* 不是首先的进入临界区方式,因为不支持中断嵌套,但是在一些编译器或CPU中也是无可奈何的选择*/ #define CPU_CRITICAL_METHOD_STATUS_STK 2 /* Push/Pop int status onto stk. 将中断状态保存到堆栈中去,然后关中断进入临界区,在退出临界区的时候从栈中恢复CPU的状态 */ /* 是推荐的进入临界区方式,但是需要编译器支持内嵌汇编,并且需要准确的入栈出栈*/ #define CPU_CRITICAL_METHOD_STATUS_LOCAL 3 /* Save/Restore int status to local var. 将中断状态保存到本地变量中去,然后关中断进入临界区,在退出临界区的时候从本地变量中恢复CPU的状态 */ /* 是推荐的进入临界区方式,因为支持多级中断且也不一定需要内嵌汇编*/ 所谓进入临界区就是 OS_CRITICAL_ENTER(); //进入临界区 /* 临界区代码*/ OS_CRITICAL_EXIT() ; //推出临界区 最终根据宏定义的具体值来决定OS_CRITICAL_ENTER() 与 OS_CRITICAL_EXIT() 具体实现方式,看源码可以知道 ,ucosii是实现的方式三 #define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_STATUS_LOCAL 由于需要将中断保存到本地变量中,所以在每个进入临界区代码起始部位都会有 #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif cpu_sr 就是保存中断的那个本地local变量 OS_CRITICAL_ENTER() 与 OS_CRITICAL_EXIT() 具体实现方式在os_cpu.h中 #if OS_CRITICAL_METHOD == 3 #define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();} #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} #endif OS_CPU_SR_Save ;CPU进入临界区代码前操作 -->OS_ENTER_CRITICAL() MRS R0, PRIMASK ;将PRIMASK状态保存存入R0(cpu_sr) CPSID I ;关中断 BX LR ;返回 OS_CPU_SR_Restore ;CPU退出临界区代码后操作 -->OS_CRITICAL_EXIT() MSR PRIMASK, R0 ;将R0(cpu_sr)的状态存入PRIMASK BX LR ;返回 ———————————————————————————— cpu.h分析 文件开始便是CPU移植相关的数据类型定义。这样做的目的主要是方便阅读、加强移植移植性。假设一款8位MCU A中 sizeof(int) = 2,另一款32位MCU B中 sizeof(int) = 4。如果有下列代码 int num = 10; printf(sizeof(num)); 两个平台运行结果完全不一样,会导致移植性很差,这就可以用数据类型重新定义来避免这种可移植性问题 typedef int cpu_int_t; //A平台 cpu_int_t num = 10; printf(sizeof(num)); typedef short int cpu_int_t; //B平台 cpu_int_t num = 10; printf(sizeof(num)); 然后确定了CPU数据宽度、地址宽度、大小端 #define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_32 /* Defines CPU address word size. */ #define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_32 /* Defines CPU data word size. */ #define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_LITTLE /* Defines CPU data word-memory order. */ 然后是一部分函数声明、宏定义,比较重要的如下 /****都是CM3内核异常标号,也是按地址排列的,是异常向量表一部分,这部分可以看我另一篇博客[ STM32启动文件全解 ]*******/ #define CPU_INT_STK_PTR 0 #define CPU_INT_RESET 1 #define CPU_INT_NMI 2 #define CPU_INT_HFAULT 3 #define CPU_INT_MEM 4 #define CPU_INT_BUSFAULT 5 #define CPU_INT_USAGEFAULT 6 #define CPU_INT_RSVD_07 7 #define CPU_INT_RSVD_08 8 #define CPU_INT_RSVD_09 9 #define CPU_INT_RSVD_10 10 #define CPU_INT_SVCALL 11 #define CPU_INT_DBGMON 12 #define CPU_INT_RSVD_13 13 #define CPU_INT_PENDSV 14 #define CPU_INT_SYSTICK 15 STM32启动文件全解 然后定义了一些内核寄存器地址。 #define CPU_REG_NVIC_NVIC (*((volatile CPU_INT32U *)(0xE000E004))) /* Int Ctrl'er Type Reg. */ #define CPU_REG_NVIC_ST_CTRL (*((volatile CPU_INT32U *)(0xE000E010))) /* SysTick Ctrl & Status Reg. */ #define CPU_REG_NVIC_ST_RELOAD (*((volatile CPU_INT32U *)(0xE000E014))) /* SysTick Reload Value Reg. */ #define CPU_REG_NVIC_ST_CURRENT (*((volatile CPU_INT32U *)(0xE000E018))) /* SysTick Current Value Reg. */ #define CPU_REG_NVIC_ST_CAL (*((volatile CPU_INT32U *)(0xE000E01C))) /* SysTick Calibration Value Reg. */ 这种寄存器访问方式是,先将地址强转为int *指针类型,然后再取内容,通过这种巧妙方式便可以直接对任何内存地址操作了! 这部分寄存器内容跟后来的中断,PendSV ,上下文切换等十分紧密。需要读者好好看看,可以参考我另一篇博客CM3内核寄存器初探 最后是一些配置宏定义依赖关系出错处理的预处理。 #ifndef CPU_CFG_ADDR_SIZE #error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h' " #error " [MUST be CPU_WORD_SIZE_08 8-bitalignment]" #error " [ || CPU_WORD_SIZE_16 16-bitalignment]" #error " [ || CPU_WORD_SIZE_32 32-bitalignment]" #elif ((CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_08) && (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_16) && (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_32)) #error "CPU_CFG_ADDR_SIZE illegally #define'd in 'cpu.h' " #error " [MUST be CPU_WORD_SIZE_08 8-bitalignment]" #error " [ || CPU_WORD_SIZE_16 16-bitalignment]" #error " [ || CPU_WORD_SIZE_32 32-bitalignment]" #endif 如果没有定义CPU_CFG_ADDR_SIZE ,则在预处理阶段就会报错 #error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h' " #error " [MUST be CPU_WORD_SIZE_08 8-bitalignment]" #error " [ || CPU_WORD_SIZE_16 16-bitalignment]" #error " [ || CPU_WORD_SIZE_32 32-bitalignment]" ——————————————————————————————— cpu_c.c分析 一开始是几个位域宏定义、位域操作函数 可能很多读者还不了解位域操作,详见我的另一篇博客STM32位域操作 #define CPU_BIT_BAND_SRAM_REG_LO 0x20000000 /* SRAM位域低地址*/ #define CPU_BIT_BAND_SRAM_REG_HI 0x200FFFFF /* SRAM位域低地址*/ #define CPU_BIT_BAND_SRAM_BASE 0x22000000 /* SRAM基地址*/ #define CPU_BIT_BAND_PERIPH_REG_LO 0x40000000 /* 外设位域低地址*/ #define CPU_BIT_BAND_PERIPH_REG_HI 0x400FFFFF /* 外设位域高地址*/ #define CPU_BIT_BAND_PERIPH_BASE 0x42000000 /* 外设位基地址*/ 大家看了我上面博客的话,两个位域操作函数就不必多讲了 然后是禁止、解禁某一优先级的函数 void CPU_IntSrcDis (CPU_INT08U pos) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif CPU_INT08U group; CPU_INT08U pos_max; CPU_INT08U nbr; switch (pos) { /* --------- 几个保留的中断地址,当然不能使能或者失能了INVALID OR RESERVED -------*/ case CPU_INT_STK_PTR: case CPU_INT_RSVD_07: case CPU_INT_RSVD_08: case CPU_INT_RSVD_09: case CPU_INT_RSVD_10: case CPU_INT_RSVD_13: break; /* -----------------几个CM内部异常不能使能或者失能 SYSTEM EXCEPTIONS ---------------- */ case CPU_INT_RESET: /* Reset (see Note #2).*/ case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ case CPU_INT_SVCALL: /* SVCall (see Note #2). */ case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ case CPU_INT_PENDSV: /* PendSV (see Note #2). */ break; case CPU_INT_MEM: /* Memory management. */ CPU_CRITICAL_ENTER(); //进入临界区 CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_MEMFAULTENA; CPU_CRITICAL_EXIT(); //退出临界区 break; case CPU_INT_BUSFAULT: /* Bus fault. */ CPU_CRITICAL_ENTER(); CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_BUSFAULTENA; CPU_CRITICAL_EXIT(); break; case CPU_INT_USAGEFAULT: /* Usage fault.*/ CPU_CRITICAL_ENTER(); CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_USGFAULTENA; CPU_CRITICAL_EXIT(); break; case CPU_INT_SYSTICK: /* SysTick. */ CPU_CRITICAL_ENTER(); CPU_REG_NVIC_ST_CTRL &= ~CPU_REG_NVIC_ST_CTRL_ENABLE; CPU_CRITICAL_EXIT(); break; /* ----------- 除去前16号系统异常外的外部中断EXTERNAL INTERRUPT ---------------- */ default: pos_max = CPU_INT_SRC_POS_MAX; if (pos < pos_max) { /* See Note #3. */ group = (pos - 16) / 32; nbr = (pos - 16) % 32; CPU_CRITICAL_ENTER(); CPU_REG_NVIC_CLREN(group) = DEF_BIT(nbr); CPU_CRITICAL_EXIT(); } break; } } #define CPU_REG_NVIC_SHCSR (*((volatile CPU_INT32U *)(0xE000ED24))) /* System Handler Ctrl & State Reg. */ #define DEF_BIT_16 0x00010000 #define CPU_REG_NVIC_SHCSR_MEMFAULTENA DEF_BIT_16 /*0000 0000 0000 0001 0000 0000 0000 0000*/ line32: CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_MEMFAULTENA; 将CPU_REG_NVIC_SHCSR 寄存器16位清零,就是将存储器异常服务屏蔽,其他操作都类似。 然后是设置、获得某一异常中断入口地址的优先级的函数 void CPU_IntSrcPrioSet (CPU_INT08U pos, CPU_INT08U prio) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif CPU_INT08U group; CPU_INT08U nbr; CPU_INT08U pos_max; CPU_INT32U prio_32; CPU_INT32U temp; prio_32 = CPU_RevBits((CPU_INT08U)prio); prio = (CPU_INT08U)(prio_32 >> (3 * DEF_OCTET_NBR_BITS)); switch (pos) { /* ---------------- INVALID OR RESERVED --------------- */ case CPU_INT_STK_PTR: case CPU_INT_RSVD_07: case CPU_INT_RSVD_08: case CPU_INT_RSVD_09: case CPU_INT_RSVD_10: case CPU_INT_RSVD_13: break; /* ----------------- SYSTEM EXCEPTIONS ---------------- */ case CPU_INT_RESET: /* Reset (see Note #2). */ case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ break; case CPU_INT_MEM: /* Memory management. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI1; temp &= ~(DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); temp |= (prio << (0 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI1 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_BUSFAULT: /* Bus fault. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI1; temp &= ~(DEF_OCTET_MASK << (1 * DEF_OCTET_NBR_BITS)); temp |= (prio << (1 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI1 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_USAGEFAULT: /* Usage fault. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI1; temp &= ~(DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); temp |= (prio << (2 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI1 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_SVCALL: /* SVCall. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI2; temp &= ~((CPU_INT32U)DEF_OCTET_MASK <<(3 * DEF_OCTET_NBR_BITS)); temp |= (prio << (3 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI2 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_DBGMON: /* Debug monitor. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI3; temp &= ~(DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); temp |= (prio << (0 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI3 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_PENDSV: /* PendSV. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI3; temp &= ~(DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); temp |= (prio << (2 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI3 = temp; CPU_CRITICAL_EXIT(); break; case CPU_INT_SYSTICK: /* SysTick. */ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI3; temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); temp |= (prio << (3 * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_SHPRI3 = temp; CPU_CRITICAL_EXIT(); break; /* ---------------- EXTERNAL INTERRUPT ---------------- */ default: pos_max = CPU_INT_SRC_POS_MAX; if (pos < pos_max) { /* See Note #3. */ group = (pos - 16) / 4; nbr = (pos - 16) % 4; CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_PRIO(group); temp &= ~(DEF_OCTET_MASK << (nbr * DEF_OCTET_NBR_BITS)); temp |= (prio << (nbr * DEF_OCTET_NBR_BITS)); CPU_REG_NVIC_PRIO(group) = temp; CPU_CRITICAL_EXIT(); } break; } } #define CPU_REG_NVIC_SHPRI1 (*((volatile CPU_INT32U *)(0xE000ED18))) /* System Handlers 4 to 7 Prio. */ #define DEF_OCTET_MASK 0xFF #define DEF_OCTET_NBR_BITS 8 /*0000 0000 0000 0000 0000 0000 0000 1000*/ CPU_CRITICAL_ENTER(); temp = CPU_REG_NVIC_SHPRI1; /*将CPU_REG_NVIC_SHPRI1 值给temp*/ temp &= ~(DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); /*然后将temp bit0 - bit7 清零 */ temp |= (prio << (0 * DEF_OCTET_NBR_BITS)); /*然后将prio赋值给temp的bit0 - bit7*/ CPU_REG_NVIC_SHPRI1 = temp; /*最后将temp写回 CPU_REG_NVIC_SHPRI1 寄存器中*/ CPU_CRITICAL_EXIT(); 就是将CPU_REG_NVIC_SHPRI1 值给temp,然后将temp bit0 - bit7 清零 ,然后将prio赋值给temp的bit0 - bit7,最后将temp写回 CPU_REG_NVIC_SHPRI1 寄存器中 这样做的主要原因是Line1 中 CPU_REG_NVIC_SHPRI1 是按 32位寄存器访问的,而存储器异常优先级寄存器只有8位,为了不影响其他24bit的值,才不得已采用这种方法。 获得某一异常地址的优先级函数也采用了相似方法。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1758 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1613 浏览 1 评论
1053 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
721 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1670 浏览 2 评论
1931浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
721浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
563浏览 3评论
588浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
548浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-19 19:39 , Processed in 0.870534 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号