stm32H750移植最新的RT-Thread
硬件是正点原子的stm32H750北极星开发板,RT-Thread版本是H750目前最新的4.1.1版本(从RT studio找的,目前RT-Thread版本git上面已经5.0.1了),IDE和编译器使用的是keil和MDK523带的ARMCC编译器
因为烧写好像要涉及算法的问题,并且hal驱动的例程也用的keil开发,所以没有用其他IDE,这样烧写也方便。
keil自带的RT-Thread扩展的版本是3.1.5,比较过时,所以进行移植,移植5.0.1版本也是可行的,替换对应文件即可。
一、代码准备
-
正点原子的stm32H750北极星开发板的跑马灯例程
-
我用RT studio添加的stm32h750-artpi例程
二、移植HAL和CMSIS
把代码进行拷贝,并且把不用的代码进行删除。
正点原子给的HAL库版本也比较老,是1.3.0的。而stm32h750-artpi例程是1.7.0的,果断用新的,先替换HAL库
其实就是把之前的C文件和h文件替换掉,没有难度,除了HAL库,CMSIS我也按照最新的替换掉了
所以跑马灯工程下的USER目录只留main.c即可,其他并不需要。
三、移植内核
RT-Thread_latest\RTOS\
│ rtconfig.h
│
├─libcpu
│ backtrace.c
│ context_rvds.S
│ cpuport.c
│ cpu_cache.c
│ div0.c
│ showmem.c
│
└─source
clock.c
components.c
cpu.c
device.c
idle.c
ipc.c
irq.c
kservice.c
mem.c
mempool.c
object.c
rtdbg.h
rtdebug.h
rtdef.h
rthw.h
rtm.h
rtservice.h
rtthread.h
scheduler.c
signal.c
thread.c
timer.c
目录怎么放都可以,添加对的编译和头文件目录就可以。因为这里用的ARMCC编译器,所以复制过来context_rvds.S
,gcc编译器的话就复制context_gcc.S
四、驱动的移植
不想光秃秃的用内核。也是需要一些driver的。按照stm32h750-artpi使用的driver进行移植,其实重要的我只想用clk、gpio、usart。所以只复制过来这么多。
DRIVER\
│ board.c
│ board.h
│ drv_clk.c
│ drv_common.c
│ drv_gpio.c
│ drv_hwtimer.c
│ drv_qspi.c
│ drv_soft_i2c.c
│ drv_usart.c
│ stm32h7xx_hal_conf.h
│
└─include
│ drv_common.h
│ drv_config.h
│ drv_dma.h
│ drv_eth.h
│ drv_flash.h
│ drv_log.h
│ drv_qspi.h
│ drv_sdio.h
│ drv_soft_i2c.h
│ drv_spi.h
│ drv_usbh.h
│
└─config
adc_config.h
dma_config.h
pwm_config.h
qspi_config.h
sdio_config.h
spi_config.h
tim_config.h
uart_config.h
usbd_config.h
五、component的移植
内核外需要一些component来运行,包括更高一级的driver比如pin、serial。还有比较重要的finsh交互式控制台,很好用。
那么把代码复制过来,别忘记把libc也移植过来,components可能要用到。
COMPONENTS\
├─drivers
│ ├─include
│ │ │ rtdevice.h
│ │ │
│ │ ├─drivers
│ │ │ adc.h
│ │ │ 。。。这里头文件太多了,不一一列举占用篇幅。
│ │ │
│ │ └─ipc
│ │ completion.h
│ │ dataqueue.h
│ │ pipe.h
│ │ poll.h
│ │ ringblk_buf.h
│ │ ringbuffer.h
│ │ waitqueue.h
│ │ workqueue.h
│ │
│ ├─ipc
│ │ completion.c
│ │ dataqueue.c
│ │ pipe.c
│ │ ringblk_buf.c
│ │ ringbuffer.c
│ │ SConscript
│ │ waitqueue.c
│ │ workqueue.c
│ │
│ ├─misc
│ │ pin.c
│ │
│ └─serial
│ SConscript
│ serial.c
│
├─finsh
│ cmd.c
│ finsh.h
│ Kconfig
│ msh.c
│ msh.h
│ msh_parse.c
│ msh_parse.h
│ SConscript
│ shell.c
│ shell.h
│
└─libc
└─compilers
├─common
│ │ cctype.c
│ │ cstdio.c
│ │ cstdlib.c
│ │ cstring.c
│ │ ctime.c
│ │ cwchar.c
│ │ readme.md
│ │ SConscript
│ │
│ ├─extension
│ │ │ readme.md
│ │ │ SConscript
│ │ │
│ │ ├─fcntl
│ │ │ │ README.md
│ │ │ │ SConscript
│ │ │ │
│ │ │ ├─msvc
│ │ │ │ fcntl.h
│ │ │ │ SConscript
│ │ │ │
│ │ │ └─octal
│ │ │ fcntl.h
│ │ │ SConscript
│ │ │
│ │ └─sys
│ │ errno.h
│ │ stat.h
│ │ types.h
│ │
│ └─include
│ │ compiler_private.h
│ │ dirent.h
│ │ unistd.h
│ │
│ ├─posix
│ │ ctype.h
│ │ stdio.h
│ │ stdlib.h
│ │ string.h
│ │ wchar.h
│ │
│ └─sys
│ ioctl.h
│ select.h
│ signal.h
│ statfs.h
│ time.h
│ unistd.h
│ vfs.h
│
└─newlib
│ fcntl.h
│ README.md
│ SConscript
│ syscalls.c
│
└─machine
time.h
六、代码的修改
当然前面只是移植的工作。目前完成一半,剩下就是代码的修改。
之说修改点吧
①板子初始化修改
hw_board_init
函数进行板子的初始化,跑马灯实验中有对cache的workaround,把它复制过来
/**
* This function will initial STM32 board.
*/
void hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq)
{
extern void rt_hw_systick_init(void);
extern void clk_init(char *clk_source, int source_freq, int target_freq);
#ifdef SCB_EnableICache
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
#endif
#ifdef SCB_EnableDCache
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
#endif
SCB->CACR|=1<<2; //1997AURORA 强制D-Cache透写,从正点原子跑马灯复制过来的
/* HAL_Init() function is called at the beginning of the program */
HAL_Init();
/* enable interrupt */
__set_PRIMASK(0);
/* System clock initialization */
clk_init(clock_src, clock_src_freq, clock_target_freq);
/* disbale interrupt */
__set_PRIMASK(1);
rt_hw_systick_init();
/* Pin driver initialization is open by default */
#ifdef RT_USING_PIN
extern int rt_hw_pin_init(void);
rt_hw_pin_init();
#endif
/* USART driver initialization is open by default */
#ifdef RT_USING_SERIAL
extern int rt_hw_usart_init(void);
rt_hw_usart_init();
#endif
}
还有就是clock的变动,因为stm32h750-artpi使用的时钟是内部时钟,要改成外部时钟,并且频率配成400Mhz:
void system_clock_config(int target_freq_mhz)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
// RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
// RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* 1997AURORA 20230723 从跑马灯例程复制过来的 */
QSPI_Enable_Memmapmode();
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/* 1997AURORA 20230723 */
__HAL_RCC_CSI_ENABLE() ;
__HAL_RCC_SYSCFG_CLK_ENABLE() ;
HAL_EnableCompensationCell();
/* end */
}
然后再把QSPI_Enable_Memmapmode
函数的实现也复制过来,直接复制,不再赘述
②rtconfig.h的修改
因为正点原子北极星开发板用的uart1,PA9作为Tx,PA10作为Rx,所以修改部分如下
#define RT_CONSOLE_DEVICE_NAME "uart1"
/* 1997AURORA 20230723 并不想用hook,看自己需要*/
// #define RT_USING_OVERFLOW_CHECK
// #define RT_USING_HOOK
// #define RT_HOOK_USING_FUNC_PTR、
。
。
。
/* 1997AURORA 20230723*/
#define RT_USING_MEMPOOL
// #define RT_USING_SMALL_MEM
// #define RT_USING_SMALL_MEM_AS_HEAP
// #define RT_USING_HEAP
这里把HEAP注释掉是因为我使用keil编译,对段地址的获取一直不成功,即使把HEAP_BEGIN变量名字换成与scf一致也会报错说找不到,所以干脆不用HEAP了,不过需要注释一些东西。我编译出错的点如下:
#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int RW_m_stmsram$$Limit;
#define HEAP_BEGIN ((void *)RW_m_stmsram$$Limit)
#elif __ICCARM__
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
#else
如果有大佬知道怎么改这部分,就可以用HEAP了,很多地方也会方便很多。欢迎评论区留言。
③board.h的修改
因为uart用的uart1,所以改一下
#define BSP_USING_UART1
#define BSP_UART1_TX_PIN "PA9"
#define BSP_UART1_RX_PIN "PA10"
clock部分也改一下
/*-------------------------- CHIP CONFIG END --------------------------*/
/*-------------------------- ROM/RAM CONFIG BEGIN --------------------------*/
#define ROM_START ((uint32_t)0x08000000)
#define ROM_SIZE (128 * 1024)
#define ROM_END ((uint32_t)(ROM_START + ROM_SIZE))
#define RAM_START (0x20000000)
#define RAM_SIZE (128 * 1024)
#define RAM_END (RAM_START + RAM_SIZE)
/*-------------------------- ROM/RAM CONFIG END --------------------------*/
/*-------------------------- CLOCK CONFIG BEGIN --------------------------*/
#define BSP_CLOCK_SOURCE ("HSE")
#define BSP_CLOCK_SOURCE_FREQ_MHZ ((int32_t)0)
#define BSP_CLOCK_SYSTEM_FREQ_MHZ ((int32_t)400)
④对于没有用HEAP宏包起来的代码修改
有些代码在用rt_malloc
或者rt_free
的时候,是不管有没有启用HEAP的。所以编译会出现几个错误,比如serial.c
,以serial.c
举例:
比如像这样修改一下,但是申请内存的时候不能这么改,不然没有内存分配给要用的了。。。
像这样定一个变量给他就可以了,注意用全局的,不要用局部的。
rt_uint8_t serial_malloc_buffer[200] = {0};
rt_uint8_t serial_malloc_fifo[200] = {0};
⑤scf散列文件修改
因为有些启动代码在qspi还未初始化之前执行,所以偷个懒,直接把qspi部分干掉就可以了,flash空间还是够的,不够的话,就把重要的文件丢在片内flash,等qspi配置完成后运行的代码部分放在qspi中
⑥main.c的修改
当然这个修改就比较简单了,我是直接做个delay就完了,跑马灯的代码不要了。
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
int main(void)
{
int count = 1;
while (count++)
{
rt_thread_mdelay(1000);
}
return RT_EOK;
}
七、编译验证
编译OK,读者们移植编译有可能会很花时间,因为笔者也是这么过来的,需要慢慢改慢慢调整。
烧写进去进行验证:
很棒,至此移植完毕,感谢大家的阅读!评论收藏支持一下!