使用Platformio平台的libopencm3开发框架来开发STM32G0,下面为使用FreeRTOS系统。

1 新建项目

  • 在PIO主页新建项目,框架选择libopencm3,开发板选择 MonkeyPi_STM32_G070RB;
  • 新建完成后在src目录新建主程序文件main.c;
  • 然后更改项目文件platformio.ini的烧写和调试方式:
1
2
upload_protocol = cmsis-dap
debug_tool = cmsis-dap

2 添加FreeRTOS源码

  • 下载FreeRTOS源码

在freertos网站:https://www.freertos.org/a00104.html 下载好源码,这里下载最新版202112.00;

  • 添加源码到项目:

直接拷贝源码下的FreeRTOS文件夹到项目的lib目录中;

  • 添加到项目编译

在lib目录的FreeRTOS文件夹下新建 library.json 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "FreeRTOS",
"version": "202112.00",
"build": {
"flags": [
"-Isource",
"-Isource/include",
"-Isource/portable/GCC/ARM_CM0",
"-Isource/portable/RVDS/ARM_CM0"
],
"srcFilter": [
"+<source/*.c>",
"+<source/portable/GCC/ARM_CM0/*.c>",
"+<source/portable/MemMang/heap_4.c>"
]
}
}
  • 添加FreeRTOS配置

从FreeRTOS源码下的demo目录中拷贝一个FreeRTOSConfig.h文件到 lib/FreeRTOS/Source目录,并更改为如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* @file FreeRTOSConfig.h
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
*/

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* These parameters and more are described within the 'configuration' section of the
* FreeRTOS API documentation available on the FreeRTOS.org web site.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/

/* USER CODE BEGIN Includes */
/* Section where include file can be added */
/* USER CODE END Includes */

/* Ensure definitions are only used by the compiler, and not by the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
#endif
#define configENABLE_FPU 0
#define configENABLE_MPU 0

#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 64000000 )
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES ( 7 )
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
#define configTOTAL_HEAP_SIZE ((size_t)1024*16)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0

/*Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 5
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE

/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
/* Defaults to size_t for backward compatibility, but can be changed
if lengths will always be less than the number of bytes in a size_t. */
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1

/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
//void vAssertCalled(const char *file, int line);
//#define configASSERT( x ) if( x == 0 ) { taskDISABLE_INTERRUPTS(); vAssertCalled(__FILE__,__LINE__); for(;;); }
/* USER CODE END 1 */

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler sv_call_handler
#define xPortPendSVHandler pend_sv_handler

/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
to prevent overwriting SysTick_Handler defined within STM32Cube HAL */

#define xPortSysTickHandler sys_tick_handler

/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
/* USER CODE END Defines */

#endif /* FREERTOS_CONFIG_H */

上面配置需要根据自己的需要进行更改,如CPU频率,是否需要打开某项功能等;

  • 配置好后的目录结构如下:

3 FreeRTOS示例

  • 首先需要设置FreeRTOS需要的时钟
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @brief systick setup for rtos tick
*/
static void systick_setup(void)
{
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
systick_set_reload(64*1000);

systick_interrupt_enable();

/* Start counting. */
systick_counter_enable();
}

这样在FreeRTOSConfig.h 文件中定义的

1
#define xPortSysTickHandler sys_tick_handler

就可以通过systick中断提供FreeRTOS时钟;

  • LED任务函数
1
2
3
4
5
6
7
8
9
10
11
static void led1_task(void *args)
{
rcc_periph_clock_enable(RCC_GPIOC);
gpio_mode_setup(GPIOC,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO12);

while (1)
{
gpio_toggle(GPIOC,GPIO12);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
  • 主程序中创建任务并开启多任务调度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/systick.h>

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


int main(void)
{
//system clock
rcc_clock_setup(&rcc_clock_config[RCC_CLOCK_CONFIG_HSI_PLL_64MHZ]);

systick_setup();

xTaskCreate(led_task,"led task", 256, NULL,2,NULL);

vTaskStartScheduler();

while(1){}

return 0;
}

通过xTaskCreate创建多任务函数,然后使用 vTaskStartScheduler 开始调度;

注:如果VSCode中提示 FreeRTOS.h 头文件include path问题,可以将项目文件夹关闭,再重新打开即可;如果是在Clion中,可以在添加lib文件夹后,右键platformio.ini文件选择re init即可;

4 烧写测试

点击 PlatformIO:Upload按钮或Ctrl+Alt+U快捷键可以直接编译烧写到目标板,看到LED按预定的程序闪烁运行;