2011年 9月 1日到 9月 16日,快来发贴分享您在学习或工作中关于应用 TI MCU 产品(MSP430、C2000、Stellaris)的各种技巧与心得、各种疑问和不解。每篇主题不少于 150字,如果是技巧心得和疑惑的帖子,请详细写出获得心得的具体过程或者经过哪些步骤的试验仍未成功。
我们期望德州仪器在线技术支持社区为大家提供一个交流经验、互相学习的平台。每个 ID 不限制参与次数,但每个 ID 只有 1 次获奖机会。(TI工程师团队具有最终解释权。)
快来讲述您和 TI MCU 的故事,精巧 4G 名片 U 盘等您拿!
所有此次活动的贴子请在此主题贴下以“回复”形式发表!我们将以此主题下的发贴作为获奖信息!热切期待大家的参与!
qianlong wang:
中午休息,分享一下我自己在学TMS320F2812DSP遇到的一些小问题。纯粹自己理解,错误之处望见谅,多指正。
首先,是延迟函数的使用:在做电机调速时,发现自己用C简单编写的延迟delay函数,会出现实际延迟时间与程序设定时间误差较大的情况,查阅一些资料,发现可以利用例程里已有的延迟汇编文件,编写较为准确的延迟函数DELAY-US(),且调用简单可靠。具体步骤如下:1,下载DSP281x_usDelay.asm文件,将内容改为
extern void DSP28x_usDelay(Uint32 Count);
.def _DSP28x_usDelay
.sect "ramfuncs"
.global __DSP28x_usDelay
_DSP28x_usDelay:
SUB ACC,#1
BF _DSP28x_usDelay,GEQ ;; Loop if ACC >= 0
LRETR
放于工程的source中;
2,在MOTOR.H文件中定义
#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT)
#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) – 9.0L) / 5.0L)
3,在GlobalPrototypes.h中定义
extern void DSP28x_usDelay(Uint32 Count);
4, 在程序中直接调用DELAY_US(A),例如 DELAY_US(1000L);,表示延迟1ms 。
其次,是2812flash烧写的问题,具体步骤如下:(1) 下载烧写FLASH配套CMD文件、LIB文件以及起始代码asm文件。
CMD文件名称:DSP281x_Headers_nonBIOS.cmd
CMD文件名称:Flash.cmd
LIB文件名称:rts2800_ml.lib
ASM文件名称:DSP281x_CodeStartBranch.asm
(2)配置C文件
配置好主程序的C文件,才能将FLASH成功烧录,并且将FLASH中的文件拷贝到RAM中运行。
关于C文件的配置。
首先在F2812.CMD文件中,我们可以看到有关于加载FLASH到RAM的内容:
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
以及在C文件中调用FLASH 到RAM的函数memcpy,将它放在系统初始化(InitSystem();)之后即可:
InitSystem();
memcpy(&RamfuncsRunStart,
&RamfuncsLoadStart,
&RamfuncsLoadEnd – &RamfuncsLoadStart);
Initflash();
关于ramfuncs,则在系统初始化中定义即可。如:sysctrl.c中
#pragma CODE_SECTION(InitFlash, "ramfuncs");
(3)我们需要定义所用变量:
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
我的这些定义都是:DSP281x_GlobalPrototypes.h 当中,当然,也可以放在其他系统初始化的地方。
Memcpy这个函数应该是rts2800_ml.lib库文件中自带的,不需要我们定义。
(4)烧写成功后的注意事项:
1. 一定要拔除仿真器(JTAG端),给电路板重新上电,方能实现FLASH启动。
2. 注意MP/MC引脚的电压。0为方式MC来作为计算机模式启动,3.3V为方式MP作为微处理器模式启动。
3. 由于GPIO引脚的F4\F12\F3\F2决定了DSP2812的启动顺序,而从FLASH必须要在F4(SCITXDA)为1,而F12\F3\F2随意的状态下启动。请大家启动前确认F4引脚电压。
Viken Zhou:
工作之余,分享一下我自己在调试Stellaris MCU: LM3S3748时遇到的一个问题,带给大家,望入门者能够快速的解决问题。错误之处望见谅,请大虾们指正!希望能和大家共同进步! 我的QQ:2547457966,email: viken@126.com
问题1:关于在调试,SPI 时序时,遇到的问题。
现象,LM3S3748做主机使用,FM25L16-G为从设备,用示波器检测SPI的时序,主机发出的时序正常,从机就是不响应。
解决办法:
在 读/写 FRAM的子程序中,在发送命令或者数据后,置位 CS 线之前,加入适当的延时。
附解决问题的部分子程序,
void MSPI_Init( void )
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
SSIDisable(SSI0_BASE);
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | // GPIO_PIN_3 | GPIO_PIN_2);
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, //SSI_FRF_NMW, // SSI_FRF_MOTO_MODE_0
SSI_MODE_MASTER, 1000000, 8);
// Enable the SSI0 module.
SSIEnable(SSI0_BASE);
FM25H20_DeCS( );
}
uchar MSPI_Transfers( uchar data )
{
uchar i;
uchar RdData;
while( !( HWREG( SSI0_BASE + SSI_O_SR ) & SSI_SR_TNF ) ); // Wait until SSI Transmit FIFO Not Full .
HWREG( SSI0_BASE + SSI_O_DR ) = data; // Write the data to the SSI.
while( !( HWREG( SSI0_BASE + SSI_O_SR ) & SSI_SR_TFE ) ); // Wait until SSI Transmit FIFO is Empty .
for( i = 0; i < 200; i++ ); // Delay XX Cycle after set CS line.
RdData = HWREG( SSI0_BASE + SSI_O_DR );
for( i = 0; i < 200; i++ );
return RdData;
}
// Sets the Write Enable Latch
void FM25H20_WriteEnable( void )
{
FM25H20_CS( ); // Select Device
MSPI_Transfers( FM25H20_WREN ); // Write Enable Op-Code
FM25H20_DeCS( ); // Deselect Device
}
// Reads the Status Registeruchar FM25H20_ReadStatus( void ){ uchar temp; FM25H20_CS( ); // Select Device MSPI_Transfers( FM25H20_RDSR ); // Read Status Register OpCode temp = MSPI_Transfers( 0x00 ); // Read Status Register FM25H20_DeCS( ); // Deselect Device
return( temp ); }
xiaochuan guo:
回复 Viken Zhou:
我们现在开发的一款化工在线仪表。里面用到MSP430F2132IPW。这款产品确实好用。编程资料多,编程效率高,程序可读性强等优点使我们的工作效率大大的提高。它的稳定性和可靠性也是我们非常认同的。它的片内资源丰富,大大的简化了在线仪表的外围电路,进一步的提高了仪表的可靠性和抗干扰性能。MSP430F2132IPW确实是一款非常出色的单片机!我们在开发其他的仪表的时候还会选择它的!
Yong SHI:
回复 xiaochuan guo:
2000系列MCU算是伴随我成长的MCU。本科时候基本上什么实践应用的东西都没学过,只上过单片机的课程,但是也没有做过实验,那时候都不知道单片机除了51系列之外还有那么多种,更不要提什么DSP了,只记得老师上课时候提过现在本科生掌握了DSP,去找工作就很容易,因而觉得DSP应用应该是奇难无比的,就被吓倒了。
读研以后,一次老师给的任务是使用2406编程,那时候觉得是世界末日,一点不懂,而且2406是16位的MCU,许多数据处理起来要用汇编语言才可以。疯狂的从图书馆找书来看,问师兄,师兄说还是先把软件装好,连上小系统板一边仿真一边摸索比较快,可是那时候没明白师兄的话,觉得还是要看书,把芯片的结构、功能模块都看懂才行,后来事实证明“不听前辈言,吃亏在眼前”,走了许多弯路,浪费很多时间。
倒不是说理论不重要,当然要看,可是当你把CCS安装好了,小系统可以连接上,可以运行了,一方面可以给你增强信心,另外一方面,看不明白的地方结合实例运行运行,对理解非常有帮助。另外,对于许多初次接触DSP的人来说,不要被别人的话吓到。DSP功能强,但是功能强不代表难掌握,它就是一个控制器,和其他单片机没什么本质区别,功能强只会使他更加好用。
初次接触DSP的时候还要充分利用TI的技术支持,遇到身边人也没法解决的问题时,可以发邮件咨询,另外网站的设计支持里面有很多例程,非常实用。
adam zhao:
我一直在学习使用f2812。准确的说是在学习关于matlab与dsp在环仿真的方法。TI公司与matlab良好合作促成了对dsp更快捷的编程方式。利用maltab便捷的优化方法、控制方法,理论与实践得到完美统一。这个过程也需要一些过程和努力。对此我给出我的经验,仅供参考:
1匹配合适的ccs版本与matlab版本。
对于一上来接触这一块的人来说。可能不知道这个的重要性。但是的确非常关键
2dsp的flash写保护解锁
编程时往往会出现这样的情况:matlab成功生成程序,也连接上dsp了。但就是无法下载。这个原因就在于此。解决方法是在ccs中首先load gel,然后再去找flash对应的解锁选项。
3maltab中的模块不是想用就能用的。有些函数必须经过一定的变化才能使用
举一个我做过的例子:要实现一个已经训练好的神经网络,在编译中会报错这是因为神经网络模块内部会有一些算法不被支持。行之有效的解决方法就是将该函数在help中搜索找到可以替换的函数。
4注意采样时间问题。采样时间往往应该长于计算时间。
有其他问题可以qq:392803559
WEN ZHAO:
回复 adam zhao:
非常感谢TI为大家提供一个这么好的交流平台,由于我还只是一名研究生,对DSP还不是很精通,不过也希望能跟大家分享一点心得。
我曾使用过的DSP型号是TMS320F2812和TMS320F2808,项目内容是利用2者的CAN总线模块,组建一个数据采集系统,3点心得:
1.在用不同时钟频率的DSP组建CAN网络时,一定要注意CAN波特率的设置,由于CAN的波特率取决于系统时钟,系统时钟不同时,便会得到不同的波特率,造成各节点无法通信,一定要根据每个节点自身的时钟频率和计算公式进行设置。
2.调试2812时,最好不要在上电的情况下用示波器探头测试引脚,这么做比较危险,容易损坏芯片,我就发生了这样的悲剧,希望大家引以为戒。
3.关于2812的功耗问题,提醒大家在设计时予以考虑,虽然2812已经属于低功耗产品,但和一些常用的51单片机相比,功耗还是高出不少了,我当时就是没有考虑到这些,使用一片最大负荷250mA的7805为两个节点供电,CAN总线一开始通信就出错,经过长时间的测试才发现是电源供电不足,两个节点同时通信时,电源的供电电流需要将近200mA,我的7805无法正常工作,所以出错,希望大家注意。
水平较低,多多指教。
Xiaojun Deng:
第一次接触TI的MCU是刚参加工作的时候,主要是2808这款控制器,在网上疯狂下载资料、囫囵吞枣的看看,大概学习了一周以后就开始做项目的下位机的软件开发设计,对于全新的环境和复杂的寄存器操作,拿到任务时,开始有些手足无措,只能啃手册,上网搜索资料等,大概再用了1周时间,基本上熟悉了开发环境,能够写出一些实用的程序来了,做了一些控制相关的开发,没有什么可以聊的。
后来接触一些复杂项目,对于软件的实时性要求很高,中断占用了大量的CPU资源,开始重新架构软件,将部分中断中的程序放在中断外执行,去掉某些不必要的中断,减少压栈出栈的次数,经过这样的修改,极大的提高了系统的资源利用率,原来大概100us左右的频率的中断就来不及响应,修改后即使20us左右的频率的中断也没有问题。
还碰到一个问题,就是在中断中执行一个查找算法,这个循环最恶劣的·情况是循环10000遍,导致中断占用时间过长,其他中断无法及时响应,修改了查找算法,增加了一个读指针,每次只需要判断是否在查找的目标位置就可以了,极大的降级了时间复杂度,系统性能得到了根本性的提高。
从使用2808这款控制器以后,我觉得有以下几点切身体会:
1)从算法上优化,提高的性能是最多的!O(∩_∩)O~,数学很重要!
2)多做实验,实用仿真器是提高开发效率的好办法,前提是你有一个好的仿真器,别是那种质量很差的,如果你从椅子上站起来,旁边的仿真器就掉了,这样会搞死人的,本人深受其害啊!
3)不太建议从代码级去一点一点抠,去做优化,我觉得如果出现了这种情况,那么在前期评估的时候工作做得不到位。从代码级优化,可能花了大量的时间,而成果却很少,往往还达不到效果。
但是,我并不是说就不去了解和实践代码级优化,因为了解和实用这些,会提高技能,在以后编写代码的时候就将这些优化已经做好了,提高效率和工作质量。
ps.啰嗦了一点!
ke chen1:
回复 Xiaojun Deng:
今天碰巧看到了这则信息,来分享一下我学习LM3S811的趣事……
我是通过参加TI M3 DAY 获得LM3S811评估板的,拿到板子后心情很是激动,于是就立刻投入了学习中。
开始没有看任何PDF的介绍就尝试着把软件附带的例程下载进了芯片中,有一个例程是JTAG-GPIO,这个例程下进去后接着就不能再下载别的例程了,那时候估计是锁住了,心想这下完蛋了,可是当我重装了驱动后竟然奇迹般的好了,后来我认真地看了看《JTAG防锁死和LM3S系列几个基本例程》,还有看了看在网上找到了M3的资料,看后第一感觉是M3其实并没有传说中的那么难学,倒是感觉很容易学的。
仅仅玩单片机无非就是对寄存器的配置(比如PX=0X…),但是玩M3不是这样的,编写M3的程序时主要是对函数的调用,对有参函数进行参数设置和匹配以及灵活运用带有返回值的函数,但是一系列函数的原型我还无从得知,我猜应该在driverlib.lib中。
关于JTAG的防锁死功能其实是很简单同时又很有趣的:
#define KEY_PERIPH SYSCTL_PERIPH_GPIOC //宏定义 加强程序的可读性
#define KEY_PORT GPIO_PORTC_BASE
#define KEY_PIN GPIO_PIN_4
void JtagWait(void)
{
SysCtlPeripheralEnable(KEY_PERIPH); // 使能KEY所在的GPIO端口 (GPIO C)
GPIOPinTypeGPIOInput(KEY_PORT, KEY_PIN); // 设置KEY所在管脚为输入
if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) // 若复位时按下KEY,则进入
{
while(1); // 死循环,以等待JTAG连接
}
GPIOPinIntDisable(KEY_PERIPH,KEY_PIN); // 禁止KEY所在的GPIO端口中断
}
LM3S811评估板上用户按键是PC4 JtagWait函数放在主程序的首位置。
当复位后先判断按键,如果没有按下程序继续向下执行,如果按下则死循环等待。
试想一下如果将JTAG作为GPIO后程序将不能下载进去,如果程序中加入JtagWait函数,那么先按下复位键再按下用户键然后松开复位键(此时保持用户键按下少许),则此时程序停在while(1);处,这时候JTAG并没有作为GPIO,因为程序停在while(1);处而并没有执行后面的程序(后面的程序将JTAG当做GPIO使用了),然后接着下载你编好的程序(有时候会不太灵敏,多试几次就好了)
有了JtagWait函数后就不用再担心芯片被锁死了。
后来又编写了几个流水灯程序,算是稍稍入门了。(当然我觉得入门单片机的基础是学会 1时钟部分 2定时器 3中断) 呵呵 个人见解
前几天用M3做了一款乒乓球游戏(在TFT彩屏上面实现的)
做这款游戏使用到M3的内部资源有TIMER0和TIMER1及其中断、外部中断(用来进行键盘输入)等,游戏分为四关,每一关速度递增(通过配置晶振来实现)。
当然做的过程中也是遇到了好多困难。
比如开始时我的外部中断用的GPIO是PB0和PB1,老是不能进入中断导致球拍不能运动,后来发现PB0和PB1连接的是LED,后来把外部中断换为了PB2和PB3,总算好了。
//******************************GPIOB中断服务函数******************************************
void GPIO_Port_B_ISR(void)
{
unsigned long ulStatus;
ulStatus = GPIOPinIntStatus(GPIO_PORTB_BASE, true); // 读取中断状态
GPIOPinIntClear(GPIO_PORTB_BASE, GPIO_PIN_2|GPIO_PIN_3); // 清除中断状态,重要
if (ulStatus & GPIO_PIN_2) // 如果PB0 的中断状态有效
{
TimerEnable(TIMER1_BASE, TIMER_A);/*启动定时器1*/
racket_dir=0;/*球拍朝左运动*/
}
if (ulStatus & GPIO_PIN_3) // 如果PB1 的中断状态有效
{
TimerEnable(TIMER1_BASE, TIMER_A);/*启动定时器1*/
racket_dir=1;/*球拍朝右运动*/
}
}
…………
当球拍没有接到球后就进入死循环,后来想了一下为什么不把死循环换为睡眠状态呢,不错就睡眠状态,呵呵 低功耗嘛
今晚就先写到这里吧…………
Fumin Li:
分享TMS570LS 系列MCU的学习心得
由于这款片子推出时间不长,使用过的人也比较少。抽空写了这篇小小心得,希望这篇小小的心得能有益于打算在此平台开发或正在使用此平台开发的朋友们,此文仅作初次使用者入门级参考,更多高级应用等我以后整理好再与大家一起探讨。
1. 学习时使用的MCU型号:TMS570LS20216,当然也可以使用这个系列的其他型号
2. 学习中使用的硬件环境:
开发板1——TMS570 MCU Development Kit (TMDX570LS20SUSB,TMS570 Safety MCU Demo Board), 这是一个USB接口开发套件,这个开发板自带一个mini emulator—TI XDS100V2 USB JTAG Emulator,直接接到PC的USB端口就可以调试程序,通过这个开发板可以了解一下TMS570的ADC, NHET, CAN, SCI等模块,有点不足的就是这个自带的emulator调试程序效率不高;
开发板2——TMS570 MCU Development Kit (MCB board, motor control board), 这个板子功能比较强大, 调试程序速度也比较快, 含JTAG,ETM等接口,可以用来学习TMS570的所有模块,自带电机控制demo程序,建议使用这块板子来进行开发,稍微不足之处就是有很多外设引脚没有引出来,所以有些时候显得不太好测试;
仿真器——XDS510 USB,JTAG调试,如果使用开发板2来开发就最好使用此emulator;
3. 学习中需要使用的软件环境:
IDE— Code Composer Studio Version: 4.2.3.00004;
外设driver代码生成工具—HAL Code Generator version 2.09.000,Hardware abstraction layer code generator;
NHET Assembler—HET Simulator version 1.1;
NowECC– Ecc generator tool;
NowFlash—烧写程序用;
4. 学习中需要参考的文档:
Technical Reference Manual (TRM)– spnu489b.pdf;
TMS570LS Serial datasheet–tms570ls20216.pdf
还有一些从TI网站上download的application note文档。
5. 小小学习心得:
这里强调一句,文档要用最新的文档,由于就版本的文档有一些信息是错误的,当然新文档也有错误的,但要少点。我在学习EMIF module时,最开始由于看的是旧版本的TRM文档,越看越晕,这章写的不好;后来得到新版本TRM后就好多了,这样不会走弯路;另外,在看TRM时,结合HAL Code Generator一起来学习,这样能加速学习进度和理解;
6. 结束语
一点小小的经验供大家参考,抛砖引玉,其他更多应用等我整理后再与大家一起探讨;
jun shao2:
回复 ke chen1:
第一次接触MSP430单片机,总体感觉非常不错,功能强,耗电低,执行效率高,JTAG调试方便直观等等。由于以前一直习惯使用51系列单片机,所以刚开始用MSP430,因为其功能强大,的确费了些功夫学习。还好多亏TI提供了很多样例程序,帮了不少忙。鉴于其功能强大、集成度、高灵活性好等优点,相信对产品开发的有很大的便捷性。
借此机会也想交流下我在实际应用中碰到的一个问题。
以下是一段MSP430内部FLASH应用样例程序,不过在调试过程中,程序可以完美的执行完前半部分,后半部分无法正常执行,暂时还没研究出是什么原因。本人用的是AQ430软件编程调试。
//****************************************************************************
// MSP-FET430P140 Demo – Flash In-System Programming, Copy SegA to SegB
//
// Description: This program first erases flash seg A, then it increments all
// values in seg A, then it erases seg B, then copies seg A to seg B.
// Assumed MCLK 550kHz – 900kHz.
// //* Set Breakpoint on NOP in the Mainloop to avoid Stressing Flash *//
//
// MSP430F149
// —————–
// /|\| XIN|-
// | | |
// –|RST XOUT|-
// | |
//
// M. Mitchell
// Texas Instruments Inc.
// Feb 2005
// Built with IAR Embedded Workbench Version: 3.21A
//******************************************************************************
#include <msp430x16x.h>
unsigned char value; // 8-bit value to write to segment A
//unsigned char DataBuffer[128];
// Function prototypes
void write_SegA (unsigned char value);
void copy_A2B (void);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
FCTL2 = FWKEY + FSSEL0 + FN0; // MCLK/2 for Flash Timing Generator
value = 0; // Initialize value
while(1) // Repeat forever
{
write_SegA(value++); // Write segment A, increment value
copy_A2B(); // Copy segment A to B
_NOP(); // SET BREAKPOINT HERE
}
}
void write_SegA (unsigned char value)
{
unsigned char *Flash_ptr; // Flash pointer
unsigned int i;
//unsigned char *Flash_ptr2; // Flash pointer
Flash_ptr = (unsigned char *) 0x1080; // Initialize Flash pointer
FCTL1 = FWKEY + ERASE; // Set Erase bit
FCTL3 = FWKEY; // Clear Lock bit
*Flash_ptr = 0; // Dummy write to erase Flash segment
FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
for (i=0; i<128; i++)
{
*Flash_ptr++ = value; // Write value to flash
}
FCTL1 = FWKEY; // Clear WRT bit
FCTL3 = FWKEY + LOCK; // Set LOCK bit
}
//无法正常实现以下部分程序功能,不知道是不是编程软件原因
void copy_A2B (void)
{
unsigned char *Flash_ptrA; // Segment A pointer
unsigned char *Flash_ptrB; // Segment B pointer
unsigned int i;
Flash_ptrA = (unsigned char *) 0x1080; // Initialize Flash segment A pointer
Flash_ptrB = (unsigned char *) 0x1000; // Initialize Flash segment B pointer
FCTL1 = FWKEY + ERASE; // Set Erase bit
FCTL3 = FWKEY; // Clear Lock bit
*Flash_ptrB = 0; // Dummy write to erase Flash segment B
FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
for (i=0; i<128; i++)
{
*Flash_ptrB++ = *Flash_ptrA++;
//DataBuffer[i] = *Flash_ptrA++;
//*Flash_ptrB++ = DataBuffer[i]; // Copy value segment A to segment B
}
FCTL1 = FWKEY; // Clear WRT bit
FCTL3 = FWKEY + LOCK; // Set LOCK bit
}