This article explains how to tackle conversion of projects distributed by TI, usually for IAR Embedded Workbench or Code Composer Essentials, into projects that compile, link, and then work in CrossStudio. This article considers only IAR Embedded Workbench.
Although this article addresses projects provided by TI, it's useful when you are converting any project from Embedded Workbench to CrossWorks.
Where to start?
CrossWorks is mostly compatible with IAR's Embedded Workbench at the source level. In fact, TI have been making Code Composer Essentials compatible with Embedded Workbench at the source level too. So we recommend that you start converting an IAR EW project rather than a CCE project and we don't consider CCE further.
There are three distinct steps to getting an EW project to work under CrossWorks:
- Convert assembly language source files to assemble under CrossWorks.
- Convert C source files to compile under CrossWorks.
- Make changes to assembly language source files to account for calling convention changes.
After step two, you should have something that compiles and links but possibly does not work. After stage three, everything should work.
Making assembly language source files assemble
The format of CrossWorks assembler source code is mostly compatible with EW, but there are differences in naming conventions and directives. We'll set aside calling conventions for the moment and focus on simply getting EW source code to compile and link under CrossStudio.
Remove redundant directives
Delete all source lines that start with MODULE or RTMODEL as these are not required and have no equivalent in CrossWorks.
Change public symbol names
All symbols that are mentioned in PUBLIC directives should have an underscore prepended to them; CrossWorks maps the C object "foobar" to the assembly-level symbol "_foobar". You will also need to change all occurrences of that symbol name in the assembly source code itself, so it's best to do this mechanically using a search-and-replace with whole-word case-sensitive matching.
Deal with section name differences
EW uses different section naming conventions to CrossWorks. It's a simple matter of replacement in most cases.
- Replace RSEG DATA16_N with BSS.
- Replace RSEG CODE with CODE. (However, see below!)
- Replace COMMON INTVEC with VECTORS.
After making these changes, the source code should compile and link. If not, please get in touch with us by adding a comment to this article and I'll update it!
Making C source files compile
The CrossWorks C compiler accepts plain old C just like the EW C compiler does. There are differences, of course, where both compilers deviate from the C standard for real-time work (interrupts) and data layout (structure packing, bitfields, and so on).
Change assembly source for calling convention differences
EW and CrossWorks have different views on parameter passing, so if you are calling C functions from assembly code, or assembly code functions from C, you must pay attention to the way that registers are used.
Bootnote
If you find errors in this article, please drop us a note or add a comment.
Example Project
As an example of what we have discussed here, I modified TI's SLAA307a application note sources and have attached them here.
You will find the original application note in PDF and the associated code files for IAR at:
http://focus.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=slaa307a
Comments
14 comments
Hello,
I've converted the zasa demo software from TI for the ez430-rf2480 kit from IAR to CrossStudio, and it now compiles error-free. However when I load the executable into the device it hangs and the debugger can't access it. I suspect the issue has to do with the translation of the interrupt-related functions (EINT, DINT, and the interrupt handlers). Have you gotten this to work, and if so, how?
The original IAR source used a series of macros to inject assembler opcodes into the instruction stream; I converted them as follows:
Original IAR interrupt handler:
INTERRUPT_PORT2()
{...
Converted to:
void isrPort2(void) __interrupt(PORT2_VECTOR)
{...
Shouldn't that work?
Thank you.
Hi,
I've not come across that software. I'd need to looik, but on the face of it your translation looks correct. I believe you should now have less work to do because we now support #pragma vector for IAR compatibility. I really wish we could all agree on a standard set of things so TI examples compile on CCE, CrossWorks, and EW, but I think the way things are going is that CCE and CrossWorks will be trying to be as close to IAR's syntax as possible.
I have an action item to put together a project file for SimpliciTI, so I'll take a look at the software you've highlighted and see what I can make of it.
Thanks Paul. Hey, one other question: when I Debug/Run on the MSP430 emulator and I stop the debug session, how do I know where in the source the code was looping when it was stopped? The source window doesn't seem to show me that. If I can figure that out, I would be happy to send you the details for what I had to do to get it to work! Steve.
No sign of life when is usually when the processor goes into low power mode. If you break (Debug > Break) rather than stop then you should be able to see where the processor has stopped. If it doesn't locate to a source line then there's no debug information (which is strange, but hapens in release mode). In this case take a look at the registers window to see the PC and then the disassembly window to see where it stopped.
Hi Paul,
Well, I'm using the internal CrossStudio MSP430 emulator as a target, building for an MSP430F2274 in DEBUG mode. The code compiles correctly and begins executing (on the emulator) continuously burning cycles. When I PAUSE DEBUG, the Disassembly window shows I'm executing in low memory (eg. 0x0000-0x15C). I know we should never be executing down here...so I checked the MSP430F2274.xml file and all seems to be in order (flash at 0x8000, ram at 0x200, etc...)
Do I need to specify an entry point to the compiler? I have a main() function in my code.
By the way, I put a breakpoint at the start of main(), and it never hits. Any ideas?
Thanks again,
Steve.
Sounds like something went wrong. If you're jumping to zero for some reason, you could always place a breakpoint at 0 (use New Breakpoint) which stops the CPU and then see how you got there. Or step frlom the start, which is what I'd do, to see where things go wrong.
Should say, in CrossWorks V2 if you're attached, F11 will start the application and stop at the first INSTRUCTION, F10 will start the app and stop at main() and F5 will start the app and run to the first breakpoint (unless configured differently).
HI Paul,
I am very interested in the SimpliciTI code/conversion. I an evaluating Crossworks now and would love to use it with the CC2520 Dev kit. So any information would be greatly appreciated. Thanks.
Hello everyone, my name is Danilo, I'm from Brazil, I'm a electrical engineer student ! i want to contact Steve Curd for the ez430-rf2480 ZASA code ported to CrossStudio! i would really appreciate it, I'm doing my graduation conclusion paper work, and it would really help me out!! Thank you!
Danilo Pozzi
danilopozzi@gmail.com
Hi Danilo,
I was able to get the SimpliciTI code to work by including the crt0.asm file...turns out this was the cause of the invalid startup address problem. However, I am no longer using CrossStudio after my brief evaluation. I'm waiting for the next project, and I'll dig in deeper! Thanks Paul for your support.
I finally took the time to document how I converted the TI ez430-rf2480 zasa code to successfully compile and link under the CrossWorks IDE. I can zip up all the source files, if anyone wants them... In the meantime, here's the step-by-step for the way I did it:
* Converting zasa from IAR to CrossWorks *
common\zaccel\cc2480.h
target\cc2480\hal_board.c
target\cc2480\hal_board.h
target\include\hal_defs.h
target\include\hal_types.h
Program Files\IAR Systems\Embedded Workbench 4.0\430\inc\msp430.h
common\mt\mt.c
common\mt\mt.h
ZASA\source\sample_app.c
ZASA\source\sample_app.h
ZASA\source\sample_main.c
ZASA\source\sample_app.cfg (not used, but we'll be stealing some of the definitions from this file)
common\zaccel\sapi.c
common\zaccel\sapi.h
common\zaccel\sapi_cb.c
common\zaccel\spi.c
common\zaccel\spi.h
common\zaccel\zaccel.c
common\zaccel\zaccel.h
Copy all of these files into a single source directory (I created and used "c:\dev\zasa 2\source")
Run CrossStudio 2
(if you haven't already, load the "Texas Instruments MSP430 CPU Support Package" from the "Tools/Package Manager…" menu)
Create a new project (File/New/New Project)
Click "Create the Project in a New Solution"
Click "A C Executable"
Fill in your project Name (I used "zasa 2")
Browse to the root directory Location where you created the "source" folder above (for me: "c:\dev\zasa 2")
Click "Next"
Select "MSP430F2274" from the Target Processor flip-down
Click "Next"
Leave "crt0.asm" checked in Links to system files, but uncheck "main.c" in the Project files (the project already includes a main)
Click "Next"
Leave MSP430 debug and MSP430 release checked
Click "Finish"
Use the CrossStudio Project Explorer (right side of the screen; if it's not visible, click "View/Project Explorer" or hit Ctrl/Alt/P). Expand your Project ('zasa 2'), and expand "Source Files". Right click "Source Files", and select "Add existing file…". Navigate to the directory where you copied the source files; you might have to click the "Files of type:" flip-down and select "C Files (*.c,*.h)". Shift/Select all of your .c and .h files from this directory and click "Open".
Now, all of your source and header files (total of 18) should appear in the Project Explorer window under Source Files.
Now the real work begins…
In hal_board.c
Comment out lines 62-65 to eliminate the IAR interrupt pragmas:
//#define _PRAGMA(x) _Pragma(#x)
//#define HAL_ISR_FUNC_DECLARATION(f,v) _PRAGMA(vector=v) __interrupt void f(void)
//#define HAL_ISR_FUNC_PROTOTYPE(f,v) _PRAGMA(vector=v) __interrupt void f(void)
//#define HAL_ISR_FUNCTION(f,v) HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v)
Comment out lines 140-143 to eliminate the funky IAR interrupt handler definitions:
//#define INTERRUPT_PORT1() HAL_ISR_FUNCTION(isrPort1, PORT1_VECTOR)
//#define INTERRUPT_PORT2() HAL_ISR_FUNCTION(isrPort2, PORT2_VECTOR)
//#define INTERRUPT_TIMERA() HAL_ISR_FUNCTION(isrTimerA, TIMERA0_VECTOR)
//#define INTERRUPT_ADC10() HAL_ISR_FUNCTION(isrADC, ADC10_VECTOR)
Comment out lines 148-149 (ditto):
//#define INTERRUPT_RX0() HAL_ISR_FUNCTION(isrRx0, USCIAB0RX_VECTOR)
//#define INTERRUPT_TX0() HAL_ISR_FUNCTION(isrTx0, USCIAB0TX_VECTOR)
At line 635, comment out INTERRUPT_PORT1() and replace it as follows:
//INTERRUPT_PORT1()
#pragma vector=PORT1_VECTOR
__interrupt void isrPort1(void)
At line 664, comment out INTERRUPT_PORT2() and replace it as follows:
//INTERRUPT_PORT2()
#pragma vector=PORT2_VECTOR
__interrupt void isrPort2(void)
At line 691, comment out INTERRUPT_TIMERA() and replace it as follows:
//INTERRUPT_TIMERA()
#pragma vector=TIMERA0_VECTOR
__interrupt void isrTimerA(void)
At line 758, comment out INTERRUPT_ADC10() and replace it as follows:
//INTERRUPT_ADC10()
#pragma vector=ADC10_VECTOR
__interrupt void isrADC(void)
At line 916, comment out INTERRUPT_RX0() and replace it as follows:
//INTERRUPT_RX0()
#pragma vector=USCIAB0RX_VECTOR
__interrupt void isrRx0(void)
At line 950, comment out INTERRUPT_TX0() and replace it as follows:
//INTERRUPT_TX0()
#pragma vector=USCIAB0TX_VECTOR
__interrupt void isrTx0(void)
In hal_board.h
At line 47, add the header file for the CrossWorks MSP Intrinsics:
#include <inmsp.h>
At line 106 (start of the Typedefs), define the istate_t type:
typedef unsigned short istate_t;
At line 127-128, change HAL_ENABLE_INTERRUPTS() and HAL_DISABLE_INTERRUPTS to use the CrossWorks functions:
//#define HAL_ENABLE_INTERRUPTS() asm("eint")
#define HAL_ENABLE_INTERRUPTS() __enable_interrupt()
//#define HAL_DISABLE_INTERRUPTS() st( asm("dint"); asm("nop"); )
#define HAL_DISABLE_INTERRUPTS() __disable_interrupt()
At line 133-135, modify the CRITICAL_SECTION macros to remove __get_interrupt_state as follows (we don't need it with CrossWorks!):
#define HAL_ENTER_CRITICAL_SECTION(x) \
st(x = /*__get_interrupt_state(); */ HAL_DISABLE_INTERRUPTS(); )
#define HAL_EXIT_CRITICAL_SECTION(x) __set_interrupt/*_state*/((x))
In hal_defs.h
At Line 40 insert a few required definitions (these were originally in the sample_app.cfg file):
#define ZACCEL_BUF_LEN 128 // standard=256, but reduced to save RAM
#define HOST_MT 1 // to include code for UARTS; change to 0 to save space
#define HOST_MT_BAUD 9600 // 9600 is max supported by the TI USB dongle
#define HOST_MT_RX_OLD 1 // seconds since last Rx to trigger event (0=disabled)
#define HOST_MT_RX_FULL (ZACCEL_BUF_LEN-1) //Max Rx count to trigger event
In zaccel.h
At line 59 insert the definitions for the ZigBee PANID and the list of ZigBee channels (these were originally in the sample_app.cfg file):
#define ZACCEL_NV_PANID 0xFFFF // any value other than 0xFFFF forces the value
//#define ZACCEL_NV_CHANLIST 0x04000000 // 26 - 0x1A // ZigBee channel selection
//#define ZACCEL_NV_CHANLIST 0x02000000 // 25 - 0x19
//#define ZACCEL_NV_CHANLIST 0x01000000 // 24 - 0x18
//#define ZACCEL_NV_CHANLIST 0x00800000 // 23 - 0x17
//#define ZACCEL_NV_CHANLIST 0x00400000 // 22 - 0x16
//#define ZACCEL_NV_CHANLIST 0x00200000 // 21 - 0x15
//#define ZACCEL_NV_CHANLIST 0x00100000 // 20 - 0x14
//#define ZACCEL_NV_CHANLIST 0x00080000 // 19 - 0x13
//#define ZACCEL_NV_CHANLIST 0x00040000 // 18 - 0x12
//#define ZACCEL_NV_CHANLIST 0x00020000 // 17 - 0x11
#define ZACCEL_NV_CHANLIST 0x00010000 // 16 - 0x10
//#define ZACCEL_NV_CHANLIST 0x00008000 // 15 - 0x0F
//#define ZACCEL_NV_CHANLIST 0x00004000 // 14 - 0x0E
//#define ZACCEL_NV_CHANLIST 0x00002000 // 13 - 0x0D
//#define ZACCEL_NV_CHANLIST 0x00001000 // 12 - 0x0C
//#define ZACCEL_NV_CHANLIST 0x00000800 // 11 - 0x0B
Well, although zasa SEEMED to work, I noticed that both red and green LEDs blinked each second when a node was endpoint mode (versus only the green). After some significant hair-pulling, I found an additional change to the TI zasa code to convert it to CrossWorks vs. IAR. Apparently typedef default typing varies between the two compilers. SOOOOO, in module cc2480.h, I had to force typing for devStates_t... You need to add "unsigned char" after the keyword "enum" at line 189 in cc2480.h. Now everything seems to work exactly as designed; although now I'm a little worried about the other enum typdefs. Would someone please verify these changes so we can get a second opinion?
So to summarize, in addition to the source changes I posted earlier, the new typedef should look like this:
/* cc2480.h, starting at line 189 */
typedef enum unsigned char
{
DEV_HOLD, // Initialized - not started automatically
DEV_INIT, // Initialized - not connected to anything
DEV_NWK_DISC, // Discovering PAN's to join
DEV_NWK_JOINING, // Joining a PAN
DEV_NWK_REJOIN, // ReJoining a PAN, only for end devices
DEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust center
DEV_END_DEVICE, // Started as device after authentication
DEV_ROUTER, // Device joined, authenticated and is a router
DEV_COORD_STARTING, // Started as Zigbee Coordinator
DEV_ZB_COORD, // Started as Zigbee Coordinator
DEV_NWK_ORPHAN // Device has lost information about its parent..
} devStates_t;
Thanks Steve Curd for the the precise and unambiguous ZASA IAR-CrossWorks port instructions.
This is very usefull. I am impressed with Crossworks and now purchased the commercial licence.
Previously I worked with IAR for all my projects with MSP430. When I convert IAR projects to Crossworks, I am getting issues and the this is very usefull for me.
Is it possible that I can work with Crossworks supprt to convert the IAR project attached to convert to Crossworks. i am going to use this evaluation board code to build our own design.
THanks for the support.
Please sign in to leave a comment.