IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> PlatformIO 创建 libopencm3 + FreeRTOS 项目 -> 正文阅读

[嵌入式]PlatformIO 创建 libopencm3 + FreeRTOS 项目

PlatformIO: libopencm3 + FreeRTOS

以下步骤基于常见的 Bluepill STM32F103C8T6, 也适用于其它 libopencm3 支持的MCU型号

方案一: 只复制需要的文件

  1. 在 PlatformIO 中, Board 选择 Bluepill F103C8, Framework 选择 libopencm3, 创建项目
  2. 在项目的lib下新建目录 FreeRTOS
  3. 解压缩最新的 FreeRTOS
    1. 复制 FreeRTOS/Source/ 目录下, 除 portable 目录以外其它全部文件和目录, 至 lib/FreeRTOS 下
    2. 复制 FreeRTOS/Source/portable/GCC/ARM_CM3 目录下所有文件(port.c, portmacro.h), 至 lib/FreeRTOS 下
    3. 复制 FreeRTOS/Source/portable/Common 目录下所有文件(mpu_wrappers.c), 至 lib/FreeRTOS 下
    4. 复制 FreeRTOS/Source/portable/MemMang 目录下 heap_4.c, 至 lib/FreeRTOS 下
  4. 复制 FreeRTOSConfig.h, 至 lib/FreeRTOS/include 下
  5. 编写 src/main.c

完成后目录结构应当为

├── include
│   └── README
├── lib
│   ├── FreeRTOS
│   │   ├── croutine.c
│   │   ├── event_groups.c
│   │   ├── heap_4.c
│   │   ├── include
│   │   │   ├── atomic.h
│   │   │   ├── croutine.h
│   │   │   ├── deprecated_definitions.h
│   │   │   ├── event_groups.h
│   │   │   ├── FreeRTOSConfig.h
│   │   │   ├── FreeRTOS.h
│   │   │   ├── list.h
│   │   │   ├── message_buffer.h
│   │   │   ├── mpu_prototypes.h
│   │   │   ├── mpu_wrappers.h
│   │   │   ├── portable.h
│   │   │   ├── projdefs.h
│   │   │   ├── queue.h
│   │   │   ├── semphr.h
│   │   │   ├── stack_macros.h
│   │   │   ├── StackMacros.h
│   │   │   ├── stdint.readme
│   │   │   ├── stream_buffer.h
│   │   │   ├── task.h
│   │   │   └── timers.h
│   │   ├── list.c
│   │   ├── mpu_wrappers.c
│   │   ├── port.c
│   │   ├── portmacro.h
│   │   ├── queue.c
│   │   ├── stream_buffer.c
│   │   ├── tasks.c
│   │   └── timers.c
│   └── README
├── platformio.ini
├── README.md
├── src
│   └── main.c
└── test
    └── README

方案二: 完整的FreeRTOS, 使用library.json

  1. 在 PlatformIO 中, Board 选择 Bluepill F103C8, Framework 选择 libopencm3, 创建项目
  2. 在项目的lib下新建目录 FreeRTOS
  3. 解压缩最新的 FreeRTOS
  4. 复制 FreeRTOS/Source/ 目录下所有文件至 lib/FreeRTOS 下
  5. 复制 FreeRTOS/Source/portable/GCC/ARM_CM3 目录下 portmacro.h 至 lib/FreeRTOS 下, 因为 library.json 还不支持多个 include 路径
  6. 复制 FreeRTOSConfig.h, 至 lib/FreeRTOS 下
  7. lib/FreeRTOS 下添加 library.json
  8. 编写 src/main.c

library.json 内容如下, 只包含需要的 c 文件

{
    "name": "FreeRTOS",
    "version": "10.4.6",
    "build": {
        "srcFilter": [
            "+<*.c>",
            "+<portable/GCC/ARM_CM3/port.c>",
            "+<portable/MemMang/heap_4.c>"
        ]
    }
}

如果是多核MCU, 需要再包含 mpu_wrappers.c, 对于 F103C8 就不需要了

"+<portable/Common/mpu_wrappers.c>",

完成后目录结构为

├── include
│   └── README
├── lib
│   ├── FreeRTOS
│   │   ├── croutine.c
│   │   ├── event_groups.c
│   │   ├── FreeRTOSConfig.h
│   │   ├── include
│   │   ├── library.json
│   │   ├── list.c
│   │   ├── miniprintf.c
│   │   ├── miniprintf.h
│   │   ├── portable
│   │   ├── portmacro.h
│   │   ├── queue.c
│   │   ├── stream_buffer.c
│   │   ├── tasks.c
│   │   └── timers.c
│   └── README
├── platformio.ini
├── README.md
├── src
│   └── main.c
└── test
    └── README

FreeRTOSConfig.h 函数名适配

在 libopencm3/lib/cm3/vector.c 中, 定义了 .sv_call,.pend_sv and .systick 的处理函数,

/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
	.memory_manage_fault = mem_manage_handler,
	.bus_fault = bus_fault_handler,
	.usage_fault = usage_fault_handler,
	.debug_monitor = debug_monitor_handler,
#endif

	.sv_call = sv_call_handler,
	.pend_sv = pend_sv_handler,
	.systick = sys_tick_handler,
	.irq = {
		IRQ_HANDLERS
	}
};

这些函数名与 FreeRTOS 中的函数名不一致, 需要将其关联. 使用宏替换的方式比使用函数转发方式效率更高, 所以在 FreeRTOSConfig.h 中需要增加如下定义, 否则 FreeRTOS 不能正常工作

/**
 * In libopencm3/lib/cm3/vector.c, these 3 handlers(right side) are for .sv_call,.pend_sv and .systick
 * These macro will rename the methods in port.c to make it work, more efficient than wrapped by method
*/
#define vPortSVCHandler sv_call_handler
#define xPortPendSVHandler pend_sv_handler
#define xPortSysTickHandler sys_tick_handler

示例代码

使用Queue的UART收发

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h>

#define mainECHO_TASK_PRIORITY                ( tskIDLE_PRIORITY + 1 )

static QueueHandle_t uart_txq;                // TX queue for UART

/*
 * Handler in case our application overflows the stack
 */
void vApplicationStackOverflowHook(
    TaskHandle_t xTask __attribute__((unused)),
    char *pcTaskName __attribute__((unused))) {

    for (;;);
}

void usart1_isr(void) {
    uint8_t data;
    /* Check if we were called because of RXNE. */
    if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) &&
        ((USART_SR(USART1) & USART_SR_RXNE) != 0)) {
        /* Retrieve the data from the peripheral. */
        data = usart_recv(USART1);
        xQueueSendFromISR(uart_txq, &data, NULL);
    }
}

static void gpio_setup(void) {
    // GPIO PB12,PC13:
    rcc_periph_clock_enable(RCC_GPIOB);
    rcc_periph_clock_enable(RCC_GPIOC);
    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
    gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
    // Turn LED off
    gpio_set(GPIOB, GPIO12);
    gpio_set(GPIOC, GPIO13);

    rcc_periph_clock_enable(RCC_GPIOA);
    gpio_set_mode(GPIOA,GPIO_MODE_OUTPUT_50_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,GPIO_USART1_TX);
    gpio_set_mode(GPIOA,GPIO_MODE_OUTPUT_50_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,GPIO11);

    gpio_set_mode(GPIOA,GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT,GPIO_USART1_RX);
    gpio_set_mode(GPIOA,GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT,GPIO12);
}

/*********************************************************************
 * Configure and initialize USART1:
 *********************************************************************/
static void
uart_setup(void) {

    rcc_periph_clock_enable(RCC_USART1);

    usart_set_baudrate(USART1,115200);
    usart_set_databits(USART1,8);
    usart_set_stopbits(USART1,USART_STOPBITS_1);
    usart_set_mode(USART1,USART_MODE_TX_RX);
    usart_set_parity(USART1,USART_PARITY_NONE);
    usart_set_flow_control(USART1,USART_FLOWCONTROL_NONE);
    usart_enable(USART1);

    nvic_enable_irq(NVIC_USART1_IRQ);
    usart_enable_rx_interrupt(USART1);

    // Create a queue for data to transmit from UART
    uart_txq = xQueueCreate(256,sizeof(char));
}

static void uart_puts(const char *s) {
    for ( ; *s; ++s ) {
        // blocks when queue is full
        xQueueSend(uart_txq,s,portMAX_DELAY); 
    }
}

/*********************************************************************
 * USART Task: 
 *********************************************************************/
static void uart_task(void *args __attribute__((unused))) {
    char ch;

    for (;;) {
        // Receive char to be TX
        if ( xQueueReceive(uart_txq,&ch,500) == pdPASS ) {
            // if not tx data buffer empty
            while ( !usart_get_flag(USART1,USART_SR_TXE) )
                taskYIELD();    // Yield until ready
            usart_send(USART1,ch);
        }
        // Toggle LED to show signs of life
        gpio_toggle(GPIOB,GPIO12);
        gpio_toggle(GPIOC,GPIO13);
    }
}

/*********************************************************************
 * Demo Task:
 *    Simply queues up two line messages to be TX, one second
 *    apart.
 *********************************************************************/
static void demo_task(void *args __attribute__((unused))) {

    for (;;) {
        uart_puts("Now this is a message..\n\r");
        uart_puts(" sent via FreeRTOS queues.\n\n\r");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

/*********************************************************************
 * Main program & scheduler:
 *********************************************************************/
int main(void) {

    rcc_clock_setup_in_hse_8mhz_out_72mhz();    // CPU clock is 72 MHz

    gpio_setup();
    uart_setup();

    xTaskCreate(uart_task,"UART",100,NULL,configMAX_PRIORITIES-1,NULL);
    xTaskCreate(demo_task,"DEMO",100,NULL,configMAX_PRIORITIES-2,NULL);

    vTaskStartScheduler();
    for (;;);
    return 0;
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:20:17  更:2022-02-14 21:20:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:36:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码