这里是BUG回报板块!

发布于 2010-04-30 17:54:12
论坛里没有一个BUG回报的集中点,那么以后就在这里回报吧!
下载附件[rtthread.rar]

查看更多

关注者
1
被浏览
74.3k
128 个回答
shellstudio
shellstudio 2010-04-30
RTT的时基函数是rt_tick_increase(),该函数有个不妥之处,比如我把每个线程的时间片长度设置为1个时基。那么,有以下情况可能发生:rt_timer_check()函数使更高优先级的线程就绪,而该线程的时间片为1。此后rt_thread_self()函数返回的就是这个就绪线程,接下来紧接着时间片计数器就被减1,变为0,也就是说线程还没执行就被rt_thread_yield()函数当作放弃了执行对待!这就是不妥之处!望Bernard兄妥善解决。
shellstudio
shellstudio 2010-04-30
RTT的定时计数器变量rt_tick在每个Tick中断内自增,自增到0xffffffff再溢出到0周而复始。
所有定时器对象的定时结束时基计算为:timer->timeout_tick = rt_tick_get() + timer->init_tick;
在时基中断,检查if (rt_tick >= t->timeout_tick)是否成立,如果成立则定时时间到。似乎很合理,但是错误就出现在这里。如果来了20个tick的定时请求在执行“timer->timeout_tick = rt_tick_get() + timer->init_tick;”时,若rt_tick为0xfffffff0,于是得出定时结束时间为0x00000004,于是该节点加入定时器列表等待超时。结果,下一次进入中断的rt_tick为0xfffffff1,使if (rt_tick >= t->timeout_tick)检查成立,所以定时时间结束,错误发生了!
这个错误平时发现不了,是因为等到rt_tick接近溢出需要很长时间(如果1毫秒一个tick的话,需要50天,10毫秒一个tick就需要500天,哈哈!),Bernard兄是不是考虑到这个情况才故意放过这个臭虫的呢?如果要解决该问题,必定添加不少冗余代码,影响性能。但留着这个漏洞又很不舒服,怎么办呢?
shellstudio
shellstudio 2010-05-01
RTT还需要很长的时间来完善才能用于商业乃至工业现场啊!今天又发现了一个很要命的漏洞,这种漏洞是对临界代码段的理解太随意导致的。
我知道,很多人有时候为了所谓的实时性,都忽略了临界代码段的重要性。但是,如果不仔细推敲代码而随意放任的话,系统会变得异常脆弱!
下面我就来给你分析以下rt_object_find()函数的漏洞。
rt_object_find()函数是通过对象的名称来查找对象,并返回指针。调用该函数之前,线程大都不会关中断来保护rt_object_find(),而该函数自身更是没有临界段保护措施,这样就造成了下面的漏洞:
在遍历链表节点的过程中,node指向当前所检查的对象节点,而在此判断过程中,有可能高优先级线程得到运行,从而导致当前对象节点有可能被删除,这时,对象的链表指针next,prev就指向它自身。之后,CPU上下文回到调用rt_object_find()函数的线程,继续遍历对象链表,结果node = node->next语句总是使node指向它自身,而且符合node != &(information->object_list)条件,因此,for()循环形成了死循环!该函数将无法退出,其结果无法预测!
我是一个思维很严谨的人,总是很小心的对待代码,即使是在单任务软件开发过程中,我也很注意中断函数和main()循环之间的临界代码段问题。希望大家能跟我一样多查看内核代码,尽快完善RTT!
(我的经验都来自ucos源代码,因为国外对RTOS的认证是很严格的,ucos是经过航空级认证的RTOS)
bernard
bernard 2010-05-01
哦,原来这里有个归总的,谢谢shellstudio的反馈。以后就使用这个做为RT-Thread的BUG反馈集中贴吧。
bernard
bernard 2010-05-01
RTT的时基函数是rt_tick_increase(),该函数有个不妥之处,比如我把每个线程的时间片长度设置为1个时基。那么,有以下情况可能发生:rt_timer_check()函数使更高优先级的线程就绪,而该线程的时间片为1。此后rt_thread_self()函数返回的就是这个就绪线程,接下来紧接着时间片计数器就被减1,变为0,也就是说线程还没执行就被rt_thread_yield()函数当作放弃了执行对待!这就是不妥之处!望Bernard兄妥善解决。


不会的,rt_thread_self()只会在当前线程的上下文环境执行,如果在中途被打断,上面相应的上下文会被保存,下一次恢复出来依然是当前这个线程对象。
bernard
bernard 2010-05-01
RTT的定时计数器变量rt_tick在每个Tick中断内自增,自增到0xffffffff再溢出到0周而复始。
所有定时器对象的定时结束时基计算为:timer->timeout_tick = rt_tick_get() + timer->init_tick;
在时基中断,检查if (rt_tick >= t->timeout_tick)是否成立,如果成立则定时时间到。似乎很合理,但是错误就出现在这里。如果来了20个tick的定时请求在执行“timer->timeout_tick = rt_tick_get() + timer->init_tick;”时,若rt_tick为0xfffffff0,于是得出定时结束时间为0x00000004,于是该节点加入定时器列表等待超时。结果,下一次进入中断的rt_tick为0xfffffff1,使if (rt_tick >= t->timeout_tick)检查成立,所以定时时间结束,错误发生了!
这个错误平时发现不了,是因为等到rt_tick接近溢出需要很长时间(如果1毫秒一个tick的话,需要50天,10毫秒一个tick就需要500天,哈哈!),Bernard兄是不是考虑到这个情况才故意放过这个臭虫的呢?如果要解决该问题,必定添加不少冗余代码,影响性能。但留着这个漏洞又很不舒服,怎么办呢?


这个问题mbbill和阿干都和我讨论过,只是一直没能够找到比较好一些的办法,所以拖着没解决。呵呵,这个也是0.4.x分支必须要解决的问题之一(解决了会merge回0.3.x分支)。

因为RT-Thread目前主要面向小型应用,如果简单的解决这个问题,只需要更改32位为两个32位变量即可(当然这样仅仅是延长了很多出错的时间,从 50天或500天延长到了4294967295 * 50天或4294967295 * 500天),这样唯一的问题就是多了4个字节。
bernard
bernard 2010-05-01
RTT还需要很长的时间来完善才能用于商业乃至工业现场啊!今天又发现了一个很要命的漏洞,这种漏洞是对临界代码段的理解太随意导致的。
我知道,很多人有时候为了所谓的实时性,都忽略了临界代码段的重要性。但是,如果不仔细推敲代码而随意放任的话,系统会变得异常脆弱!
下面我就来给你分析以下rt_object_find()函数的漏洞。
rt_object_find()函数是通过对象的名称来查找对象,并返回指针。调用该函数之前,线程大都不会关中断来保护rt_object_find(),而该函数自身更是没有临界段保护措施,这样就造成了下面的漏洞:
在遍历链表节点的过程中,node指向当前所检查的对象节点,而在此判断过程中,有可能高优先级线程得到运行,从而导致当前对象节点有可能被删除,这时,对象的链表指针next,prev就指向它自身。之后,CPU上下文回到调用rt_object_find()函数的线程,继续遍历对象链表,结果node = node->next语句总是使node指向它自身,而且符合node != &(information->object_list)条件,因此,for()循环形成了死循环!该函数将无法退出,其结果无法预测!
我是一个思维很严谨的人,总是很小心的对待代码,即使是在单任务软件开发过程中,我也很注意中断函数和main()循环之间的临界代码段问题。希望大家能跟我一样多查看内核代码,尽快完善RTT!
(我的经验都来自ucos源代码,因为国外对RTOS的认证是很严格的,ucos是经过航空级认证的RTOS)


这个确实是问题,其他的几个object函数都加了相应的保护,当时实现这个函数时仅仅是临时的,直接关中断又不忍心,而使用semaphore一类的机制后,那么整个object容器的操作将不能够在中断服务程序中使用。

这个地方确实处理得不太好,而且这个也不是主函数一类的,这个函数还是直接删除掉比较好,这样也比较容易分别进行对待。
xiao苦
xiao苦 2010-05-13
如下。。。
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_realloc (referred from region.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_strdup (referred from rtgui_object.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_free (referred from rtgui_system.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_malloc (referred from rtgui_system.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rtgui_filerw_create_file (referred from image.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_mq_create (referred from server.o).
.objrtthread-stm32.axf: Error: L6218E: Undefined symbol rt_thread_create (referred from server.o).

可以看到在实例里面的mdk里面, 内存管理的函数都提示没有定义, 无法调用。。。。
bernard
bernard 2010-05-13
你的工程文件有问题?

关于使用RT-Thread/GUI的例子,可以参考STM32 Radio的例程
xiao苦
xiao苦 2010-05-14
嗯, 谢谢, 是我的配置文件rtconfig.h没有配置好, 问题已经解决了, 但是还有个问题, 正式版里面的rtgui的液晶是用spi模式的, 但是我的是16位总线的驱动的, 这样原先的驱动虽然可以改,但是把基本函数改了之后会不会有很多问题, 目前已经把报错的全都改成适应16位color的。。。。就是不知道窗体会怎么样, 另外求stm32 radio的源码, 我找不到, 谢谢。。。
pupist
pupist 2010-07-09
将rtconfig.py 中的CROSS_TOOL = 'gcc'改为CROSS_TOOL = 'keil'
使用scons --target=mdk -s声称keil mdk工程 编译之后有几个问题

1.缺少scatter文件 rtthread-mini2440.sct
2.....examplesguidemo_view_dc.c(14): error: #5: cannot open source input file "play.hdh": No such file or directory
从工程中删除这个文件之后提示下面
D:02rttbspmini2440rtthread-mini2440.plg(899): *** Error: Referred Memory Range 'ROM1' is undefined.
应该还是scatter的问题
pupist
pupist 2010-07-09
是从svn上取得最新版本
bernard
bernard 2010-07-10
因为地址空间存在些差别,所以mini2440目前还不能支持Keil MDK工程方式编译。
pupist
pupist 2010-07-10
scons -j 2
这样 缺少头文件的问题还是存在阿
bernard
bernard 2010-07-11
scons -j 2
这样 缺少头文件的问题还是存在阿


这个是check in的文件有些问题,把错误的测试代码也一起提交上去了。你可以往回退一个版本。
rt-uncile_evil
rt-uncile_evil 2010-09-14
RTT的定时计数器变量rt_tick在每个Tick中断内自增,自增到0xffffffff再溢出到0周而复始。
所有定时器对象的定时结束时基计算为:timer->timeout_tick = rt_tick_get() + timer->init_tick;
在时基中断,检查if (rt_tick >= t->timeout_tick)是否成立,如果成立则定时时间到。似乎很合理,但是错误就出现在这里。如果来了20个tick的定时请求在执行“timer->timeout_tick = rt_tick_get() + timer->init_tick;”时,若rt_tick为0xfffffff0,于是得出定时结束时间为0x00000004,于是该节点加入定时器列表等待超时。结果,下一次进入中断的rt_tick为0xfffffff1,使if (rt_tick >= t->timeout_tick)检查成立,所以定时时间结束,错误发生了!
这个错误平时发现不了,是因为等到rt_tick接近溢出需要很长时间(如果1毫秒一个tick的话,需要50天,10毫秒一个tick就需要500天,哈哈!),Bernard兄是不是考虑到这个情况才故意放过这个臭虫的呢?如果要解决该问题,必定添加不少冗余代码,影响性能。但留着这个漏洞又很不舒服,怎么办呢?


这个问题mbbill和阿干都和我讨论过,只是一直没能够找到比较好一些的办法,所以拖着没解决。呵呵,这个也是0.4.x分支必须要解决的问题之一(解决了会merge回0.3.x分支)。

因为RT-Thread目前主要面向小型应用,如果简单的解决这个问题,只需要更改32位为两个32位变量即可(当然这样仅仅是延长了很多出错的时间,从 50天或500天延长到了4294967295 * 50天或4294967295 * 500天),这样唯一的问题就是多了4个字节。

刚接触rtt,也发现了这个问题,本想另外发帖说的呢……
借鉴一下uCOS-II,所有tick处理都使用减计数,能否解决这个问题呢?
使用2个32位变量来延缓问题的发生有点“山寨”的感觉
bernard
bernard 2010-09-14
这个问题已经在svn的版本中修复了(0.3.1分支和0.4.0分支都修复了),可以更新下最新的代码看看。预计0.3.1版本在这个月发布。
yuan_jeff
yuan_jeff 2010-09-19
从google下载了最新的rt代码,打开stm3210里面的工程,选我使用的STM32F101VB,报错如下:
sdcard.c(3007): error: #20: identifier "SDIO_IRQn" is undefined
sdcard.c: NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
sdcard.c: ^
sdcard.c: sdcard.c: 0 warnings, 1 error
compiling enc28j60.c...
enc28j60.c(214): warning: #550-D: variable "duplex" was set but never used
enc28j60.c: int duplex;
enc28j60.c: ^
enc28j60.c: enc28j60.c: 1 warning, 0 errors
Target not created
请问,如何解决?我在哪里改设置?谢谢
yuan_jeff
yuan_jeff 2010-09-19
另外,1.是不是要在system_stm32f10x.c line72-77这里把时钟改到36M?
/* #define SYSCLK_FREQ_HSE HSE_Value */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000

2.是不是要在stm32f10x_conf.h的line25-48,把使用的文件打开?
/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
/* #include "stm32f10x_adc.h" */
#include "stm32f10x_bkp.h"
/* #include "stm32f10x_can.h" */
/* #include "stm32f10x_crc.h" */
/* #include "stm32f10x_dac.h" */
/* #include "stm32f10x_dbgmcu.h" */
/* #include "stm32f10x_dma.h" */
#include "stm32f10x_exti.h"
#include "stm32f10x_flash.h"
//#include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
/* #include "stm32f10x_i2c.h" */
/* #include "stm32f10x_iwdg.h" */
#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_rtc.h"
/* #include "stm32f10x_sdio.h" */
//#include "stm32f10x_spi.h"
/* #include "stm32f10x_tim.h" */
#include "stm32f10x_usart.h"
/* #include "stm32f10x_wwdg.h" */
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */

我用的是4.12版本。
bernard
bernard 2010-09-19
工程默认是为STM32F103ZE准备的,所以
时钟需要按照相应的芯片类型更改

而STM32F101VB是不存在SDIO的,所以sdcard.c文件可以直接删除(建议开始时屏蔽文件系统)

enc28j60也可以考虑删除,即网络部分也可以屏蔽掉(或者你确实接了enc8j60芯片,打算跑网络?)。

建议开始从简单的点灯开始(project_led),对于STM32F101VB,还需要在board.h中更改片内SRAM大小(VB应该是片内SRAM 20kB吧,请自行再确认下):
#define STM32_SRAM_SIZE 20
yuan_jeff
yuan_jeff 2010-09-19
1。屏蔽文件系统:
/* SECTION: device filesystem
#define RT_USING_DFS
#define RT_USING_DFS_ELMFAT */

从工程中“remove sdcard.c”和“filesystem”文件夹及其文件。
2。
网络屏蔽:
/* SECTION: lwip, a lighwight TCP/IP protocol stack 
#define RT_USING_LWIP */
/* LwIP uses RT-Thread Memory Management
#define RT_LWIP_USING_RT_MEM */

删除encj8c60。c和“LWIP”文件夹及其文件.

结果:
Program Size: Code=37646 RO-data=4322 RW-data=440 ZI-data=4912


谢谢熊老师这么快的回复,让我们这些生手十分感谢!
yuan_jeff
yuan_jeff 2010-09-19
另外熊老师,google上的代码没有example,0.3.0上的project_led报很多错误:
Build target 'RT-Thread STM32'
compiling stm32f10x_it.c...
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(23): error: #256: invalid redeclaration of type name "s32" (declared at line 312 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef signed long s32;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(27): error: #256: invalid redeclaration of type name "sc32" (declared at line 316 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef signed long const sc32; /* Read Only */
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(31): error: #256: invalid redeclaration of type name "vs32" (declared at line 320 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef volatile signed long vs32;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(35): error: #256: invalid redeclaration of type name "vsc32" (declared at line 324 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef volatile signed long const vsc32; /* Read Only */
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(39): error: #256: invalid redeclaration of type name "u32" (declared at line 328 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef unsigned long u32;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(43): error: #256: invalid redeclaration of type name "uc32" (declared at line 332 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef unsigned long const uc32; /* Read Only */
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(47): error: #256: invalid redeclaration of type name "vu32" (declared at line 336 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef volatile unsigned long vu32;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(51): error: #256: invalid redeclaration of type name "vuc32" (declared at line 340 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef volatile unsigned long const vuc32; /* Read Only */
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(55): error: #101: "FALSE" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {FALSE = 0, TRUE = !FALSE} bool;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(55): error: #101: "TRUE" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {FALSE = 0, TRUE = !FALSE} bool;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(55): error: #256: invalid redeclaration of type name "bool" (declared at line 345 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {FALSE = 0, TRUE = !FALSE} bool;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(57): error: #101: "RESET" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(57): error: #101: "SET" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(57): error: #256: invalid redeclaration of type name "FlagStatus" (declared at line 348 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(57): error: #256: invalid redeclaration of type name "ITStatus" (declared at line 348 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(59): error: #101: "DISABLE" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(59): error: #101: "ENABLE" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(59): error: #256: invalid redeclaration of type name "FunctionalState" (declared at line 350 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(62): error: #101: "ERROR" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(62): error: #101: "SUCCESS" has already been declared in the current scope
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_type.h(62): error: #256: invalid redeclaration of type name "ErrorStatus" (declared at line 353 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
C:KeilARMINCSTSTM32F10xstm32f10x_type.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_conf.h(147): warning: #47-D: incompatible redefinition of macro "HSE_Value" (declared at line 85 of "C:KeilARMINCSTSTM32F10xstm32f10x.h")
C:KeilARMINCSTSTM32F10xstm32f10x_conf.h: #define HSE_Value ((u32)8000000) /* Value of the External oscillator in Hz*/
C:KeilARMINCSTSTM32F10xstm32f10x_conf.h: ^
C:KeilARMINCSTSTM32F10xstm32f10x_conf.h: stm32f10x_it.c: 1 warning, 21 errors
compiling board.c...
board.c: Error: #5: cannot open source input file "board.c": No such file or directory
board.c: board.c: 0 warnings, 1 error
Target not created


改哪里啊 [s:182]
bernard
bernard 2010-09-19
0.3.0正式版发布中有份不那么正式的说明文档,估计你没看到:
所有project_xx目录下的文件都不是独立的工程,需要把它们复制到上级目录(即stm3210目录)才是一个完整的工程。
yuan_jeff
yuan_jeff 2010-09-20
在simple led中,我的usart1不能做调试用,其他串口做IO了,所以把
#define RT_USING_DEVICE    
#define RT_USING_UART1

屏蔽掉,把usart.C去掉。结果报错。应该怎么办?
yuan_jeff
yuan_jeff 2010-09-20
还改了这里:
#define STM32_CONSOLE_USART 0
bernard
bernard 2010-09-20
#define RT_USING_DEVICE
保留。

uart.c保留,uart相关的初始化不执行即可。
yuan_jeff
yuan_jeff 2010-09-20
只好使用延时:rt_thread_delay(2);。代码如下:
   while (1)
{
if( myFlagUsart1WaitFor == FLAG_OVER )
{
usart1_cmd_process( );
//重回接收态;
DIR485_1_RE;
myFlagUsart1WaitFor = FLAG_SOI ;
}
//COM1重回接收状态;
//myFlagUsart1WaitFor = SOI ;
rt_thread_delay(2);//rt_thread_yield (); /* switch to other tasks */
}
rt-uncile_evil
rt-uncile_evil 2010-11-29
如题。一些函数在使用rt_thread_defunct这个变量时没做处理
bernard
bernard 2010-11-29
是的,还在修之中,因为最近做版本发布,改的东西比较多。

还有那个device->private,最近也更改为user_data了,编译也刚能够通过。
weywong
weywong 2010-12-16
0.3.1中object.c 26行开始rt_object_container的定义,其中62行有RT_Object_Class_Module;这个在rtdef.h的enum rt_object_class_type中没有啊。代码合并的问题?
bernard
bernard 2010-12-16
是的,这块是以前遗留的代码,在0.3.x中module是不使能的。
cole3
cole3 2011-02-16
将listdir.c中的 struct dfs_dirent 和 struct dfs_stat
改为 struct dirent 和 struct stat 才能正常编译。 [s:157]
longxiguang
longxiguang 2011-03-09
在\bsp\stm3210\project_lwip这个工程目录下,这个本来是一个LWIP的演示项目,但我想做个TCP通讯怎么都连不上,UDP通讯怎么都发不出去。后来分析代码才发现,在初始化DM9000A网卡的时候,网卡数据中断用的是外部中断4,而在stm32f10x_it.c文件中,却把中断处理放在了EXTI9_5_IRQHandler函数中,而不是EXTI4_IRQHandler,MCU收不到网络数据导致,我发现这个问题是在0.3.0版本,后来下载了0.3.1版本还是没改掉这个问题
bernard
bernard 2011-03-09
在spstm3210project_lwip这个工程目录下,这个本来是一个LWIP的演示项目,但我想做个TCP通讯怎么都连不上,UDP通讯怎么都发不出去。后来分析代码才发现,在初始化DM9000A网卡的时候,网卡数据中断用的是外部中断4,而在stm32f10x_it.c文件中,却把中断处理放在了EXTI9_5_IRQHandler函数中,而不是EXTI4_IRQHandler,MCU收不到网络数据导致,我发现这个问题是在0.3.0版本,后来下载了0.3.1版本还是没改掉这个问题


这个是由于无相对应的开发板照成的。或许以后完全按照STM32Radio来进行?又或者,我们需要把驱动做得更智能化,更容易修改些。Anyway,谢谢你指出问题。
longxiguang
longxiguang 2011-03-09
在spstm3210project_lwip这个工程目录下,这个本来是一个LWIP的演示项目,但我想做个TCP通讯怎么都连不上,UDP通讯怎么都发不出去。后来分析代码才发现,在初始化DM9000A网卡的时候,网卡数据中断用的是外部中断4,而在stm32f10x_it.c文件中,却把中断处理放在了EXTI9_5_IRQHandler函数中,而不是EXTI4_IRQHandler,MCU收不到网络数据导致,我发现这个问题是在0.3.0版本,后来下载了0.3.1版本还是没改掉这个问题


这个是由于无相对应的开发板照成的。或许以后完全按照STM32Radio来进行?又或者,我们需要把驱动做得更智能化,更容易修改些。Anyway,谢谢你指出问题。


不对,这个跟开发板没有关系,只是提供的工程中网卡用的中断和中断服务程序对不上,我想不管什么板子,这两个肯定是要对应起来的,当然,这只是一点小小的建议!
violet701
violet701 2011-03-20
在iar环境下使用pthread的时候,发现posix_types.h似乎有问题。比较如下两个代码片段,上面一段是原先的,下面一段是我修改了预定义位置的。原先的无法编译,修改之后可以。请确认

#ifdef __CC_ARM                				/* ARM Compiler 	*/
【省略的代码】
#elif defined (__IAR_SYSTEMS_ICC__) /* IAR Compiler */
#elif defined (__GNUC__) /* GNU GCC Compiler, with minilibc */
#endif


#ifdef __CC_ARM                				/* ARM Compiler 	*/
#elif defined (__IAR_SYSTEMS_ICC__) /* IAR Compiler */
【省略的代码】
#elif defined (__GNUC__) /* GNU GCC Compiler, with minilibc */
#endif
bernard
bernard 2011-03-20
当前的pthread还未支持IAR,你已经修改并让它能够在IAR下编译了吧?

嗯,你修改的代码是什么?最好是能够对pthread进行一些测试(在examples目录下有相应的例子、测试程序)
w
w 2011-04-10
项目中有如下代码:
void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler)
{
if(vector >= 0 && vector < MAX_HANDLERS)
{
/* get VIC address */
rt_uint32_t* vect_addr = (rt_uint32_t *)(VIC_BASE_ADDR + 0x100 + (vector << 2));
rt_uint32_t* vect_ctl = (rt_uint32_t *)(VIC_BASE_ADDR + 0x200 + (vector << 2));

/* assign IRQ slot and enable this slot */
*vect_ctl = 0x20 | (vector & 0x1F);

if (old_handler != RT_NULL) *old_handler = (rt_isr_handler_t) *vect_addr;
if (new_handler != RT_NULL) *vect_addr = (rt_uint32_t) new_handler;
}
}

但是,LPC2148的向量IRQ中断最多只能设置16个,如按以上代码指令,则无法对 EINT2_INT,EINT3_INT,ADC0_INT,I2C1_INT,BOD_INT,ADC1_INT,USB_INT这些中断进行安装,不知道我的理解是否有问题,特向各位高手请教。
rt-uncile_evil
rt-uncile_evil 2011-05-13
在dfs_fs.c的dfs_unmount()函数中存在死锁:
355   /* lock filesystem */
356 dfs_lock();
357
358 fs = dfs_filesystem_lookup(fullpath);

dfs_filesystem_lookup()也会去获取锁,356行和358需调换位置
bernard
bernard 2011-05-13
在dfs_fs.c的dfs_unmount()函数中存在死锁:
355   /* lock filesystem */
356 dfs_lock();
357
358 fs = dfs_filesystem_lookup(fullpath);

dfs_filesystem_lookup()也会去获取锁,356行和358需调换位置


因为用的是互斥锁,它是不会出现死锁的。
joychen
joychen 2011-05-30
請問我目前使用STM32F + MDK環境開發
用SVN版的RT-Thread遇到只要設complier flag -O1 以上就會有context switch無動作的情形

請問有人遇到跟我一樣的問題嗎:?:
bernard
bernard 2011-05-30
請問我目前使用STM32F + MDK環境開發
用SVN版的RT-Thread遇到只要設complier flag -O1 以上就會有context switch無動作的情形

請問有人遇到跟我一樣的問題嗎:?:


嗯,Aozima看到后测试下

ls也可以试试0.3.1的发布版本是否有这个问题
joychen
joychen 2011-06-01
更正一下是-Otime -O1同時啟用時才會發生, MDK版本是4.1.0.481

請問我目前使用STM32F + MDK環境開發
用SVN版的RT-Thread遇到只要設complier flag -O1 以上就會有context switch無動作的情形

請問有人遇到跟我一樣的問題嗎:?:
csz_cmy
csz_cmy 2011-07-18
版本是RT-Thread 0.4.0 beta1
在kservice.c中:
void* rt_memmove(void *dest, const void *src, rt_ubase_t n)
{
char *tmp = (char *) dest, *s = (char *) src;

if (s < tmp && tmp < s + n)
{
tmp+=n;
s+=n;

while (n--)
*tmp-- = *s--;
}
else
{
while (n--)
*tmp++ = *s++;
}

return dest;
}

建议:
void* rt_memmove(void *dest, const void *src, rt_ubase_t n)
{
char *tmp = (char *) dest, *s = (char *) src;

if (tmp < s)
{
while (n--)
*tmp++ = *s++;
}
else if(tmp == s)
{
// do nothing!
}
else
{
tmp += n-1;
s += n-1;

while (n--)
*tmp-- = *s--;
}

return dest;
}
zycfrank
zycfrank 2011-09-24
/* copy name */
for (temp = 0; temp < RT_NAME_MAX; temp ++)
{
object->name[temp] = name[temp];
}
这个代码是否有问题,如果name比较长的话,会不会导致截断的字符串没有/0结束符
aozima
aozima 2011-09-24
/* copy name */
for (temp = 0; temp < RT_NAME_MAX; temp ++)
{
object->name[temp] = name[temp];
}
这个代码是否有问题,如果name比较长的话,会不会导致截断的字符串没有/0结束符

是没有'/0',不过搜索了所有的访问的 object->name 的地方,
都没有把 object->name 当成一个数组来对待.
而是当成name[RT_NAME_MAX]来主动限制了其长度.应该没有问题,不过总感觉怪怪的.
当然.这要等ffxz来确认一下了.
bernard
bernard 2011-09-24
name,本身就不是强制要求'\0'终结符的,所以当名称超出长度时,打印输出会产生乱码。
huangxw
huangxw 2011-10-16
发到另外一个版块了,版主帮忙移动过来,谢谢。
http://www.rt-thread.org/phpbbforum/vie ... f=2&t=1171
sky-blue
sky-blue 2011-10-21
今年六七月份的时候,在网上偶然发现国人的实时操作系统RT-Thread,令我欣喜无限。实验室正好一个项目需要做个网关,了解到RT-Thread已移入了TCP/IP协议栈LwIP,性能也不错,而且基于C的面向对象设计很有特色,就尝试使用了RT-Thread。现已做了一段时间,后来也一直关注着RT-Thread的发展,在此把开发过程中发现的RT-Thread的一些问题和建议反馈在这,希望对RT-Thread的发展有一点点点的帮助,不对的地方还请不吝赐教。

PS:如果能投入实际使用,我会向RT-Thread工作组申请License的,哈哈...

****
既然函数rt_thread_delay()与rt_thread_sleep()是相同的,就不要使用函数调用的方式编写函数rt_thread_delay(),只要将rt_thread_delay()使用宏替换为rt_thread_sleep()就好了,这样可避免由于函数调用而产生的额外的运行时间和空间的消耗,效率更高。
还有函数rt_sem_trytake()等类似。

****
typedef定义的命名风格不统一。
有的typedef后加了后缀_t而有的没有。
对于加后缀的,指针加_t后缀,非指针类型的也加后缀_t,这样导致不能从类型名的字面上区分指针和非指针变量。
改进:
① 对于typedef定义,要么统一加后缀_t,要么都不加后缀_t。
② 区别指针与非指针,若加了后缀_t,则以_pt和_t区别,若不加_t,则以加_p和不加_p区别。

另建议,RT-Thread作为一个开源项目,从开源的角度来看,应该让编程的风格易于用户理解,提高可读性,下面附上Linux中代码风格说明中Typedef的部分,是不是能参考下。

--------------------------------------------------------------------------------
第五章:Typedef

不要使用类似“vps_t”之类的东西。

对结构体和指针使用typedef是一个错误。当你在代码里看到:

vps_t a;

这代表什么意思呢?

相反,如果是这样

struct virtual_container *a;

你就知道“a”是什么了。

很多人认为typedef“能提高可读性”。实际不是这样的。它们只在下列情况下有用:

(a) 完全不透明的对象(这种情况下要主动使用typedef来隐藏这个对象实际上是什么)。

例如:“pte_t”等不透明对象,你只能用合适的访问函数来访问它们。

注意!不透明性和“访问函数”本身是不好的。我们使用pte_t等类型的原因在于真的是
完全没有任何共用的可访问信息。

(b) 清楚的整数类型,如此,这层抽象就可以帮助消除到底是“int”还是“long”的混淆。

u8/u16/u32是完全没有问题的typedef,不过它们更符合类别(d)而不是这里。

再次注意!要这样做,必须事出有因。如果某个变量是“unsigned long“,那么没有必要

typedef unsigned long myflags_t;

不过如果有一个明确的原因,比如它在某种情况下可能会是一个“unsigned int”而在
其他情况下可能为“unsigned long”,那么就不要犹豫,请务必使用typedef。

(c) 当你使用sparse按字面的创建一个新类型来做类型检查的时候。

(d) 和标准C99类型相同的类型,在某些例外的情况下。

虽然让眼睛和脑筋来适应新的标准类型比如“uint32_t”不需要花很多时间,可是有些
人仍然拒绝使用它们。

因此,Linux特有的等同于标准类型的“u8/u16/u32/u64”类型和它们的有符号类型是被
允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。

当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选择。

(e) 可以在用户空间安全使用的类型。

在某些用户空间可见的结构体里,我们不能要求C99类型而且不能用上面提到的“u32”
类型。因此,我们在与用户空间共享的所有结构体中使用__u32和类似的类型。

可能还有其他的情况,不过基本的规则是永远不要使用typedef,除非你可以明确的应用上
述某个规则中的一个。

总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们就不
应该是一个typedef。
--------------------------------------------------------------------------------

****
字符数组越界读取,虽然一般不会导致什么异常,但数组越界操作总是不好的,而且有些空间确实不能随便读取,否则会产生错误。
/* copy name */
for (temp = 0; temp < RT_NAME_MAX; temp ++)
{
object->name[temp] = name[temp];
}

****
struct rt_object
{
char name[RT_NAME_MAX]; /* name of kernel object */
rt_uint8_t type; /* type of kernel object */
rt_uint8_t flag; /* flag of kernel object */
rt_list_t list; /* list pointer of kernel object */
};
其中type的类型直接使用枚举类型enum rt_object_class_type,这样更容易明白type的意义,虽然使用rt_uint8_t也一般不会出错。枚举类型实际上为整型,但是不同的编译器对枚举定义的长度是不一定相同的,可能并不是rt_uint8_t,当然编译器会自动截短长变量给短变量,但我觉得应该避免这种隐式类型转换。

另建议在合适的地方多使用枚举类型:若变量的取值的数值大小本身没有什么实际意义,而只是用于区分,或者只能取有限的、特定的值(如这些取值一般都使用#define的宏定义值),那么,若使用枚举类型的话,从变量的定义类型的字面就可以看出变量的意义,进一步的从枚举类型的定义处就可以知道该类型变量的所有取值范围,这样是不是可以使得程序有更好地可读性呢?

****
《RT-Thread实时操作系统编程指南》98页,“接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部”,从源程序看,实际上是空闲消息链表的“头部”,而不是“尾部”。
函数rt_mq_recv()中相关部分代码:
/* put message to free list */
msg->next = (struct rt_mq_message*)mq->msg_queue_free;
mq->msg_queue_free = msg;

****
函数rt_mp_init()和rt_mp_create()中构建链表的操作部分
/* init free block list */
block_ptr = (rt_uint8_t*) mp->start_address;
for (offset = 0; offset < mp->block_total_count; offset ++)
{
*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
}

*(rt_uint8_t**)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;

mp->block_list = block_ptr;

for()循环的边界减1,改为mp->block_total_count-1,可减少一次无意义的循环,相应倒数第2个语句改为
*(rt_uint8_t**)(block_ptr + offset* (block_size + sizeof(rt_uint8_t*))) = RT_NULL;
更改之后为:
/* init free block list */
block_ptr = (rt_uint8_t*) mp->start_address;
for (offset = 0; offset < mp->block_total_count - 1; offset++)
{
*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
}

*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;

mp->block_list = block_ptr;

在函数rt_mq_init()和rt_mq_create()中也有类似的构建链表的操作,使用的方法不如rt_mp_create()函数中的,循环中的计算量大,多次辗转赋值,且较之不易理解,可改为rt_mp_create()函数中的方法。
/* init message empty list */
mq->msg_queue_free = RT_NULL;
for (temp = 0; temp < mq->max_msgs; temp ++)
{
head = (struct rt_mq_message*)((rt_uint8_t*)mq->msg_pool +
temp * (mq->msg_size + sizeof(struct rt_mq_message)));
head->next = mq->msg_queue_free;
mq->msg_queue_free = head;
}

****
RT-Thread不能操作存在复用的逻辑中断下的物理中断。
S3C2440具有60个物理中断源,但在中断控制系统中源挂起寄存器SRCPND和中断挂起寄存器INTPND都是32位,即只有32个逻辑中断源,所以物理中断源与逻辑中断源为多对一的关系,存在多个物理中断源复用一个逻辑中断位的情况。
对于存在复用的逻辑中断源产生的中断,要判断产生中断的具体物理中断源则需要再查询辅助源挂起寄存器SUBSRCPND。相应的也存在中断辅助屏蔽寄存器INTSUBMSK。而RT-Thread中没有对这些辅助寄存器的操作接口,比如屏蔽复用逻辑中断源下的某个具体的物理中断源等。

****
测试例程timer_control.c存在BUG,运行这个例程导致程序无法返回。
① 第23行:rt_timer_control(timer1, RT_TIMER_CTRL_SET_TIME, (void*)50);
此语句的本意是想改定时器的超时值为50,但参数表达式(void*)50显然是不能达到这个目的的,rt_timer_control函数会把50当作一个地址,然后取地址50处的存储器单元中的数据当做新的超时值,这个值是随机的无法预知的。
可以先定义一个变量并赋值为50,然后取这个变量的地址作为rt_timer_control()函数的参数。当然也可以改变函数的实现,在RT_TIMER_CTRL_SET_TIME情况下,将输入的void*指针参数类型转换为整型的超时值。

② 而且函数_tc_timer_control()中最后返回100,也就是整个例程只运行100个tick,在修改新的定时值50前程序会耗时10x8=80tick,剩下的20tick在新的定时值50下连一次超时都不能发生,测试程序不能反映出更改新的超时值50的效果,所以返回值应该大于130。

****
《RT-Thread实时操作系统编程指南》P135.
表中close项提到设备控制块中有一个ocount数据域,但是实际上在0.32、0.4版中都不存在这个数据域?

****
serial.c中函数rt_serial_write()存在BUG。
当串口使用中断发送模式时,如果发送缓冲空闲字节数大于要发送的数据的字节数,那么就可能会出现越界读取并将发送这不该发送的数据,因为while循环的结束条件只是发送缓冲是否满,并没有判断数据是否发送完毕。

****
建议:发布新得版本时,至少在发布稳定版时,能否随之发布个升级指导文档,以便老用户的应用升级。

****
《指南》P39,禁止中断的代码不可抢占吗?不一定吧!
如这样的情况下:低优先级的线程运行进入禁止中断区,在其中释放信号量等就可能导致挂起在此信号量上的高优先级线程就绪,并抢占低优先级的线程运行。

****
《RT-Thread实时操作系统编程指南》文字等错误
P43:最上方图中,“运行状态”指向“挂起状态”缺少箭头。
P61:“arg必须是一个线程控制块指针”中“arg”应为“thread”。
P105:“初始化邮箱”->“初始化内存池”。
P124:“脱离信号量使用以下接口”->“脱离定时器...”
bernard
bernard 2011-10-21
非常感谢你反馈的信息,一下反馈了很多,都有些看不过来了,谢谢。

今年六七月份的时候,在网上偶然发现国人的实时操作系统RT-Thread,令我欣喜无限。实验室正好一个项目需要做个网关,了解到RT-Thread已移入了TCP/IP协议栈LwIP,性能也不错,而且基于C的面向对象设计很有特色,就尝试使用了RT-Thread。现已做了一段时间,后来也一直关注着RT-Thread的发展,在此把开发过程中发现的RT-Thread的一些问题和建议反馈在这,希望对RT-Thread的发展有一点点点的帮助,不对的地方还请不吝赐教。

PS:如果能投入实际使用,我会向RT-Thread工作组申请License的,哈哈...



****
既然函数rt_thread_delay()与rt_thread_sleep()是相同的,就不要使用函数调用的方式编写函数rt_thread_delay(),只要将rt_thread_delay()使用宏替换为rt_thread_sleep()就好了,这样可避免由于函数调用而产生的额外的运行时间和空间的消耗,效率更高。
还有函数rt_sem_trytake()等类似。

这部分从兼容度来考虑,还是直接使用函数吧。如果是优化编译,编译器应该也能够处理这类情况的。至于是否最终采用#define宏定义的方式,会再行考虑下。


****
typedef定义的命名风格不统一。
有的typedef后加了后缀_t而有的没有。
对于加后缀的,指针加_t后缀,非指针类型的也加后缀_t,这样导致不能从类型名的字面上区分指针和非指针变量。
改进:
① 对于typedef定义,要么统一加后缀_t,要么都不加后缀_t。
② 区别指针与非指针,若加了后缀_t,则以_pt和_t区别,若不加_t,则以加_p和不加_p区别。

另建议,RT-Thread作为一个开源项目,从开源的角度来看,应该让编程的风格易于用户理解,提高可读性,下面附上Linux中代码风格说明中Typedef的部分,是不是能参考下。

能指出哪些是未包含_t的吗?这块想做大的修改,会有一定困难了。原则上都会使用_t的方式以标识出这个是一个typedef,但是由外部导入的部分则不会强制性的更改过来。



****
字符数组越界读取,虽然一般不会导致什么异常,但数组越界操作总是不好的,而且有些空间确实不能随便读取,否则会产生错误。
/* copy name */
for (temp = 0; temp < RT_NAME_MAX; temp ++)
{
object->name[temp] = name[temp];
}

因为object->name本身并不一定会以''做为终结符,所以这里是全长度的字符复制。


****
struct rt_object
{
char name[RT_NAME_MAX]; /* name of kernel object */
rt_uint8_t type; /* type of kernel object */
rt_uint8_t flag; /* flag of kernel object */
rt_list_t list; /* list pointer of kernel object */
};
其中type的类型直接使用枚举类型enum rt_object_class_type,这样更容易明白type的意义,虽然使用rt_uint8_t也一般不会出错。枚举类型实际上为整型,但是不同的编译器对枚举定义的长度是不一定相同的,可能并不是rt_uint8_t,当然编译器会自动截短长变量给短变量,但我觉得应该避免这种隐式类型转换。

另建议在合适的地方多使用枚举类型:若变量的取值的数值大小本身没有什么实际意义,而只是用于区分,或者只能取有限的、特定的值(如这些取值一般都使用#define的宏定义值),那么,若使用枚举类型的话,从变量的定义类型的字面就可以看出变量的意义,进一步的从枚举类型的定义处就可以知道该类型变量的所有取值范围,这样是不是可以使得程序有更好地可读性呢?

枚举类型的宽度确实是随编译器的不同而不同,但是object这里实际上是希望能够得到一个固定长度的类型,所以直接使用了rt_uint8_t来表示。


****
《RT-Thread实时操作系统编程指南》98页,“接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部”,从源程序看,实际上是空闲消息链表的“头部”,而不是“尾部”。
函数rt_mq_recv()中相关部分代码:
/* put message to free list */
msg-&gt;next = (struct rt_mq_message*)mq-&gt;msg_queue_free;
mq-&gt;msg_queue_free = msg;

《编程指南》中的一些表达、代码确实存在一些问题,这些会在书稿发给出版社的过程一一修正。多谢指出《编程指南》中存在的一些问题,如果您能够留下信箱,或给我发一封邮件,我很乐意提前把一些章节的书稿发给你做校审。后面针对《编程指南》就不再专门做回复了,我到时会一一合并到书稿中。


****
函数rt_mp_init()和rt_mp_create()中构建链表的操作部分
/* init free block list */
block_ptr = (rt_uint8_t*) mp-&gt;start_address;
for (offset = 0; offset &lt; mp-&gt;block_total_count; offset ++)
{
*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
}

*(rt_uint8_t**)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;

mp-&gt;block_list = block_ptr;

for()循环的边界减1,改为mp-&gt;block_total_count-1,可减少一次无意义的循环,相应倒数第2个语句改为
*(rt_uint8_t**)(block_ptr + offset* (block_size + sizeof(rt_uint8_t*))) = RT_NULL;
更改之后为:
/* init free block list */
block_ptr = (rt_uint8_t*) mp-&gt;start_address;
for (offset = 0; offset &lt; mp-&gt;block_total_count - 1; offset++)
{
*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
}

*(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;

mp-&gt;block_list = block_ptr;

在函数rt_mq_init()和rt_mq_create()中也有类似的构建链表的操作,使用的方法不如rt_mp_create()函数中的,循环中的计算量大,多次辗转赋值,且较之不易理解,可改为rt_mp_create()函数中的方法。
/* init message empty list */
mq-&gt;msg_queue_free = RT_NULL;
for (temp = 0; temp &lt; mq-&gt;max_msgs; temp ++)
{
head = (struct rt_mq_message*)((rt_uint8_t*)mq-&gt;msg_pool +
temp * (mq-&gt;msg_size + sizeof(struct rt_mq_message)));
head-&gt;next = mq-&gt;msg_queue_free;
mq-&gt;msg_queue_free = head;
}

确实可以考虑这样实现。


****
RT-Thread不能操作存在复用的逻辑中断下的物理中断。
S3C2440具有60个物理中断源,但在中断控制系统中源挂起寄存器SRCPND和中断挂起寄存器INTPND都是32位,即只有32个逻辑中断源,所以物理中断源与逻辑中断源为多对一的关系,存在多个物理中断源复用一个逻辑中断位的情况。
对于存在复用的逻辑中断源产生的中断,要判断产生中断的具体物理中断源则需要再查询辅助源挂起寄存器SUBSRCPND。相应的也存在中断辅助屏蔽寄存器INTSUBMSK。而RT-Thread中没有对这些辅助寄存器的操作接口,比如屏蔽复用逻辑中断源下的某个具体的物理中断源等。

这部分可以由BSP来提供、完善。


****
测试例程timer_control.c存在BUG,运行这个例程导致程序无法返回。
① 第23行:rt_timer_control(timer1, RT_TIMER_CTRL_SET_TIME, (void*)50);
此语句的本意是想改定时器的超时值为50,但参数表达式(void*)50显然是不能达到这个目的的,rt_timer_control函数会把50当作一个地址,然后取地址50处的存储器单元中的数据当做新的超时值,这个值是随机的无法预知的。
可以先定义一个变量并赋值为50,然后取这个变量的地址作为rt_timer_control()函数的参数。当然也可以改变函数的实现,在RT_TIMER_CTRL_SET_TIME情况下,将输入的void*指针参数类型转换为整型的超时值。

② 而且函数_tc_timer_control()中最后返回100,也就是整个例程只运行100个tick,在修改新的定时值50前程序会耗时10x8=80tick,剩下的20tick在新的定时值50下连一次超时都不能发生,测试程序不能反映出更改新的超时值50的效果,所以返回值应该大于130。

确实,一些测试例程还存在些问题,这部分应该会在1.0.0版本发布前做相应的更新。


****
《RT-Thread实时操作系统编程指南》P135.
表中close项提到设备控制块中有一个ocount数据域,但是实际上在0.32、0.4版中都不存在这个数据域?

****
serial.c中函数rt_serial_write()存在BUG。
当串口使用中断发送模式时,如果发送缓冲空闲字节数大于要发送的数据的字节数,那么就可能会出现越界读取并将发送这不该发送的数据,因为while循环的结束条件只是发送缓冲是否满,并没有判断数据是否发送完毕。

是那个平台分支的代码?


****
建议:发布新得版本时,至少在发布稳定版时,能否随之发布个升级指导文档,以便老用户的应用升级。

请参考wiki中相应的文档。


****
《指南》P39,禁止中断的代码不可抢占吗?不一定吧!
如这样的情况下:低优先级的线程运行进入禁止中断区,在其中释放信号量等就可能导致挂起在此信号量上的高优先级线程就绪,并抢占低优先级的线程运行。

没错,所以新的书稿上这部分会做相应的改动。


****
《RT-Thread实时操作系统编程指南》文字等错误
P43:最上方图中,“运行状态”指向“挂起状态”缺少箭头。
P61:“arg必须是一个线程控制块指针”中“arg”应为“thread”。
P105:“初始化邮箱”-&gt;“初始化内存池”。
P124:“脱离信号量使用以下接口”-&gt;“脱离定时器...”

[/quote]

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友