GD32f103VBT6-移植freertos的记录

一、已知条件

1. 由于硬件原因,本单片机无外部晶振,所以建立工程时需要设置为内部晶振

2. 本工程已经完成裸机的开发工作,所有功能均已正常实现。

3.GD32f103VBT6 内存大小只有20K。

二、移植记录

一. 初步版本的建立。(2022-09-05)
1. freertos  来自FreeRTOSv202012.04-LTS.zip解压
2. portable 选择ARM_CM3
3. MemMang 选择heap_4.c
4.FreeRTOSConfig.h 来自网络代码的拷贝。注意该文件中的内容。
5.因为本单片机无外部晶振,所以需要设置选择内部晶振的方式。
6.移植一个led的闪烁实验,已经成功运行。(PB4正好与调试接口有关联,需要关闭部分调试接口)


二、做了串口的移植(2022-09-09)
1。出现了两个问题,一个是串口移植总是卡死,二是再次增加一个任务后,在vTaskStartScheduler函数中报错(其实手动只创建了两个任务)
2.串口卡死的问题是因为在中断函数中进入了临界代码函数,导致卡死,不能退出(uart_debug_handle.c中有详细描述)
3.第二个问题,需要修改栈的大小configTOTAL_HEAP_SIZE ,我改为了10k。
4.现在两个问题都已经解决,串口还只有基本功能。
5.倒是有个担心,每个任务消耗的内存都不少啊,任务太多,可能内存都不够用了!!!


三、模拟iic的移植
1. 考虑iic的时序是否不能打断,则考虑每一次iic通信能否进入临界段。设置临界段后,出现一个问题,模拟iic中有延时函数,这时是应该切换任务还是继续等待
2.进入临界段(关中断taskENTER_CRITICAL()、taskEXIT_CRITICAL()),能否调用vTaskDelay,即这个函数能否正确延时并返回呢?实验证明不行!!!!直接卡死
为啥我要禁止中断呢?因为键盘会触发外部中断。
3.改禁止任务调度的方式试试,vTaskSuspendAll(),xTaskResumeAll(),能否调用vTaskDelay,即这个函数能否正确延时并返回呢?实验证明不行!!!!直接卡死
4.最后只能把之前用的裸机的延时函数(Delay1us)重新移植过来了。因为模拟iic是一个us的延时,而freertos最小是ms,而且不能禁止任务切换。
5.由于systick的初始化在vTaskStartScheduler函数中,而我在初始化串口的时候就需要用到systick的定时器,所以。。。要么把初始化改到任务函数的while1前面。
6.改变思路,任务有关的初始化应该放在任务的函数中!!其他无任务的初始化函数可以安排在main函数中。测试正常了。
7.任务使用(裸机时的)全局变量的方式,不利于任务的休眠,改为其他方法:比如信号量等。任务在等待信号量时阻塞休眠。
8.修改为任务通知的方式,测试暂无问题。注意中断的优先级!!!

四、想合并串口的接收和发送到一个任务中。
1.使用了任务通知的方法,但是问题是,每次通知只能对一个字符有效。通知是设置某个位。
2.解决办法,xStreamBufferBytesAvailable读出缓存的数据个数,然后使用for循环处理缓存数据。
3.有一个问题,在串口输入的处理中,有一个打印帮助信息,由于缓存比较小,导致当执行打印帮助信息时,串口部分卡死。解决办法,把streambuff扩大到512字节
4.这里还有一个问题,连续输入打印,让串口打印帮助信息,导致缓存被用完卡死。xStreamBufferSend 写入发送缓存时不等待(之前是写不进的时候无限等待),可以解决卡死的问题。
5.合并带来的麻烦就是串口接收的时候不能打印,会导致打印的数据堆积起来。
6.感觉还是拆开会不会好一点?
7.改为发送中断模式,这样也能节省一个任务。发送缓存必须大一点,不然打印的内容只有一部分。
8.xStreamBufferSend(_uart_tx_StreamBuffer_Handle,&c,1,x10ms); 把等待时间改为10ms,好像可以使缓存小一点,目前调到64字节没啥问题。(32和16卡死)

五、串口通信(与cpu之间)的移植
1.初始化和接收任务、发送中断可以参考调试串口,但是通信协议的解析这里需要重新考虑一下。
2.与cpu通信的串口,使用了接收中断,空闲中断,发送空中断。发送数据的时候使能发送空中断,查询到缓存没有数据的时候,关闭发送空中断。
3.接收时,直接存入缓存。空闲中断时,发出任务唤醒。
4.接收处理任务。被空闲中断唤醒。处理接收到的数据。
5.开始的时候出现超时问题,调整优先级后处理正常了。优先级已调整到最高了(4)。

六、移植lt9211时(gd32f103vbt6内存只有20k,比较吃紧)
1. iic通信再次卡死,configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );  task.c
2.已经调整任务栈的最小值,本来是130*4=520字节,改为64,即256字节
3.iic的不允许任务切换还是会带来卡死的问题。主要还是因为iic通信的时候,出现错误,然后出错的时候,又要调用printf函数,而此时正好又不允许任务调度,则出现一些互锁的问题。
改进:把允许任务切换放到出错的第一句。即允许任务切换后,再去做出错处理。


七、调试的时候发现调试串口不能正常解析命令了
1.可以打印出调试信息,但是按键盘没有任何输出,使用调试模式,可以追到有中断,但是任务那里就没有执行。原因未知
2.调试模式下,观察串口的时候,出现HardFault_Handler(void)的出错,停在这里面了。任务的缓存太小,改为512字节就正常了,
但是如果只修改串口(接收任务)的缓存未512,其他(任务)256,就还是不能响应串口的输入。
这里可能的问题是printf这个库函数需要的栈变量比较多,凡是使用printf的任务,对栈的要求就会多而导致(卡死)的,稍后尽量减少printf的使用,看能否把栈的空间进一步缩小。


八、去掉printf的函数后,任务栈可以到64字节了。
1.任务运行正常,
2.如果要打印数值的话,自己实现也需要增加栈的空间,才能不让串口接收正常,否则出现串口接收无响应现象。

九、找到一个原因
1. 3399在运行test程序,并且看门狗没有关闭。此时单片机的程序重新烧写,单片机重启。
2.3399(人为)退出test程序,它默认会关闭看门狗。此时单片机端会删除看门狗的任务,但是此时看门狗的任务句柄为空(NULL),调用任务删除时,实际把与cpu通信的任务删除。
因为是cpu通信的任务调用的,相当于删除任务函数的参数是NULL,此时正好是删除任务本身。
3.导致3399再次运行test,无法启动,每次都是超时错误。查看任务的时候,发现原来tocpu的任务已经不存在了,所以就不会再应答了。

十、加入了任务信息
1.通过任务信息,比较方便去定位问题,而且可以监控栈是否够用的问题!!!适当的调整了某些任务的栈大小。
2.不能再调用printf函数,会导致卡死(因为栈比较小)。


 


版权声明:本文为zhaozhi0810原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。