记录代码移植过程,成功一步记录一步
第一步:建立裸机程序
使用STM32CubeMx建立一个裸机程序
生成MDK5工程
第二步:参考0-bare-metal完成board.c、board.h文件
在Drivers组下添加board.c、board.h文件
添加board.c文件实现board.c里面关于关于时钟配置、串口初始化、GPIO初始化等函数
void bsp_uart_init(void)
{
MX_USART1_UART_Init();
}
void bsp_uart_send(char c)
{
while ((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET));
huart1.Instance->DR = c;
}
void bsp_led_init(void)
{
MX_GPIO_Init();
}
void bsp_led_on(void)
{
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin, GPIO_PIN_RESET);
}
void bsp_led_off(void)
{
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin, GPIO_PIN_SET);
}
void rt_hw_board_init()
{
/* HAL_Init() function is called at the beginning of program after reset and before * the clock configuration. */
HAL_Init();
/* Clock Config:
* System Clock : 80M
* HCLK : 80M
* PCLK1 : 80M
* PCLK2 : 80M
* SDMMC1 : 48M
* USART1 : PCLK2 */
SystemClock_Config();
bsp_led_init();
bsp_uart_init();
}
void SystemClock_Config(void)
void _Error_Handler(char *file, int line)
以上两个函数采用cubemx工具生成的函数,main函数和例程中一样
现象:
第三步:添加RT-Thread源码
拷贝RT-Thread源代码到工程路径下,当然也可以不移动,就是指定路径的时候长一点,没关系
添加两个新组一个叫做kernel,防止内核代码,另一个叫做CROTEX-M3放置平台相关代码,我用的是STM32F103ZET6使用的是crotex-m3内核。
添加相关文件到对应的组下面,添加完如图,对了还有一个rtconfig.h文件,用于配置和裁剪内核。
添加代码之后别忘了添加头文件,rtconfig.h文件放在了工程的根目录之下,别忘了添加头文件。
在编译之后有了有符号重定义,注释掉原有的函数
在编译之后有了有符号重定义,注释掉原有的函数
//void HardFault_Handler(void)
//{
// /* USER CODE BEGIN HardFault_IRQn 0 */
// /* USER CODE END HardFault_IRQn 0 */
// while (1)
// {
// /* USER CODE BEGIN W1_HardFault_IRQn 0 */
// /* USER CODE END W1_HardFault_IRQn 0 */
// }
// /* USER CODE BEGIN HardFault_IRQn 1 */
// /* USER CODE END HardFault_IRQn 1 */ //}
//void PendSV_Handler(void)
//{
// /* USER CODE BEGIN PendSV_IRQn 0 */
// /* USER CODE END PendSV_IRQn 0 */
// /* USER CODE BEGIN PendSV_IRQn 1 */
// /* USER CODE END PendSV_IRQn 1 */
//}
编译下载正常运行
第四步:console移植,实现控制台输出功能
实现函数
void rt_hw_console_output(const char *str)
{
RT_ASSERT(str != RT_NULL);
while (*str != '\0')
{
if (*str == '\n')
{
bsp_uart_send('\r');
}
bsp_uart_send(*str++);
}
}
这个函数主要是实现bsp_usart_send,此函数在第二步已经实现。
接下来修改SysTick_Handler函数
/** * @brief This function handles System tick timer. */
void SysTick_Handler(void)
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
注意包含rtthread.h头文件
修改main函数如下
int main(void)
{
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
rt_kprintf("led on\n");
rt_thread_delay(RT_TICK_PER_SECOND);
rt_kprintf("led off\n");
rt_thread_delay(RT_TICK_PER_SECOND);
}
/* USER CODE END 3 */
}
编译下载输出如图
第五步:内存堆配置,实现动态内存管理功能
在rt_config.h中添加宏
//#define RT_USING_NOHEAP
#define RT_USING_SMALL_MEM
#define RT_USING_HEAP
注意:注释掉RT_USING_NOHEAP,如果有的话
在rt_hw_board_init函数中添加动态内存管理初始化函数
void rt_hw_board_init()
{
static uint8_t heap_buf[10 * 1024];
……….
rt_system_heap_init(heap_buf, heap_buf + sizeof(heap_buf) - 1);
}
在main函数中初始化一个线程函数
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
void test_thread_entry(void *parameter)
{
while (1)
{
rt_kprintf("enter test thread\n");
rt_thread_delay(RT_TICK_PER_SECOND);
}
}
/** * @brief The application entry point. * * @retval None */
int main(void)
{
rt_thread_t tid;
tid = rt_thread_create("test",
test_thread_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
return 0;
}
else
{
return -1;
}
}
编译下载,输出如图
第六步:实现Finsh Shell功能
将components组件文件夹下的drivers和finsh文件添加到工程
新建finsh组和DeviceDrivers组,添加文件
在前几步添加文件的时候在Kernel组莫名少添加了device.c文件在调试的时候浪费很长时间,
在官方的1-basic的rt-thread\src文件下也没有,感受到来自NPC的调戏。
添加代码之后先修改board.c文件里的rt_hw_board_init函数,
/** * This function will initial STM32 board. */
void rt_hw_board_init()
{
static uint8_t heap_buf[10 * 1024];
/* HAL_Init() function is called at the beginning of program after reset and before * the clock configuration. */
HAL_Init();
/* Clock Config:
* System Clock : 80M
* HCLK : 80M
* PCLK1 : 80M
* PCLK2 : 80M
* SDMMC1 : 48M
* USART1 : PCLK2
*/
SystemClock_Config();
/* Configure the Systick interrupt time */
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND);
/* Configure the Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
//bsp_led_init();
stm32_hw_usart_init();
#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif #ifdef RT_USING_HEAP
rt_system_heap_init(heap_buf, heap_buf + sizeof(heap_buf) - 1);
#endif
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
stm32_hw_usart_init();
用来初始化并注册串口
屏蔽掉board.c文件里面串口初始化函数、串口发送函数、控制台输出函数,工作交给drv_usart.c。
接下来修改rtconfig.h中的宏定义
添加#define BSP_USING_UART1等
添加后rtconfig.h如下
#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__
/* Automatically generated file; DO NOT EDIT. */
/* RT-Thread Configuration */
/* RT-Thread Kernel */
#define RT_NAME_MAX 8
#define RT_ALIGN_SIZE 4
#define RT_THREAD_PRIORITY_32
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND 1000
#define RT_USING_OVERFLOW_CHECK
#define RT_USING_HOOK
#define RT_IDEL_HOOK_LIST_SIZE 4
#define IDLE_THREAD_STACK_SIZE 256
#define RT_DEBUG
/* Inter-Thread communication */
#define RT_USING_SEMAPHORE
#define RT_USING_MUTEX
#define RT_USING_EVENT
#define RT_USING_MAILBOX
#define RT_USING_MESSAGEQUEUE
/* Memory Management */
//#define RT_USING_NOHEAP
#define RT_USING_SMALL_MEM
#define RT_USING_HEAP
/* Kernel Device Object */
#define RT_USING_DEVICE
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 128
#define RT_CONSOLE_DEVICE_NAME "uart1"
/* RT-Thread Components */
#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 2048
#define RT_MAIN_THREAD_PRIORITY 10
/* C++ features */
/* Command shell */
#define RT_USING_FINSH
#define FINSH_THREAD_NAME "tshell"
#define FINSH_USING_HISTORY
#define FINSH_HISTORY_LINES 5
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION
#define FINSH_THREAD_PRIORITY 20
#define FINSH_THREAD_STACK_SIZE 4096
#define FINSH_CMD_SIZE 80
#define FINSH_USING_MSH
#define FINSH_USING_MSH_DEFAULT
#define FINSH_ARG_MAX 10
/* Device virtual file system */
/* Device Drivers */
#define RT_USING_DEVICE_IPC
#define RT_PIPE_BUFSZ 512
#define RT_USING_SERIAL
/* Env config */
#define SYS_PKGS_DOWNLOAD_ACCELERATE
#define BSP_USING_UART1
#endif
之前mian函数中的初始化函数去掉
编译下载如图
出了问题,finsh没有跑起来,没有msh>,重启、没有、重启、还没有
调试了很久还是不行,之后经大神指点在rtdef.h文件如图位置添加了RT_USED
编译下载,还是没有,不过这次是因为串口接收引脚模式配置错误,修改之后编译下载运行,
成功运行,但是为什么要加RT_USED,还是不知道。
以上
对了,这种移植模式值得吐槽,希望以后官方可以更加人性化一点
这里可以下载移植好的程序
https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=7794&page=1&extra=#pid37101