为ALIENTEK 阿波罗STM32F429开发板移植openvela
本文介绍了为ALIENTEK阿波罗STM32F429开发板移植openvela操作系统的关键步骤。主要内容包括:1)移植原理与启动流程,重点阐述了板级支持包(BSP)的核心功能接口和硬件配置要求;2)详细的代码实现步骤,包括创建目录结构、实现初始化函数(如stm32_boardinitialize)以及配置时钟树等关键硬件参数。移植过程主要基于NuttX官方对STM32F429芯片的支持,通过实现
为ALIENTEK 阿波罗STM32F429开发板移植openvela
本指南(参考为STM32F407 开发板移植 openvela)详细介绍了如何为 ALIENTEK 阿波罗STM32F429开发板(后文简称“开发板”)移植openvela 操作系统。核心板的主控芯片为 STM32F429IGT6。由于 NuttX 官方已提供对 STM32F429I 系列芯片的支持,本指南将重点阐述板级支持包(Board Support Package, BSP)的适配过程。
文章目录
准备工作
在开始之前,请确保您已完成以下准备工作:
-
获取源码:参考文档快速入门下载最新代码。
-
了解
openvela架构:建议您预先阅读 openvela 架构以理解其分层设计。 -
查阅系统启动流程文档,获取更详细的启动时序和函数调用关系图。
一、移植原理与启动流程
openvela 的移植本质上是为操作系统框架提供一套与特定硬件交互的接口。这些接口构成了板级支持包(BSP),它位于 nuttx/boards/ 目录下。本指南将通过实现一个最小功能的 BSP,让openvela在 开发板上启动并运行。
关键启动函数
openvela 在启动过程中,会按照特定顺序调用一系列由 BSP 提供的函数来完成硬件初始化。要成功启动系统,您必须在 BSP 中实现以下关键函数:
| 函数 | 描述 |
|---|---|
| void stm32_boardinitialize(void) | 由系统启动代码 __start 调用。这是最早执行的板级初始化函数,用于配置最基础的硬件,如时钟和调试串口。 |
| void board_late_initialize(void) | 如果配置了 CONFIG_BOARD_LATE_INITIALIZE,此函数会在 OS 初始化后期被调用,通常用于初始化那些依赖 OS 服务的驱动。 |
| int stm32_bringup(void) | 如果配置 CONFIG_BOARD_LATE_INITIALIZE 选项,由 board_late_initialize() 调用; 如果没有配置 CONFIG_BOARD_LATE_INITIALIZE 选项,由 board_app_initialize(arg) 调用。 在 stm32_bringup 里将实现驱动的初始化。 |
| int board_app_initialize(uintptr_t arg) | 由 boardctl() 接口通过 BOARDIOC_INIT 命令触发,用于执行应用层或用户自定义的初始化。 |
此外,如果您的系统配置CONFIG_ARCH_LEDS用于显示系统状态(如启动、Panic),则还需要实现以下函数:
| 函数 | 描述 |
|---|---|
| void board_autoled_initialize(void) | 初始化用于系统状态指示的 LED 引脚,通常设置为 GPIO 输出模式。 |
| void board_autoled_on(int led) | 根据系统状态(如 LED_STARTED)点亮指定的 LED。 |
| void board_autoled_off(int led) | 根据系统状态(如 LED_PANIC 结束)熄灭指定的 LED。 |
硬件配置:时钟与引脚
除了实现函数接口,您还需要在板级头文件board.h中定义宏,以配置 STM32 的时钟树、外设引脚功能等。这些宏将被芯片级的驱动代码(如 stm32_rcc.c)使用。
以下是开发板时钟树的配置示例,它描述了如何将 25MHz 的外部高速晶振(HSE)通过 PLL 倍频至 168MHz 作为系统主时钟(SYSCLK)。
/* Clocking *****************************************************************/
/* The APOLLO Discovery board features a single 25MHz crystal.
* Space is provided for a 32kHz RTC backup crystal, but it is not stuffed.
*
* This is the canonical configuration:
* System Clock source : PLL (HSE)
* SYSCLK(Hz) : 168000000 Determined by PLL
* configuration
* HCLK(Hz) : 168000000 (STM32_RCC_CFGR_HPRE)
* AHB Prescaler : 1 (STM32_RCC_CFGR_HPRE)
* APB1 Prescaler : 4 (STM32_RCC_CFGR_PPRE1)
* APB2 Prescaler : 2 (STM32_RCC_CFGR_PPRE2)
* HSE Frequency(Hz) : 25000000 (STM32_BOARD_XTAL)
* PLLM : 25 (STM32_PLLCFG_PLLM)
* PLLN : 336 (STM32_PLLCFG_PLLN)
* PLLP : 2 (STM32_PLLCFG_PLLP)
* PLLQ : 7 (STM32_PLLCFG_PLLQ)
* Main regulator output voltage : Scale1 mode Needed for high speed
* SYSCLK
* Flash Latency(WS) : 5
* Prefetch Buffer : OFF
* Instruction cache : ON
* Data cache : ON
* Require 48MHz for USB OTG FS, : Enabled
* SDIO and RNG clock
*/
二、代码实现步骤
本节将指导您完成本项目的文件创建和代码编写。
1.创建代码目录结构
首先,在nuttx/boards/arm/stm32/目录下,创建一个名为 apollo-disco的新目录,并建立如下的子目录和文件结构。
代码路径: nuttx/boards/arm/stm32/apollo-disco/
apollo-disco
├── CMakeLists.txt
├── configs # defconfig 配置路径
│ └── nsh
│ └── defconfig # NuttShell (NSH) 的默认配置
├── include
│ └── board.h # 板级硬件配置头文件
├── Kconfig # 板级 Kconfig 配置文件
├── scripts # 链接脚本
│ ├── ld.script # 链接器脚本
│ └── Make.defs # 板级 Make 定义
└── src
├── CMakeLists.txt
├── Make.defs
├── stm32_appinit.c # 实现 board_app_initialize
├── stm32_autoleds.c # 实现系统状态 LED 控制
├── stm32_boot.c # 实现 stm32_boardinitialize
├── stm32_bringup.c # 实现驱动初始化
├── apollo-disco.h # 板级私有头文件,定义 GPIO
└── stm32_userleds.c # 实现用户层 LED 驱动接口
└── stm32_extmem.c # 实现 stm32_sdram_initialize
2.实现核心初始化函数
在 src/ 目录下,您需要创建并填充以下 C 文件。
stm32_boot.c:早期硬件初始化
此文件负责实现 stm32_boardinitialize(),用于在系统启动的最初阶段配置必要的硬件。
#include <nuttx/config.h>
#include "apollo-disco.h" // 板级私有定义
void stm32_boardinitialize(void)
{
#ifdef CONFIG_ARCH_LEDS
/* 如果启用了系统状态LED,则初始化它们 */
board_autoled_initialize();
#endif
#ifdef CONFIG_STM32_FMC
stm32_sdram_initialize();
#endif
}
#ifdef CONFIG_BOARD_LATE_INITIALIZE
void board_late_initialize(void)
{
/* 执行板级后期初始化 */
stm32_bringup();
}
#endif
stm32_bringup.c:设备驱动初始化
此文件中的 stm32_bringup() 函数负责初始化并注册所有板载设备的驱动程序。在本例中,我们啥都不用干。
#include "stm32.h"
#ifdef CONFIG_USERLED
# include <nuttx/leds/userled.h>
#endif
#include "apollo-disco.h"
int stm32_bringup(void)
{
int ret = OK;
/* 在此添加其他驱动的初始化,例如 I2C, SPI, SDIO 等 */
UNUSED(ret);
return OK;
}
stm32_appinit.c:应用初始化桥梁
主要实现 int board_app_initialize(uintptr_t arg) 函数:
- 如果打开
CONFIG_BOARD_LATE_INITIALIZE,stm32_bringup()将由board_late_initialize()调用。 - 如果没有打开
CONFIG_BOARD_LATE_INITIALIZE,stm32_bringup()将由board_app_initialize(arg)调用。
int board_app_initialize(uintptr_t arg)
{
#ifdef CONFIG_BOARD_LATE_INITIALIZE
/* 如果定义了后期初始化,bringup 已被调用,此处无需操作 */
return OK;
#else
/* 否则,在此处调用 bringup 来初始化驱动 */
return stm32_bringup();
#endif
}
3.实现 LED 驱动
openvela将 LED 分为两类:一类用于指示系统状态(autoleds),另一类供用户应用程序控制(userleds)。
stm32_autoleds.c:系统状态 LED
该文件实现 board_autoled_* 系列函数,来控制实现 LED 的亮灭,由系统内核在特定事件(如启动、断言失败)发生时自动调用。此部分实现参照nuttx/boards/arm/stm32/stm32f429i-disco/src/stm32_autoleds.c
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"
#include "apollo-disco.h"
#ifdef CONFIG_ARCH_LEDS
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* The following definitions map the encoded LED setting to GPIO settings */
#define STM32F4_LED1 (1 << 0)
#define STM32F4_LED2 (1 << 1)
#define ON_SETBITS_SHIFT (0)
#define ON_CLRBITS_SHIFT (4)
#define OFF_SETBITS_SHIFT (8)
#define OFF_CLRBITS_SHIFT (12)
#define ON_BITS(v) ((v) & 0xff)
#define OFF_BITS(v) (((v) >> 8) & 0x0ff)
#define SETBITS(b) ((b) & 0x0f)
#define CLRBITS(b) (((b) >> 4) & 0x0f)
#define ON_SETBITS(v) (SETBITS(ON_BITS(v))
#define ON_CLRBITS(v) (CLRBITS(ON_BITS(v))
#define OFF_SETBITS(v) (SETBITS(OFF_BITS(v))
#define OFF_CLRBITS(v) (CLRBITS(OFF_BITS(v))
#define LED_STARTED_ON_SETBITS ((STM32F4_LED1) << ON_SETBITS_SHIFT)
#define LED_STARTED_ON_CLRBITS ((STM32F4_LED2) << ON_CLRBITS_SHIFT)
#define LED_STARTED_OFF_SETBITS (0 << OFF_SETBITS_SHIFT)
#define LED_STARTED_OFF_CLRBITS ((STM32F4_LED1|STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_HEAPALLOCATE_ON_SETBITS ((STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_HEAPALLOCATE_ON_CLRBITS ((STM32F4_LED1) << ON_CLRBITS_SHIFT)
#define LED_HEAPALLOCATE_OFF_SETBITS ((STM32F4_LED1) << OFF_SETBITS_SHIFT)
#define LED_HEAPALLOCATE_OFF_CLRBITS ((STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_IRQSENABLED_ON_SETBITS ((STM32F4_LED1|STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_IRQSENABLED_ON_CLRBITS ((STM32F4_LED2) << ON_CLRBITS_SHIFT)
#define LED_IRQSENABLED_OFF_SETBITS ((STM32F4_LED2) << OFF_SETBITS_SHIFT)
#define LED_IRQSENABLED_OFF_CLRBITS ((STM32F4_LED1) << OFF_CLRBITS_SHIFT)
#define LED_STACKCREATED_ON_SETBITS ((STM32F4_LED1) << ON_SETBITS_SHIFT)
#define LED_STACKCREATED_ON_CLRBITS ((STM32F4_LED1|STM32F4_LED2) << ON_CLRBITS_SHIFT)
#define LED_STACKCREATED_OFF_SETBITS ((STM32F4_LED1|STM32F4_LED2) << OFF_SETBITS_SHIFT)
#define LED_STACKCREATED_OFF_CLRBITS ((STM32F4_LED1|STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_INIRQ_ON_SETBITS ((STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_INIRQ_ON_CLRBITS ((0) << ON_CLRBITS_SHIFT)
#define LED_INIRQ_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_INIRQ_OFF_CLRBITS ((STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_SIGNAL_ON_SETBITS ((STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_SIGNAL_ON_CLRBITS ((0) << ON_CLRBITS_SHIFT)
#define LED_SIGNAL_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_SIGNAL_OFF_CLRBITS ((STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_ASSERTION_ON_SETBITS ((STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_ASSERTION_ON_CLRBITS ((0) << ON_CLRBITS_SHIFT)
#define LED_ASSERTION_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_ASSERTION_OFF_CLRBITS ((STM32F4_LED2) << OFF_CLRBITS_SHIFT)
#define LED_PANIC_ON_SETBITS ((STM32F4_LED2) << ON_SETBITS_SHIFT)
#define LED_PANIC_ON_CLRBITS ((0) << ON_CLRBITS_SHIFT)
#define LED_PANIC_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_PANIC_OFF_CLRBITS ((STM32F4_LED2) << OFF_CLRBITS_SHIFT)
/****************************************************************************
* Private Data
****************************************************************************/
static const uint16_t g_ledbits[8] =
{
(LED_STARTED_ON_SETBITS | LED_STARTED_ON_CLRBITS |
LED_STARTED_OFF_SETBITS | LED_STARTED_OFF_CLRBITS),
(LED_HEAPALLOCATE_ON_SETBITS | LED_HEAPALLOCATE_ON_CLRBITS |
LED_HEAPALLOCATE_OFF_SETBITS | LED_HEAPALLOCATE_OFF_CLRBITS),
(LED_IRQSENABLED_ON_SETBITS | LED_IRQSENABLED_ON_CLRBITS |
LED_IRQSENABLED_OFF_SETBITS | LED_IRQSENABLED_OFF_CLRBITS),
(LED_STACKCREATED_ON_SETBITS | LED_STACKCREATED_ON_CLRBITS |
LED_STACKCREATED_OFF_SETBITS | LED_STACKCREATED_OFF_CLRBITS),
(LED_INIRQ_ON_SETBITS | LED_INIRQ_ON_CLRBITS |
LED_INIRQ_OFF_SETBITS | LED_INIRQ_OFF_CLRBITS),
(LED_SIGNAL_ON_SETBITS | LED_SIGNAL_ON_CLRBITS |
LED_SIGNAL_OFF_SETBITS | LED_SIGNAL_OFF_CLRBITS),
(LED_ASSERTION_ON_SETBITS | LED_ASSERTION_ON_CLRBITS |
LED_ASSERTION_OFF_SETBITS | LED_ASSERTION_OFF_CLRBITS),
(LED_PANIC_ON_SETBITS | LED_PANIC_ON_CLRBITS |
LED_PANIC_OFF_SETBITS | LED_PANIC_OFF_CLRBITS)
};
/****************************************************************************
* Private Functions
****************************************************************************/
static inline void led_clrbits(unsigned int clrbits)
{
if ((clrbits & STM32F4_LED1) != 0)
{
stm32_gpiowrite(GPIO_LED_RED, false);
}
if ((clrbits & STM32F4_LED2) != 0)
{
stm32_gpiowrite(GPIO_LED_GREEN, false);
}
}
static inline void led_setbits(unsigned int setbits)
{
if ((setbits & STM32F4_LED1) != 0)
{
stm32_gpiowrite(GPIO_LED_RED, true);
}
if ((setbits & STM32F4_LED2) != 0)
{
stm32_gpiowrite(GPIO_LED_GREEN, true);
}
}
static void led_setonoff(unsigned int bits)
{
led_clrbits(CLRBITS(bits));
led_setbits(SETBITS(bits));
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_autoled_initialize
****************************************************************************/
void board_autoled_initialize(void)
{
/* Configure LED1-4 GPIOs for output */
stm32_configgpio(GPIO_LED_GREEN);
stm32_configgpio(GPIO_LED_RED);
}
/****************************************************************************
* Name: board_autoled_on
****************************************************************************/
void board_autoled_on(int led)
{
ledinfo("board_autoled_on(%d)\n", led);
led_setonoff(ON_BITS(g_ledbits[led]));
}
/****************************************************************************
* Name: board_autoled_off
****************************************************************************/
void board_autoled_off(int led)
{
led_setonoff(OFF_BITS(g_ledbits[led]));
}
#endif /* CONFIG_ARCH_LEDS */
stm32_userleds.c:用户应用 LED
该文件为通用的 LED 驱动(位于 drivers/leds/userled_lower.c)提供底层的硬件操作接口。应用程序通过标准的 open(), write(), ioctl() 等VFS接口访问 /dev/userleds 来控制这些 LED。
我们需要提供下面的函数接口给 userled_lower.c 调用:
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <arch/board/board.h>
#include <nuttx/power/pm.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"
#include "apollo-disco.h"
#ifndef CONFIG_ARCH_LEDS
/****************************************************************************
* Private Data
****************************************************************************/
/* This array maps an LED number to GPIO pin configuration */
static uint32_t g_ledcfg[BOARD_NLEDS] =
{
GPIO_LED_GREEN, GPIO_LED_RED
};
/****************************************************************************
* Private Function Protototypes
****************************************************************************/
/****************************************************************************
* Name: board_userled_initialize
****************************************************************************/
uint32_t board_userled_initialize(void)
{
int i;
/* 定义板载用户 LED 对应的 GPIO 配置 */
for (i = 0; i < BOARD_NLEDS; i++)
{
stm32_configgpio(g_ledcfg[i]);
}
return BOARD_NLEDS;
}
void board_userled(int led, bool ledon)
{
/* 初始化用户 LED 的 GPIO */
if ((unsigned)led < BOARD_NLEDS)
{
stm32_gpiowrite(g_ledcfg[led], ledon);
}
}
void board_userled_all(uint32_t ledset)
{
int i;
/* Configure LED GPIOs for output */
for (i = 0; i < BOARD_NLEDS; i++)
{
stm32_gpiowrite(g_ledcfg[i], (ledset & (1 << i)) != 0);
}
}
#endif /* !CONFIG_ARCH_LEDS */
最终,在 userled_upper.c 实现下面 LED 驱动接口:
static int userled_open(FAR struct file *filep);
static int userled_close(FAR struct file *filep);
static ssize_t userled_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static int userled_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
4、实现外部 SDRAM驱动
我们将通过STM32F429的FMC接口,来驱动W9825G6KH这颗SDRAM芯片。
stm32_extmem.c:外部 SDRAM驱动
该文件实现 stm32_sdram_initialize 函数,供 stm32_bringup() 函数负责初始化并注册外部 SDRAM驱动。此部分实现参照nuttx/boards/arm/stm32/stm32f429i-disco/src/stm32_extmem.c
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"
#include "apollo-disco.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_STM32_FMC
#warning "FMC is not enabled"
#endif
#if STM32_NGPIO_PORTS < 6
#error "Required GPIO ports not enabled"
#endif
#define STM32_SDRAM_CLKEN FMC_SDCMR_CMD_CLK_ENABLE | FMC_SDCMR_BANK_1
#define STM32_SDRAM_PALL FMC_SDCMR_CMD_PALL | FMC_SDCMR_BANK_1
#define STM32_SDRAM_REFRESH FMC_SDCMR_CMD_AUTO_REFRESH | FMC_SDCMR_BANK_1 |\
FMC_SDCMR_NRFS(4)
#define STM32_SDRAM_MODEREG FMC_SDCMR_CMD_LOAD_MODE | FMC_SDCMR_BANK_1 |\
FMC_SDCMR_MDR_BURST_LENGTH_1 | \
FMC_SDCMR_MDR_BURST_TYPE_SEQUENTIAL |\
FMC_SDCMR_MDR_CAS_LATENCY_3 |\
FMC_SDCMR_MDR_WBL_SINGLE
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/* GPIO configurations common to most external memories */
static const uint32_t g_sdram_config[] =
{
/* 16 data lines */
GPIO_FMC_D0, GPIO_FMC_D1, GPIO_FMC_D2, GPIO_FMC_D3,
GPIO_FMC_D4, GPIO_FMC_D5, GPIO_FMC_D6, GPIO_FMC_D7,
GPIO_FMC_D8, GPIO_FMC_D9, GPIO_FMC_D10, GPIO_FMC_D11,
GPIO_FMC_D12, GPIO_FMC_D13, GPIO_FMC_D14, GPIO_FMC_D15,
/* 13 address lines */
GPIO_FMC_A0, GPIO_FMC_A1, GPIO_FMC_A2, GPIO_FMC_A3,
GPIO_FMC_A4, GPIO_FMC_A5, GPIO_FMC_A6, GPIO_FMC_A7,
GPIO_FMC_A8, GPIO_FMC_A9, GPIO_FMC_A10, GPIO_FMC_A11,
GPIO_FMC_A12,
/* control lines */
GPIO_FMC_SDCKE0, GPIO_FMC_SDNE0, GPIO_FMC_SDNWE, GPIO_FMC_NBL0,
GPIO_FMC_SDNRAS, GPIO_FMC_NBL1, GPIO_FMC_BA0, GPIO_FMC_BA1,
GPIO_FMC_SDCLK, GPIO_FMC_SDNCAS,
};
#define NUM_SDRAM_GPIOS (sizeof(g_sdram_config) / sizeof(uint32_t))
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_sdram_initialize
*
* Description:
* Called from stm32_bringup to initialize external SDRAM access.
*
****************************************************************************/
void stm32_sdram_initialize(void)
{
uint32_t val;
int i;
volatile int count;
/* Enable GPIOs as FMC / memory pins */
for (i = 0; i < NUM_SDRAM_GPIOS; i++)
{
stm32_configgpio(g_sdram_config[i]);
}
/* Enable AHB clocking to the FMC */
stm32_fmc_enable();
/* Configure and enable the SDRAM bank1
*
* FMC clock = 168MHz/2 = 84MHz
* 84MHz = 11,90 ns
* All timings from the datasheet for Speedgrade -7 (=7ns)
*/
val = FMC_SDCR_RPIPE_1 | /* rpipe = 1 hclk */
FMC_SDCR_SDCLK_2X | /* sdclk = 2 hclk */
FMC_SDCR_CAS_LATENCY_3 | /* cas latency = 3 cycles */
FMC_SDCR_NBANKS_4 | /* 4 internal banks */
FMC_SDCR_WIDTH_16 | /* width = 16 bits */
FMC_SDCR_ROWS_13 | /* numrows = 13 */
FMC_SDCR_COLS_9; /* numcols = 9 bits */
stm32_fmc_sdram_set_control(1, val);
val = FMC_SDTR_TRCD(2) | /* tRCD min = 15ns */
FMC_SDTR_TRP(2) | /* tRP min = 15ns */
FMC_SDTR_TWR(2) | /* tWR = 2CLK */
FMC_SDTR_TRC(6) | /* tRC min = 60ns */
FMC_SDTR_TRAS(6) | /* tRAS min = 60ns */
FMC_SDTR_TXSR(7) | /* tXSR min = 72ns */
FMC_SDTR_TMRD(2); /* tMRD = 2CLK */
stm32_fmc_sdram_set_timing(1, val);
/* SDRAM Initialization sequence */
stm32_fmc_sdram_command(STM32_SDRAM_CLKEN); /* Clock enable command */
for (count = 0; count < 10000; count++); /* Delay */
stm32_fmc_sdram_command(STM32_SDRAM_PALL); /* Precharge ALL command */
stm32_fmc_sdram_command(STM32_SDRAM_REFRESH); /* Auto refresh command */
stm32_fmc_sdram_command(STM32_SDRAM_MODEREG); /* Mode Register program */
/* Set refresh count
*
* FMC_CLK = 84MHz
* Refresh_Rate = 7.81us
* Counter = (FMC_CLK * Refresh_Rate) - 20
*/
stm32_fmc_sdram_set_refresh_rate(636);
/* Disable write protection */
/* stm32_fmc_sdram_write_protect(2, false); */
}
说明:
此文件中相关配置与定义,需按照《STM32F429开发指南 V1.1 – HAL库版本 −ALIENTEK阿波罗STM32F429开发板教程 》
第十八章 SDRAM实验 18.3 软件设计 中的相应内容完成。例如:
使能FMC时钟
void stm32_sdram_initialize(void) { ...... stm32_fmc_enable(); ...... }配置FMC相关的IO
参考 图18.1.2.5
W9825G6KH原理图 和 1.2.3 阿波罗 IO引脚分配/* GPIO configurations common to most external memories */ static const uint32_t g_sdram_config[] = { /* 16 data lines */ GPIO_FMC_D0, GPIO_FMC_D1, GPIO_FMC_D2, GPIO_FMC_D3, GPIO_FMC_D4, GPIO_FMC_D5, GPIO_FMC_D6, GPIO_FMC_D7, GPIO_FMC_D8, GPIO_FMC_D9, GPIO_FMC_D10, GPIO_FMC_D11, GPIO_FMC_D12, GPIO_FMC_D13, GPIO_FMC_D14, GPIO_FMC_D15, /* 13 address lines */ GPIO_FMC_A0, GPIO_FMC_A1, GPIO_FMC_A2, GPIO_FMC_A3, GPIO_FMC_A4, GPIO_FMC_A5, GPIO_FMC_A6, GPIO_FMC_A7, GPIO_FMC_A8, GPIO_FMC_A9, GPIO_FMC_A10, GPIO_FMC_A11, GPIO_FMC_A12, /* control lines */ GPIO_FMC_SDCKE0, GPIO_FMC_SDNE0, GPIO_FMC_SDNWE, GPIO_FMC_NBL0, GPIO_FMC_SDNRAS, GPIO_FMC_NBL1, GPIO_FMC_BA0, GPIO_FMC_BA1, GPIO_FMC_SDCLK, GPIO_FMC_SDNCAS, }; #define NUM_SDRAM_GPIOS (sizeof(g_sdram_config) / sizeof(uint32_t)) void stm32_sdram_initialize(void) { ...... /* Enable GPIOs as FMC / memory pins */ for (i = 0; i < NUM_SDRAM_GPIOS; i++) { stm32_configgpio(g_sdram_config[i]); } ...... }初始化
SDRAM控制参数和时间参数参考 图18.1.2.5 W9825G6KH原理图 可知,阿波罗STM32F429核心板板载的
W9825G6KH芯片挂在FMC SDRAM的控制器1上面(SDNE0),因此需设置寄存器FMC_SDCR1和FMC_SDTR1以实现初始化SDRAM控制参数和时间参数。
寄存器
FMC_SDCR1用来设置SDRAM的相关控制参数,比如地址线宽度、CAS延迟、SDRAM时钟等。对于W9825G6KH,相关配置信息如下:
- 内部有4个BANK:FMC_SDCR_NBANKS_4
- 数据位宽为16位:FMC_SDCR_WIDTH_16
- 13位行地址:FMC_SDCR_ROWS_13
- 9位列地址:FMC_SDCR_COLS_9
- SDRAM的时钟周期为2倍HCLK时钟周期:FMC_SDCR_SDCLK_2X
- RPIPE延迟为1个HCLK时钟周期:FMC_SDCR_RPIPE_1
- CAS延迟为3个存储器时钟周期:FMC_SDCR_CAS_LATENCY_3
因此:
void stm32_sdram_initialize(void) { uint32_t val; ...... val = FMC_SDCR_RPIPE_1 | /* rpipe = 1 hclk */ FMC_SDCR_SDCLK_2X | /* sdclk = 2 hclk */ FMC_SDCR_CAS_LATENCY_3 | /* cas latency = 3 cycles */ FMC_SDCR_NBANKS_4 | /* 4 internal banks */ FMC_SDCR_WIDTH_16 | /* width = 16 bits */ FMC_SDCR_ROWS_13 | /* numrows = 13 */ FMC_SDCR_COLS_9; /* numcols = 9 bits */ stm32_fmc_sdram_set_control(1, val); ...... }
寄存器FMC_SDTR1用来设置SDRAM时间相关参数,比如自刷新时间、恢复延迟、预充电延迟等。对于
W9825G6KH,相关配置信息如下:
- 加载模式到激活时间的延迟为2个存储器时钟周期:FMC_SDTR_TMRD(2)
- 退出自刷新延迟为7个存储器时钟周期:FMC_SDTR_TXSR(7)
- 自刷新时间为6个存储器时钟周期:FMC_SDTR_TRAS(6)
- 行循环延迟为6个存储器存储器时钟周期:FMC_SDTR_TRC(6)
- 恢复延迟为2个存储器时钟周期:FMC_SDTR_TWR(2)
- 行预充电延迟为2个存储器时钟周期:FMC_SDTR_TRP(2)
- 行到列延迟为2个存储器时钟周期:FMC_SDTR_TMRD(2)
因此
void stm32_sdram_initialize(void) { uint32_t val; ...... val = FMC_SDTR_TRCD(2) | /* tRCD min = 15ns */ FMC_SDTR_TRP(2) | /* tRP min = 15ns */ FMC_SDTR_TWR(2) | /* tWR = 2CLK */ FMC_SDTR_TRC(6) | /* tRC min = 60ns */ FMC_SDTR_TRAS(6) | /* tRAS min = 60ns */ FMC_SDTR_TXSR(7) | /* tXSR min = 72ns */ FMC_SDTR_TMRD(2); /* tMRD = 2CLK */ stm32_fmc_sdram_set_timing(1, val); ...... }发送SDRAM初始化序列
SDRAM初始化步骤为:
- 首先使能时钟配置,
- 然后等待至少200us,
- 对所有BANK进行预充电,
- 执行自刷新命令等,
- 最后配置模式寄存器。
#define STM32_SDRAM_CLKEN FMC_SDCMR_CMD_CLK_ENABLE | FMC_SDCMR_BANK_1 #define STM32_SDRAM_PALL FMC_SDCMR_CMD_PALL | FMC_SDCMR_BANK_1 #define STM32_SDRAM_REFRESH FMC_SDCMR_CMD_AUTO_REFRESH | FMC_SDCMR_BANK_1 |\ FMC_SDCMR_NRFS(8) #define STM32_SDRAM_MODEREG FMC_SDCMR_CMD_LOAD_MODE | FMC_SDCMR_BANK_1 |\ FMC_SDCMR_MDR_BURST_LENGTH_1 | \ FMC_SDCMR_MDR_BURST_TYPE_SEQUENTIAL |\ FMC_SDCMR_MDR_CAS_LATENCY_3 |\ FMC_SDCMR_MDR_WBL_SINGLE void stm32_sdram_initialize(void) { ...... /* SDRAM Initialization sequence */ stm32_fmc_sdram_command(STM32_SDRAM_CLKEN); /* Clock enable command */ for (count = 0; count < 10000; count++); /* Delay */ stm32_fmc_sdram_command(STM32_SDRAM_PALL); /* Precharge ALL command */ stm32_fmc_sdram_command(STM32_SDRAM_REFRESH); /* Auto refresh command */ stm32_fmc_sdram_command(STM32_SDRAM_MODEREG); /* Mode Register program */ ...... }设置刷新频率
W9825G6KH的刷新周期为64ms,行数为8192行,所以刷新速率为:
刷新速率 = 64 m s / 8192 = 7.81 u s 刷新速率=64ms/8192=7.81us 刷新速率=64ms/8192=7.81us而SDRAM时钟频率=168Mhz/2=84Mhz(降频12M),所以COUNT的值为:
C O U N T = 7.81 u s / 11.9 n s = 656 COUNT=7.81us/11.9ns=656 COUNT=7.81us/11.9ns=656而如果SDRAM在接受读请求后,出现内部刷新请求,则必须将刷新速率增加20个SDRAM时钟周期,以获得充足的余量,所以,实际设计的COUNT值应该是:COUNT-20=636。所以,我们设置FMC_SDRTR的COUNT=636。
static const uint32_t g_sdram_config[] = { ...... /* Set refresh count * * FMC_CLK = 84MHz * Refresh_Rate = 7.81us * Counter = (FMC_CLK * Refresh_Rate) - 20 */ stm32_fmc_sdram_set_refresh_rate(636); ...... };
5、定义硬件宏
在src/apollo-disco.h和 include/board.h 中定义与硬件相关的宏。
apollo-disco.h:板级私有定义
此文件定义了板载外设的 GPIO 引脚和其他私有配置。参考boards/arm/stm32/stm32f429i-disco/src/stm32f429i-disco.h
/* Configuration ************************************************************/
/* LED.
* User LED1: the green LED is a user LED connected to board LED DS1
* corresponding to MCU I/O PB0.
* User LED2: the red LED is a user LED connected to board LED DS0
* corresponding to MCU I/O PB1.
*
* - When the I/O is HIGH value, the LED is on.
* - When the I/O is LOW, the LED is off.
*/
#define GPIO_LED_RED (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN1)
#define GPIO_LED_GREEN (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN0)
/* BUTTONS -- NOTE that all have EXTI interrupts configured */
/*
* KEY0 : the KEY0 button is connected to the I/O PH3 of the STM32, PULLUP
* KEY1 : the KEY1 button is connected to the I/O PH2 of the STM32, PULLUP
* KEY2 : the KEY2 button is connected to the I/O PC13 of the STM32, PULLUP
* KEY3 : the KEY3 button is connected to the I/O PA0 of the STM32, PULLDOWM
*
*/
#define MIN_IRQBUTTON BUTTON_KEY0
#define MAX_IRQBUTTON BUTTON_KEY3
#define NUM_IRQBUTTONS 4
#define GPIO_BTN_KEY0 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTH|GPIO_PIN3)
#define GPIO_BTN_KEY1 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTH|GPIO_PIN2)
#define GPIO_BTN_KEY2 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTC|GPIO_PIN13)
#define GPIO_BTN_KEY3 (GPIO_INPUT|GPIO_PULLDOWN|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTA|GPIO_PIN0)
#define NUM_BUTTONS 4
#define BUTTON_KEY0_BIT (1 << BUTTON_KEY0)
#define BUTTON_KEY1_BIT (1 << BUTTON_KEY1)
#define BUTTON_KEY2_BIT (1 << BUTTON_KEY2)
#define BUTTON_KEY3_BIT (1 << BUTTON_KEY3)
include/board.h:公共板级定义
此文件包含被 NuttX 内核和应用共享的板级定义,如时钟配置。参考boards/arm/stm32/stm32f429i-disco/include/board.h
#ifndef __BOARDS_ARM_STM32_APOLLO_DISCO_INCLUDE_BOARD_H
#define __BOARDS_ARM_STM32_APOLLO_DISCO_INCLUDE_BOARD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifndef __ASSEMBLY__
# include <stdint.h>
#endif
/* DO NOT include STM32 internal header files here */
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Clocking *****************************************************************/
/* The APOLLO Discovery board features a single 25MHz crystal.
* Space is provided for a 32kHz RTC backup crystal, but it is not stuffed.
*
* This is the canonical configuration:
* System Clock source : PLL (HSE)
* SYSCLK(Hz) : 168000000 Determined by PLL
* configuration
* HCLK(Hz) : 168000000 (STM32_RCC_CFGR_HPRE)
* AHB Prescaler : 1 (STM32_RCC_CFGR_HPRE)
* APB1 Prescaler : 4 (STM32_RCC_CFGR_PPRE1)
* APB2 Prescaler : 2 (STM32_RCC_CFGR_PPRE2)
* HSE Frequency(Hz) : 25000000 (STM32_BOARD_XTAL)
* PLLM : 25 (STM32_PLLCFG_PLLM)
* PLLN : 336 (STM32_PLLCFG_PLLN)
* PLLP : 2 (STM32_PLLCFG_PLLP)
* PLLQ : 7 (STM32_PLLCFG_PLLQ)
* Main regulator output voltage : Scale1 mode Needed for high speed
* SYSCLK
* Flash Latency(WS) : 5
* Prefetch Buffer : OFF
* Instruction cache : ON
* Data cache : ON
* Require 48MHz for USB OTG FS, : Enabled
* SDIO and RNG clock
*/
/* HSI - 16 MHz RC factory-trimmed
* LSI - 32 KHz RC
* HSE - On-board crystal frequency is 25MHz
* LSE - 32.768 kHz
*/
#define STM32_BOARD_XTAL 25000000ul
#define STM32_HSI_FREQUENCY 16000000ul
#define STM32_LSI_FREQUENCY 32000
#define STM32_HSE_FREQUENCY STM32_BOARD_XTAL
#define STM32_LSE_FREQUENCY 32768
/* Main PLL Configuration.
*
*
* Formulae:
*
* VCO input freq = PLL input clock freq/PLLM 2 <= PLLM <= 63
* VCO output freq = VCO input freq × PLLN, 192 <= PLLN <= 432
* PLL output clock freq = VCO freq / PLLP, PLLP = 2,4,6 or 8
* USB OTG FS clock freq = VCO freq / PLLQ, 2 <= PLLQ <= 15
*
* There is no config for 180 MHz and 48 MHz for usb,
* so we would like to have SYSYCLK=168 MHz and we must have the USB
* clock = 48MHz
*
* PLLQ = 7 PLLP = 2 PLLN=336 PLLM=25
*
* PLL source is HSE
* PLL_VCO = (STM32_HSE_FREQUENCY / PLLM) * PLLN
* = (25,000,000 / 25) * 336
* = 336,000,000
* SYSCLK = PLL_VCO / PLLP
* = 336,000,000 / 2 = 168,000,000
* USB OTG FS, SDIO and RNG Clock
* = PLL_VCO / PLLQ
* = 48,000,000
*/
#define STM32_PLLCFG_PLLM RCC_PLLCFG_PLLM(25)
#define STM32_PLLCFG_PLLN RCC_PLLCFG_PLLN(336)
#define STM32_PLLCFG_PLLP RCC_PLLCFG_PLLP_2
#define STM32_PLLCFG_PLLQ RCC_PLLCFG_PLLQ(7)
#define STM32_SYSCLK_FREQUENCY 168000000ul
/* AHB clock (HCLK) is SYSCLK (168MHz) */
#define STM32_RCC_CFGR_HPRE RCC_CFGR_HPRE_SYSCLK /* HCLK = SYSCLK / 1 */
#define STM32_HCLK_FREQUENCY STM32_SYSCLK_FREQUENCY
/* APB1 clock (PCLK1) is HCLK/4 (42MHz) */
#define STM32_RCC_CFGR_PPRE1 RCC_CFGR_PPRE1_HCLKd4 /* PCLK1 = HCLK / 4 */
#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY/4)
/* Timers driven from APB1 will be twice PCLK1 */
#define STM32_APB1_TIM2_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM3_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM4_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM5_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM6_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM7_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM12_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM13_CLKIN (2*STM32_PCLK1_FREQUENCY)
#define STM32_APB1_TIM14_CLKIN (2*STM32_PCLK1_FREQUENCY)
/* APB2 clock (PCLK2) is HCLK/2 (84MHz) */
#define STM32_RCC_CFGR_PPRE2 RCC_CFGR_PPRE2_HCLKd2 /* PCLK2 = HCLK / 2 */
#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY/2)
/* Timers driven from APB2 will be twice PCLK2 */
#define STM32_APB2_TIM1_CLKIN (2*STM32_PCLK2_FREQUENCY)
#define STM32_APB2_TIM8_CLKIN (2*STM32_PCLK2_FREQUENCY)
#define STM32_APB2_TIM9_CLKIN (2*STM32_PCLK2_FREQUENCY)
#define STM32_APB2_TIM10_CLKIN (2*STM32_PCLK2_FREQUENCY)
#define STM32_APB2_TIM11_CLKIN (2*STM32_PCLK2_FREQUENCY)
/* Timer Frequencies, if APBx is set to 1, frequency is same to APBx
* otherwise frequency is 2xAPBx.
* Note: TIM1,8 are on APB2, others on APB1
*/
#define BOARD_TIM1_FREQUENCY STM32_HCLK_FREQUENCY
#define BOARD_TIM2_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM3_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM4_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM5_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM6_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM7_FREQUENCY (STM32_HCLK_FREQUENCY/2)
#define BOARD_TIM8_FREQUENCY STM32_HCLK_FREQUENCY
/* LED definitions **********************************************************/
/*
* If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs in
* any way. The following definitions are used to access individual LEDs.
*/
/* LED index values for use with board_userled() */
#define BOARD_LED1 0
#define BOARD_LED2 1
#define BOARD_NLEDS 2
#define BOARD_LED_GREEN BOARD_LED1
#define BOARD_LED_ORANGE BOARD_LED2
/* LED bits for use with board_userled_all() */
#define BOARD_LED1_BIT (1 << BOARD_LED1)
#define BOARD_LED2_BIT (1 << BOARD_LED2)
/* If CONFIG_ARCH_LEDs is defined, then NuttX will control the 2 LEDs on
* board the apollo-disco.
* The following definitions describe how NuttX controls the LEDs:
*/
#define LED_STARTED 0 /* LED1 */
#define LED_HEAPALLOCATE 1 /* LED2 */
#define LED_IRQSENABLED 2 /* LED1 + LED2 */
#define LED_STACKCREATED 3 /* LED3 */
#define LED_INIRQ 4 /* LED1 + LED3 */
#define LED_SIGNAL 5 /* LED2 + LED3 */
#define LED_ASSERTION 6 /* LED1 + LED2 + LED3 */
#define LED_PANIC 7 /* N/C + N/C + N/C + LED4 */
/* Button definitions *******************************************************/
/* The APOLLO Discovery supports 4 button: */
#define BUTTON_KEY0 0 /* KEY0 */
#define BUTTON_KEY1 1 /* KEY1 */
#define BUTTON_KEY2 2 /* KEY2 */
#define BUTTON_KEY3 3 /* KEY_UP*/
#define NUM_BUTTONS 4
#define BUTTON_KEY0_BIT (1 << BUTTON_KEY0)
#define BUTTON_KEY1_BIT (1 << BUTTON_KEY1)
#define BUTTON_KEY2_BIT (1 << BUTTON_KEY2)
#define BUTTON_KEY3_BIT (1 << BUTTON_KEY3)
/* Alternate function pin selections ****************************************/
/* USART1:
*
* The Apollo Discovery has no on-board serial devices, but the console is
* brought out to PA9 (TX) and PA10 (RX) for connection to an external serial
* device. (See the README.txt file for other options)
*/
#define GPIO_USART1_RX GPIO_USART1_RX_1
#define GPIO_USART1_TX GPIO_USART1_TX_1
#endif /* __BOARDS_ARM_STM32_APOLLO_DISCO_INCLUDE_BOARD_H */
6、编写项目配置文件
编写src/Make.defs
参考boards/arm/stm32/stm32f429i-disco/src/Make.defs
include $(TOPDIR)/Make.defs
CSRCS = stm32_boot.c stm32_bringup.c
ifeq ($(CONFIG_ARCH_LEDS),y)
CSRCS += stm32_autoleds.c
else
CSRCS += stm32_userleds.c
endif
ifeq ($(CONFIG_BOARDCTL),y)
CSRCS += stm32_appinit.c
endif
ifeq ($(CONFIG_STM32_FMC),y)
CSRCS += stm32_extmem.c
endif
DEPPATH += --dep-path board
VPATH += :board
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
编写src/CMakeLists.txt
参考boards/arm/stm32/stm32f429i-disco/src/CMakeLists.txt)
set(SRCS stm32_boot.c stm32_bringup.c)
if(CONFIG_ARCH_LEDS)
list(APPEND SRCS stm32_autoleds.c)
else()
list(APPEND SRCS stm32_userleds.c)
endif()
if(CONFIG_BOARDCTL)
list(APPEND SRCS stm32_appinit.c)
endif()
if(CONFIG_STM32_FMC)
list(APPEND SRCS stm32_extmem.c)
endif()
target_sources(board PRIVATE ${SRCS})
set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/ld.script")
编写CMakeLists.txt
参考boards/arm/stm32/stm32f429i-disco/CMakeLists.txt
add_subdirectory(src)
7、链接脚本
scripts/Make.defs
参考boards/arm/stm32/stm32f429i-disco/scripts/Make.defs
include $(TOPDIR)/.config
include $(TOPDIR)/tools/Config.mk
include $(TOPDIR)/arch/arm/src/armv7-m/Toolchain.defs
ifeq ($(CONFIG_SYSTEM_OFLOADER),y)
LDSCRIPT = ofloader.ld
else
LDSCRIPT = ld.script
endif
ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT)
ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10
CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS)
CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
AFLAGS := $(CFLAGS) -D__ASSEMBLY__
NXFLATLDFLAGS1 = -r -d -warn-common
NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections
LDNXFLATFLAGS = -e main -s 2048
scripts/ld.script
参考boards/arm/stm32/stm32f429i-disco/scripts/ld.script
/* The STM32F429IGT6 has 1024Kb of FLASH beginning at address 0x0800:0000 and
* 256Kb of SRAM. SRAM is split up into four blocks:
*
* 1) 112Kb of SRAM beginning at address 0x2000:0000
* 2) 16Kb of SRAM beginning at address 0x2001:c000
* 3) 64Kb of SRAM beginning at address 0x2002:0000
* 4) 64Kb of CCM SRAM beginning at address 0x1000:0000
*
* When booting from FLASH, FLASH memory is aliased to address 0x0000:0000
* where the code expects to begin execution by jumping to the entry point in
* the 0x0800:0000 address
* range.
*/
MEMORY
{
flash (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
}
OUTPUT_ARCH(arm)
EXTERN(_vectors)
ENTRY(_stext)
SECTIONS
{
.text : {
_stext = ABSOLUTE(.);
*(.vectors)
*(.text .text.*)
*(.fixup)
*(.gnu.warning)
*(.rodata .rodata.*)
*(.gnu.linkonce.t.*)
*(.glue_7)
*(.glue_7t)
*(.got)
*(.gcc_except_table)
*(.gnu.linkonce.r.*)
_etext = ABSOLUTE(.);
} > flash
.init_section : ALIGN(4) {
_sinit = ABSOLUTE(.);
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors))
_einit = ABSOLUTE(.);
} > flash
.ARM.extab : ALIGN(4) {
*(.ARM.extab*)
} > flash
.ARM.exidx : ALIGN(4) {
__exidx_start = ABSOLUTE(.);
*(.ARM.exidx*)
__exidx_end = ABSOLUTE(.);
} > flash
.tdata : {
_stdata = ABSOLUTE(.);
*(.tdata .tdata.* .gnu.linkonce.td.*);
_etdata = ABSOLUTE(.);
} > flash
.tbss : {
_stbss = ABSOLUTE(.);
*(.tbss .tbss.* .gnu.linkonce.tb.* .tcommon);
_etbss = ABSOLUTE(.);
} > flash
_eronly = ABSOLUTE(.);
/* The RAM vector table (if present) should lie at the beginning of SRAM */
.ram_vectors : {
*(.ram_vectors)
} > sram
.data : ALIGN(4) {
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
.bss : ALIGN(4) {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = ABSOLUTE(.);
} > sram
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_info 0 : { *(.debug_info) }
.debug_line 0 : { *(.debug_line) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_aranges 0 : { *(.debug_aranges) }
}
scripts/ofloader.script
参考boards/arm/stm32/stm32f429i-disco/scripts/ofloader.ld
/* The STM32F429IGT6 has 1024Kb of sram beginning at address 0x0800:0000 and
* 256Kb of SRAM. SRAM is split up into four blocks:
*
* 1) 112Kb of SRAM beginning at address 0x2000:0000
* 2) 16Kb of SRAM beginning at address 0x2001:c000
* 3) 64Kb of SRAM beginning at address 0x2002:0000
* 4) 64Kb of CCM SRAM beginning at address 0x1000:0000
*
* When booting from sram, FLASH memory is aliased to address 0x0000:0000
* where the code expects to begin execution by jumping to the entry point in
* the 0x0800:0000 address
* range.
*/
MEMORY
{
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
}
OUTPUT_ARCH(arm)
EXTERN(_vectors)
ENTRY(_stext)
SECTIONS
{
PrgCode : ALIGN(4) {
KEEP(*(PrgCode PrgCode.*));
. = ALIGN(4);
} > sram
.text : {
_stext = ABSOLUTE(.);
*(.vectors)
*(.text .text.*)
*(.fixup)
*(.gnu.warning)
*(.rodata .rodata.*)
*(.gnu.linkonce.t.*)
*(.glue_7)
*(.glue_7t)
*(.got)
*(.gcc_except_table)
*(.gnu.linkonce.r.*)
_etext = ABSOLUTE(.);
} > sram
.init_section : ALIGN(4) {
_sinit = ABSOLUTE(.);
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors))
_einit = ABSOLUTE(.);
} > sram
.ARM.extab : ALIGN(4) {
*(.ARM.extab*)
} > sram
.ARM.exidx : ALIGN(4) {
__exidx_start = ABSOLUTE(.);
*(.ARM.exidx*)
__exidx_end = ABSOLUTE(.);
} > sram
.tdata : {
_stdata = ABSOLUTE(.);
*(.tdata .tdata.* .gnu.linkonce.td.*);
_etdata = ABSOLUTE(.);
} > sram
.tbss : {
_stbss = ABSOLUTE(.);
*(.tbss .tbss.* .gnu.linkonce.tb.* .tcommon);
_etbss = ABSOLUTE(.);
} > sram
PrgData : ALIGN(4) {
KEEP(*(PrgData PrgData.*))
. = ALIGN(4);
} > sram
_eronly = ABSOLUTE(.);
/* The RAM vector table (if present) should lie at the beginning of SRAM */
.ram_vectors : {
*(.ram_vectors)
} > sram
.data : ALIGN(4) {
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
DevDscr : ALIGN(4) {
KEEP(*(DevDscr DevDscr.*));
KEEP(*(DevStack DevStack.*))
. = ALIGN(4);
/* StackBuff are the stack used to run opeflashloder,
* and the location of the transmitted buffer.
*/
} > sram
.bss : ALIGN(4) {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = ABSOLUTE(.);
} > sram
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_info 0 : { *(.debug_info) }
.debug_line 0 : { *(.debug_line) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_aranges 0 : { *(.debug_aranges) }
}
三、集成到构建系统
完成代码编写后,需要修改构建系统配置,使 openvela 能够识别和编译您的新 BSP。
1、Kconfig 集成
Kconfig 用于管理内核和应用的功能配置。您需要执行以下三步来集成新板。
1.在 nuttx/boards/Kconfig 中定义板级选项:
添加一个新的 config 条目,用于在配置菜单中显示您的开发板。
config ARCH_BOARD_APOLLO_DISCO
bool "ATK APOLLO-Discovery board"
depends on ARCH_CHIP_STM32F429I
select ARCH_HAVE_LEDS
select ARCH_HAVE_BUTTONS
select ARCH_HAVE_IRQBUTTONS
---help---
ATK Apollo-Discovery board based on the STMicro STM32F429IGT6 MCU.
上述可参考条目config ARCH_BOARD_STM32F429I_DISCO
2.在 nuttx/boards/Kconfig 中设置默认板名:
当选中您的板型时,让 ARCH_BOARD 变量自动设置为您的 BSP 目录名。
config ARCH_BOARD
string
# ... 其他板的 default 设置 ...
default "apollo-disco" if ARCH_BOARD_APOLLO_DISCO
上述可参考条目default "stm32f429i-disco"
3.在 nuttx/boards/Kconfig 中加载板级 Kconfig 文件:
确保选中您的板型时,会加载 BSP 目录下的 Kconfig 文件。
if ARCH_BOARD_APOLLO_DISCO
source "boards/arm/stm32/apollo-disco/Kconfig"
endif
上述可参考条目if ARCH_BOARD_STM32F429I_DISCO"
4.在 apollo-disco/Kconfig 文件中可以添加此板特有的配置选项。
可参照boards/arm/stm32/stm32f429i-disco/Kconfig
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
if ARCH_BOARD_APOLLO_DISCO
config APOLLO_DISCO_FLASH
bool "MTD driver for external 32Mbyte W25Q256 FLASH on SPI5"
default n
select MTD
select MTD_W25QXXXJV
select MTD_SMART
select FS_SMARTFS
select STM32_SPI5
select MTD_BYTE_WRITE
---help---
Configures an MTD device for use with the onboard flash
config APOLLO_DISCO_FLASH_MINOR
int "Minor number for the FLASH /dev/smart entry"
default 0
depends on APOLLO_DISCO_FLASH
---help---
Sets the minor number for the FLASH MTD /dev entry
config APOLLO_DISCO_FLASH_PART
bool "Enable partition support on FLASH"
default n
depends on APOLLO_DISCO_FLASH
---help---
Enables creation of partitions on the FLASH
config APOLLO_DISCO_FLASH_CONFIG_PART
bool "Create application config data partition on FLASH"
default y
depends on APOLLO_DISCO_FLASH_PART
depends on PLATFORM_CONFIGDATA
---help---
Enables creation of a /dev/config partition on the FLASH
config APOLLO_DISCO_FLASH_CONFIG_PART_NUMBER
int "Index number of config partition (in list below)"
default 0
depends on APOLLO_DISCO_FLASH_CONFIG_PART
---help---
Specifies the index number of the config data partition
from the partition list.
config APOLLO_DISCO_FLASH_PART_LIST
string "Flash partition size list"
default "4,8188"
depends on APOLLO_DISCO_FLASH_PART
---help---
Comma separated list of partition sizes in KB.
config APOLLO_DISCO_FLASH_PART_NAMES
string "Flash partition name list"
default "config,rfs"
depends on APOLLO_DISCO_FLASH_PART
depends on MTD_PARTITION_NAMES
---help---
Comma separated list of partition names.
config APOLLO_DISCO_RAMMTD
bool "MTD driver for SMARTFS RAM disk"
default n
select MTD
select RAMMTD
---help---
Configures an MTD based RAM device for use with SMARTFS.
config APOLLO_DISCO_RAMMTD_MINOR
int "Minor number for RAM /dev/smart entry"
default 1
depends on APOLLO_DISCO_RAMMTD
---help---
Sets the minor number for the RAM MTD /dev entry
config APOLLO_DISCO_RAMMTD_SIZE
int "Size in KB of the RAM device to create"
default 32
depends on APOLLO_DISCO_RAMMTD
---help---
Sets the size of static RAM allocation for the SMART RAM device
config APOLLODISCO_USBHOST_STACKSIZE
int "USB host waiter stack size"
default 1024
depends on USBHOST
config APOLLODISCO_USBHOST_PRIO
int "USB host waiter task priority"
default 100
depends on USBHOST
config PM_BUTTONS
bool "PM Button support"
default n
depends on PM && ARCH_IRQBUTTONS
---help---
Enable PM button EXTI interrupts to support PM testing
config PM_BUTTON_ACTIVITY
int "Button PM activity weight"
default 10
depends on PM_BUTTONS
---help---
The activity weight to report to the power management subsystem when a button is pressed.
config PM_ALARM_SEC
int "PM_STANDBY delay (seconds)"
default 15
depends on PM && RTC_ALARM
---help---
Number of seconds to wait in PM_STANDBY before going to PM_STANDBY mode.
config PM_ALARM_NSEC
int "PM_STANDBY delay (nanoseconds)"
default 0
depends on PM && RTC_ALARM
---help---
Number of additional nanoseconds to wait in PM_STANDBY before going to PM_STANDBY mode.
config PM_SLEEP_WAKEUP
bool "PM_SLEEP wake-up alarm"
default n
depends on PM && RTC_ALARM
---help---
Wake-up of PM_SLEEP mode after a delay and resume normal operation.
config PM_SLEEP_WAKEUP_SEC
int "PM_SLEEP delay (seconds)"
default 10
depends on PM && RTC_ALARM
---help---
Number of seconds to wait in PM_SLEEP before going to PM_STANDBY mode.
config PM_SLEEP_WAKEUP_NSEC
int "PM_SLEEP delay (nanoseconds)"
default 0
depends on PM && RTC_ALARM
---help---
Number of additional nanoseconds to wait in PM_SLEEP before going to PM_STANDBY mode.
config APOLLO_DISCO_HIGHPRI
bool "High priority interrupt test"
default n
endif # ARCH_BOARD_APOLLO_DISCO
说明
- 参考《STM32F429开发指南 V1.1 – HAL库版本 −ALIENTEK阿波罗STM32F429开发板教程 》1.1.2 STM32F429核心板资源 和 第三十二章 SPI实验 可知,阿波罗开发板的上的
SPI FLASHW25Q256是直接连在STM32F429的SPI5上的,因此apollo-disco/Kconfig文件中的相关配置项描述需符合硬件配置。- 本阶段不考虑接入LCD屏,因此不包含相关配置项。
2、创建默认配置 (defconfig)
defconfig 文件是一个最小化的系统配置集合,为用户提供了一个开箱即用的配置起点。您应该为每个核心功能(如 NSH、特定示例)提供一个 defconfig。
参照nuttx/boards/arm/stm32/stm32f429i-disco/configs/nsh/deconfig,创建 nuttx/boards/arm/stm32/apollo-disco/configs/nsh/deconfig 如下:
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_ARCH_FPU is not set
# CONFIG_STM32_FLASH_PREFETCH is not set
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="apollo-disco"
CONFIG_ARCH_BOARD_APOLLO_DISCO=y
CONFIG_ARCH_BUTTONS=y
CONFIG_ARCH_CHIP="stm32"
CONFIG_ARCH_CHIP_STM32=y
CONFIG_ARCH_CHIP_STM32F429I=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_HEAP2_BASE=0xC0000000
CONFIG_HEAP2_SIZE=33554432
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_MM_REGIONS=3
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_LINELEN=64
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_SPI=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
CONFIG_STM32_EXTERNAL_RAM=y
CONFIG_STM32_FMC=y
CONFIG_STM32_JTAG_SW_ENABLE=y
CONFIG_STM32_PWR=y
CONFIG_STM32_USART1=y
CONFIG_SYSTEM_NSH=y
CONFIG_TASK_NAME_SIZE=0
CONFIG_USART1_SERIAL_CONSOLE=y
说明:
- 参考《STM32F429开发指南 V1.1 – HAL库版本 −ALIENTEK阿波罗STM32F429开发板教程 》1.1.2 STM32F429核心板资源 , 第十八章 SDRAM实验 和图17.1.2.2 FMC存储块地址映像 可知,阿波罗STM32F429开发板板载了一颗32M字节容量的SDRAM芯片:W9825G6KH,挂载于
SDRAM Bank1,因此有CONFIG_HEAP2_BASE=0xC0000000,CONFIG_HEAP2_SIZE=33554432(1024*1024*32)。
四、运行Demo
1、编译代码
在完成上面的步骤后,按以下流程为 阿波罗STM32F429 开发板生成所需二进制文件:
# 进入 openvela 根目录
# 编译
./build.sh apollo-disco:nsh -j8
编译完成后,生成的文件位于 nuttx 目录下,包括:
- nuttx.bin
- nuttx.hex
2、烧录固件
参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::5、烧录固件
3、连接串口
参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::6、连接串口
4、交互测试
重新打开 minicom,连接成功后,在 Minicom 终端中按回车,您会看到 nsh> 提示符。
输入一些常用命令(如ls,help)若反馈正常,则证明本文代码移植实验成功。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐





所有评论(0)