Cornell University
Electrical Engineering 476

Older versions of a
CodeVision 1.24.6 Debugger
for Atmel Mega32 microcontrollers

Debugger based on aOS. Codevision 1.24.6

A simplified version of aOS was constructed to act as a debugger. The intent was to make a system in which a student could debug any C program with very minimal modification. How successful the attempt is remains to be seen (stay tuned until Spring 2006). The program memory used for the debugger is about 3k words of flash. Debugger time overhead when running the target application is zero (At RESET time the debugger runs briefly to set up its structures). SRAM overhead is about 800 bytes, so the debugger is not useful for data-hungry programs like video.

Note that the debugger code has compiler-version dependencies! The dependencies occur because local variables are stored in specific ways in different compiler versions and the variables have to be manipulated directly in assembler. A version which compiles in 1.23.8 is linked in a section below.

There are only a few changes that have to be made to the target C program to run it with the debugger:

When you enter the debugger, the three MCU timers are frozen, but interrupts are left on. If you don't like this particular behavior, you can hack on the following macro debug (in debugger.c) to change the defaults. The saveitall and loaddatareg functions are asm routines to make it easier for the debugger to get the stack pointers and register values.

 #define debug(id) \
	do{      	\
	aos_t0temp = TCCR0;  \
	aos_t1temp = TCCR1B; \
	aos_t2temp = TCCR2;  \
	TCCR0 = 0;  \
	TCCR1B = 0; \
	TCCR2 = 0;  \
	saveitall(); \
	aos_break_id = id;  \          
	aos_resume_task(cmd_tcb); \ 
	loaddatareg(); \
	TCCR0 = aos_t0temp;	\
	TCCR1B = aos_t1temp;\
	TCCR2 = aos_t2temp;	\
	}while(0)  
 

If you want to be able to enter the debugger with a <control-c> from hyperterm, uncomment the following line near the beginning of the debugger.c file.

//#define use_rxc_isr

You might have to increase the stack sizes defined near the beginning of the debugger.c file if you do any recursion, or deeply nested function calls, or define lots of local variables in functions. In Codevision C, the hardware stack contains return addresses and the results of any assembler-level push opcodes, inlcuding register saves when entering an ISR. The data stack contains parameters passed to functions and local variables. Change these two lines near the beginning of the file debugger.c.

#define AOS_TASK_HSTK_SIZE 100
#define AOS_TASK_DSTK_SIZE 200

The commands available at the db> prompt (appearing on the PC hyperterm window) are:

h
Prints a short version of this table
g
Exit command shell and run target program
<control-c>
Stop target program and enters command shell with DebugID=255. NOTE: you must uncomment a line near the beginning of debugger.c for this command to work.
debug(char debugID)
When used in the target program being debugged, this macro enters the command shell with the specified debugID. The debugID can be used as an error code.
Example: debug(4)
x
Forces a RESET of the MCU and trashes the state of your program. This is implemented using the watchdog timer reset function.
i ioregAddress
Read an i/o register. The register address is entered in hexadecimal. The result displayed in in hex.
Example: i 13
Reads the state of the pushbuttons attached to PINC.
I ioregAddress iodata

Write to an i/o register. The register address and data are entered in hexadecimal
Example: I 18 f0
Turns on LEDs 0 to 3 attached to PORTB (If DDRB=0xff).

r datareg
Read data register. The register number is in decimal. The result displayed is in hex. The .map file generated by the compiler will show you where variables are stored. Note that Codevision can store varibles in SRAM or in registers. You have to look at the map file to verify where a variable is stored. Registers 1 to 15 are available for global variables. Registers 16 to 21 can store local variables. Registers 22 to 31 store state information for Codevision. Normally, no user information should be in these registers.
Example: r 16
Displays the value 55 if the demo program is running and button one is pressed to enter the command shell. This is because the running program writes a 0x55 to data register sixteen just before it calls the debug(3) macro.
R datareg data
Write task data register. The register number is in decimal. The data is in hex.
Example: R 0 aa
Writes 0xaa to register 0. The debugger does not allow you to modify registers 22 to 31 because of the dynamic contents of these internal C registers make it hard to predict the results of a modification. If the demo program is running, it stops with debugID=1 just after reset time. There are six local variables in registers when it stops.
m address

Read memory. Address is given in hex. The .map file generated by the compiler will show you where variables are stored. Remember that by default, Codevision stores the first few variables you define into registers.
Example: m 7d0

M address data
Write data to memory. Address and data are in hex.
Example: M 7d0 aa
Writes 0xaa to address 7d0. Remember that there is NO memory protection, so you can easily trash the system with this command.
s
Read the memory location of the top of the hardware stack. This is mostly useful to make sure that you have not overrun the space allocated to the hardware stack. The value reported by this command is the stack location before the context switch to the debugger stores 32 bytes on the stack.
d

Read the memory location of the top of the data stack. This is mostly useful to make sure that you have not overrun the space allocated to the data stack. If you are looking for local variables, remember that Codevision puts the first six bytes of local variables defined in a function in data registers R16-R21. After that they are placed on the data stack. The example program stops with debugID=1 at reset time. The data stack has 6 stored bytes, then six local variables in registers.

The Backspace key works at the debugger command line, but does not echo the erased characters. After backspacing, new characters type over old characters. No error checking is done at the command line. Unrecognized commands are ignored. Poorly formed parameters (e.g. letters in a number) default to whatever C does to them, which is usually to return a zero.

Note that there is compiler-version dependent code in several places in debugger.c. This code compiled on Codevision 1.24.6.


Debugger for Codevision 1.23.8

Please note that this version of the debugger does not work in Codevision versions 1.24 and above. See above for the current version.

There are only a few changes that have to be made to a standalone C program to run it with the debugger:

When you enter the debugger, the three MCU timers are frozen, but interrupts are left on. If you don't like this particular behavior, you can hack on the following macro debug (in debugger.c) to change the defaults.

#define debug(id) \\ 
	do{      		\\
	aos_t0temp = TCCR0;      \\
	aos_t1temp = TCCR1B;      \\
	aos_t2temp = TCCR2;      \\
	TCCR0 = 0;                \\
	TCCR1B = 0;               \\
	TCCR2 = 0;                \\
	aos_break_id = id;        \\
	aos_resume_task(cmd_tcb); \\
	}while(0) 

If you want to be able to enter the debugger with a <control-c> from hyperterm, uncomment the following line near the beginning of the debugger.c file.

//#define use_rxc_isr

You might have to increase the stack sizes defined near the beginning of the debugger.c file if you do any recursion, or deeply nested function calls, or define lots of local variables in functions. In Codevision C, the hardware stack contains return addresses and the results of any assembler-level push opcodes, inlcuding register saves when entering an ISR. The data stack contains parameters passed to functions and local variables. Change these two lines near the beginning of the file debugger.c.

#define AOS_TASK_HSTK_SIZE 100
#define AOS_TASK_DSTK_SIZE 200

The commands available at the db> prompt (appearing on the PC hyperterm window) are:

h
Prints a short version of this table
g
Exit command shell and run other tasks
<control-c>
Stop other tasks and enters command shell with BreakID=255. NOTE: you must uncomment a line near the beginning of debugger.c for this command to work.
debug(char debugID)
When used in the target program being debugged, this macro enters the command shell with the specified debugID. The debugID can be used as an error code.
Example: debug(4)
x
Forces a RESET of the MCU and trashes the state of your program.
i ioregAddress
Read an i/o register. The register address is entered in hexadecimal. The result displayed in in hex.
Example: i 13
Reads the state of the pushbuttons attached to PINC.
I ioregAddress iodata

Write to an i/o register. The register address and data are entered in hexadecimal
Example: I 18 f0
Turns on LEDs 0 to 3 attached to PORTB.

r datareg
Read data register. The register number is in decimal. The result displayed is in hex. The .map file generated by the compiler will show you where variables are stored. A few of the registers are modified by the scheduler before the debugger takes control. r22,r23, and r26-r31 are used by the context switch. Normally, no user information should be in these registers.
Example: r 0
Displays the value 55 if the demo program is running and button zero is pressed to enter the command shell. This is because the running program writes a 0x55 to data register zero just before it calls the debug macro.
R datareg data
Write task data register. The register number is in decimal. The data is in hex.
Example: R 0 aa
Writes 0xaa register 0
m address
Read memory. Address is given in hex. The .map file generated by the compiler will show you where variables are stored. Remember that by default, Codevision stores the first few variables you define into registers.
Example: m 7d0
M address data
Write data to memory. Address and data are in hex.
Example: M 7d0 aa
Writes 0xaa to address 7d0. Remember that there is NO memory protection, so you can easily trash the system with this command.
s
Read the memory location of the top of the hardware stack. This is mostly useful to make sure that you have not overrun the space allocated to the hardware stack. The top 31 bytes on the target program hardware stack are the registers saved during the context switch to the debugger, plus the SREG. SREG is stored at top of stack, but is probably modifed (relative to the target program) by the scheduler before the context switch to the debugger. To access the registers, use the r command.
d

Read the memory location of the top of the data stack. This is mostly useful to make sure that you have not overrun the space allocated to the data stack. If you are looking for local variables, remember that Codevision puts the first six bytes of local variables defined in a function in data registers R16-R21. After that they are placed on the data stack along with lots of other stuff which makes local variables hard to find.

The Backspace key works at the debugger command line, but does not echo the erased characters. After backspacing, new characters type over old characters. No error checking is done at the command line. Unrecognized commands are ignored. Poorly formed parameters (e.g. letters in a number) default to whatever C does to them, which is usually to return a zero.


Copyright Cornell University August 2005