Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
ARMv8
cortex-A
SMP
双核Cortex-A7 rt-thread移植笔记
1.00
发布于 2021-04-10 17:34:42 浏览:8715
订阅该版
[tocm] # Cortex-A7 rt-thread移植笔记 ## 前言 公司安排在双核Cortex-A7平台上移植rt-thread,并测试在开启SMP后测试一下各项性能。 从拿到这个任务开始,到移植结束用了一个多月,超过了预期的时间。主要还是一些原理没有弄清楚,如双核SMP的运行原理、cp15协处理的各项配置等。还有被以前的经验所误导,认知也不够,耽误了蛮久的时间。下面就听我聊一下,这一个月的踩坑记录。 ## 软硬件介绍 * CPU:双核Coretx-A7 + Cortex-M33的多核异构芯片 * Cortex-M33:已移植好了rt-thread,相关的硬件外设由Cortex-M33负责初始化。 * Cortex-M33负责启动Cortex-A7 ## 目标 * 支持浮点 FPU * 支持 NEON * 支持MMU * rt-thread 开启SMP能正常运行 * coremark、内存读写等跑分测试达到相同等级硬件平台的水平 ## 移植步骤 #### 一、参考合适的BSP 1. 选择参考bsp目录下qemu-vexpress-a9的代码,因为cortex-A9体和cortex-A7差异不大,而且这个bsp默认开启了SMP,对移植有一定的价值。 2. 这个bsp 是在qemu下运行的,外设相关的依赖比较少,可以避免一些坑。 #### 二、编译运行 1. 找到参考的bsp后,首先要修改link.lds脚本中的链接地址,因为每个平台的代码运行空间不一样。 ```c 将. = 0x60010000; 修改为. = 0x3c000000; //这个地址类似于STM32H750的0x08000000 ``` 2. MMU配置,MMU的初始化大佬们已经整好了,我只需要在`board.c`中改一下页表配置,将原来qemu A9的改成现在平台的 ```c struct mem_desc platform_mem_desc[] = { {0x00000000, 0xFFFFFFFF-1, 0x00000000, NORMAL_MEM}, {0x50000000, 0x50300000-1, 0x50000000, DEVICE_MEM}, // SRAM {0x3C000000, 0x3C800000-1, 0x3C000000, NORMAL_MEM}, // PSRAM 代码空间 {0x40000000, 0x40100000-1, 0x40000000, DEVICE_MEM}, // peripheral 外设空间 }; ``` 2. 添加打印日志的代码,开始采用写共享内存,由M33轮训并输出的方式,事实证明这种方式没有串口输出更直接,对调试效率造成了一定的影响, 所以一种好用得调试手段很重要。如果有JTAG或者SWD这种接口,就先把这种调试环境搭建起来,不要想偷懒,人生没有捷径。因为后面遇到棘手的问题,这些高级的调试手段,会事半功倍。 3. 去除掉一些和外设相关的代码,编译运行(满怀欢喜的等待),结果没跑起来,继续查原因,这里折腾了一周多。 #### 三、踩坑过程 本来想着大佬们已经把体系相关的整好了,如GIC初始化、中断的压栈,进程调度等,到我这里就是简单的改改,事实证明,工资不是那么好拿的,需要掉点头发。 ##### 1. 通过日志查看,代码能运行到rtthread_startup中,但是有个很诡异的情况。增加或者删除日志打印的代码后,有时能进入,有时候不能,这玩意颠覆认知啊。事实证明这世界没有鬼的,这种问题一般都是和硬件有关,经过一周多的时间终于发现了,原来我手上的cortex-a7双核启动与qemu-vexpress-a9不一样。 * **qemu-vexpress-a9启动流程** ![qemu-vexpress-a9.png](https://oss-club.rt-thread.org/uploads/20210410/0adcb23c5bb154b9a476df3ffb7ef2d8.png) 关键代码实现: ```c void rt_hw_secondary_cpu_up(void) { extern void set_secondary_cpu_boot_address(void); set_secondary_cpu_boot_address(); __asm__ volatile ("dsb":::"memory"); rt_hw_ipi_send(0, 1 << 1); } void secondary_cpu_c_start(void) { rt_hw_vector_init(); rt_hw_spin_lock(&_cpus_lock); arm_gic_cpu_init(0, REALVIEW_GIC_CPU_BASE); arm_gic_set_cpu(0, IRQ_PBA8_TIMER0_1, 0x2); timer_init(0, 10000); rt_hw_interrupt_install(IRQ_PBA8_TIMER0_1, rt_hw_timer2_isr, RT_NULL, "tick"); rt_hw_interrupt_umask(IRQ_PBA8_TIMER0_1); rt_system_scheduler_start(); } ``` * **友商双核cortex-A7启动流程** ![cortex-a7启动.png](https://oss-club.rt-thread.org/uploads/20210410/b8d1c9dc614c0392aad8a17b1f0edb59.png) 从启动流程可以看出,我手上的这个cortex-a7在启动时,两个核心启动时是运行的同一份代码,导致了整个代码运行全乱了,出现了很多诡异的现象,所以需要修改启动代码。 * 修改启动代码,插入对cpu 编号的判断 ``` //读取cpu编号 @ get cpu id, and subtract the offset from the stacks base address MRC P15, 0, R5, C0, C0, 5 @ read multiprocessor affinity register AND R5, R5, #3 @ mask off, leaving CPU ID field CMP R5, #0 BEQ normal_setup //CPU0 跳转到正常启动流程 //下面是cpu1的流程 #ifdef RT_USING_SMP ldr r0, =secondary_cpu_entry mov r1, #0 str r1, [r0] /* clean secondary_cpu_entry */ #endif /* RT_USING_SMP */ secondary_loop: @ cpu core 1 goes into sleep until core 0 wakeup it wfe //休眠,等待cpu0 发送sev事件 #ifdef RT_USING_SMP ldr r1, =secondary_cpu_entry ldr r0, [r1] cmp r0, #0 //跳转到CPU0设置的入口地址 blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */ #endif /* RT_USING_SMP */ b secondary_loop ``` ##### 2. 解决完了启动问题后,每次都能正常进入到`rt_hw_board_init`中了,这个函数一般在board.c中实现,每个芯片会有一些差异。 ```c /** * This function will initialize beaglebone board */ void rt_hw_board_init(void) { /* initialize hardware interrupt */ rt_hw_interrupt_init(); /* initialize system heap */ rt_system_heap_init(heap_start, &heap_start[heap_len/sizeof(uint32_t)]); //rt_system_heap_init(HEAP_BEGIN, HEAP_END); rt_components_board_init(); //SystemClock_Init(); rt_console_set_device(RT_CONSOLE_DEVICE_NAME); rt_thread_idle_sethook(idle_wfi); rt_hw_systick_init(RT_TICK_PER_SECOND); #ifdef RT_USING_SMP /* install IPI handle */ rt_hw_ipi_handler_install(RT_SCHEDULE_IPI, rt_scheduler_ipi_handler); #endif } ``` 结果在调用rt_hw_interrupt_init 时挂了,继续加日志打印呗。 ```c /** * This function will initialize hardware interrupt */ void rt_hw_interrupt_init(void) { rt_uint32_t gic_cpu_base; rt_uint32_t gic_dist_base; rt_uint32_t gic_irq_start; /* initialize vector table */ rt_hw_vector_init(); /* initialize exceptions table */ rt_memset(isr_table, 0x00, sizeof(isr_table)); /* initialize ARM GIC */ gic_dist_base = platform_get_gic_dist_base(); gic_cpu_base = platform_get_gic_cpu_base(); gic_irq_start = GIC_IRQ_START; arm_gic_dist_init(0, gic_dist_base, gic_irq_start); arm_gic_cpu_init(0, gic_cpu_base); } ``` 日志显示,是在`arm_gic_dist_init(0, gic_dist_base, gic_irq_start);` 这句代码挂了,是访问了GIC控制器的基地址,等等GIC控制器基地址不应该都是一样的吗,我的第一反应这些属于arm的应该都一样。既然挂了,就得查资料, 最后在`Cortex-A7 MPCore Technical Reference Manual`中看到描述。 > The GIC registers are memory-mapped, and the base address is specified by PERIPHBASE[39:15]. This input must be tied to a constant value. The PERIPHBASE value is sampled during reset into the Configuration Base Address (CBAR) for each processor in the cluster. See Configuration Base Address Register on page 4-83. 果然这里有毒,需要读取CBAR寄存器获取GIC基地址,bsp引用的是realview.h中定义好的。 ```c #define REALVIEW_GIC_CPU_BASE 0x1E000100 /* Generic interrupt controller CPU interface */ #define REALVIEW_GIC_DIST_BASE 0x1E001000 /* Generic interrupt controller distributor */ ``` CBAR寄存器是通过CP15协处理访问,具体指令如下: ``` MRC p15, 4, r0, c15, c0, 0 ; ``` 读出来果然不是`0x1E000100`,更新GIC基地址后能过了。到这里两个周过去了,emmm,忍无可忍了,我终于把串口打印整上了,出现异常是又可以看到熟悉的打印了,真香。 ##### 3. 到这里串口能看到熟悉的shell了。 ``` \ | / - RT - Thread Operating System / | \ 4.0.3 build Apr 10 2021 2006 - 2021 Copyright by rt-thread team hello rt-thread msh> ``` ##### 4. 前面都是在单核下运行的,现在使能SMP。惴惴不安,使能SMP后,main线程不运行,代码如下: ```c int main(void) { int count = 0; printf("hello rt-thread\n"); rt_kprintf("a7 mian up %s\r\n", __TIME__); while (1) { rt_kprintf("a7 mian loop %d\r\n", count); count++; rt_thread_delay(1000); if(count > 10000) { break; } } return 0; } ``` ``` \ | / - RT - Thread Operating System / | \ 4.0.3 build Apr 10 2021 2006 - 2021 Copyright by rt-thread team hello rt-thread a7 mian up 06:1s: 3> a7 mian loop 0 ``` 没有实现1s打印一次的效果,直觉是中断没有触发,卡死在rt_thread_delay中了。经过几天的排查,发现在mmu配置忘记把定时器相关的地址段配置成设备内存属性,导致定时器有时候没有初始化成功。 细节很重要, 这个问题在移植前期MMU配置就有异常,粗心把问题放过去了,后面导致涉及的点太多,排查了很久。 * 内存段宏定义 ```c #define DESC_SEC (0x2) #define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */ #define MEMWB (3<<2) /* write back, no write allocate */ #define MEMWT (2<<2) /* write through, no write allocate */ #define SHAREDEVICE (1<<2) /* shared device */ #define STRONGORDER (0<<2) /* strong ordered */ #define XN (1<<4) /* eXecute Never */ #define AP_RW (3<<10) /* supervisor=RW, user=RW */ #define AP_RO (2<<10) /* supervisor=RW, user=RO */ #define SHARED (1<<16) /* shareable */ #define DOMAIN_FAULT (0x0) #define DOMAIN_CHK (0x1) #define DOMAIN_NOTCHK (0x3) #define DOMAIN0 (0x0<<5) #define DOMAIN1 (0x1<<5) #define DOMAIN0_ATTR (DOMAIN_CHK<<0) #define DOMAIN1_ATTR (DOMAIN_FAULT<<2) /* device mapping type */ #define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN) /* normal memory mapping type */ #define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC) ``` * mmu页表配置, `rt_hw_init_mmu_table`初始化时使用 ``` struct mem_desc platform_mem_desc[] = { {0x00000000, 0xFFFFFFFF-1, 0x00000000, NORMAL_MEM}, {0x50000000, 0x50300000-1, 0x50000000, DEVICE_MEM}, // SRAM {0x3C000000, 0x3C800000-1, 0x3C000000, NORMAL_MEM}, // PSRAM {0x40000000, 0x40100000-1, 0x40000000, DEVICE_MEM}, // peripheral {0x58000000, 0x58100000-1, 0x58000000, DEVICE_MEM}, // 定时器地址空间的内存描述 {0x58300000, 0x58400000-1, 0x58300000, DEVICE_MEM}, }; ``` 经过增加`0x58000000` 定时器外设基地址的的描述后,在每次都能稳定运行了。 ##### 5. neon使能 a7是需要跑算法的,所以neon必须打开,将`rtconfig.py`编译参数修改下。 * qemu A9 BSP中的原参数 ```python import os DEVICE = ' -march=armv7-a -marm -msoft-float' ``` * 使能neon后的参数 ``` import os DEVICE = ' -march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -ftree-vectorize -mfloat-abi=softfp -ffunction-sections -fdata-sections ' ``` * 参数介绍, [neon编译参数介绍](https://blog.csdn.net/u014470361/article/details/87931856) ``` Cortex-A7 -mcpu=cortex-a7 -mfpu=vfpv4 -mfpu=vfpv4-d16 -mfpu=neon-vfpv4 // 使能neon与vfp编译 -fp16表明支持16bit半精度浮点操作 ``` 运行就炸了,哎,仰天长叹。 ``` \ | / - RT - Thread Operating System / | \ 4.0.3 build Apr 6 2021 2006 - 2020 Copyright by rt-thread team undefined instruction: Execption: r00:0x00000000 r01:0x3c0447a8 r02:0x3c03bbac r03:0x3c0446dc r04:0xdeadbeef r05:0xdeadbeef r06:0xdeadbeef r07:0xdeadbeef r08:0xdeadbeef r09:0xdeadbeef r10:0xdeadbeef fp :0x3c044704 ip :0xfefefeff sp :0x3c0446d8 lr :0x3c002228 pc :0x3c0360bc cpsr:0x80000013 thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- sys_work 23 ready 0x00000044 0x00000800 03% 0x0000000a 000 mmcsd_de 22 ready 0x00000044 0x00000400 06% 0x00000014 000 tidle0 31 ready 0x00000048 0x00000400 07% 0x00000020 000 timer 4 suspend 0x0000007c 0x00000400 12% 0x0000000a 000 main 10 running 0x00000044 0x00000800 15% 0x00000014 000 shutdown... ``` 反汇编看看挂掉的地方是啥,反汇编关键代码: ``` 3c0360a8
: 3c0360a8: e92d4800 push {fp, lr} 3c0360ac: e28db004 add fp, sp, #4 3c0360b0: e24dd028 sub sp, sp, #40 ; 0x28 3c0360b4: e24b3028 sub r3, fp, #40 ; 0x28 3c0360b8: f2c00050 vmov.i32 q8, #0 ; 0x00000000 //大致在这个位置挂掉了 3c0360bc: f4430a0f vst1.8 {d16-d17}, [r3] 3c0360c0: f26021b0 vorr d18, d16, d16 3c0360c4: edc32b04 vstr d18, [r3, #16] 3c0360c8: f26021b0 vorr d18, d16, d16 3c0360cc: edc32b06 vstr d18, [r3, #24] 3c0360d0: edc30b07 vstr d16, [r3, #28] ``` 从`pc :0x3c0360bc` 向上查找可疑地方(arm流水线的原因PC值总比执行的值大一些),看到`3c0360b8`处的代码是一个vmov指令,带V开头的是neon与fpu的指令。这里证明neon编译参数是OK的,那就是系统配置选项可能没开,看了下`RT_USING_FPU`定义了。 * 日志显示进入未定义指令中断了,去看看 ```c void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) { #ifdef RT_USING_FPU { uint32_t ins; uint32_t addr; if (regs->cpsr & (1 << 5)) { /* thumb mode */ addr = regs->pc - 2; ins = (uint32_t)*(uint16_t*)addr; if ((ins & (3 << 11)) != 0) { /* 32 bit ins */ ins <<= 16; ins += *(uint16_t*)(addr + 2); } } else { addr = regs->pc - 4; ins = *(uint32_t*)addr; } if ((ins & 0xe00) == 0xa00) { /* float ins */ uint32_t val = (1U << 30); asm volatile ("vmsr fpexc, %0"::"r"(val):"memory"); regs->pc = addr; return; } } #endif rt_kprintf("undefined instruction:\n"); rt_hw_show_register(regs); #ifdef RT_USING_FINSH list_thread(); #endif rt_hw_cpu_shutdown(); } ``` 这段代码我找大佬问了下,大佬解释说这是rt-thread为了节约栈空间和压栈的时间,默认没开FPU,当产生异常时通过指令判断是不是neon或者vfp指令造成的异常,是就开启FPU,没有用到neon和vfp的任务就不会开启,确实是一个很巧妙的操作。 ``` 3c0360b8: f2c00050 vmov.i32 q8, #0 ; 0x00000000 //异常的指令 //指令判断条件 if ((ins & 0xe00) == 0xa00) { /* float ins */ uint32_t val = (1U << 30); //使能FPU asm volatile ("vmsr fpexc, %0"::"r"(val):"memory"); regs->pc = addr; return; } ``` 通过对比原判段条件不能覆盖到所有的neon和fpu指令,所以直接改成判断FPU是否开启,如果开启过还有异常,那就是真的未定义指令。 优化后的代码: ```c uint32_t val; asm volatile ("vmrs %0, fpexc" : "=r"(val)::"memory"); if (!(val & 0x40000000)) { /* float ins */ val = (1U << 30); asm volatile ("vmsr fpexc, %0"::"r"(val):"memory"); regs->pc = addr; return; } ``` 修改完毕后能正常启动了。 ##### 6. 内存性能测试 基础系统的移植完成后,还需要性能测试保证移植的质量,这里又搞了接近两周。 * 内存读写测试,使用的是软件包中的[MemoryPerf](http://packages.rt-thread.org/detail.html?package=MemoryPerf)。 * 因为开始SMP使能后有问题,第一轮测试时没有开启SMP,测试结果为。 | 平台 | 8bit读写(M/s) | 16bit读写(M/s) | 32bit读写(M/s) | | --- | --- | --- | --- | --- | | 其他rtos同平台 | 303.9 / 725.6 | 533.6 / 765.4 | 595.8 / 765.4 | | rt-thread | 5.3 / 15.9 | 10.6 / 31.9 | 21.2 / 63.7 | 与相同平台的其他rtos的测试结果对比差距很大,没办法只能对比原厂bsp,无数次测试后没有效果。最后在cortex-A7的手册中发现,开启SMP是使能dcache的前提条件,然后开启SMP。 ```c mrc p15, 0, r1, c1, c0, 1 mov r0, #(1<<6) orr r1, r0 mcr p15, 0, r1, c1, c0, 1 //enable smp ``` | 平台 | SMP | 8bit读写(M/s) | 16bit读写(M/s) | 32bit读写(M/s) | | --- | --- | --- | --- | --- | | 其他rtos同平台 | ON | 303.9 / 725.6 | 533.6 / 765.4 | 595.8 / 765.4 | | rt-thread | ON | 140.8 / 144.9 | 268.9 / 290.1 | 515.3 / 579.3 | | rt-thread | OFF | 5.3 / 15.9 | 10.6 / 31.9 | 21.2 / 63.7 | 开启后性能提升20多倍,但还有差距,原因后面慢慢到来。现在有点查不动了,跑个coremark。 ##### 7. coremark跑分测试 coremark跑分也是使用的软件包的工具[Coremark](http://packages.rt-thread.org/detail.html?package=CoreMark),居然还有这么多小工具,不用自己撸了,对rt-thread爱意增加100分。 rt-thread跑分结果 ```c Benchmark started, please make sure it runs for at least 10s. 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 16865 Total time (secs): 16 Iterations/Sec : 625 Iterations : 10000 Compiler version : GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] Compiler flags : Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0x988c Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 625 / GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] / STACK msh /> ``` 结果625分,总感觉哪里不对,去[coremark网站](https://www.eembc.org/coremark/scores.php)看看其他的平台跑分,居然还没有stm32H7的跑分高,瑟瑟发抖,感觉无法说服领导了。还是需要对比下,在同平台的其他rtos也跑一下。 ```c Benchmark started, please make sure it runs for at least 10s. 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 35038 Total time (secs): 35 Iterations/Sec : 2857 Iterations : 100000 Compiler version : GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] Compiler flags : Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0xd340 Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 2857 / GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] ``` 2875分,这个分数就很正常了,下面就查原因了,这时第4周已经要结束了。 ### 原因分析: 这时候系统已经能稳定运行,只是性能比较差,那是不是CPU主频设置不对呢?接下来询问原厂的兄弟,等待回复中。 * 这时不能闲着,反汇编代码看看bsp在cortex-a7里面干了什么,屏蔽掉时钟部分的设置,最后将测试代码提前到汇编启动代码中,测出来分数还是2857分。完犊子了,路子完全走错了。 * 最后想到,会不会是代码优化等级的问题,现在用的是-o0编译,改成-o2整一把,跑分2941分了。没想到优化等级会造成5倍差距,认知不够,被领导狠批了一顿(两周前就叫看看的)。 ``` Benchmark started, please make sure it runs for at least 10s. 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 17287 Total time (secs): 17 Iterations/Sec : 2941 Iterations : 50000 Compiler version : GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] Compiler flags : Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0xa14c Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 2941 / GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] / STACK ``` * rt-thread 编译等级的修改在`rtconfig.py`,设置BUILD = 'release'就可以了。 ```python import os BUILD = 'debug' # generate debug info in all cases AFLAGS += ' -gdwarf-2' CFLAGS += ' -g -gdwarf-2' if BUILD == 'debug': CFLAGS += ' -O0' else: CFLAGS += ' -O2' ``` ##### 7. 收尾 上面还留了一个小尾巴,内存性能测试有差距,最后在开启SMP, -O2编译的情况下测试一下。 | 平台 | SMP | 优化等级 | 8bit读写(M/s) | 16bit读写(M/s) | 32bit读写(M/s) | | --- | --- | --- | --- | --- | --- | | 其他rtos同平台 | ON | -o2 | 303.9 / 725.6 | 533.6 / 765.4 | 595.8 / 765.4 | | rt-thread | ON | -o2 | 304.8 / 725.7 | 536.4 / 765.4 | 606.1 / 765.4 | | rt-thread | ON | -o0 |140.8 / 144.9 | 268.9 / 290.1 | 515.3 / 579.3 | | rt-thread | OFF | -o0 | 5.3 / 15.9 | 10.6 / 31.9 | 21.2 / 63.7 | 内存读写也正常了,到现在移植完成,所有的指标完成。 ## 总结 1. 必要的调试工具是不可少的,会缩短解决问题的时间,比如调时序就要上逻辑分析仪,调代码就要整GDB这些。 2. 调试过程中要做记录,将可能项列成表格,最后逐个排查,免得后面都晕菜了,不知道调了啥,这个要被吊的。 3. 养成良好的工作习惯,多学习计算机原理,学会分析问题。
16
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
小鳄鱼
rt-thread脑残粉
文章
8
回答
45
被采纳
7
关注TA
发私信
相关文章
1
aarch64有计划支持SMP吗
2
SMP重新定义中断处理函数的问题
3
rt_tick_increase()在SMP时只增加当前核的TICK?
4
RISCV smp系统调度异常问题请教
5
qemu-vexpress-a9 在SMP情况下GDB无法调试
6
为什么在k210上使用多核smp总是会卡死
7
RT-Thread SMP核弹碰撞树莓派
8
请教多核SMP功能验证
9
明年开始玩SMP多核处理器
10
建议RT-Thread支持SMP
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
289
次被采纳
张世争
808
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
catcatbing
3
篇文章
4
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部