从 Kinetis 的 sample code 中的一个例程说起

发布时间:2013-8-27 14:39    发布者:绝对好文
关键词: Kinetis , 例程
作者:allen_zhan  

[前言]


在前文"关于 FREESCALE 的 DEMO 中 PSOR与PCOR 操作的常见错误 "中, 我们讨论了 kinetis L series 的 Sample 中容易出现的, 关于 PSOR 的常见错误, 我们分析, 这种错误, 大致可能与未曾熟读 RM 有关.

在之后对 kinetis L series 的 samples 继续短暂的了解过程中, 我们发现参考例程其他的较明显的错误, 或者说不足疏漏之处.

因其常常表现为 uController 的新生容易发生的错误, 故我想称其为"初学者错误", 或者说是"初学者不足".

[例程]
让我们引 Blinky sample 中的, 开启 Interrupt 的例程作为例子, 如下图例1:

[图例1: Blinky sample 中的使能例程]

1.jpg

这个例程, 让我们觉得不能沉默以对.

因为, 作为 Freescale 官方例程, 可能类似的代码会被我们国内的初学者诸君, 作为效仿的对象. 从而产生错误的引导效果, 不利于我们工程师的自我完善和提升.

[可能的疏漏或错误]
这里我们想主要指出, 这段短短的例程中可能出现的 4 个不足:

(1) 首先, 这个 (irq%32) 浪费代码空间并影响效率.
    -- 其本质原因, 可能存在着逻辑上混淆不清.

(2) 其次, IRQ的值域为: [0, 31]. 而该 code sample 却允许对 32 的计算.
    -- 其本质原因, 应该是未作越界(边界)检查. 并未仔细阅读 Register bit field定义.

(3) 第三, 对 irq=31 时的可能情况, 也就是 (1<<31) 的情况, 毫无敏感.
    -- 这里毫无敏感的意思, 大致反应为: (a) 对有符号数与无符号数区别不敏感, (b) 对左移操作不敏感.

(4) 第四, 正如同我们在 PSOR 中分析到的 |= 错误, 在这段简单的例程中, 仍然存在 ICPR 在 bit 被 write 0时无任何影响,  ISER 在 bit 被 write 0 时无任何影响. 都应该改为 =.

[讨论(1<<31)的特例]

让我们用例子来讨论这个 (1<<31):
(1) 首先, IAR 中定义的常量, 都是有符号的 int 类型.

这个前提为大家公认, 但是我没有找到出处```
麻烦读到此处的同行, 能给我一个出处链接, 或者是 IAR help documentation 中的说明. 蟹蟹.

(2) 有符号数 1, 在左移 31 bit 后, 将导致符号位被置1, 也就是计算得到一个负整数.

如果我们只看这里 NVIC_ICPR |= 1 << 31; 似乎没有影响到最终逻辑结果.
但是, 其真实原因是, 该负整数被强制转化为 unsigned int 的结果, 也即是最终正确的 0x80000000.

但这并不表示, coder 清楚这个结果是由强制转换产生,

从这段代码本身, 我们合理判断该 coder 将分不清下面代码的执行结果, 也就是容易犯一些"初学者错误".

比方说: 我怀疑该 coder 会毫无自觉写出下面的代码:
if( (1<<31) > 1 ) { do what he wants; }

显然我们知道, 这片代码永远不能为真, 去执行 what he want to do.

(3) 根据图例2, 我们对 (1<<31) 进行详论:

[图例2: Allen 随手编码给出3个例子讨论 (1<<31) ]

2.jpg

我们把3个例子的结果, 都有注释, 可以见到:
(a) (1<<31) 的值, 不是正数 0x80000000, 而是负数 -2147483648.
(b) (1u<<31) 的值, 才是 0x80000000.
(c) 条件比较语句, 首先是两边转化为同类型才能比较. 由于无符号数优先级高于 int, 故 (1<<31) 被强制转化为 unsigned int, 也就是 0x80000000, 用于比较, 导致和 sample1 的结果截然不同.

上面3个例子, 清楚表明了 (1<<31) 的值为何(如果我有任何错误请告诉我).

[我们修改的代码]
因此, Allen 尝试修改这个例程如下, 见图例3:

[图例3: 被修改后的例程]

3.jpg

[结论]
我们通过对一个 enable interrupt 例程的修改, 讨论了 firmware programmer 可能容易犯的问题, 主要有:
(1) 不能熟读 datasheet, 了解 register 的具体用法.
(2) 代码逻辑混乱.
(3) 忽视边界检查.
(4) 对有符号和无符号数区别不够重视.
(5) 不了解左移时牵涉符号位的特例.
(6) 不清楚在条件比较时强制转换现象.

上述问题, 一般多见于 uController 的初级选手.

作为公司新晋员工, 或者任何致力于 MCU code 实现 application 的新进同行们, 可以将上述错误作为范例保存而自省.

另外, 我们说不定应谨慎检阅各种 Freescale 给出的 kinetis L series 的参考 samples, 反复测试, 可能避免出货后造成不可预料之损失.

本文地址:https://www.eechina.com/thread-120005-1-1.html     【打印本页】

本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。
您需要登录后才可以发表评论 登录 | 立即注册

厂商推荐

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表