stm32f1移植FreeRTOS及问题解决

之前尝试了移植freertos,参考了文章:【FreeRTOS】FreeRTOS移植stm32详细步骤介绍_freertos 202212.01下载-CSDN博客

版本是2022.12,但是笔者发现根本不能执行rtos,经过不断踩坑,靠着笔者对rtos内核的理解反复调试,终于成功移植。在这里将笔者的踩坑经历分享给大家:

1.注释

首先,在stm32f10x_it.c注释这两个函数456925d5247e4258839253ea4ae55f73.png

2.时钟

进入delay.c文件,有一些程序的裸机版本这里标注的是os的程序,请把这个文件改成这样:(注意,SYSTEM_SUPPORT_OS的值为1开启rtos,定义在sys.h)

#include "delay.h"
#include "sys.h"

#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"						  
#include "task.h"
#endif



extern void xPortSysTickHandler(void);
 

void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();	
    }
}
			   


void delay_init(void)
{
	 
  RCC->CR |= RCC_CR_HSEON;

  while ((RCC->CR & RCC_CR_HSERDY) == 0)
  {
  }
  
  RCC->CFGR |= RCC_CFGR_PLLMULL9;
  RCC->CFGR |= RCC_CFGR_PLLSRC;

  FLASH->ACR |= FLASH_ACR_LATENCY_2; 

  RCC->CR |= RCC_CR_PLLON;
  while ((RCC->CR & RCC_CR_PLLRDY) == 0) 
  {
  }

  RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

  RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
  RCC->CFGR &= (~(RCC_CFGR_SW));
  RCC->CFGR |= RCC_CFGR_SW_PLL;

  while ((RCC->CFGR & RCC_CFGR_SWS) != 0x08)
  {
  }

}								    
void delay_us(uint32_t time)
{
   uint8_t i = 0;
   while (time--)
   {
      i = 10; 
      while (i--)
         ;
   }
}

void delay_ms(uint32_t time)
{
   while (time--)
   {
      delay_us(1000);
   }
}


void delay_xms(u32 nms)
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}

			 

3.延时

延时上面已经改了,如果你使用rtos自带的systick时钟,不管是摘取时钟法还是其他方法,程序都容易卡死,笔者也是多次调试才发现。不过读者可以像裸机一样,先获取systick指向的值,再手动装载计数,计数完以后再复原时钟。如果对时钟精度有要求,可以考虑这种方法:

void delay_us(uint32_t us)
{
	uint32_t val_temp=SysTick->VAL;
	uint32_t load_temp=SysTick->LOAD;
	uint16_t ctrl_temp=SysTick->CTRL;
	SysTick->LOAD = 72 * us;	
	SysTick->VAL = 0x00;		
	SysTick->CTRL = 0x00000001; 
	while (!(SysTick->CTRL & 0x00010000));

	SysTick->LOAD = load_temp;
	SysTick->VAL = val_temp;
	SysTick->CTRL = ctrl_temp;

}

4.PendSV_Handler

下载程序,发现仍然不能运行,使用软件模拟,发现卡在PendSV_Handler这里,

91e164025aa74b0e92ff334ee6bead38.png                

后面提示weak,意思到可能是这两个函数在搞鬼,搜索了一下,在portmacro.h文件添加

#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
 

5.时钟频率与堆栈大小

现在程序理论上可以进入rtos了,但是笔者调试发现仍然不行,转到FreerRTOSconfig.h文件看了一下,发现分配的堆栈空间是17*1024,下载了elf文件,在linux下使用readelf命令,结果如下:

f9d51eec7c864dd684d69173e9829346.png

stm32f103c8t6的ram就是截至到20005000,这已经逼近了,于是笔者把FreeRTOSconfig.h这里修改为10*1024:(大概在40-50行,记得把晶振频率和configTICK_RATE_HZ也改了)

5d835c1758cc472c8e3a2eef53099b8a.png

到了这一步,FreeRTOS一般是可以顺利执行了,读者可以进行下载或仿真验证,如果成功了,后面的可以忽略了,如果Freertos还未启动成功,请继续看下文。

6.临界区函数的问题

到这一步,rtos应该是可以使用了,但是笔者发现并没有。经过调试发现,在注释了临界区函数(也就是taskENTER_CRITICAL())后,rtos执行了:cc7dd49216da452fa696260bb2def8e4.png

7.系统节拍和优先级

仔细研究,猜测是临界区没有启到屏蔽作用,转到FreeRTOSconfig.h文件的configMAX_SYSCALL_INTERRUPT_PRIORITY一看,发现它的值是191,根据笔者的理解该宏是高四位有效,也就是等于11,但是191并没有起到屏蔽作用,改成11发现成功了,这是因为SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号15),也就是说191并没有取高四位,优先级小于15,临界区的屏蔽就不起作用了。

1b1e577cb1d44b41a059b222eb2fcf17.png

经过笔者的调试,认为这是大小端序的问题。

于是笔者修改portmarco.h文件的vPortRaiseBASEPRI函数,如下所示:

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
    {
        uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

        __asm
        {
            /* Set BASEPRI to the max syscall priority to effect a critical
             * section. */

			mov  r1,ulNewBASEPRI
			revsh r1,r1
            msr basepri, r1
            dsb
            isb
/* *INDENT-ON* */
        }
    }

改成这样后,设置为191就能正常执行程序了,当然直接改为11也是一样的。

此时笔者发现rtos仍未执行,猜测可能是被系统时钟滴答计数器中断打断,改为1后也是一样的,我们知道系统延时和阻塞时间都是以系统节拍时钟周期为单位,于是修改#define configTICK_RATE_HZ            ( ( TickType_t ) 100 ),改为100,也就是10ms执行一次中断,此时rtos才顺利执行(修改的地方参考第五节标注的位置):

2c7e91110b1b43339259e69a36f9304d.png

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值