Your first impression of the Metrowerks Code Warrior tool chain is probably, "Gee, why is this all so complicated?" The complexity is due to the nature of embedded applications. Unlike tools for PCs and workstations which face an environment of relative ease, the following is a partial list of hurdles that any embedded application must overcome.
In running a program on a PC, the actual memory locations are resolved on the fly. Before your program executes, a program called a loader relocates the actual application into memory. Without an operating system, there is no such loader. The parameter file instructs the linker how to deal with the patchwork memory system, performing any necessary program relocation.
By now it should be clear that, building and executing the traditional hello world program in an embedded system is a more profound experience. Before asking what the minimum number of files is to do anything useful, we have provided you with stationary, that is pre-configured project files. Think of stationary as a set of templates. You can even make your own custom stationary. In the College of Engineering (COE) at the University of Hartford we use 68HC12 development boards from Axiom Manufacturing. The part number is CME12BC32. To get you started, download the zip-file, and uncompress in the stationary folder. Depending on the version of Code Warrior, this might be C:\Metrowerks\Stationary\HC12\ or C:\Metrowerks\Stationery\HC12\
Axiom12B32.zip stationary folder
With the stationary folder in place, start Metrowerks Code Warrior as you did before. This time you will start a new project from stationary. In the Metrowerks CodeWarrior window select
In the New Project window, enter hello into the project, click the Set button, navigate to find the workspace you are using and then click save. In the left pane of the New Project window, double click HC12 Stationary.File => New
In the next window left click to select AxiomPE_CME12-B32 and then click OK. Congratulations, you just created a new project from stationary.
To implement this program, we will use the file main.c provided with the stationary, and make a new file for I/O functions. Briefly consider that without a file system, operating system, or standard I/O devices, much of the standard I/O library that does exist doesn't make sense here.
Below the Metrowerks CodeWarrior toolbar, left click the New Text File button.
With the untitled window open, select:
In the pop-up window, navigate to your work area, double click to open the hello project folder and then double click to open the sources folder. Enter the file name bxlib.c and click SAVE. Next, in the Metrowerks CodeWarrior tool bar, select:File => Save As
In the Add Files window that appears, check that all build targets are selected and click OK. While this new file is actually located in the sources file in the actual file system, the File View simply shows it as a new file. In the File View, click left to select the file bxlib.c and press left to drag the file to the sources group folder. In the file bxlib.c enter the following text:Project => Add bxlib.c to project
/**************************************************************
* bxlib.c - UH COE - ECE591 Embedded Microprocessors
*
* A small library of blocking serial I/O related functions
* built upon the simple notion of a spin-lock.
*************************************************************/
#include "includes.h"
/**************************************************************
* bx_scinit()
* Initialize the SCI port for 8bit, no parity, tx/rx active
*************************************************************/
void bx_scinit(unsigned int BaudRate)
{
unsigned long BR;
// The following rounds like you would expect
BR = P_CLOCK_FREQ / (8 * (unsigned long)BaudRate);
BR = (BR + 1)/2;
// Assign upper and lower 8 bits separately
SC0BDH = (BR >> 8)&0xFF;
SC0BDL = BR & 0xFF;
// Configure the remaining parts
SC0CR1 = 0x04;
SC0CR2 = 0x0C;
}
/**************************************************************
* bx_putstr()
* Send a null terminated string, one character at a time
*************************************************************/
void bx_putstr(char A[])
{
char *pntr;
// Send characters till the NULL is encountered
for (pntr = A; *pntr != '\0'; pntr++) {
bx_putchar(*pntr);
}
}
/**************************************************************
* bx_putchar()
* Send a character out the SCI port
*************************************************************/
void bx_putchar(char A)
{
// Send a character only when ready
while (TDRE == 0);
SC0DRL = A;
}
In the project manager 'Files' view, click to open the Sources group folder and double click to open the file includes.h. Before the final comment in the file, insert the following prototypes, then select File => Save.
void bx_scinit(unsigned int BaudRate); void bx_putstr(char A[]); void bx_putchar(char A);
Back in the project File View pane, double click to open the file main.c. Make the necessary changes to the file so it contains the following:
/*************************************************************
* main.c
*
* A not-so traditional version of "Hello World!"
* Jonathan Hill - University of Hartford COE - Spring 2003
************************************************************/
#include "includes.h"
void main(void) {
int done = 0;
static char greeting[] = {"Hello World!\n\r"};
bx_scinit(9600);
bx_putstr(greeting);
while (done == 0);
}
In the project window change the build target to Simulation.
Click the build button to make the build target.
After a few moments the message window appears, indicating success or failure of the build. If you have any errors, go back and fix your code. Assuming success, click to close the message window. Before you can simulate the project, it is necessary to enable the debugger:
Project => Enable Debugger
The simulation build target differs from the others in the stationary in that an I/O subsystem model is loaded along with a simulator. You will next use a model that simulates the behavior of an serial communications terminal. In the debugger window select:
Component => Open
In the pop-up window that appears, select the item titled Terminal and click OK.
The default size of the terminal component is quite large. Using the mouse, drag the left, right, and bottom borders to reduce the size of the new window. Click the Start button to start the simulation, a predefined break point stops execution at main().
Clicking the Start button a second time continues the program execution. Click the Halt button to stop program execution.
The familiar greeting should clearly be visible in the terminal window.
Before you exit the simulator, take a moment to look at each window and try a few things. The file Start12.c is quite a bit more complicated than start12.asm, but in preparing an environment for your program it basically does similar chores.
Take a moment to examine how the function bx_putchar() executes. If you like, first set a break point. Click left to select a line in the source code, then right click. In the pop-up window make a selection to insert a break point. The reset button resets the program, so you can restart it. Use the simulator to count the number of cycles that pass during the time that it takes to send one ASCII character. Once you receive an actual board, you will be able to run this program on the actual hardware.
A closing comment is in order, to run the other build targets it will be necessary to use a serial communications program such as the freely available teraterm program or hyperterm which comes with Windows. The above program is set for 9600 Baud, and each character is represented with 8 data bits, but with no parity. Finally, to program your Axiom board, refer to the readme.txt text file that is provided in the project stationary. There may still be some odd details in the current version of the stationary, be sure to check in as we make improvements.