C Language Programming with Code Warrior

Copyright 2008 Hrafnkell Eiriksson TF3HR 

The MC68HC908AB32 MCU that the HC908 daughtercard uses is designed so that it effectively supports programming in the C language. The purpose of this application note is to help those who wish to program the HC908 using the C to get started. This application note will both show how to modify the default CodeWarrior setting so that software written will cooperate with the HCMon software and how to do interrupt processing in C. 

The reader is refered to other sources to learn the C language.

Getting the C compiler and related tools

Freescale, the maker of the MC68HC908AB32 MCU distribute a version of the MetroWerks CodeWarrior IDE and compiler/assembler/linker/debugger toolchain that can generate code for the HC08 family of MCUs. There is a free (as in free beer) version of CodeWarrior for 8-bit microcontrolers called the "Special" edition. It can be downloaded from the Freescale website. You may have to register with them.

The CodeWarrior C compiler suite contains a source level debugger, a full software simulation of the MCU and an implementation of the ANSI C library.

Installing CodeWarrior

To be written, you know the drill, click next next next and accept to sell your grandmother :-)

Creating a C language project in CodeWarrior

Start up the CodeWarrior IDE and create a new project, either with the startup Wizard or from the File menu.

Select our MCU, the HC68HC908AB32 from the AB Family of HC08. For this first project select Full Chip Simulation for the target conncetion. Click Next.

On the next page, select only C of the supported languages. Name the project something like HelloHC08 and choose a good location for it on your computer. Click Next. Directly click Next again on the next page as we don't want to add any files at this stage to the project.

Just leave this page as it is with None selected for the Rapid Application Development. Then click Next.

Also leave this as it is. The ANSI startup code simplifies initialization of variables among other things. Note the option of having floating point support. The MCU on the HC908 doesn't have a floating point arithmetic unit but it is simulated in software instead. Click Next.

No changes are needed here, just click Finish to have CodeWarrior create a project based on these choices.

The project is actually fully buildable at this stage and will result in a program that does nothing but run in an endless loop. Try it by pressing F7 or selecting Make from the Project menu.

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */



void main(void) {

EnableInterrupts; /* enable interrupts */
/* include your code here */



for(;;) {
__RESET_WATCHDOG(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}

The code from the main.c source file. Runs an endless for loop.

Changing the default project to work with the HC908 daughtercard

The CodeWarrior linker generates an .s19 file that could in theory be downloaded to the HC908 daugtercard with the help of the HCMon and TeraTerm. This file can be found in the bin directory of the project folder. This file would however not run. The reason is that the HCMon bootloader/monitor software on the HC908 daughtercard has reserved the first part of the flash memory but the default linker setup places the software there. Also, the HCMon bootcode expects the entry point of any application we download into the HC908 card to be at memory address 0x8040. The default linker setup will not place it there.


First, the linker setup must be changed. This is done in the Project.prm file in the Linker Files folder of the Project.

The default Project.prm file looks like this

/* This is a linker parameter file for the mc68hc908ab32 */

NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */

SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
    Z_RAM                    =  READ_WRITE   0x0050 TO 0x00FF;
    RAM                      =  READ_WRITE   0x0100 TO 0x044F;
    ROM                      =  READ_ONLY    0x8000 TO 0xFDFF;
    EEPROM                   =  NO_INIT      0x0800 TO 0x09FF;
 /* INTVECTS                 =  READ_ONLY    0xFFD0 TO 0xFFFF; Reserved for Interrupt Vectors */
END

PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
    DEFAULT_RAM                         /* non-zero page variables */
                                        INTO  RAM;

    _PRESTART,                          /* startup code */
    STARTUP,                            /* startup data structures */
    ROM_VAR,                            /* constant variables */
    STRINGS,                            /* string literals */
    VIRTUAL_TABLE_SEGMENT,              /* C++ virtual table segment */
    DEFAULT_ROM,
    COPY                                /* copy down information: how to initialize variables */
                                        INTO  ROM;

    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END


STACKSIZE 0x50

VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */
 

The Code Warrior documentation describes the syntax of this files. However it is easy to change it to support the HC908 daughtercard. A changed version follows

/* This is a linker parameter file for the mc68hc908ab32 */

NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */

SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
    Z_RAM                    =  READ_WRITE   0x0050 TO 0x00FF;
    RAM                      =  READ_WRITE   0x0100 TO 0x044F;
    ROM                      =  READ_ONLY    0x8044 TO 0xFDFF;
    EEPROM                   =  NO_INIT      0x0800 TO 0x09FF;
 /* INTVECTS                 =  READ_ONLY    0xFFD0 TO 0xFFFF; Reserved for Interrupt Vectors */
END

PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
    DEFAULT_RAM                         /* non-zero page variables */
                                        INTO  RAM;

    _PRESTART,                          /* startup code */
    STARTUP,                            /* startup data structures */
    ROM_VAR,                            /* constant variables */
    STRINGS,                            /* string literals */
    VIRTUAL_TABLE_SEGMENT,              /* C++ virtual table segment */
    DEFAULT_ROM,
    COPY                                /* copy down information: how to initialize variables */
                                        INTO  ROM;

    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END


STACKSIZE 0x50

//VECTOR 0 _Startup

The changed lines are shown in red.

The purpose of these changes is to leave space for the interrupt vector jump table the HCMon software assumes at the beginning of the flash and to make it possible for us to add code to jump from the 0x8040 flash memory address where the HCMon assumes user code starts to the _Startup routine the CodeWarrior creates.

The only thing missing to let the code run on the HC908 card is to add the assembler code to jump from 0x8040 to the _Startup symbol. This is easy. Create a new file with the following contents and save it as entry.asm in the sources folder of the project

  XREF _Startup
  ORG $8040
  ;
  jmp _Startup

 Add this file to the project sources by selecting Add Files... from the Projects menu.

This is all that is needed. Try building this project by selecting Make from the Project menu.

You should look at the Project.map file that has been generated. It will show you where things are located in memory. 

Lets make the diode blink

There is a diode on the HC908 card. This diode can be controlled by the MCU by toggling a digital output.

According to the HC908 card schematic the diode is connected to line 6 of port F

The MCU has a programmable timer interrupt generator (PIT). To use it to blink the diode we must add an interrupt service routine for the PIT generator and add an interrupt vector jump table that conforms to the HCMon code.

Interrupt service routines are like normal functions in C. The difference is though that the MCU may at any time during execution of your code suspend the execution of it, call the interrupt service routine and then return to the original code. The compiler therefore has to know which routines are interrupt service routines so it can add code to save and restore the state of the MCU when it transfers to and from the interrupt service routine. This is done by adding the keyword interrupt to the declaration of the function.

An interupt service routine that would change the state of the diode could look like this

void interrupt pit_isr(void) {
  static unsigned char diode_state = 0;
 
  if(PSC_POF==1) {  
    PTF_PTF6 = diode_state;
    diode_state = !diode_state;  
    PSC_POF = 0;
  }
 

In order for the MCU to know when to jump to the pit_isr() function whenever there is a PIT interrupt a table of service routines is usually set up. The CodeWarrior linker could do this but because the HCMon expects it to be at a certain place and in a certain way, we do it rather "by hand". That is, by writing an assembler file with jump statements.

This is done by add the following in a file named interrupt_jmp.asm

        XREF dummy_isr
        XREF pit_isr
        org $8000
        ;
        jmp  dummy_isr    ; ADC Conversion Complete
        jmp  dummy_isr    ; Keyboard Vector
        jmp  dummy_isr    ; SCI Transmit Vector
        jmp  dummy_isr    ; SCI Receive Vector
        jmp  dummy_isr    ; SCI Error Vector
        jmp  dummy_isr    ; TIMB Channel 3 vector
        jmp  dummy_isr    ; TIMB Channel 2 vector       
        jmp  dummy_isr    ; SPI Transmit Vector
        jmp  dummy_isr    ; SPI Receive Vector       
        jmp  dummy_isr    ; TIM2 Overflow Vector
        jmp  dummy_isr    ; TIM2 Channel 1 Vector
        jmp  dummy_isr    ; TIM2 Channel 0 Vector
        jmp  dummy_isr    ; TIM1 Overflow Vector
        jmp  dummy_isr    ; TIM1 Channel 3 Vector
        jmp  dummy_isr    ; TIM1 Channel 2 Vector
        jmp  dummy_isr    ; TIM1 Channel 1 Vector
        jmp  dummy_isr    ; TIM1 Channel 0 Vector
        jmp  pit_isr      ; PIT Vector
        jmp  dummy_isr    ; PLL Vector
        jmp  dummy_isr    ; IRQ1 Vector


The org statement in the file places this at the beginning of the flash memory where the HCmon expects them. Remember to add this file to the project.

Ofcourse the PIT has to be configured to interrupt at the rate we want. Here below follows an updated main.c file with all that is needed.

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */


void interrupt pit_isr(void) {
  static unsigned char diode_state = 0;
 
  if(PSC_POF==1) { 
    PTF_PTF6 = diode_state;
    diode_state = !diode_state; 
    PSC_POF = 0;
  }
 
}

void interrupt dummy_isr(void) {
 
  /* do nothing */
}

void setup() {
  DDRF_DDRF6 = 1; /* set F6 as output */ 

  /* Set up the programmable interrupt timer to interrupt every 500msec */
  PSC_POIE = 1;    // enable PIT interrupts
  PSC_PPS = 0b110; // select internal bus clock/64 for the time counter
  PMOD = 33594;    // 0.5 secs equals 33594 counts
  PSC_PSTOP = 0;   // start the counting
}

 
void main(void) {

  setup();

  EnableInterrupts; /* enable interrupts */
  /* include your code here */

  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

Now build your project (Project->Make or F7) and download the resulting Project.abs.s19 file to your HC908 card using TeraTerm. Run the C program either by removing the monitor jumper or jumping to user code with the x command in HCmon. The LED on the HC908 daughtercard should blink.

Running in the debugger

You can see how the MCU starts the HCMon code and the transfers control to your program written in C using the debugger.

Easiest way to do this is to start up the debugger using the Project->Debug menu. Then in the debugger select Load... from the HC08FCS menu and load the HCmon_v2.s19 file. Then load the Project.abs file (not the s19, then you loose debug info) for your program using the same method (it is in the bin directory of your project directory). Then simulate that the jumper is between pin 19 and 20 on the HCMon card by selecting the HC08FCS->Port Pins Module->Set Input Levels menu. Enter A0 for Port F.

Now simulate a MCU reset with Reset in the HC08FCS menu. Then try single stepping through the code with F10 and watch how the HCMon code starts up and then jumps to the C code. You can even add breakpoints in the interrupt_jmp.asm file or main.c and let the simulator run until something interesting happens.

Now write some cool software!

I've been meaning to write this guide for a long time, mainly because I needed to figure out how to write software for the HC908 in C. Now I know! Hopefully you can use this too and write some really cool new software for the HC908 daughtercard and please share the sourcecode with the amateur radio homebrew community. 

gl es mni tnx de TF3HR


  Sign in   Recent Site Activity   Terms   Report Abuse   Print page  |  Powered by Google Sites