This demo project is a simple example of how to develop an xgate co-processor thread with the Imagecraft compiler (http://www.imagecraft.com/). Several years ago Edward Karpicz developed a xgate macro assembler for the ICCV712 compiler and I've managed to get it working with the invaluable assistance of Joël Pétrique (http://dieseinfo.com/). Although a linker for xgate was not implemented (7.07A is the version as I write) it is possible to utilize the xgate by carefully extracting address data from the map file and output file and feeding it back into the project for a recompile. This demo uses the realtime interrupt (rti) peripheral to illustrate this process. My goal with the demo is to demystify xgate programming for those already using the ICC compiler so I won't go into the details of the source code that are not specific to the xgate. Note that the demo will function without the xgate if the XGATE define in all.h is commented out.
The hardware I use for this demo is the DEMO9S12XDT512 board that I purchased from Digikey. This board is excellent value considering that it has an integrated USB P&E Micro bdm pod which makes programming and debugging a breeze. The kit comes with a code limited version of the CodeWarrior C compiler however this demo will be using ICC along with the NoICE debugger. Note that there is a standard bdm connector on the board so that you can use alternative pod/debuggers. An important caveat with respect to NoICE is that has no ability to debug within the xgate co-processor. Debugging xgate code with a debugger tool will require prototyping in CodeWarrior or other toolchain first. Please correct me in the comments if I am mistaken on this or any other point.
Developing xgate threads with ICC assumes that the reader has at least a passing knowledge of the paged addressing scheme used in Freescale HC12 microcontrollers. Unfortunately the Freescale documentation seems to be written for exclusively for engineers which makes understanding of this concept difficult for hobbyists and those new to the chip. My own understanding is incomplete so I will not offer a definitive discussion of paging here. In short, the HC12 architecture is based on the HC11 but with addressing beyond 64Kbyte via the use of paged windows. Each window (flash, ram, eeprom) has an associated register that determines where this area resides in the global memory space. The global memory space for the S12X micros is half of the 24 bit range (8Mbyte) though only a small fraction of that area is implemented. I have no love for this addressing scheme but I can understand why it was adopted since HC11 was the most popular microcontroller of its time.
In my humble opinion Freescale should provide additional documentation that makes it easier for ordinary people to understand the memory architecture. It seems to me that the intended user base of HC12 are either engineers with legacy HC11 experience or new users who can ignore the complexity of paged addressing because it is hidden inside the CodeWarrior compiler that Freescale sells for a hefty price.
The demo is without copyright or guarantee.
| Attachment | Size |
|---|---|
Archive of complete ICC project | 149.89 KB |
The following screendumps show the compiler settings for the project.
The 'Project' tab has the default settings.
The 'Paths' tab must be adjusted to reflect your location of the project unless you choose to install it to the root of the C drive as I have. My preference is to separate header, code and output objects into separate folders.
The 'Compiler' settings must include the "__XDP512__" macro. The selected output format includes the symbols required for debugger operation.
The settings in the 'Target' tab that are partially hidden in this view are :
The process for building a new project for xgate is as follows:
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
bss 2012 0023 = 35. bytes (rel,con,rom)
Addr Global Symbol
----- --------------------------------
2012 __bss_start
2012 _tick_counter
2016 xgate.c:xg_vectors_rpage
2018 xgate.c:xg_vectors_addr
2035 __bss_end
The hex variable address 2012 is now placed back into the xg_threads.s file as follows:
; Address of tick_counter long variable is found in .mp file RTI_THREAD_DATA = 0x2012
This address is passed to the xgate rti thread via register R1 when it starts execution.
Note that there is a XGATE_RAM define at the top of xgate.c that permits you to skip the ram copy procedure if you prefer to run xgate from flash, however this will throttle the co-processor to the same clock speed as the cpu. Running out of ram allows up to double the performance.
The xgate thread vector table begins after the 2K register space at address 0x780800 and ends at 0x7809e8. Note that the cpu sees these addresses as 0x8800 and 0x89e8 (the 16K flash window lies between 0x8000 and 0xC000) when the ppage register is set to E0. SetupXGATE() uses these addresses as arguments for copying the xgate thread vector table from flash to ram.
// Copy the thread vector table to RAM // XDT512 has 20K of RAM starting at xgate address of 0xB000 (0x8000 for XDP512 with 32K RAM) // thread vector table spans 0x8800 to 0x89e8 in flash window (ppage = E0) // (verify table in .s19 between 0x780800 and 0x7809E8) // returned xg_addr is the next free address for first thread xg_addr = CopyXGateVectorsToRam((void*)0xB000, (void*)0x8800, (void*)0x89e8);
Note that the RAM address of 0xB000 is the start of the 20K ram space of the XDT512 (XDP512 chips have 32K of ram and would copy the code to 0x8000 instead). The return value is the end address of the copied vector table and the starting point for the first xgate thread that will be copied next. This start address for the next thread must also be placed back into the vector table via the UpdateXGateThreadVector() function so that when the thread is scheduled to run it will be directed to the proper ram address.
// Change the RTI vector to point to start of RTI thread in RAM UpdateXGateThreadVector(Vrti, xg_addr);
Next we copy the RTI thread to ram using the start and end addresses found in our .s19 file. In this demo the thread is located between 0x780A14 and 0x780A30 (Note: 0x780A30 is the address after the _RTS instruction (0x0200)).
// Copy the RTI thread to address pointed to by RTI vector // (verify RTI thread in .s19 between 0x780A14 and 0x780A30) xg_thread.s12_flash_page = 0xe0; // ppage for RTI flash window xg_thread.s12_start = (void*)0x8a14; // start of RTI thread in flash window xg_thread.s12_stop = (void*)0x8a30; // end of RTI thread in flash window // xg_add is the next free address for next thread xg_addr = CopyXGateThreadToRam(xg_addr, &xg_thread);
Lastly the XGVBR register is set to the start of the xgate thread vector table, the RTI interrupt is routed to xgate and the co-processor is started.
**xgate tests** (0) LED test 0 (1) LED test 1
Hitting a 0 or 1 key inside your serial terminal will now run small test functions that utilize the RTI timer interrupt.