工具:FRDM-KL25Z开发板
问题:在调试PWM驱动的过程中一直无法找到设备节点。
1、查找pwm注册pwm_register的地方。
->board_app_initialize()
->kl_pwm_setup()
->pwm_register()
2、发现board_app_initialize在这里被调用:
#ifdef CONFIG_BOARD_INITIALIZE
void board_initialize(void)
{
/* Perform NSH initialization here instead of from the NSH. This
* alternative NSH initialization is necessary when NSH is ran in user-space
* but the initialization function must run in kernel space.
*/
#if defined(CONFIG_NSH_LIBRARY) && !defined(CONFIG_LIB_BOARDCTL)
(void)board_app_initialize(0);
#endif
/* CC3000 wireless initialization */
#ifdef CONFIG_WL_CC3000
wireless_archinitialize(0);
#endif
}
#endif
该函数从字面来理解就是板级初始化的意思,但依赖于配置BOARD_INITIALIZE,在make menuconfig中找到该配置所在位置:
│ CONFIG_BOARD_INITIALIZE: │
│ │
│ By default, there are three points in time where you can insert │
│ custom initialization logic: │
│ │
│ 1) <arch>_boardinitialize(): This function is used only for │
│ initialization of very low-level things like configuration of │
│ GPIO pins, power setting. The OS has not been initialized │
│ at this point, so you cannot allocate memory or initialize │
│ device drivers at this phase. │
│ │
│ 2) The next level of initialization is performed by a call to │
│ up_initialize() (in arch/<arch>/src/common/up_initialize.c). │
│ The OS has been initialized at this point and it is okay to │
│ initialize drivers in this phase. │
│ │
│ 3) And, finally, when the user application code starts. │
│ │
│ If BOARD_INITIALIZE is selected, then an additional initialization │
│ call will be performed in the boot-up sequence to a function │
│ called board_initialize(). board_initialize() will be │
│ call between phases 2) and 3) above, immediately after │
│ up_initialize() is called. This additional initialization │
│ phase may be used, for example, to initialize board-specific │
│ device drivers. │
│ │
│ Symbol: BOARD_INITIALIZE [=n] │
│ Type : boolean │
│ Prompt: Custom board/driver initialization │
│ Location: │
│ -> RTOS Features │
│ -> RTOS hooks │
│ Defined at sched/Kconfig:970
很明显,在这里分析了三种设备驱动初始化的情况。
第一种情况是调用<arch>_boardinitialize(),这个函数只能进行一些低级的初始化,因为系统还没有完全完成初始化,无法分配内存来完成设备初始化。
第二种情况是调用up_initialize(),在这个时间节点,系统已经完成了初始化,可以进行设备驱动的初始化。
第三种情况是在用户应用程序中进行。
从以上的分析可以看出,很明显在第二个阶段和第三个阶段中间是最适合进行板级设备初始化的。而board_initialize()刚好就是用来完成这个任务的。
但是
board_app_initialize
依赖于
CONFIG_NSH_LIBRARY
!CONFIG_LIB_BOARDCTL
其中NSH是命令行库,不能使用BOARDCTL接口。
后来发现,之所以有这样的限制,是因为BOARDCTL接口有同样的功能。
3、BOARDCTL接口实现初始化
void nsh_initialize(void)
{
#if defined(CONFIG_NSH_READLINE) && defined(CONFIG_READLINE_TABCOMPLETION)
/* Configure the NSH prompt */
(void)readline_prompt(g_nshprompt);
#ifdef CONFIG_READLINE_HAVE_EXTMATCH
/* Set up for tab completion on NSH commands */
(void)readline_extmatch(&g_nsh_extmatch);
#endif
#endif
/* Mount the /etc filesystem */
(void)nsh_romfsetc();
#ifdef CONFIG_NSH_ARCHINIT
/* Perform architecture-specific initialization (if configured) */
(void)boardctl(BOARDIOC_INIT, 0);
#endif
/* Bring up the network */
(void)nsh_netinit();
}
boardctl函数在这里:
int boardctl(unsigned int cmd, uintptr_t arg)
{
int ret;
switch (cmd)
{
/* CMD: BOARDIOC_INIT
* DESCRIPTION: Perform one-time application initialization.
* ARG: The boardctl() argument is passed to the
* board_app_initialize() implementation without modification.
* The argument has no meaning to NuttX; the meaning of the
* argument is a contract between the board-specific
* initalization logic and the matching application logic.
* The value cold be such things as a mode enumeration value,
* a set of DIP switch switch settings, a pointer to
* configuration data read from a file or serial FLASH, or
* whatever you would like to do with it. Every
* implementation should accept zero/NULL as a default
* configuration.
* CONFIGURATION: CONFIG_LIB_BOARDCTL
* DEPENDENCIES: Board logic must provide board_app_initialization
*/
case BOARDIOC_INIT:
{
ret = board_app_initialize(arg);
}
break;
... ...
}
通过boardctl接口可以在用户应用程序中对设备驱动进行初始化。
这两种方式设备驱动初始化有什么区别呢?暂时还没有了解到。