[活动专区] [活动专区] 【开源活动】- 国民N32G45x的SD卡IAP升级折腾笔记

[复制链接]
1486|5
 楼主| walker2048 发表于 2023-4-2 19:10 | 显示全部楼层 |阅读模式
本帖最后由 walker2048 于 2023-4-2 19:10 编辑

很高兴能参加本次国民N32G45x的SD卡IAP升级开发活动,通过本次活动,我学到了SDIO的SD卡读写,腾讯TinyOS的fatfs移植等内容。虽然没能完成本次活动作业,但是在折腾的过程中,也学到了不少东西。
以下是本次活动的个人折腾笔记和部分心得。

一、国民技术N32G45x的VSCode开发环境配置
由于我个人非常喜欢用VSCode开发单片机程序,所以只习惯在VSCode下开发。如果单片机不支持VSCode的,那也得想办法弄。经过在网上搜索,学习OpenOCD的芯片移植,把N32G45x的构建系统移植到GN + Ninja上,成功实现了VSCode下的编译和debug调试。以下是运行截图。

VSCode.png

移植N32G45x源码到GN + Ninja构建系统上,需要添加以下内容。
  • 添加厂家和单片机的gcc编译配置(build/config/nationstech/BUILD.gn)
  • 添加开发板配置文件和bsp源码文件(hardware/board/n32g45xvl_STB目录下的内容)
  • 添加厂家芯片级SDK文件(hardware/chip/nationstech/n32g457目录下的内容)


单片机的gcc编译配置 build/config/nationstech/BUILD.gn文件内容,此文件定义了编译选项,全局宏定义配置和头文件目录等内容
  1. config("default") {
  2.   defines = []
  3.   cflags = []
  4.   cflags += [
  5.     "-ffunction-sections",
  6.     "-fdata-sections",
  7.     "-fdiagnostics-color=always",
  8.     "-fno-common",
  9.   ]
  10.   cflags += [
  11.     "-Wunused",
  12.     "-Wuninitialized",
  13.   ]
  14.   ldflags = [
  15.     "-nostartfiles",
  16.     "--specs=nosys.specs",
  17.     "-Xlinker",
  18.     "--gc-sections",
  19.   ]
  20.   asmflags = [
  21.     "-g",
  22.     "-x",
  23.     "assembler-with-cpp",
  24.   ]
  25. }

  26. config("n32g457") {
  27.   defines = [
  28.     "N32G45X",
  29.     "USE_STDPERIPH_DRIVER",
  30.   ]
  31.   cflags = [
  32.     "-mcpu=cortex-m4",
  33.     "-mthumb",
  34.     "-mfpu=fpv4-sp-d16",
  35.     "-mfloat-abi=hard",
  36.   ]
  37.   asmflags = cflags
  38.   cflags += [
  39.     "-g",
  40.     "-gdwarf-2",
  41.     "-Os",
  42.   ]
  43.   asmflags += [ "-g" ]
  44.   cflags_c = [ "-std=gnu99" ]
  45.   cflags_cc = [ "-std=c++11" ]
  46.   ldflags = cflags
  47.   ldflags += [
  48.     "-T",
  49.     "../../hardware/chip/${vendor}/${chip}/Link.ld",
  50.   ]
  51.   include_dirs = [
  52.     "//hardware/chip/${vendor}/${chip}/",
  53.     "//hardware/chip/${vendor}/${chip}/algo_lib/inc",
  54.     "//hardware/chip/${vendor}/${chip}/cmsis",
  55.     "//hardware/chip/${vendor}/${chip}/Peripheral/inc",
  56.     "//hardware/chip/${vendor}/${chip}/USBFS/inc",
  57.     "//hardware/board/${product}",
  58.   ]
  59. }

开发板配置文件内容,GN构建生成系统根据此文件确定顶层组件。
hardware/board/n32g45xvl_STB/BUILD.gn文件
  1. # Executable for board   --------------------------------------------------
  2. #
  3. # Executable target configuration.
  4. #
  5. # Setting up configeration fot chip and board.
  6. executable("n32g45xvl_STB") {
  7.   # Common deps for executable target.
  8.   # --------------------------------
  9.   deps = [
  10.     #"//components/net/at",
  11.     ":bsp",
  12.     ":startup",
  13.     "//components/fs/fatfs",
  14.     "//components/fs/kv",
  15.     "//components/fs/vfs",
  16.     "//components/utils",

  17.     #"//applications/${app}",
  18.     "//hardware/arch/arm",
  19.     "//hardware/chip/${vendor}/${chip}:${chip}_sdk",
  20.   ]

  21.   deps += [ "//kernel" ]
  22. }

  23. # Startup sources config.
  24. # --------------------------------
  25. source_set("startup") {
  26.   sources = [ "//hardware/chip/${vendor}/${chip}/startup_n32g45x.s" ]
  27. }

  28. # Startup sources config.
  29. # --------------------------------
  30. source_set("bsp") {
  31.   sources = [
  32.     "main.c",
  33.     "n32g45x_it.c",
  34.   ]
  35. }



hardware/board/n32g45xvl_STB/product.gni文件,GN构建系统根据此文件确定编译工具链,芯片和厂家配置,内核以及app配置
  1. declare_args() {
  2.   # 工具链名称
  3.   # --------------------------------
  4.   compiler = "arm_none_eabi_gcc"

  5.   # gcc,检测工具链用
  6.   # --------------------------------
  7.   gcc = "arm-none-eabi-gcc"

  8.   # 芯片型号
  9.   # --------------------------------
  10.   chip = "n32g457"

  11.   # 厂商
  12.   # --------------------------------
  13.   vendor = "nationstech"

  14.   # 应用
  15.   # --------------------------------
  16.   app = "dummy"

  17.   # RTOS内核
  18.   # --------------------------------
  19.   kernel = "TinyOS"

  20.   # bin类型
  21.   # --------------------------------
  22.   build_type = "debug"

  23.   # ccache缓存
  24.   # --------------------------------
  25.   ccache = true
  26. }

Debug调试配置
调试使用的是cortex-debug插件(只需要安装这个),以下是调试文件配置内容(本项目会根据选择的开发板自行生成该文件)。
.vscode/launch.json
  1. {
  2.     // 使用 IntelliSense 了解相关属性。
  3.     // 悬停以查看现有属性的描述。
  4.     // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  5.     "version": "0.2.0",
  6.     "configurations": [
  7.         {
  8.             "name": "Cortex Debug",
  9.             "cwd": "${workspaceFolder}/out/n32g45xvl_STB",
  10.             "executable": "./bin/n32g45xvl_STB.elf",
  11.             "device": "n32g457",
  12.             "svdFile": "${workspaceFolder}/hardware/chip/nationstech/n32g457/n32g457.svd",
  13.             "request": "launch",
  14.             "type": "cortex-debug",
  15.             "runToEntryPoint": "main",
  16.             "servertype": "openocd",
  17.             "configFiles": [
  18.                 "${workspaceFolder}/hardware/chip/nationstech/debug.cfg"
  19.             ]
  20.         }
  21.     ]
  22. }

配置完以上内容后,还需要编译和安装移植好的OpenOCD,添加hardware/chip/nationstech/debug.cfg文件,检查源码和linkScript文件是否正确匹配,然后就可以开始愉快的用VSCode开发啦。
 楼主| walker2048 发表于 2023-4-2 19:10 | 显示全部楼层
本帖最后由 walker2048 于 2023-4-2 19:23 编辑

二、移植腾讯TinyOS
1. 线程的栈信息初始化
N32G457使用的是Cortex-M4F内核,而Cortex-M3和Cortex-M4都基于ARMv7-M架构。腾讯TinyOS的ARMv7-M架构支持已经很完善了。这里我们不需要自己去写对应的代码,只需要使用系统里自带的源码即可。
RTOS想从主程序切换到线程上,或者进行线程间的切换,就需要线程的栈信息。然后在准备线程的相关信息时,线程的栈保存是很关键的,如果sp地址没指向正确的地址,就跑飞了。
如果是自己从零开始写,就需要注意port.S文件里,保存寄存器时的顺序,和这个初始化函数里定义的顺序是否一致。
源码的文件路径,hardware/arch/arm/arm-v7m/common/tos_cpu.c
  1. /*----------------------------------------------------------------------------
  2. * Tencent is pleased to support the open source community by making TencentOS
  3. * available.
  4. *
  5. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
  6. * If you have downloaded a copy of the TencentOS binary from Tencent, please
  7. * note that the TencentOS binary is licensed under the BSD 3-Clause License.
  8. *
  9. * If you have downloaded a copy of the TencentOS source code from Tencent,
  10. * please note that TencentOS source code is licensed under the BSD 3-Clause
  11. * License, except for the third-party components listed below which are
  12. * subject to different license terms. Your integration of TencentOS into your
  13. * own projects may require compliance with the BSD 3-Clause License, as well
  14. * as the other licenses applicable to the third-party components included
  15. * within TencentOS.
  16. *---------------------------------------------------------------------------*/

  17. #include "tos_k.h"

  18. __API__ uint32_t tos_cpu_clz(uint32_t val)
  19. {
  20. #if defined(TOS_CFG_CPU_LEAD_ZEROS_ASM_PRESENT) && (TOS_CFG_CPU_LEAD_ZEROS_ASM_PRESENT == 0u)
  21.     uint32_t nbr_lead_zeros = 0;

  22.     if (!(val & 0XFFFF0000)) {
  23.         val <<= 16;
  24.         nbr_lead_zeros += 16;
  25.     }

  26.     if (!(val & 0XFF000000)) {
  27.         val <<= 8;
  28.         nbr_lead_zeros += 8;
  29.     }

  30.     if (!(val & 0XF0000000)) {
  31.         val <<= 4;
  32.         nbr_lead_zeros += 4;
  33.     }

  34.     if (!(val & 0XC0000000)) {
  35.         val <<= 2;
  36.         nbr_lead_zeros += 2;
  37.     }

  38.     if (!(val & 0X80000000)) {
  39.         nbr_lead_zeros += 1;
  40.     }

  41.     if (!val) {
  42.         nbr_lead_zeros += 1;
  43.     }

  44.     return (nbr_lead_zeros);
  45. #else
  46.     return port_clz(val);
  47. #endif
  48. }

  49. __API__ void tos_cpu_int_disable(void)
  50. {
  51.     port_int_disable();
  52. }

  53. __API__ void tos_cpu_int_enable(void)
  54. {
  55.     port_int_enable();
  56. }

  57. __API__ cpu_cpsr_t tos_cpu_cpsr_save(void)
  58. {
  59.     return port_cpsr_save();
  60. }

  61. __API__ void tos_cpu_cpsr_restore(cpu_cpsr_t cpsr)
  62. {
  63.     port_cpsr_restore(cpsr);
  64. }

  65. __KNL__ void cpu_init(void)
  66. {
  67.     k_cpu_cycle_per_tick = TOS_CFG_CPU_CLOCK / k_cpu_tick_per_second;
  68.     cpu_systick_init(k_cpu_cycle_per_tick);

  69. #if (TOS_CFG_CPU_HRTIMER_EN > 0)
  70.     tos_cpu_hrtimer_init();
  71. #endif
  72. }

  73. __KNL__ void cpu_reset(void)
  74. {
  75.     port_cpu_reset();
  76. }

  77. __KNL__ void cpu_sched_start(void)
  78. {
  79.     port_sched_start();
  80. }

  81. __KNL__ void cpu_context_switch(void)
  82. {
  83.     port_context_switch();
  84. }

  85. __KNL__ void cpu_irq_context_switch(void)
  86. {
  87.     port_irq_context_switch();
  88. }

  89. __KNL__ void cpu_systick_init(k_cycle_t cycle_per_tick)
  90. {
  91.     port_systick_priority_set(TOS_CFG_CPU_SYSTICK_PRIO);
  92.     port_systick_config(cycle_per_tick);
  93. }

  94. #if TOS_CFG_TICKLESS_EN > 0u

  95. /**
  96. * [url=home.php?mod=space&uid=247401]@brief[/url] Set value to systick reload value register
  97. *
  98. * @param cycles The value set to register
  99. *
  100. * [url=home.php?mod=space&uid=266161]@return[/url] None
  101. */
  102. __STATIC_INLINE__ void cpu_systick_reload(k_cycle_t cycle_per_tick)
  103. {
  104.     port_systick_reload(cycle_per_tick);
  105. }

  106. /**
  107. * @brief Enable systick interrupt
  108. *
  109. * @return None
  110. */
  111. __KNL__ void cpu_systick_resume(void)
  112. {
  113.     port_systick_resume();
  114. }

  115. /**
  116. * @brief Disable systick interrupt
  117. *
  118. * @return None
  119. */
  120. __KNL__ void cpu_systick_suspend(void)
  121. {
  122.     port_systick_suspend();
  123. }

  124. __KNL__ k_time_t cpu_systick_max_delay_millisecond(void)
  125. {
  126.     return port_systick_max_delay_millisecond();
  127. }

  128. __KNL__ void cpu_systick_expires_set(k_time_t millisecond)
  129. {
  130.     k_cycle_t cycles;

  131.     cycles = (k_cycle_t)((uint64_t)millisecond * TOS_CFG_CPU_CLOCK / K_TIME_MILLISEC_PER_SEC); /* CLOCK means cycle per second */

  132.     cpu_systick_reload(cycles - 12); /* interrupt delay */
  133. }

  134. __KNL__ void cpu_systick_pending_reset(void)
  135. {
  136.     port_systick_pending_reset();
  137. }

  138. __KNL__ void cpu_systick_reset(void)
  139. {
  140.     cpu_systick_reload(k_cpu_cycle_per_tick);
  141. }

  142. #endif /* TOS_CFG_TICKLESS_EN */

  143. #if TOS_CFG_PWR_MGR_EN > 0u

  144. __KNL__ void cpu_sleep_mode_enter(void)
  145. {
  146.     port_sleep_mode_enter();
  147. }

  148. __KNL__ void cpu_stop_mode_enter(void)
  149. {
  150.     port_stop_mode_enter();
  151. }

  152. __KNL__ void cpu_standby_mode_enter(void)
  153. {
  154.     port_standby_mode_enter();
  155. }

  156. #endif /* TOS_CFG_PWR_MGR_EN */

  157. __KNL__ k_stack_t *cpu_task_stk_init(void *entry,
  158.                                               void *arg,
  159.                                               void *exit,
  160.                                               k_stack_t *stk_base,
  161.                                               size_t stk_size)
  162. {
  163.     cpu_data_t *sp;

  164.     sp = (cpu_data_t *)&stk_base[stk_size];
  165.     sp = (cpu_data_t *)((cpu_addr_t)sp & 0xFFFFFFF8);

  166. #if TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN > 0u
  167.     uint8_t *slot = (uint8_t *)&stk_base[0];
  168.     for (; slot < (uint8_t *)sp; ++slot) {
  169.         *slot = 0xCC;
  170.     }
  171. #endif

  172.     /* auto-saved on exception(pendSV) by hardware */
  173.     *--sp = (cpu_data_t)0x01000000u;    /* xPSR     */
  174.     *--sp = (cpu_data_t)entry;          /* entry    */
  175.     *--sp = (cpu_data_t)exit;           /* R14 (LR) */
  176.     *--sp = (cpu_data_t)0x12121212u;    /* R12      */
  177.     *--sp = (cpu_data_t)0x03030303u;    /* R3       */
  178.     *--sp = (cpu_data_t)0x02020202u;    /* R2       */
  179.     *--sp = (cpu_data_t)0x01010101u;    /* R1       */
  180.     *--sp = (cpu_data_t)arg;            /* R0: arg  */

  181.     /* Remaining registers saved on process stack */
  182.     /* EXC_RETURN = 0xFFFFFFFDL
  183.        Initial state: Thread mode +  non-floating-point state + PSP
  184.        31 - 28 : EXC_RETURN flag, 0xF
  185.        27 -  5 : reserved, 0xFFFFFE
  186.        4       : 1, basic stack frame; 0, extended stack frame
  187.        3       : 1, return to Thread mode; 0, return to Handler mode
  188.        2       : 1, return to PSP; 0, return to MSP
  189.        1       : reserved, 0
  190.        0       : reserved, 1
  191.      */
  192. #if defined (TOS_CFG_CPU_ARM_FPU_EN) && (TOS_CFG_CPU_ARM_FPU_EN == 1U)
  193.     *--sp = (cpu_data_t)0xFFFFFFFDL;
  194. #endif

  195.     *--sp = (cpu_data_t)0x11111111u;    /* R11      */
  196.     *--sp = (cpu_data_t)0x10101010u;    /* R10      */
  197.     *--sp = (cpu_data_t)0x09090909u;    /* R9       */
  198.     *--sp = (cpu_data_t)0x08080808u;    /* R8       */
  199.     *--sp = (cpu_data_t)0x07070707u;    /* R7       */
  200.     *--sp = (cpu_data_t)0x06060606u;    /* R6       */
  201.     *--sp = (cpu_data_t)0x05050505u;    /* R5       */
  202.     *--sp = (cpu_data_t)0x04040404u;    /* R4       */

  203.     return (k_stack_t *)sp;
  204. }

  205. #if TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN > 0u

  206. __KNL__ k_err_t cpu_task_stack_draught_depth(k_stack_t *stk_base, size_t stk_size, int *depth)
  207. {
  208.     uint8_t *slot;
  209.     uint8_t *sp, *bp;
  210.     int the_depth = 0;

  211.     bp = (uint8_t *)&stk_base[0];

  212.     sp = &stk_base[stk_size];
  213.     sp = (uint8_t *)((cpu_addr_t)sp & 0xFFFFFFF8);

  214.     for (slot = sp - 1; slot >= bp; --slot) {
  215.         if (*slot != 0xCC) {
  216.             the_depth = sp - slot;
  217.         }
  218.     }

  219.     *depth = the_depth;
  220.     if (the_depth == stk_size) {
  221.         return K_ERR_TASK_STK_OVERFLOW;
  222.     }

  223.     return K_ERR_NONE;
  224. }

  225. #endif

  226. #if TOS_CFG_FAULT_BACKTRACE_EN > 0u

  227. #if defined (TOS_CFG_CPU_ARM_FPU_EN) && (TOS_CFG_CPU_ARM_FPU_EN == 1U)
  228. __KNL__ void cpu_flush_fpu(void)
  229. {
  230.     (void)__get_FPSCR();
  231. }
  232. #endif

  233. __KNL__ void cpu_fault_diagnosis(void)
  234. {
  235.     port_fault_diagnosis();
  236. }

  237. #endif /* TOS_CFG_FAULT_BACKTRACE_EN */

如果确定这个线程栈信息是正确初始化了,那接下来就可以看线程切换时,保存和恢复现场的相关代码了。
2. 现场保存和恢复相关功能
在初始化了线程的相关内容后,就可以准备开始第一次的线程调度了。然后线程调度的相关汇编代码是在hardware/arch/arm/arm-v7m/cortex-m4/port_s.S这个文件里。
相关的代码也是不需要我们写的,除了下面展示的现场保存和恢复部分的汇编代码以外,开关中断,初次调度线程,唤起调度中断等等内容都是实现好了的。没必要自己去写,有兴趣研究的,可以用一块能运行TinyOS的开发板,在对应的功能上打断点,然后再查看运行前后的mcu寄存器值去学习和了解。
  1. .global port_int_disable
  2.     .global port_int_enable

  3.     .global port_cpsr_save
  4.     .global port_cpsr_restore

  5.     .global port_sched_start
  6.     .global port_context_switch
  7.     .global port_irq_context_switch

  8.     .global port_clz

  9.     .global PendSV_Handler

  10.     .extern k_curr_task
  11.     .extern k_next_task


  12. .equ SCB_VTOR,              0xE000ED08
  13. .equ NVIC_INT_CTRL,         0xE000ED04
  14. .equ NVIC_SYSPRI14,         0xE000ED22
  15. .equ NVIC_PENDSV_PRI,       0xFF
  16. .equ NVIC_PENDSVSET,        0x10000000


  17.    .text
  18.    .align 2
  19.    .thumb
  20.    .syntax unified


  21. .type port_int_disable, %function
  22. port_int_disable:
  23.     CPSID   I
  24.     BX      LR


  25. .type port_int_enable, %function
  26. port_int_enable:
  27.     CPSIE   I
  28.     BX      LR


  29. .type port_cpsr_save, %function
  30. port_cpsr_save:
  31.     MRS     R0, PRIMASK
  32.     CPSID   I
  33.     BX      LR


  34. .type port_cpsr_restore, %function
  35. port_cpsr_restore:
  36.     MSR     PRIMASK, R0
  37.     BX      LR


  38. .type port_clz, %function
  39. port_clz:
  40.     CLZ     R0, R0
  41.     BX      LR


  42. .thumb_func
  43. .type port_sched_start, %function
  44. port_sched_start:
  45.     CPSID   I

  46.     [url=home.php?mod=space&uid=72445]@[/url] set pendsv priority lowest
  47.     @ otherwise trigger pendsv in port_irq_context_switch will cause a context switch in irq
  48.     @ that would be a disaster
  49.     MOVW    R0, #:lower16:NVIC_SYSPRI14
  50.     MOVT    R0, #:upper16:NVIC_SYSPRI14

  51.     MOVW    R1, #:lower16:NVIC_PENDSV_PRI
  52.     MOVT    R1, #:upper16:NVIC_PENDSV_PRI
  53.     STRB    R1, [R0]

  54.     MOVW    R0, #:lower16:SCB_VTOR
  55.     MOVT    R0, #:upper16:SCB_VTOR
  56.     LDR     R0, [R0]
  57.     LDR     R0, [R0]
  58.     MSR     MSP, R0

  59.     MOVW    R0, #:lower16:k_curr_task
  60.     MOVT    R0, #:upper16:k_curr_task

  61.     @ k_curr_task = k_next_task;
  62.     MOVW    R1, #:lower16:k_next_task
  63.     MOVT    R1, #:upper16:k_next_task
  64.     LDR     R2, [R1]
  65.     STR     R2, [R0]

  66.     @ sp = k_next_task->sp
  67.     LDR     R0, [R2]
  68.     @ PSP = sp
  69.     MSR     PSP, R0

  70.     MRS     R0, CONTROL
  71.     ORR     R0, R0, #2
  72.     MSR     CONTROL, R0

  73.     ISB

  74.     @ restore r4-11 from new process stack
  75.     LDMFD    SP!, {R4 - R11}

  76.     #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
  77.     @ ignore EXC_RETURN the first switch
  78.     LDMFD   SP!, {R0}
  79.     #endif

  80.     @ restore r0, r3
  81.     LDMFD    SP!, {R0 - R3}
  82.     @ load R12 and LR
  83.     LDMFD    SP!, {R12, LR}   
  84.     @ load PC and discard xPSR
  85.     LDMFD    SP!, {R1, R2}

  86.     CPSIE    I
  87.     BX       R1


  88. .thumb_func
  89. .type port_context_switch, %function
  90. port_context_switch:
  91.     LDR     R0, =NVIC_INT_CTRL
  92.     LDR     R1, =NVIC_PENDSVSET
  93.     STR     R1, [R0]
  94.     BX      LR


  95. .thumb_func
  96. .type port_irq_context_switch, %function
  97. port_irq_context_switch:
  98.     LDR     R0, =NVIC_INT_CTRL
  99.     LDR     R1, =NVIC_PENDSVSET
  100.     STR     R1, [R0]
  101.     BX      LR


  102. .thumb_func
  103. .type PendSV_Handler, %function
  104. PendSV_Handler:
  105.     CPSID   I
  106.     MRS     R0, PSP

  107. _context_save:
  108.     @ R0-R3, R12, LR, PC, xPSR is saved automatically here
  109.     #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
  110.     @ is it extended frame?
  111.     TST     LR, #0x10
  112.     IT      EQ
  113.     VSTMDBEQ  R0!, {S16 - S31}
  114.     @ S0 - S16, FPSCR saved automatically here

  115.     @ save EXC_RETURN
  116.     STMFD   R0!, {LR}
  117.     #endif

  118.     @ save remaining regs r4 - 11 on process stack
  119.     STMFD   R0!, {R4 - R11}

  120.     @ k_curr_task->sp = PSP;
  121.     MOVW    R5, #:lower16:k_curr_task
  122.     MOVT    R5, #:upper16:k_curr_task
  123.     LDR     R6, [R5]
  124.     @ R0 is SP of process being switched out
  125.     STR     R0, [R6]

  126. _context_restore:
  127.     @ k_curr_task = k_next_task;
  128.     MOVW    R1, #:lower16:k_next_task
  129.     MOVT    R1, #:upper16:k_next_task
  130.     LDR     R2, [R1]
  131.     STR     R2, [R5]

  132.     @ R0 = k_next_task->sp
  133.     LDR     R0, [R2]

  134.     @ restore R4 - R11
  135.     LDMFD   R0!, {R4 - R11}

  136.     #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
  137.     @ restore EXC_RETURN
  138.     LDMFD   R0!, {LR}
  139.     @ is it extended frame?
  140.     TST     LR, #0x10
  141.     IT      EQ
  142.     VLDMIAEQ    R0!, {S16 - S31}
  143.     #endif

  144.     @ Load PSP with new process SP
  145.     MSR     PSP, R0
  146.    
  147.     CPSIE   I

  148.     @ R0-R3, R12, LR, PC, xPSR restored automatically here
  149.     @ S0 - S16, FPSCR restored automatically here if FPCA = 1
  150.     BX      LR

  151. .end

3. 系统心跳
在hardware/chip/nationstech/n32g457/cmsis/core_cm4.h文件里,已经实现了通用的系统心跳配置函数,这个也是不需要我们去写的。配置系统心跳的相关内容也不需要我们管,在TinyOS启动内核时会初始化系统心跳。
  1. /* ##################################    SysTick function  ############################################ */
  2. /**
  3.   \ingroup  CMSIS_Core_FunctionInterface
  4.   \defgroup CMSIS_Core_SysTickFunctions SysTick Functions
  5.   \brief    Functions that configure the System.
  6.   @{
  7. */

  8. #if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)

  9. /**
  10.   \brief   System Tick Configuration
  11.   \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
  12.            Counter is in free running mode to generate periodic interrupts.
  13.   \param [in]  ticks  Number of ticks between two interrupts.
  14.   \return          0  Function succeeded.
  15.   \return          1  Function failed.
  16.   \note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
  17.            function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
  18.            must contain a vendor-specific implementation of this function.
  19. */
  20. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  21. {
  22.   if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  23.   {
  24.     return (1UL);                                                   /* Reload value impossible */
  25.   }

  26.   SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  27.   NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  28.   SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  29.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  30.                    SysTick_CTRL_TICKINT_Msk   |
  31.                    SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  32.   return (0UL);                                                     /* Function successful */
  33. }

  34. #endif
我们只需要在bsp目录里的hardware/board/n32g45xvl_STB/n32g45x_it.c文件,把SysTick_Handler的实现函数修改一下就可以了。
  1. /**
  2. * @brief  This function handles SysTick Handler.
  3. */
  4. void SysTick_Handler(void) {
  5.     if (tos_knl_is_running()) {
  6.         tos_knl_irq_enter();
  7.         tos_tick_handler();
  8.         tos_knl_irq_leave();
  9.     }
  10. }
最后,我们在main.c文件(hardware/board/n32g45xvl_STB/main.c)里创建两个调试线程
  1. #define APPLICATION_TASK_STK_SIZE 1024
  2. k_task_t application_task;
  3. __aligned(4) uint8_t application_task_stk[APPLICATION_TASK_STK_SIZE];
  4. k_task_t application_task1;
  5. __aligned(4) uint8_t application_task1_stk[APPLICATION_TASK_STK_SIZE];

  6. void application_entry(void *arg) {
  7.     while (1) {
  8.         tos_task_delay(2500);
  9.         printf("task1 running!\r\n");
  10.     };
  11. }

  12. void application_entry2(void *arg) {
  13.     while (1) {
  14.         tos_task_delay(1200);
  15.         printf("task2 running!\r\n");
  16.     };
  17. }


然后在main函数里创建这两个线程,并开启调度就可以啦


  1. /*********************************************************************
  2. * @fn      main
  3. *
  4. * @brief   Main program.
  5. *
  6. * @return  none
  7. */
  8. int main(void) {
  9.     bsp_init(); // 初始化debug串口和板级外设

  10.     tos_knl_init(); // 初始化TencentOS tiny内核

  11.     printf("TinyOS demo!\r\n");

  12.     // 创建一个优先级为5的任务
  13.     tos_task_create(&application_task, "task_prio5", application_entry, NULL, 4,
  14.                     application_task_stk, APPLICATION_TASK_STK_SIZE, 0);
  15.     // 创建一个优先级为5的任务
  16.     tos_task_create(&application_task1, "task_prio5", application_entry2, NULL, 4,
  17.                     application_task1_stk, APPLICATION_TASK_STK_SIZE, 0);
  18.     // 开始内核调度,线程中不允许有睡死代码。
  19.     tos_knl_start();

  20.     while (1) {
  21.     }
  22. }


然后就编译、烧录,最后看到串口欢快的跳起线程里的输出内容啦。


tos.png
 楼主| walker2048 发表于 2023-4-2 19:11 | 显示全部楼层
本帖最后由 walker2048 于 2023-4-2 20:13 编辑

三、适配腾讯TinyOS的vfs和fatfs组件
1. 由于第一次使用单片机实现SD卡读取,对这方面并不熟悉,所以我只能先使用国民技术官方SDIO的demo来学习。通过demo源码的阅读,可以看出该源码支持SDIO 1bit,4bit,8bit模式(8bit模式应该是适配emmc的)。然后我手上的SD卡模块是spi方式接入,通过对比spi模式和SDIO 1bit模式的引脚,可以使用。以下是接线图。 connect.png

通过修改源码里传递给SD_Init()函数的第三个参数(由原来的4改为1),即可运行该demo,并对SD卡进行读写测试。测试内容如下。

sdio_1bit.png

demo正确获取到了SD卡的信息(除容量获取错误以外),也正确写入和读出了扇区的内容。可以开始移植了。

2. 处理原sdio源码文件
可能是出于兼容性的考虑,腾讯TinyOS的sd卡初始化函数是不传递任何参数的,所以我们需要将原sdio实现代码中的SD_Init函数更名为__SD_Init,并在文件尾重写一个SD_Init函数。以下为改写内容。
  1. SD_Error SD_Init(){
  2.     return __SD_Init(0, 3, 1);
  3. }


3. 实现tos_hal_sd的接口函数
腾讯TinyOS的Fatfs组件里会调用tos_hal_sd层级的函数,避免直接调用芯片级的hal函数,实现多种芯片的软件兼容。所以我们需要为国民N32G457编写对应的文件。
hardware/chip/nationstech/tos_hal/tos_hal_sd.c(文件路径)
  1. #include "tos_k.h"
  2. #include "tos_hal.h"
  3. #include "sdio_tf.h"

  4. __API__ int tos_hal_sd_init(hal_sd_t *sd)
  5. {
  6.     (void)sd;

  7.     return SD_Init() == SD_OK ? 0 : -1;
  8. }

  9. __API__ int tos_hal_sd_read(hal_sd_t *sd, uint8_t *buf, uint32_t blk_addr, uint32_t blk_num, uint32_t timeout)
  10. {
  11.     uint8_t err;

  12.     (void)sd;

  13.     if (!buf) {
  14.         return -1;
  15.     }

  16.     err = SD_ReadDisk(buf, blk_addr, blk_num);
  17.     err = SD_WaitWriteOperation();

  18.     return err == SD_OK ? 0 : -1;
  19. }

  20. __API__ int tos_hal_sd_write(hal_sd_t *sd, const uint8_t *buf, uint32_t blk_addr, uint32_t blk_num, uint32_t timeout)
  21. {
  22.     uint8_t err;

  23.     (void)sd;

  24.     if (!buf) {
  25.         return -1;
  26.     }

  27.     err = SD_WriteDisk((uint8_t *)buf, blk_addr, blk_num);
  28.     err = SD_WaitWriteOperation();
  29.     return err == SD_OK ? 0 : -1;
  30. }

  31. __API__ int tos_hal_sd_read_dma(hal_sd_t *sd, uint8_t *buf, uint32_t blk_addr, uint32_t blk_num)
  32. {
  33.     return -1;
  34. }

  35. __API__ int tos_hal_sd_write_dma(hal_sd_t *sd, const uint8_t *buf, uint32_t blk_addr, uint32_t blk_num)
  36. {
  37.     return -1;
  38. }

  39. __API__ int tos_hal_sd_erase(hal_sd_t *sd, uint32_t blk_add_start, uint32_t blk_addr_end)
  40. {
  41.     return 0;
  42. }

  43. __API__ int tos_hal_sd_info_get(hal_sd_t *sd, hal_sd_info_t *info)
  44. {
  45.     SD_Error err;
  46.     SD_CardInfo card_info;

  47.     (void)sd;

  48.     if (!sd || !info) {
  49.         return -1;
  50.     }

  51.     err = SD_GetCardInfo(&card_info);
  52.     if (err != SD_OK) {
  53.         return -1;
  54.     }

  55.     info->card_type             = card_info.CardType;
  56.     info->blk_num               = card_info.CardCapacity / card_info.CardBlockSize;
  57.     info->blk_size              = card_info.CardBlockSize;

  58.     return 0;
  59. }

  60. __API__ int tos_hal_sd_state_get(hal_sd_t *sd, hal_sd_state_t *state)
  61. {
  62.     int ret = 0;
  63.     SDCardState sd_state;

  64.     (void)sd;

  65.     if (!sd || !state) {
  66.         return -1;
  67.     }

  68.     sd_state = SD_GetState();
  69.     switch (sd_state) {
  70.         case SD_CARD_READY:
  71.             *state = HAL_SD_STAT_READY;
  72.             break;

  73.         case SD_CARD_SENDING:
  74.             *state = HAL_SD_STAT_PROGRAMMING;
  75.             break;

  76.         case SD_CARD_RECEIVING:
  77.             *state = HAL_SD_STAT_RECEIVING;
  78.             break;

  79.         case SD_CARD_TRANSFER:
  80.             *state = HAL_SD_STAT_TRANSFER;
  81.             break;

  82.         case SD_CARD_ERROR:
  83.             *state = HAL_SD_STAT_ERROR;
  84.             break;

  85.         default:
  86.             ret = -1;
  87.             break;
  88.     }
  89.     return ret;
  90. }

  91. __API__ int tos_hal_sd_deinit(hal_sd_t *sd)
  92. {
  93.     (void)sd;
  94.     return 0;
  95. }
4. 将对应文件添加到GN构建配置文件中
添加了新的c源文件,我们需要把对应的文件添加到GN构建配置文件中,每个组件的根目录下都有一个BUILD.gn配置文件。该文件定义了组件包含的文件,组件编译选项(若需要添加),组件依赖等等内容。
由于腾讯TinyOS并没有实现完整的系统级hal层函数,这个tos_hal_sd.c文件就暂时放在厂商芯片代码目录中(hardware/chip/nationstech/),我们在配置文件的最后添加这个文件的配置。
  1. source_set("n32g457_sdk") {
  2.   sources = [
  3.     "Peripheral/misc.c",
  4.     "Peripheral/n32g45x_adc.c",
  5.     "Peripheral/n32g45x_bkp.c",
  6.     "Peripheral/n32g45x_can.c",
  7.     "Peripheral/n32g45x_comp.c",
  8.     "Peripheral/n32g45x_crc.c",
  9.     "Peripheral/n32g45x_dbg.c",
  10.     "Peripheral/n32g45x_dma.c",
  11.     "Peripheral/n32g45x_dvp.c",
  12.     "Peripheral/n32g45x_eth.c",
  13.     "Peripheral/n32g45x_exti.c",
  14.     "Peripheral/n32g45x_flash.c",
  15.     "Peripheral/n32g45x_gpio.c",
  16.     "Peripheral/n32g45x_i2c.c",
  17.     "Peripheral/n32g45x_iwdg.c",
  18.     "Peripheral/n32g45x_opamp.c",
  19.     "Peripheral/n32g45x_pwr.c",
  20.     "Peripheral/n32g45x_qspi.c",
  21.     "Peripheral/n32g45x_rcc.c",
  22.     "Peripheral/n32g45x_rtc.c",
  23.     "Peripheral/n32g45x_sdio.c",
  24.     "Peripheral/n32g45x_spi.c",
  25.     "Peripheral/n32g45x_tim.c",
  26.     "Peripheral/n32g45x_usart.c",
  27.     "Peripheral/n32g45x_wwdg.c",
  28.   ]
  29.   sources += [
  30.     "USBFS/usb_core.c",
  31.     "USBFS/usb_init.c",
  32.     "USBFS/usb_int.c",
  33.     "USBFS/usb_mem.c",
  34.     "USBFS/usb_regs.c",
  35.     "USBFS/usb_sil.c",
  36.   ]
  37.   sources += [
  38.     "sdio_tf.c",
  39.     "system_n32g45x.c",
  40.   ]
  41.   sources += [ "../tos_hal/tos_hal_sd.c" ]
  42. }
适配完毕后,编译源码,默认配置下,TinyOS的fatfs还是比较大的体积的。通过psize命令,可以看到fs/fatfs组件体积又182.3K这么大,如此大的体积,是不符合BootLoader的需求的。
fatfs.png

5. 检查代码是否可以读写tf卡
通过修改hardware/board/n32g45xvl_STB/main.c文件,我们尝试初始化SD卡和擦写部分扇区(直接调用SD_WriteBlock函数
  1. /*****************************************************************************
  2. * Copyright (c) 2019, Nations Technologies Inc.
  3. *
  4. * All rights reserved.
  5. * ****************************************************************************
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * - Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the disclaimer below.
  12. *
  13. * Nations' name may not be used to endorse or promote products derived from
  14. * this software without specific prior written permission.
  15. *
  16. * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  19. * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  21. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  22. * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  23. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  24. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  25. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. * ****************************************************************************/

  27. /**
  28. * [url=home.php?mod=space&uid=288409]@file[/url] main.c
  29. * [url=home.php?mod=space&uid=187600]@author[/url] Nations
  30. * [url=home.php?mod=space&uid=895143]@version[/url] v1.0.0
  31. *
  32. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
  33. */
  34. #include "main.h"
  35. #include "n32g45x.h"
  36. #include "sdio_tf.h"
  37. #include "stdint.h"
  38. #include "stdio.h"
  39. #include "tos_k.h"

  40. #define USARTx USART1
  41. #define USARTx_GPIO GPIOA
  42. #define USARTx_CLK RCC_APB2_PERIPH_USART1
  43. #define USARTx_GPIO_CLK RCC_APB2_PERIPH_GPIOA
  44. #define USARTx_RxPin GPIO_PIN_10
  45. #define USARTx_TxPin GPIO_PIN_9

  46. #define GPIO_APBxClkCmd RCC_EnableAPB2PeriphClk
  47. #define USART_APBxClkCmd RCC_EnableAPB2PeriphClk

  48. #ifdef __GNUC__
  49. /* With GCC, small printf (option LD Linker->Libraries->Small printf
  50.    set to 'Yes') calls __io_putchar() */
  51. #define PUTCHAR_PROTOTYPE int __io_putchar(char ch)
  52. #define GETCHAR_PROTOTYPE int __io_getchar()
  53. #else
  54. #define PUTCHAR_PROTOTYPE int fputc(char ch)
  55. #define GETCHAR_PROTOTYPE int fgetc()
  56. #endif /* __GNUC__ */

  57. PUTCHAR_PROTOTYPE {
  58.     if (ch == '\n') {
  59.         while (USART_GetFlagStatus(USARTx, USART_FLAG_TXC) == RESET)
  60.             ;
  61.         USART_SendData(USARTx, '\r');
  62.     }
  63.     while (USART_GetFlagStatus(USARTx, USART_FLAG_TXC) == RESET)
  64.         ;
  65.     USART_SendData(USARTx, ch);
  66.     return ch;
  67. }

  68. GETCHAR_PROTOTYPE {
  69.     uint8_t ch = 0;
  70.     ch = USART_ReceiveData(USARTx);
  71.     return ch;
  72. }

  73. /** @addtogroup N32G45X_StdPeriph_Examples
  74. * @{
  75. */

  76. /** @addtogroup USART_Printf
  77. * @{
  78. */

  79. typedef enum { FAILED = 0, PASSED = !FAILED } TestStatus;

  80. #define countof(a) (sizeof(a) / sizeof(*(a)))

  81. USART_InitType USART_InitStructure;

  82. void RCC_Configuration(void);

  83. #define APPLICATION_TASK_STK_SIZE 1024
  84. k_task_t application_task;
  85. __aligned(4) uint8_t application_task_stk[APPLICATION_TASK_STK_SIZE];

  86. u8 buf[512];
  87. u8 Readbuf[512];

  88. /*********************************************************************
  89. * @fn      show_sdcard_info
  90. *
  91. * [url=home.php?mod=space&uid=247401]@brief[/url]   SD Card information.
  92. *
  93. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  94. */
  95. void show_sdcard_info(void) {
  96.     printf("SD Card initialization success!\r\n");
  97.     printf("*CardType            is: %d\r\n", SDCardInfo.CardType);
  98.     printf("*CardCapacity        is: %lld\r\n",
  99.            SDCardInfo.CardCapacity / (1024 * 1024));
  100.     printf("*CardBlockSize       is: %d\r\n", (int)SDCardInfo.CardBlockSize);
  101.     printf("*RCA                 is: %d\r\n", SDCardInfo.RCA);
  102.     printf("*Manufacture(MID)    is: %d\r\n", SDCardInfo.SD_cid.ManufacturerID);
  103.     printf("*OEM/Appli(OID)      is: %d\r\n", SDCardInfo.SD_cid.OEM_AppliID);
  104.     printf("*Product Name(PNM)   is: %d\r\n", (int)SDCardInfo.SD_cid.ProdName1);
  105.     printf("*Serial Number(PSN)  is: %x\r\n",
  106.            (unsigned int)SDCardInfo.SD_cid.ProdSN);
  107.     printf("*Manu Date COde(MDT) is: %x\r\n", SDCardInfo.SD_cid.ManufactDate);
  108.     printf("*Card SysSpecVersion is: %d\r\n", SDCardInfo.SD_csd.SysSpecVersion);
  109.     printf("*Card MaxBusClkFrec  is: %d\r\n", SDCardInfo.SD_csd.MaxBusClkFrec);
  110.     printf("*Card MaxRdBlockLen  is: %d\r\n", SDCardInfo.SD_csd.RdBlockLen);
  111.     printf("*Card RdCurrent VDD  is: %d -> %d\r\n",
  112.            SDCardInfo.SD_csd.MaxRdCurrentVDDMin,
  113.            SDCardInfo.SD_csd.MaxRdCurrentVDDMax);
  114.     printf("*Card WrSpeedFact    is: %d\r\n", SDCardInfo.SD_csd.WrSpeedFact);
  115.     printf("*Card MaxWrBlockLen  is: %d\r\n", SDCardInfo.SD_csd.MaxWrBlockLen);
  116.     printf("*Card WrCurrent VDD  is: %d -> %d\r\n",
  117.            SDCardInfo.SD_csd.MaxWrCurrentVDDMin,
  118.            SDCardInfo.SD_csd.MaxWrCurrentVDDMax);
  119. }

  120. SD_Error Status = SD_OK;

  121. void application_entry(void *arg) {
  122.     u32 i;
  123.     u32 Sector_Nums;

  124.     while (SD_Init()) {
  125.         printf("SD Card Error!\r\n");
  126.         tos_task_delay(1000);
  127.     }

  128.     show_sdcard_info();

  129.     printf("SD Card OK\r\n");
  130.     Sector_Nums = ((u32)(SDCardInfo.CardCapacity >> 20)) / 2;
  131.     printf("Sector_Nums:%d\r\n", Sector_Nums);

  132.     for (i = 0; i < 512; i++) {
  133.         buf[i] = i;
  134.     }

  135.     for (i = 0; i < 512; i++) {
  136.         Status = SD_WriteBlock(buf, i, 1);
  137.         Status = SD_WaitWriteOperation();
  138.         while (SD_GetStatus() != SD_TRANSFER_OK)
  139.             ;
  140.         if (Status != SD_OK) {
  141.             printf("SD Card write block failed!\r\n");
  142.         }
  143.         Status = SD_ReadBlock(Readbuf, i, 1);
  144.         Status = SD_WaitReadOperation();
  145.         while (SD_GetStatus() != SD_TRANSFER_OK)
  146.             ;

  147.         if (memcmp(buf, Readbuf, 512)) {
  148.             printf(" %d sector Verify fail\n", i);
  149.             break;
  150.         }
  151.     }
  152.     if (i == Sector_Nums / 2) {
  153.         printf("SD OK\r\n");
  154.     }
  155. }

  156. /**
  157. * @brief  Main program
  158. */
  159. int main(void) {
  160.     /* System Clocks Configuration */
  161.     RCC_Configuration();

  162.     NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

  163.     /* Configure the GPIO ports */
  164.     GPIO_InitType GPIO_InitStructure;

  165.     /* Configure USARTx Tx as alternate function push-pull */
  166.     GPIO_InitStructure.Pin = USARTx_TxPin;
  167.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  168.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  169.     GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);

  170.     /* Configure USARTx Rx as input floating */
  171.     GPIO_InitStructure.Pin = USARTx_RxPin;
  172.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  173.     GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);

  174.     /* USARTy and USARTz configuration
  175.      * ------------------------------------------------------*/
  176.     USART_InitStructure.BaudRate = 115200;
  177.     USART_InitStructure.WordLength = USART_WL_8B;
  178.     USART_InitStructure.StopBits = USART_STPB_1;
  179.     USART_InitStructure.Parity = USART_PE_NO;
  180.     USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
  181.     USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;

  182.     /* Configure USARTx */
  183.     USART_Init(USARTx, &USART_InitStructure);
  184.     /* Enable the USARTx */
  185.     USART_Enable(USARTx, ENABLE);

  186.     tos_knl_init(); // 初始化TencentOS tiny内核

  187.     printf("TinyOS demo!\r\n");

  188.     // 创建一个优先级为5的任务
  189.     tos_task_create(&application_task, "task_prio5", application_entry, NULL, 4,
  190.                     application_task_stk, APPLICATION_TASK_STK_SIZE, 0);
  191.     // 开始内核调度,线程中不允许有睡死代码。
  192.     tos_knl_start();

  193.     while (1) {
  194.     }
  195. }

  196. /**
  197. * @brief  Configures the different system clocks.
  198. */
  199. void RCC_Configuration(void) {
  200.     /* Enable GPIO clock */
  201.     GPIO_APBxClkCmd(USARTx_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE);
  202.     /* Enable USARTy and USARTz Clock */
  203.     USART_APBxClkCmd(USARTx_CLK, ENABLE);
  204. }
烧录到开发板上,可以正确获取SD卡信息,并读写SD卡扇区。SDIO代码没问题。

四、fatfs编译优化注意事项

1. 回到上一个步骤的fatfs体积的问题,通过搜索引擎可以查到,我们可以调整FF_USE_LFN 宏定义的值,关闭长文件名的支持。以下为修改后的代码。
文件路径 components/fs/fatfs/wrapper/include/tos_ffconf.h (由于腾讯TinyOS改写了fatfs的源码,并重命名了ffconf.h文件,我们需要修改这个文件才能生效)。
  1. #define FF_USE_LFN                0
  2. #define FF_MAX_LFN                255
  3. /* The FF_USE_LFN switches the support for LFN (long file name).
  4. /
  5. /   0: Disable LFN. FF_MAX_LFN has no effect.
  6. /   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
  7. /   2: Enable LFN with dynamic working buffer on the STACK.
  8. /   3: Enable LFN with dynamic working buffer on the HEAP.
  9. /
  10. /  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
  11. /  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
  12. /  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
  13. /  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
  14. /  be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
  15. /  specification.
  16. /  When use stack for the working buffer, take care on stack overflow. When use heap
  17. /  memory for the working buffer, memory management functions, ff_memalloc() and
  18. /  ff_memfree() in ffsystem.c, need to be added to the project. */
执行mclean命令清空了编译产物后,重新执行mbuild和psize命令,可以看到fatfs的组件体积减小到了8.9K,体积减小了不少。
fatfs_l.png

虽然整体体积34K的flash,对于16K的目标BootLoader大小来说还是相差比较大。目前就暂时不管他,先考虑完成IAP功能(SDIO功能占用体积极大,估计要换成SPI或者软SPI读写SD卡能降低不少体积)。


这里我们用TinyOS的VFS层代码进行测试,测试代码如下(同样是修改上文提到的main.c文件):
  1. /*****************************************************************************
  2. * Copyright (c) 2019, Nations Technologies Inc.
  3. *
  4. * All rights reserved.
  5. * ****************************************************************************
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * - Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the disclaimer below.
  12. *
  13. * Nations' name may not be used to endorse or promote products derived from
  14. * this software without specific prior written permission.
  15. *
  16. * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  19. * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  21. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  22. * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  23. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  24. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  25. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. * ****************************************************************************/

  27. /**
  28. * @file main.c
  29. * @author Nations
  30. * @version v1.0.0
  31. *
  32. * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
  33. */
  34. #include "main.h"
  35. #include "n32g45x.h"
  36. #include "sdio_tf.h"
  37. #include "stdint.h"
  38. #include "stdio.h"
  39. #include "tos_k.h"

  40. #define USARTx USART1
  41. #define USARTx_GPIO GPIOA
  42. #define USARTx_CLK RCC_APB2_PERIPH_USART1
  43. #define USARTx_GPIO_CLK RCC_APB2_PERIPH_GPIOA
  44. #define USARTx_RxPin GPIO_PIN_10
  45. #define USARTx_TxPin GPIO_PIN_9

  46. #define GPIO_APBxClkCmd RCC_EnableAPB2PeriphClk
  47. #define USART_APBxClkCmd RCC_EnableAPB2PeriphClk

  48. #ifdef __GNUC__
  49. /* With GCC, small printf (option LD Linker->Libraries->Small printf
  50.    set to 'Yes') calls __io_putchar() */
  51. #define PUTCHAR_PROTOTYPE int __io_putchar(char ch)
  52. #define GETCHAR_PROTOTYPE int __io_getchar()
  53. #else
  54. #define PUTCHAR_PROTOTYPE int fputc(char ch)
  55. #define GETCHAR_PROTOTYPE int fgetc()
  56. #endif /* __GNUC__ */

  57. PUTCHAR_PROTOTYPE {
  58.     if (ch == '\n') {
  59.         while (USART_GetFlagStatus(USARTx, USART_FLAG_TXC) == RESET)
  60.             ;
  61.         USART_SendData(USARTx, '\r');
  62.     }
  63.     while (USART_GetFlagStatus(USARTx, USART_FLAG_TXC) == RESET)
  64.         ;
  65.     USART_SendData(USARTx, ch);
  66.     return ch;
  67. }

  68. GETCHAR_PROTOTYPE {
  69.     uint8_t ch = 0;
  70.     ch = USART_ReceiveData(USARTx);
  71.     return ch;
  72. }

  73. /** @addtogroup N32G45X_StdPeriph_Examples
  74. * @{
  75. */

  76. /** @addtogroup USART_Printf
  77. * @{
  78. */

  79. typedef enum { FAILED = 0, PASSED = !FAILED } TestStatus;

  80. #define countof(a) (sizeof(a) / sizeof(*(a)))

  81. USART_InitType USART_InitStructure;

  82. void RCC_Configuration(void);

  83. #define APPLICATION_TASK_STK_SIZE 1024
  84. k_task_t application_task;
  85. __aligned(4) uint8_t application_task_stk[APPLICATION_TASK_STK_SIZE];

  86. /*********************************************************************
  87. * @fn      show_sdcard_info
  88. *
  89. * @brief   SD Card information.
  90. *
  91. * @return  none
  92. */
  93. void show_sdcard_info(void) {
  94.     printf("SD Card initialization success!\r\n");
  95.     printf("*CardType            is: %d\r\n", SDCardInfo.CardType);
  96.     printf("*CardCapacity        is: %lld\r\n",
  97.            SDCardInfo.CardCapacity / (1024 * 1024));
  98.     printf("*CardBlockSize       is: %d\r\n", (int)SDCardInfo.CardBlockSize);
  99.     printf("*RCA                 is: %d\r\n", SDCardInfo.RCA);
  100.     printf("*Manufacture(MID)    is: %d\r\n", SDCardInfo.SD_cid.ManufacturerID);
  101.     printf("*OEM/Appli(OID)      is: %d\r\n", SDCardInfo.SD_cid.OEM_AppliID);
  102.     printf("*Product Name(PNM)   is: %d\r\n", (int)SDCardInfo.SD_cid.ProdName1);
  103.     printf("*Serial Number(PSN)  is: %x\r\n",
  104.            (unsigned int)SDCardInfo.SD_cid.ProdSN);
  105.     printf("*Manu Date COde(MDT) is: %x\r\n", SDCardInfo.SD_cid.ManufactDate);
  106.     printf("*Card SysSpecVersion is: %d\r\n", SDCardInfo.SD_csd.SysSpecVersion);
  107.     printf("*Card MaxBusClkFrec  is: %d\r\n", SDCardInfo.SD_csd.MaxBusClkFrec);
  108.     printf("*Card MaxRdBlockLen  is: %d\r\n", SDCardInfo.SD_csd.RdBlockLen);
  109.     printf("*Card RdCurrent VDD  is: %d -> %d\r\n",
  110.            SDCardInfo.SD_csd.MaxRdCurrentVDDMin,
  111.            SDCardInfo.SD_csd.MaxRdCurrentVDDMax);
  112.     printf("*Card WrSpeedFact    is: %d\r\n", SDCardInfo.SD_csd.WrSpeedFact);
  113.     printf("*Card MaxWrBlockLen  is: %d\r\n", SDCardInfo.SD_csd.MaxWrBlockLen);
  114.     printf("*Card WrCurrent VDD  is: %d -> %d\r\n",
  115.            SDCardInfo.SD_csd.MaxWrCurrentVDDMin,
  116.            SDCardInfo.SD_csd.MaxWrCurrentVDDMax);
  117. }

  118. SD_Error Status = SD_OK;

  119. #include "ff.h"
  120. #include "tos_vfs.h"
  121. #include "tos_fatfs_drv.h"
  122. #include "tos_fatfs_vfs.h"

  123. char buf[512];

  124. void application_entry(void *arg) {
  125.     int fd, ret;
  126.     vfs_err_t err;
  127.     extern vfs_blkdev_ops_t sd_dev;
  128.     extern vfs_fs_ops_t fatfs_ops;

  129.     err = tos_vfs_block_device_register("/dev/sd", &sd_dev);
  130.     if (err != VFS_ERR_NONE) {
  131.         printf("/dev/sd block device register failed!\n");
  132.     }

  133.     err = tos_vfs_fs_register("fatfs_sd", &fatfs_ops);
  134.     if (err != VFS_ERR_NONE) {
  135.         printf("fatfs_sd fs register failed!\n");
  136.     }

  137.     if (tos_vfs_fs_mkfs("/dev/sd", "fatfs_sd", FM_FAT32, 0) != 0) {
  138.         printf("mkfs failed!\n");
  139.     }

  140.     if (tos_vfs_fs_mount("/dev/sd", "/fs/fatfs_sd", "fatfs_sd") != 0) {
  141.         printf("mount failed!\n");
  142.     }

  143.     fd = tos_vfs_open("/fs/fatfs_sd/test_file.txt", VFS_OFLAG_CREATE_ALWAYS | VFS_OFLAG_WRITE);
  144.     if (fd < 0) {
  145.         printf("open failed!\n");
  146.     }

  147.     ret = tos_vfs_write(fd, "fatfs sample content", strlen("fatfs sample content"));
  148.     if (ret >= 0) {
  149.         printf("write ok\n");
  150.         printf("write data:\n%s\n", "fatfs sample content");
  151.     } else {
  152.         printf("write error: %d\n", ret);
  153.     }
  154.     ret = tos_vfs_close(fd);
  155.     if (ret < 0) {
  156.         printf("close failed!\n");
  157.     }

  158.     fd = tos_vfs_open("/fs/fatfs_sd/test_file.txt", VFS_OFLAG_EXISTING | VFS_OFLAG_READ);
  159.     if (fd < 0) {
  160.         printf("open file error!\n");
  161.     }

  162.     memset(buf, 0, sizeof(buf));
  163.     ret = tos_vfs_read(fd, buf, sizeof(buf));
  164.     if (ret >= 0) {
  165.         printf("read ok: %d\n", ret);
  166.         printf("read data:\n%s\n", buf);
  167.     } else {
  168.         printf("read error: %d\n", ret);
  169.     }

  170.     ////////////////////////////////////////////////
  171.     ret = tos_vfs_lseek(fd, 2, VFS_SEEK_CUR);
  172.     if (ret < 0) {
  173.         printf("lseek error\n");
  174.     }

  175.     memset(buf, 0, sizeof(buf));
  176.     ret = tos_vfs_read(fd, buf, sizeof(buf));
  177.     if (ret >= 0) {
  178.         printf("read ok: %d\n", ret);
  179.         printf("read data:\n%s\n", buf);
  180.     } else {
  181.         printf("read error: %d\n", ret);
  182.     }
  183.     /////////////////////////////////////////////////

  184.     tos_vfs_close(fd);
  185. }

  186. /**
  187. * @brief  Main program
  188. */
  189. int main(void) {
  190.     /* System Clocks Configuration */
  191.     RCC_Configuration();

  192.     NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

  193.     /* Configure the GPIO ports */
  194.     GPIO_InitType GPIO_InitStructure;

  195.     /* Configure USARTx Tx as alternate function push-pull */
  196.     GPIO_InitStructure.Pin = USARTx_TxPin;
  197.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  198.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  199.     GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);

  200.     /* Configure USARTx Rx as input floating */
  201.     GPIO_InitStructure.Pin = USARTx_RxPin;
  202.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  203.     GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);

  204.     /* USARTy and USARTz configuration
  205.      * ------------------------------------------------------*/
  206.     USART_InitStructure.BaudRate = 115200;
  207.     USART_InitStructure.WordLength = USART_WL_8B;
  208.     USART_InitStructure.StopBits = USART_STPB_1;
  209.     USART_InitStructure.Parity = USART_PE_NO;
  210.     USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
  211.     USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;

  212.     /* Configure USARTx */
  213.     USART_Init(USARTx, &USART_InitStructure);
  214.     /* Enable the USARTx */
  215.     USART_Enable(USARTx, ENABLE);

  216.     tos_knl_init(); // 初始化TencentOS tiny内核

  217.     printf("TinyOS demo!\r\n");

  218.     // 创建一个优先级为5的任务
  219.     tos_task_create(&application_task, "task_prio5", application_entry, NULL, 4,
  220.                     application_task_stk, APPLICATION_TASK_STK_SIZE, 0);
  221.     // 开始内核调度,线程中不允许有睡死代码。
  222.     tos_knl_start();

  223.     while (1) {
  224.     }
  225. }

  226. /**
  227. * @brief  Configures the different system clocks.
  228. */
  229. void RCC_Configuration(void) {
  230.     /* Enable GPIO clock */
  231.     GPIO_APBxClkCmd(USARTx_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE);
  232.     /* Enable USARTy and USARTz Clock */
  233.     USART_APBxClkCmd(USARTx_CLK, ENABLE);
  234. }


编译代码后,烧录到板子上测试结果如下:

vfs_mount_fail.png

经过调试和阅读相关源码,暂时未找到为何设备注册错误。阅读原厂SDIO源码发现默认是启用了SDIO的DMA模式(似乎也可以通过宏定义不开启DMA模式,禁用后仍是出现上图的报错),但是由于时间仓储,未能继续再往下开发下去。

总结:通过本次活动,我学习到了N32G457的SDIO读写SD卡,以及腾讯TinyOS的相关移植知识。由于本人的能力不足,未能实现本次活动的目标,但也让我学到了不少知识。由于活动时间结束了,本次的分享只能分享部分经验,而不是完整的IAP功能,只能在4月抽空再完成对应功能,并在本帖跟进对应内容。本次活动的相关源码在https://gitee.com/walker2048/mcu_playground/tree/dev/可以获取到。

jobszheng 发表于 2023-4-3 11:21 | 显示全部楼层
楼主还是厉害!
我也一直想折腾TencentOS,时间,精力,更缺乏了一定的勇气。
jobszheng 发表于 2023-4-3 11:22 | 显示全部楼层
不过,单从项目本身来说。bootloader的程序还是要首选前后台程序,甚至是无中断的仅状态机程序。
 楼主| walker2048 发表于 2023-4-3 11:49 | 显示全部楼层
本来以为TinyOS自带的东西好整一点,结果翻车了。。。
ch32v307上是可以正常用的。继续折腾吧,反正也要学
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

31

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部