LED模块的PCB硬件设计和PX4驱动配置
大部分PX4的飞控板都有三个LED,分别是红色、绿色、蓝色。
飞控板的配置文件夹结构
飞控板的配置文件夹结构为下列所示。
YanQi
├─extras
| └─UCAS_YanQi_bootloader.bin
├─init
| ├─rc.board_defaults
| └─rc.board_sensors
├─nuttx-config
| ├─bootloader
| | └─defconfig
| ├─include
| | ├─board.h
| | └─board_dma_map.h
| ├─nsh
| | └─defconfig
| ├─scripts
| | ├─bootloader_script.ld
| | └─script.ld
| ├─src
| └─Kconfig
├─src
| ├─board_config.h
| ├─bootloader_main.c
| ├─CMakeLists.txt
| ├─hw_config.h
| ├─i2c.cpp
| ├─init.c
| ├─...
| └─usb.c
├─bootloader.px4board
├─default.px4board
└─firmware.prototype
nuttx-config/include/board.h文件
如果CONFIG_ARCH_LEDS
标识符被定义,那么LED的控制权在NuttX操作系统手中,如果标识符没有被定义,则用户(PX4程序)可以对LED进行控制。
如果CONFIG_ARCH_LEDS
标识符没有被定义,LED号的定义在下列代码。
/* LED index values for use with board_userled() */
#define BOARD_LED1 0
#define BOARD_LED2 1
#define BOARD_LED3 2
#define BOARD_NLEDS 3
#define BOARD_LED_RED BOARD_LED1
#define BOARD_LED_GREEN BOARD_LED2
#define BOARD_LED_BLUE BOARD_LED3
/* LED bits for use with board_userled_all() */
#define BOARD_LED1_BIT (1 << BOARD_LED1)
#define BOARD_LED2_BIT (1 << BOARD_LED2)
#define BOARD_LED3_BIT (1 << BOARD_LED3)
如果CONFIG_ARCH_LEDS
标识符被定义,LED显示模式对应操作系统的状态的表格如下。
/* If CONFIG_ARCH_LEDS is defined, the usage by the board port is defined in
* include/board.h and src/stm32_leds.c. The LEDs are used to encode OS-related
* events as follows:
*
*
* SYMBOL Meaning LED state
* Red Green Blue
* ---------------------- -------------------------- ------ ------ ----*/
#define LED_STARTED 0 /* NuttX has been started OFF OFF OFF */
#define LED_HEAPALLOCATE 1 /* Heap has been allocated OFF OFF ON */
#define LED_IRQSENABLED 2 /* Interrupts enabled OFF ON OFF */
#define LED_STACKCREATED 3 /* Idle stack created OFF ON ON */
#define LED_INIRQ 4 /* In an interrupt N/C N/C GLOW */
#define LED_SIGNAL 5 /* In a signal handler N/C GLOW N/C */
#define LED_ASSERTION 6 /* An assertion failed GLOW N/C GLOW */
#define LED_PANIC 7 /* The system has crashed Blink OFF N/C */
#define LED_IDLE 8 /* MCU is is sleep mode ON OFF OFF */
/* Thus if the Green LED is statically on, NuttX has successfully booted and
* is, apparently, running normally. If the Red LED is flashing at
* approximately 2Hz, then a fatal error has been detected and the system
* has halted.
*/
src/board_config.h文件
Trace功能,即ITM,(英文:Instrumentation Trace Macrocell,指令跟踪宏单元),是一种针对MCU进行跟踪调试的新方法,与打断点(Breakpoint)不同,ITM方法不需要暂停程序运行,可以在程序全速运行的过程中实时输出变量的数值以便观察。
该Trace功能有五个引脚,TRACECLK、TRACED0、TRACED1、TRACED2和TRACED3,需要占用引脚PE2、PE3、PE4、PE5、PC12,这与三个LED的GPIO引脚和UART5_TX_TELEM2的GPIO引脚产生冲突,所以Trace功能和这两个功能只能选择其一,代码如下。
/* Trace Clock and D0-D3 are available on the trace connector
*
* TRACECLK PE2 - Dedicated - Trace Connector Pin 1
* TRACED0 PE3 - nLED_RED - Trace Connector Pin 3
* TRACED1 PE4 - nLED_GREEN - Trace Connector Pin 5
* TRACED2 PE5 - nLED_BLUE - Trace Connector Pin 7
* TRACED3 PC12 - UART5_TX_TELEM2 - Trace Connector Pin 8
*/
#undef TRACE_PINS
/* LEDs are driven with push open drain to support Anode to 5V or 3.3V or used as TRACE0-2 */
#if !defined(TRACE_PINS)
# define GPIO_nLED_RED /* PE3 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN3)
# define GPIO_nLED_GREEN /* PE4 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4)
# define GPIO_nLED_BLUE /* PE5 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN5)
# define BOARD_HAS_CONTROL_STATUS_LEDS 1
# define BOARD_OVERLOAD_LED LED_RED
# define BOARD_ARMED_STATE_LED LED_BLUE
#else
# if defined(CONFIG_STM32H7_UART5) && (GPIO_UART5_TX == GPIO_UART5_TX_3)
# error Need to disable CONFIG_STM32H7_UART5 for Trace 3 (Retarget to CAN2 if need be)
# endif
#endif
如果需要修改LED对应的GPIO,可以在这里进行修改,这里选择Push-Pull推挽输出,也可以选择Open-Drain开漏输出。
推挽输出可以输出高电平,也可以输出低电平,支持连接LED阳极、阴极,支持共阳、共阴的三色LED。
开漏输出只能输出低电平,只支持连接LED阴极,只支持共阳的三色LED。
LED共阴极是指LED灯中的二极管的阴极有一个共同的接点,并且该接点连接在GND端,即处于低电平状态。
LED共阳极是指LED灯中的二极管的阳极有一个共同的接点,并且该接点连接在VCC端,即处于高电平状态。
# define GPIO_nLED_RED /* PE3 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN3)
# define GPIO_nLED_GREEN /* PE4 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4)
# define GPIO_nLED_BLUE /* PE5 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN5)
设置了红色LED为过载状态指示灯,蓝色LED为飞机解锁状态指示灯。
# define BOARD_HAS_CONTROL_STATUS_LEDS 1
# define BOARD_OVERLOAD_LED LED_RED
# define BOARD_ARMED_STATE_LED LED_BLUE
src/hw_config.h文件
设置了蓝色LED为工作状态指示灯,绿色LED为BootLoader状态指示灯。
这里配置的是运行BootLoader时LED的定义,输出低电平是打开LED,输出高电平是关闭LED。
#define BOARD_PIN_LED_ACTIVITY GPIO_nLED_BLUE // BLUE
#define BOARD_PIN_LED_BOOTLOADER GPIO_nLED_GREEN // GREEN
#define BOARD_LED_ON 0
#define BOARD_LED_OFF 1
src/led.c文件
这个文件是LED的驱动文件。
声明了LED初始化、打开、关闭、翻转等函数的函数头。
__BEGIN_DECLS
extern void led_init(void);
extern void led_on(int led);
extern void led_off(int led);
extern void led_toggle(int led);
__END_DECLS
CONFIG_ARCH_LEDS
标识符是否被定义两种情况下的LED号的编号。
#ifdef CONFIG_ARCH_LEDS
static bool nuttx_owns_leds = true;
// B R S G
// 0 1 2 3
static const uint8_t xlatpx4[] = {1, 2, 4, 0};
# define xlat(p) xlatpx4[(p)]
static uint32_t g_ledmap[] = {
GPIO_nLED_GREEN, // Indexed by BOARD_LED_GREEN
GPIO_nLED_BLUE, // Indexed by BOARD_LED_BLUE
GPIO_nLED_RED, // Indexed by BOARD_LED_RED
GPIO_nSAFETY_SWITCH_LED_OUT, // Indexed by LED_SAFETY by xlatpx4
};
#else
# define xlat(p) (p)
static uint32_t g_ledmap[] = {
GPIO_nLED_BLUE, // Indexed by LED_BLUE
GPIO_nLED_RED, // Indexed by LED_RED, LED_AMBER
0, // Indexed by LED_SAFETY (defaulted to an input)
GPIO_nLED_GREEN, // Indexed by LED_GREEN
};
#endif
LED初始化、打开、关闭、翻转等函数的函数体。
__EXPORT void led_init(void)
{
for (size_t l = 0; l < (sizeof(g_ledmap) / sizeof(g_ledmap[0])); l++) {
if (g_ledmap[l] != 0) {
stm32_configgpio(g_ledmap[l]);
}
}
}
static void phy_set_led(int led, bool state)
{
/* Drive Low to switch on */
if (g_ledmap[led] != 0) {
stm32_gpiowrite(g_ledmap[led], !state);
}
}
static bool phy_get_led(int led)
{
/* If Low it is on */
if (g_ledmap[led] != 0) {
return !stm32_gpioread(g_ledmap[led]);
}
return false;
}
__EXPORT void led_on(int led)
{
phy_set_led(xlat(led), true);
}
__EXPORT void led_off(int led)
{
phy_set_led(xlat(led), false);
}
__EXPORT void led_toggle(int led)
{
phy_set_led(xlat(led), !phy_get_led(xlat(led)));
}
这里默认输出低电平是打开LED,led_on()
函数中调用phy_set_led(xlat(led), true)
函数,则在phy_set_led()
函数中state
为true,命令stm32_gpiowrite(g_ledmap[led], !state)
即把GPIO输出低电平。
同时获取LED状态,默认低电平时LED是打开状态,phy_get_led()
函数中调用stm32_gpioread(g_ledmap[led])
函数,低电平时返回值是0,则return !stm32_gpioread(g_ledmap[led])
返回值是1,即LED为打开状态。
src/init.c文件
board_app_initialize()
函数中有关于LED的代码,board_app_initialize()
函数中调用了初始化LED状态的代码,包括点亮绿色LED表示系统已经上电等。
/* initial LED state */
drv_led_start();
led_off(LED_RED);
led_on(LED_GREEN); // Indicate Power.
led_off(LED_BLUE);
if (board_hardfault_init(2, true) != 0) {
led_on(LED_RED);
}