-
seanwaye 发表于 2017-4-14 10:37
ucosIII是你说的这个方法,ucosII还是直接给堆栈的首地址,应该直接移植ucosIII就好了,头脑发热想尝试下 ...
应该新版有改进,
要低耦合高内聚才能易于使用
-
seanwaye 发表于 2017-4-13 23:19
其实我们传递给堆栈初始化函数的堆栈首地址是&tastk_stk,所以应该就是 * (p_stk ) = ( INT32U ) 0x01 ...
对的!,真没想到这么有名气的OS也有这种低级BUG
创建任务的函数应该只需要使用者提供栈首地址与栈字节大小即可,剩下的事情与使用者无关!或者仅提供栈大小,OS自动分配
-
本帖最后由 samos2011 于 2017-4-13 18:47 编辑
如果官方代码就是这么写的,那只能呵呵了!
如果OSTaskStkInit函数之后到任务运行前堆栈指针不变,那这段代码就绝对有BUG.
p_stk= ( OS_STK * ) ( ( OS_STK ) ( p_stk ) & 0xFFFFFFF8u ); 这句话的意图明显是对其8字节,但函数退出时又变成没有对齐.除非另外有改变指针的地方.
ARM堆栈向下生长,* (p_stk)=0x01000000uL虽然也可以,但结果就是非8字节对齐(也不符合CPU入栈步骤,ARM先将堆栈减4再写入内容,出栈时先读内容再加4),如果这样也能运行,那么OSTaskStkInit函数的ptos参数应该是这样求出的(&buff[size]),不然就会破坏其它内存.
如果你细心也许发现启动代码都是将初始MSP设置为内存的结尾,这个值必须先减4才能写入内容,可想而知
正规写法应该是:ptos的初始值为(栈内存起始地址+栈字节大小),
使用* (--p_stk)=0x01000000uL 包行,且必须这样写,否则也会破坏其它内存.
-
按规定,堆栈必须8字节对齐,也就是进入任务函数的第一条语句时必须8字节对齐,这是OS必须要遵守的,如果你的源码是没修改过的,应该不会出现这个错误,你可以仿真,在汇编窗口找到任务的入口,在此断点,查看此时PSP的值是否8字节对齐
但你的 OSTaskStkInit 函数貌似有问题,p_stk 指针只减了15次,要偶数才对,
* (p_stk ) = ( INT32U ) 0x01000000uL; 这句应该有问题
* (--p_stk ) = ( INT32U ) 0x01000000uL; 这样才对
所以你去掉了对齐语句就刚好8字节对齐了,但不明白这样也能运行,没用过这个OS,
建议你用RTX.如果你不考虑代码会运行在非ARM内核上的话
-
将任务printfTask略修改一下
int x = chanelDataArray[i]; // 增加这一句,C语言可能需要将定义移至函数的前面
R = x/8388607.0/8*2*810+180;
printf("%5.2d , %4.2f ;", x, R);
// 只要chanelDataArray[i]是整型,基本可以解决打印混乱的问题
// 请不要怀疑RTX
-
淡定独钓翁 发表于 2016-6-20 16:28
学习了,感谢分享…………
几句代码而已,不客气
-
虽然没详细看,但楼主的分享精神应该要有掌声
-
ybbrdfxk0922 发表于 2016-5-31 14:16
好厉害!膜拜
不用膜拜,你研究透这几行代码以后你也可以自己编写RTOS了
-
louis_xm 发表于 2016-5-28 14:37
高手。值得学习研究。
谢谢,单步执行,研究精髓.
其它OS入门太难,我这个精简到只有160行,能有多难!
-
21楼说的很好,应该要这样做!使用queue就对了
-
板凳,顶{:1_103:}
-
本帖最后由 samos2011 于 2016-5-24 17:17 编辑
如果是切换到一个新创建的任务没有问题而切换到一个已运行过的任务时有问题则是上下文保存不正确
给个容易理解的例子给你:
// 假设C代码有以下定义
typedef struct TCB{
//...
void* stack; // 任务栈顶地址 汇编使用,offset 0x0C
//...
}TCB;
struct _OS{
TCB* run; // 正在运行的任务 汇编使用,offset 0x00
TCB* rdy; // 就绪的任务 汇编使用,offset 0x04
// ...
}os;
;***************************************
; * @brief 任务切换宏,使用了R0,R1,R2,R3寄存器
;***************************************
MACRO
OS_TASK_SWITCH
; os.run->stack = SP;
LDR R2,=os
LDR R1,[R2,#0x0]
MRS R3,PSP
STR R3,[R1,#0xC]
; os.run = os.rdy;
LDR R0,[R2,#0x4]
STR R0,[R2,#0x0]
; SP = os.rdy->stack
LDR R1,[R2,#0x4]
LDR R0,[R1,#0xC]
MSR PSP,R0
MEND
;****************************************
; * @brief 【PendSV异常处理】
;****************************************
PendSV_Handler
PUSH {LR}
MRS R0,PSP
STMFD R0!,{R4-R11}
MSR PSP,R0
BL OS_Sched ; C语言任务调度
OS_TASK_SWITCH
MRS R0,PSP
LDMFD R0!,{R4-R11}
MSR PSP,R0
POP {PC}
复制代码
-
uart的发送与接收,can,tcp/ip协议栈,等等,都离不开queue
-
再次总结一下昨天的测试结果,有以下代码,ARMCC编译器
short x;
// p无论是什么类型的指针或是不是指针都不影响汇编代码
void f1(short* p) {
x = (short)p; // 前者
}
void f2(short* p) {
x = *(short*)&p; // 后者
}复制代码
前者当p为指针时只有在类型为int时编译器才不会警告 当 (short)p (char)p 都会警告
后者都没有警告,
虽然汇编的最终结果一样,但如果非要这样用,且不能接受编译器警告,为了消除警告,恐怕要写成这样: (short)(int)p; 当p为形参时汇编结果非常高效:
0x10000516 4919 LDR r1,[pc,#100] ; @0x1000057C
0x10000518 8048 STRH r0,[r1,#0x02]复制代码
(short)p同样也是上面的汇编结果,只不过编译器警告!
后者写法虽然复杂,但没有任何错误,对一个变量取地址,再通知编译器按新的方式读取里面的内容,无论这个变量是什么类型,是不是指针,得出的汇编代码也都一样!
由于取地址是个伪操作,意思可以简化为,(编译器:请将这个内存地址的内容按新的方式对待,并读取来),只不过汇编代码显得有些复杂.可能是编译器优化得不够狠!
前提条件是,编程者要知道这个地址里面的东西是什么!
基于这个前提,再看前者写法,意思为(编译器,将这个变量的内容读出来,按新的内容对待,)于是,编译器发现变量是指针,里面的内容是地址,而你却明显不当地址用,直接警告你
后者写法则绕过了编译器的这个判断.
论性能,我喜欢前者,但为了哄编译器,不得不写成这样(short)(int)p
-
本帖最后由 samos2011 于 2016-2-17 15:00 编辑
辛昕 发表于 2016-2-17 14:40
别闹了,跟我回家。
完全暴露出和我半斤八两的水平,咱跑吧,别在这丢人了。
这帖子接下来的时间交给 f ...
我们都不是研究编译器的,也没有在那个编译器手册中看到这方面的规定
在32位机下 xx = *(long long*)&GPIOx; 同样给出警告 warning: C4487E: read from variable 'GPIOx' with offset out of bounds
也许ARMCC默认了,只是是将指针变量转换为整型,就默认允许,否则就是非常规应用,就给出警告!
free叔我可惹不起!祝他新年快乐!
-
本帖最后由 samos2011 于 2016-2-17 14:40 编辑
有以下代码:
char xx;
void GPIO_DeInit1(GPIO4_TypeDef* GPIOx) {
xx = (char)GPIOx;
}
void GPIO_DeInit2(GPIO4_TypeDef* GPIOx) {
xx = *(char*)&GPIOx;
}复制代码
在32位机测试结果如下:(ARMCC编译器,优化级别-O0,-O1,-O2,-O3都一样)
xx = (char)GPIOx;
0x10000558 4919 LDR r1,[pc,#100] ; @0x100005C0
0x1000055A 7008 STRB r0,[r1,#0x00]复制代码
前者虽然效果非常好,但编译器给出警告: warning: #767-D: conversion from pointer to smaller integer
xx = *(char*)&GPIOx;
0x1000055E B501 PUSH {r0,lr}
0x10000560 4668 MOV r0,sp
0x10000562 4917 LDR r1,[pc,#92] ; @0x100005C0
0x10000564 7800 LDRB r0,[r0,#0x00]
0x10000566 7008 STRB r0,[r1,#0x00]
0x10000568 BD08 POP {r3,pc}复制代码
最终结果还是一样
当把char修改为int型,编译器才能对这句xx = *(char*)&GPIOx优化
xx = (int)GPIOx;
0x10000516 4919 LDR r1,[pc,#100] ; @0x1000057C
0x10000518 6048 STR r0,[r1,#0x04]复制代码
xx = *(int*)&GPIOx;
0x1000051C 4917 LDR r1,[pc,#92] ; @0x1000057C
0x1000051E 6048 STR r0,[r1,#0x04]复制代码
对于这个编译器警告,我猜想,编译器认为不应该把指针变量(即内存地址)强制转换为小于这个地址宽度的值,地址就应该当地址用,不要破坏地址
通过你们的争论,让我对这两个写法产生了好奇,至于用那种,没有警告没有错误就行!
-
(uint32) GPIOx 还是 *(uint32_t*)&GPIOx
如果GPIOx是形参,无论哪种写法,得出的汇编都一样,都是直接取R0,
如果GPIOx 是全局变量,汇编结果也是一样,都是取GPIOx变量的内容
如果GPIOx变量存放到0x10001000,直接取0x10001000里面的内容
编译器非常聪明,认为对指针变量X取地址A再取A里面的内容和直接取X里面的内容是一样的!
-
RTX4.73 编译消息: 生成.lib文件
RTX_Blinky项目,使用刚才生成的.lib文件,
编译输出:
VS2015新增的快速预览定义功能,非常好用,请看下图:
用VS2015阅读代码是非常爽的!
-
本帖最后由 samos2011 于 2016-2-16 17:16 编辑
不支持jlink,本人很少使用jlink仿真,我有其他debug方式,jlink仅用于第一次烧录程序
其实有.axf文件就可以使用keil仿真了,而且不需要完整代码,可度娘搜索相关关键词!
其实开发过程中大部分时间都是在编写代码,阅读代码,能改善这个我就满意了!
-
本帖最后由 samos2011 于 2015-10-27 11:25 编辑
建议使用RTX
Cortex M版本的RTX源码就在你的C:\Keil\ARM\RL\RTX\SRC\CM目录下
海量例程就在你的C:\Keil\ARM\Boards\目录下的 RTX_Blinky文件下
楼主使用STM32,那么就参考C:\Keil\ARM\Boards\ST\STM32-Discovery\RTX_Blinky下的例子
帮助与参考文档在:C:\Keil\ARM\Hlp\rlarm.chm
你分分钟就可以学会使用
RTX是专为Cortex-M写的,没有之一!其他的全是垃圾!