由于CLion出色的代码提示和现代化的工具界面,就想着在CLion下开发stm32-RTT的开发
> 环境:
>
> 1. 工具链:arm-none-eabi-gcc
> 2. IDE: CLion
> 3. 生成工具: stm32cubemx cmake
> 4. 开发板: 野火指南者
> 5. 下载工具: openocd
- 新建工程
在新建完成后,点击 open with stm32cubemx
- 选择stm32f103VETx
- 参数配置
RCC时钟选择外部晶振
由于野火使用的是CMISI-DAP,所以选择Debug 选择 Serial Wire
serial
如果不选择的话,可能会导致无法再次烧写.需要进行一次重置
LED灯配置
选择Pin口,置为GPIO_Output
配置时钟
串口配置,选择USART1作为Debug口,选择异步实现
- RTT第三方组件加入
点击Additional Software
选择RTT并配置参数
由于RTT重写了HardFault_Handler 、 PendSV_Handler 、 SysTick_Handler 中断,所以需要取消生成三个中断
- 其他配置
将每个外设作为独立的文件输出
选择SW4STM32 IDE
stm32cube配置结束
回到CLion,CLion会自动为项目生成CmakeFile,之后会弹出一个串口选择openocd的配置参数.这里先退出选择.在后面会给出详细的参数配置
- 初始化
在boart.c中的
rt_hw_board_init
中进行初始化,将main函数的中初始化函数移入到rt_hw_board_init
中
/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
HAL_Init(); // from main
SystemClock_Config();// from main
SystemCoreClockUpdate();
/* System Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
}
由于RTT中不是从main函数开始执行的,若想要初始化RTT,需要修改文件 startup_stm32f103xe.s
中 bl main
,将其修改为 bl entry
或者添加编译参数-eentry指定c入口函数
原因如下:
在RTT中的 components.c
中,有这样一段代码
#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
#elif defined(__ICCARM__)
extern int main(void);
/* __low_level_init will auto called by IAR cstartup */
extern void __iar_data_init3(void);
int __low_level_init(void)
{
// call IAR table copy function.
__iar_data_init3();
rtthread_startup();
return 0;
}
#elif defined(__GNUC__)
extern int main(void);
/* Add -eentry to arm-none-eabi-gcc argument */
int entry(void)
{
rtthread_startup();
return 0;
}
#endif
在上面这段中,使用了编译器宏进行条件编译,由于我使用的是 arm-none-eabi-gcc
,内置宏为GNUC,执行的就是最后一段代码,entry中调用了rtthread_startup()函数,在此函数中指定了初始化,初始化完成后创建一个main线程执行main函数,entry线程中自然死亡.
- finsh移植
在rtconfig.h中打开宏
#define RT_USING_FINSH
定义void rt_hw_console_output(const char *str)
和char rt_hw_console_getchar(void)
函数
void rt_hw_console_output(const char *str) {
rt_size_t i = 0, size = 0;
char a = '\r';
__HAL_UNLOCK(&huart1);
size = rt_strlen(str);
for (i = 0; i < size; i++) {
if (*(str + i) == '\n') {
HAL_UART_Transmit(&huart1, (uint8_t *)&a, 1, 1);
}
HAL_UART_Transmit(&huart1, (uint8_t *)(str + i), 1, 1);
}
}
char rt_hw_console_getchar(void) {
int ch = -1;
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET) {
ch = huart1.Instance->DR & 0xff;
} else {
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) != RESET) {
__HAL_UART_CLEAR_OREFLAG(&huart1);
}
rt_thread_mdelay(10);
}
return ch;
}
在rtthread_startup中初始化finsh->调用finsh_system_init.注:初始化需要放在 rt_system_scheduler_start();
函数后面,否则会有异常.
在finsh_system_init中有
extern const int __fsymtab_start;
extern const int __fsymtab_end;
extern const int __vsymtab_start;
extern const int __vsymtab_end;
此时编译会出现未定义的错误
所以需要在STM32F103VETx_FLASH.ld文件定义字段
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
/* section information for initial. */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
最后异步,在main函数主循环中,使用 rt_thread_mdelay(1000);
函数,让出CPU控制器,否则while循环会一直持有cpu控制权,其他线程堵塞.
- 下载验证
下载调试程序使用openocd,openocd需要使用配置文件进行下载.以下是我的配置文件
adapter driver cmsis-dap
transport select swd
source [find target/stm32f1x.cfg]
最后的最后,成果图:
项目工程路径→ RTT_CLion