手把手教你学BSP(一)--BSP概念

目录

1. 硬件初始化代码

主要任务:

示例代码(ARM Cortex-M3为例):

2. 设备驱动程序

主要任务:

示例代码(Linux驱动程序):

3. 硬件抽象层(HAL)

主要作用:

示例代码(STM32 HAL库):

4. 启动加载程序(Bootloader)

主要功能:

示例代码(U-Boot):

总结


下面将详细介绍BSP(Board Support Package)中的四个关键组成部分:硬件初始化代码、设备驱动程序、硬件抽象层(HAL)和启动加载程序(Bootloader)。

1. 硬件初始化代码

硬件初始化代码是BSP中最基础的部分之一,它负责在操作系统加载之前初始化硬件设备,确保它们处于可用状态。这些代码通常会包含以下几个方面的内容:

主要任务:
  • 处理器初始化:设置CPU寄存器,配置处理器的工作模式(如ARM架构中的ARM或Thumb模式)。
  • 内存初始化:配置内存控制器,设置内存映射,分配内存区域。
  • 时钟初始化:配置系统时钟,确保各外设能够正常工作。
  • 中断控制器初始化:配置中断控制器(如ARM Cortex-M中的NVIC),设置中断优先级和向量表。
  • 外设初始化:初始化I/O端口、定时器、ADC、DAC、SPI、I2C、UART等外设。
  • 电源管理初始化:配置电源管理模块,如设置休眠模式下的电源策略。
示例代码(ARM Cortex-M3为例):
 

c

深色版本

void SystemInit(void) {
    // 设置系统时钟
    RCC->CR |= RCC_CR_HSEON;         // 开启外部高速时钟
    while ((RCC->CR & RCC_CR_HSERDY) == 0) {} // 等待HSE稳定
    RCC->CFGR &= ~RCC_CFGR_SW_Msk;   // 设置系统时钟源为HSE
    RCC->CFGR |= RCC_CFGR_SWS_1;     // 设置系统时钟源为HSE
    RCC->CFGR &= ~RCC_CFGR_PLLON_Msk; // 关闭PLL
    RCC->CFGR |= RCC_CFGR_PLLON;     // 开启PLL
    while ((RCC->CFGR & RCC_CFGR_PLLRDY) == 0) {} // 等待PLL稳定
    RCC->CFGR &= ~RCC_CFGR_SW_Msk;   // 设置系统时钟源为PLL
    RCC->CFGR |= RCC_CFGR_SW_PLL;    // 设置系统时钟源为PLL

    // 配置AHB/APB1/APB2时钟
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // AHB频率为系统频率
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; // APB1频率为系统频率的一半
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; // APB2频率为系统频率的一半

    // 使能GPIO时钟
    RCC->APB2ENR |= RCC_APB2ENR_GPIOAEN | RCC_APB2ENR_GPIOBEN;

    // GPIO初始化
    GPIOA->MODER = (1 << GPIO_MODER_MODER0_Pos); // 设置PA0为输出模式
}

void NVIC_Init(void) {
    // 设置中断优先级
    NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); // 2位预取,2位子优先级
    NVIC_SetPriority(NMI_IRQn, 0x00);               // 设置NMI中断优先级为0
    NVIC_SetPriority(HardFault_IRQn, 0x01);         // 设置HardFault中断优先级为1
    NVIC_SetPriority(Default_IRQ, 0x0F);             // 设置默认中断优先级为15
}

2. 设备驱动程序

设备驱动程序是操作系统与硬件设备之间的重要桥梁,它们为操作系统提供了一种与硬件设备进行交互的方式。设备驱动程序通常需要完成以下几项任务:

主要任务:
  • 硬件初始化:在设备首次使用前对其进行初始化。
  • 设备控制:提供一组API函数,用于控制硬件设备的状态和行为。
  • 数据传输:实现数据的读写操作,如读取传感器数据、发送指令给执行器等。
  • 错误处理:检测并处理硬件故障或异常情况。
示例代码(Linux驱动程序):
 

c

深色版本

static int my_device_open(struct inode *inode, struct file *file) {
    /* 设备打开时的处理 */
    return 0;
}

static int my_device_release(struct inode *inode, struct file *file) {
    /* 设备关闭时的处理 */
    return 0;
}

static ssize_t my_device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
    /* 读取数据 */
    return count;
}

static ssize_t my_device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
    /* 写入数据 */
    return count;
}

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_device_open,
    .release = my_device_release,
    .read = my_device_read,
    .write = my_device_write,
};

static int __init my_driver_init(void) {
    /* 注册设备驱动 */
    register_chrdev(DEVICE_NR, DEVICE_NAME, &my_fops);
    return 0;
}

static void __exit my_driver_exit(void) {
    /* 卸载设备驱动 */
    unregister_chrdev(DEVICE_NR, DEVICE_NAME);
}

module_init(my_driver_init);
module_exit(my_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver");

3. 硬件抽象层(HAL)

硬件抽象层(HAL)是一个软件层,它为操作系统提供了统一的硬件访问接口,从而屏蔽了不同硬件平台之间的差异。HAL的主要作用如下:

主要作用:
  • 硬件独立性:允许操作系统在不同的硬件平台上运行而无需修改代码。
  • 简化开发:提供一致的API,使得开发人员可以专注于应用逻辑而非底层硬件细节。
  • 易维护性:当更换硬件平台时,只需修改HAL层即可,无需改动操作系统核心代码。
示例代码(STM32 HAL库):
 

c

深色版本

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Initializes the CPU, AHB and APB busses clocks 
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB busses clocks 
     */
    RCC_ClkInitStruct.ClockOutput = RCC_CLOCKOUTPUT_NONE;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}

4. 启动加载程序(Bootloader)

启动加载程序(Bootloader)是系统启动时最先运行的程序之一,它的主要职责是引导操作系统启动。Bootloader通常具有以下功能:

主要功能:
  • 硬件初始化:初始化硬件设备,如内存、时钟等。
  • 加载内核:将操作系统内核从存储介质(如闪存)加载到内存中。
  • 启动内核:跳转到内核的入口点,开始执行内核代码。
  • 故障恢复:提供一定的故障恢复机制,如检测并修复启动错误。
示例代码(U-Boot):
 

c

深色版本

int board_init_f(int flag)
{
    /* Initialize common hardware */

    /* Enable clocks */
    enable_clocks();

    /* Setup GPIO pins */
    setup_gpio();

    /* Setup memory controller */
    setup_memory_controller();

    /* Setup UART */
    setup_uart();

    /* Setup NAND flash */
    setup_nand_flash();

    return 0;
}

int do_bootm(cmd_table_t *cmdtp, int flag, int argc, char *argv[])
{
    ulong loadaddr, entrypoint;
    int ret;

    /* Load kernel image */
    loadaddr = load_kernel_image();

    /* Set entry point */
    entrypoint = get_entry_point(loadaddr);

    /* Jump to kernel */
    ret = jump_to_kernel(entrypoint);

    return ret;
}

总结

通过上述介绍,你已经了解了BSP中硬件初始化代码、设备驱动程序、硬件抽象层(HAL)和启动加载程序(Bootloader)的基本概念和实现方法。每部分都是BSP不可或缺的一部分,它们共同作用以确保嵌入式系统的正常启动和运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值