C MACRO DEFINITIONS FOR THE MC68HC(7)11D3/D0

INTRODUCTION

With more microcontroller users moving to high level languages like C, 
macro definition files like the one outlined in this document can speed 
software development efforts.  The file reproduced in the following pages 
is available on the Motorola Freeware AMCU Bulletin Board System at (512) 
891-3733.  Download and unzip the "hc11d3h.zip" file from the MCU11 
directory on the BBS.  If you have questions about doing this, please call 
your local Motorola Field Applications Engineer.

The "hc11d3h.zip" file includes this ASCII text copy of the documentation 
and the actual "hc11d3.h" text file.  The "hc11d3.h" file, and others like 
it, use Motorola's designated register and bit names for each device 
described.  Any user already familiar with MC68HC11 assembly language and 
architecture (a requirement even for those who think they will only program 
in C), will readily be able to make use of this file.

CONVENTIONS

The contents of the actual file will be indented with this ">>" notation.  
Thus the following lines appear in the "hc11d3.h" file:

>>  /* (C) MOTOROLA, INC., 1993
>>   *
>>   * FILENAME: hc11d3.h
>>   *
>>   * DESCRIPTION: Register and bit macro definitions for the MC68HC11D3,
>>   * MC68HC711D3, and MC68HC11D0 microcontrollers.
>>   *
>>   * CREATED: 11/20/93
>>   *
>>   * NOTE: Your comments, suggestions, and corrections are requested and
>>   * greatly appreciated.
>>   */

CONCEPTS, DEVELOPMENT, AND USAGE

In C, we can make just about anything an lvalue, that is, something that 
appears to the left of the equal sign in an assignment expression.  We can 
even use a number as an lvalue.  In particular, we would like to use 
register addresses as lvalues.  To do this, we must cast the lvalue as a 
pointer to a particular data type.  For example...

(unsigned char *) 0x1000

...would be an lvalue that points to an unsigned character (an 8 bit 
unsigned value) at memory location 0x1000 ($1000 for those used to assembly 
language).  In this particular form, however, we cannot yet assign a value 
to the memory location.  To do this, we must dereference the pointer.  
Dereferencing a pointer specifies the value that is pointed to and not the 
pointer itself.  So, to assign the value 0xFF to memory location 0x1000, we 
would use the following C assignment expression:

*(unsigned char *) 0x1000 = 0xFF;

Likewise, if we wish to assign the contents of memory location 0x1000 to 
the variable A, we would use the following assignment:

A = *(unsigned char *) 0x1000;

This is all that is really necessary to manipulate the memory mapped 
registers of the MC68HC11.  Unfortunately, *(unsigned char *) 0x1000 is not 
particularly indicative of the function memory location 0x1000 performs 
(PORT A on most MC68HC11 devices).  The extra typing required to use this 
memory location can also be a source of minor, but unnecessary compilation 
errors.  A better idea is to use the following line (remember, lines 
appearing in the "hc11d3.h" file are indented with ">>"):

>>  #define REGISTER unsigned char

Thus to access memory location 0x1000, we can now type:

A = *(REGISTER *) 0x1000;

This is an improvement, but it would be even better if we could define a 
register as PORTA or DDRC as we do when programming in assembly.  Thus the 
following line...

#define SOMEDEVICE *(REGISTER *)0x1000

...will allow us to address 0x1000 in a very convenient fashion.  For 
example, we can now type...

SOMEDEVICE = 0xFF;

...to assign 0xFF to memory location 0x1000, and we can also type...

A = SOMEDEVICE;

...to assign the contents of 0x1000 to the variable A.

The MC68HC11 has an INIT register which is used to remap internal RAM and 
registers to the beginning of any 4K page of memory.  Some applications may 
require register remapping, so it would be convenient if we could make a 
simple change to the macro definition file to account for this.  The 
following line (part of "hc11d3.h") allows us to do this:

>>  #define REG_BASE 0x0000

We can thus use the following macro definition to handle register 
relocation:

#define SOMEDEVICE *(REGISTER *)(REG_BASE + 0x00)

If we leave REG_BASE as 0x0000, then pointers to the MC68HC11's peripheral 
registers will be addressed at 0x0000 in our source code.  If we decide to 
remap the registers to 0x4000, we can simply replace 0x0000 in the #define 
REG_BASE macro with 0x4000.  Note that this does not actually modify the 
MC68HC11's INIT register.  This must be done by modifying your C compiler's 
run-time start up code.  Refer to your compiler's documentation before 
making any such changes.

Before proceeding with the rest of the "hc11d3.h" file, we need to 
understand the use of C's volatile keyword.  By specifying a variable as 
volatile, we tell the C compiler not to optimize expressions using that 
variable.

#define PORT *(REGISTER *)(REG_BASE + 0xA0)

void main()
{
	PORT = 0x00;
	
	etc... /* PORT is not used until while(PORT) */
	
	while (PORT)
	{
		etc...
	}
}

In this program fragment, we immediately initialize PORT to 0x00, but we 
will not reference it again until the while (PORT) expression.  Unless PORT 
were to somehow change, while (PORT) would be false, and code in the braces 
immediately following would not execute.  Some C compilers may view this as 
unnecessary if PORT never changes, and it is possible these lines could be 
optimized out of the resulting object code.

On the MC68HC11, PORT may point to a bi-directional I/O port whose inputs 
may change during the course of program execution, thus the while (PORT) 
expression could actually be true when it is executed.  As a precaution, we 
can designate the PORT pointer as volatile so that the optimizer will not 
attempt to remove any questionable references to it.  We would thus change 
the #define macro to be...

#define PORT *(volatile REGISTER *)(REG_BASE + 0xA0)

By doing this, references to PORT will not be optimized.  Several registers 
on the MC68HC11 can change without the intervention of user code.  These 
register include port data registers (PORTC), peripheral status registers 
(SPSR), peripheral data registers (SCDR, ADR1), flag registers (TFLG1), and 
timer registers (TCNT, TIC3).

We could use the volatile keyword with every register macro definition to 
simplify matters, but this runs counter to good code documentation.  By 
specifying only those registers which require it as volatile, the resulting 
code will be better documented.  Only registers which can receive data 
externally or be changed by the processor without user intervention will be 
declared volatile.  Write only registers will be easily recognized because 
they will lack the volatile declaration.

The following macro definitions are used for the registers on the 
MC68HC11D3, MC68HC711D3, and MC68HC11D0 devices:

>>  #define PORTA   (*(volatile REGISTER *)(REG_BASE + 0x00))
>>  #define PIOC    (*(volatile REGISTER *)(REG_BASE + 0x02))
>>  #define PORTC   (*(volatile REGISTER *)(REG_BASE + 0x03))
>>  #define PORTB   (*(REGISTER *)(REG_BASE + 0x04))
>>  #define DDRB    (*(REGISTER *)(REG_BASE + 0x06))
>>  #define DDRC    (*(REGISTER *)(REG_BASE + 0x07))
>>  #define PORTD   (*(volatile REGISTER *)(REG_BASE + 0x08))
>>  #define DDRD    (*(REGISTER *)(REG_BASE + 0x09))
>>  #define CFORC   (*(REGISTER *)(REG_BASE + 0x0B))
>>  #define OC1M    (*(REGISTER *)(REG_BASE + 0x0C))
>>  #define OC1D    (*(REGISTER *)(REG_BASE + 0x0D))

The following registers (TCNT, TICx, and TOCx) are declared as unsigned 
integers because they are 16 bit registers and should be accessed as such.  
It is much simpler and clearer to change, for example, the output compare 4 
register by using TOC4 = 0x4000, TOC4 = TCNT + 0x20FF, or TOC4 += 0x3200.

>>  #define TCNT    (*(volatile unsigned int *)(REG_BASE + 0x0E))
>>  #define TIC1    (*(volatile unsigned int *)(REG_BASE + 0x10))
>>  #define TIC2    (*(volatile unsigned int *)(REG_BASE + 0x12))
>>  #define TIC3    (*(volatile unsigned int *)(REG_BASE + 0x14))
>>  #define TOC1    (*(unsigned int *)(REG_BASE + 0x16))
>>  #define TOC2    (*(unsigned int *)(REG_BASE + 0x18))
>>  #define TOC3    (*(unsigned int *)(REG_BASE + 0x1A))
>>  #define TOC4    (*(unsigned int *)(REG_BASE + 0x1C))
>>  #define TI4O5   (*(volatile unsigned int *)(REG_BASE + 0x1E))
>>  #define TCTL1   (*(REGISTER *)(REG_BASE + 0x20))
>>  #define TCTL2   (*(REGISTER *)(REG_BASE + 0x21))
>>  #define TMSK1   (*(REGISTER *)(REG_BASE + 0x22))
>>  #define TFLG1   (*(volatile REGISTER *)(REG_BASE + 0x23))
>>  #define TMSK2   (*(REGISTER *)(REG_BASE + 0x24))
>>  #define TFLG2   (*(volatile REGISTER *)(REG_BASE + 0x25))
>>  #define PACTL   (*(REGISTER *)(REG_BASE + 0x26))
>>  #define PACNT   (*(volatile REGISTER *)(REG_BASE + 0x27))
>>  #define SPCR    (*(REGISTER *)(REG_BASE + 0x28))
>>  #define SPSR    (*(volatile REGISTER *)(REG_BASE + 0x29))
>>  #define SPDR    (*(volatile REGISTER *)(REG_BASE + 0x2A))
>>  #define BAUD    (*(REGISTER *)(REG_BASE + 0x2B))

SCCR1 is declared volatile because it has the R8 bit, the ninth data bit 
received when SCI mode 1 is used.  The remaining bits in this register are 
write only.

>>  #define SCCR1   (*(volatile REGISTER *)(REG_BASE + 0x2C))
>>  #define SCCR2   (*(REGISTER *)(REG_BASE + 0x2D))
>>  #define SCSR    (*(volatile REGISTER *)(REG_BASE + 0x2E))
>>  #define SCDR    (*(volatile REGISTER *)(REG_BASE + 0x2F))
>>  #define OPTION  (*(REGISTER *)(REG_BASE + 0x39))
>>  #define COPRST  (*(REGISTER *)(REG_BASE + 0x3A))
>>  #define PPROG   (*(REGISTER *)(REG_BASE + 0x3B))
>>  #define HPRIO   (*(REGISTER *)(REG_BASE + 0x3C))
>>  #define INIT    (*(REGISTER *)(REG_BASE + 0x3D))
>>  #define TEST1   (*(REGISTER *)(REG_BASE + 0x3E))
>>  #define CONFIG  (*(REGISTER *)(REG_BASE + 0x3F))

C also allows us to declare individual bit fields as constants.  This 
allows us to make simple register bit assignments and comparisons.  For 
instance...

while (!(SPSR & SPIF));

...can be used to halt program execution until the SPI status register SPIF 
bit has set.  Likewise, we can use...

SPCR = SPIE + SPE + MSTR + CPHA + SPR0;

...to configure the SPI for master operation with interrupts using clock 
phase 1 and a baud rate of E clock divided by 4.  We can also use these 
constants to clear individual bit fields in the timer flag registers.

TFLG1 &= OC3F;

This clears output compare flag 3 without affecting the other bits in the 
TFLG1 register.

The following macro definitions are used for the register bit fields on the 
MC68HC11D3, MC68HC711D3, and MC68HC11D0 devices:

>>  /* Bit names for general use */
>>  #define bit7    0x80
>>  #define bit6    0x40
>>  #define bit5    0x20
>>  #define bit4    0x10
>>  #define bit3    0x08
>>  #define bit2    0x04
>>  #define bit1    0x02
>>  #define bit0    0x01

>>  /* PORTA bit definitions 0x00 */
>>  #define PA7     bit7
>>  #define PA6     bit6
>>  #define PA5     bit5
>>  #define PA4     bit4
>>  #define PA3     bit3
>>  #define PA2     bit2
>>  #define PA1     bit1
>>  #define PA0     bit0

>>  /* PIOC bit definitions 0x02 */
>>  #define CWOM    bit5

>>  /* PORTC bit definitions 0x03 */
>>  #define PC7     bit7
>>  #define PC6     bit6
>>  #define PC5     bit5
>>  #define PC4     bit4
>>  #define PC3     bit3
>>  #define PC2     bit2
>>  #define PC1     bit1
>>  #define PC0     bit0

>>  /* PORTB bit definitions 0x04 */
>>  #define PB7     bit7
>>  #define PB6     bit6
>>  #define PB5     bit5
>>  #define PB4     bit4
>>  #define PB3     bit3
>>  #define PB2     bit2
>>  #define PB1     bit1
>>  #define PB0     bit0

>>  /* DDRB bit definitions 0x06 */
>>  #define DDB7    bit7
>>  #define DDB6    bit6
>>  #define DDB5    bit5
>>  #define DDB4    bit4
>>  #define DDB3    bit3
>>  #define DDB2    bit2
>>  #define DDB1    bit1
>>  #define DDB0    bit0

>>  /* DDRC bit definitions 0x07 */
>>  #define DDC7    bit7
>>  #define DDC6    bit6
>>  #define DDC5    bit5
>>  #define DDC4    bit4
>>  #define DDC3    bit3
>>  #define DDC2    bit2
>>  #define DDC1    bit1
>>  #define DDC0    bit0

>>  /* PORTD bit definitions 0x08 */
>>  #define PD7     bit7
>>  #define PD6     bit6
>>  #define PD5     bit5
>>  #define PD4     bit4
>>  #define PD3     bit3
>>  #define PD2     bit2
>>  #define PD1     bit1
>>  #define PD0     bit0

>>  /* DDRD bit definitions 0x09 */
>>  #define DDD7    bit7
>>  #define DDD6    bit6
>>  #define DDD5    bit5
>>  #define DDD4    bit4
>>  #define DDD3    bit3
>>  #define DDD2    bit2
>>  #define DDD1    bit1
>>  #define DDD0    bit0

>>  /* CFORC bit definitions 0x0B */
>>  #define FOC1    bit7
>>  #define FOC2    bit6
>>  #define FOC3    bit5
>>  #define FOC4    bit4
>>  #define FOC5    bit3

>>  /* OC1M bit definitions 0x0C */
>>  #define OC1M7   bit7
>>  #define OC1M6   bit6
>>  #define OC1M5   bit5
>>  #define OC1M4   bit4
>>  #define OC1M3   bit3

>>  /* OC1D bit definitions 0x0D */
>>  #define OC1D7   bit7
>>  #define OC1D6   bit6
>>  #define OC1D5   bit5
>>  #define OC1D4   bit4
>>  #define OC1D3   bit3

>>  /* TCTL1 bit definition 0x20 */
>>  #define OM2     bit7
>>  #define OL2     bit6
>>  #define OM3     bit5
>>  #define OL3     bit4
>>  #define OM4     bit3
>>  #define OL4     bit2
>>  #define OM5     bit1
>>  #define OL5     bit0

>>  /* TCTL2 bit definitions 0x21 */
>>  #define EDG4B   bit7
>>  #define EDG4A   bit6
>>  #define EDG1B   bit5
>>  #define EDG1A   bit4
>>  #define EDG2B   bit3
>>  #define EDG2A   bit2
>>  #define EDG3B   bit1
>>  #define EDG3A   bit0

>>  /* TMSK1 bit definitions 0x22 */
>>  #define OC1I    bit7
>>  #define OC2I    bit6
>>  #define OC3I    bit5
>>  #define OC4I    bit4
>>  #define I4O5I   bit3
>>  #define IC1I    bit2
>>  #define IC2I    bit1
>>  #define IC3I    bit0

>>  /* TFLG1 bit definitions 0x23 */
>>  #define OC1F    bit7
>>  #define OC2F    bit6
>>  #define OC3F    bit5
>>  #define OC4F    bit4
>>  #define I4O5F   bit3
>>  #define IC1F    bit2
>>  #define IC2F    bit1
>>  #define IC3F    bit0

>>  /* TMSK2 bit definitions 0x24 */
>>  #define TOI     bit7
>>  #define RTII    bit6
>>  #define PAOVI   bit5
>>  #define PAII    bit4
>>  #define PR1     bit1
>>  #define PR0     bit0

>>  /* TFLG2 bit definitions 0x25 */
>>  #define TOF     bit7
>>  #define RTIF    bit6
>>  #define PAOVF   bit5
>>  #define PAIF    bit4

>>  /* PACTL bit definitions 0x26 */
>>  #define DDRA7   bit7
>>  #define PAEN    bit6
>>  #define PAMOD   bit5
>>  #define PEDGE   bit4
>>  #define DDRA3   bit3
>>  #define I4O5    bit2
>>  #define RTR1    bit1
>>  #define RTR0    bit0

>>  /* SPCR bit definitions 0x28 */
>>  #define SPIE    bit7
>>  #define SPE     bit6
>>  #define DWOM    bit5
>>  #define MSTR    bit4
>>  #define CPOL    bit3
>>  #define CPHA    bit2
>>  #define SPR1    bit1
>>  #define SPR0    bit0

>>  /* SPSR bit definitions 0x29 */
>>  #define SPIF    bit7
>>  #define WCOL    bit6
>>  #define MODF    bit4

>>  /* BAUD bit definitions 0x2B */
>>  #define TCLR    bit7
>>  #define SCP1    bit5
>>  #define SCP0    bit4
>>  #define RCKB    bit3
>>  #define SCR2    bit2
>>  #define SCR1    bit1
>>  #define SCR0    bit0

>>  /* SCCR1 bit definition 0x2C */
>>  #define R8      bit7
>>  #define T8      bit6
>>  #define M       bit4
>>  #define WAKE    bit3

>>  /* SCCR2 bit definitions 0x2D */
>>  #define TIE     bit7
>>  #define TCIE    bit6
>>  #define RIE     bit5
>>  #define ILIE    bit4
>>  #define TE      bit3
>>  #define RE      bit2
>>  #define RWU     bit1
>>  #define SBK     bit0

>>  /* SCSR  bit definitions 0x2E */
>>  #define TDRE    bit7
>>  #define TC      bit6
>>  #define RDRF    bit5
>>  #define IDLE    bit4
>>  #define OR      bit3
>>  #define NF      bit2
>>  #define FE      bit1

>>  /* SCDR bit definitions 0x2F */
>>  #define R7T7    bit7
>>  #define R6T6    bit6
>>  #define R5T5    bit5
>>  #define R4T4    bit4
>>  #define R3T3    bit3
>>  #define R2T2    bit2
>>  #define R1T1    bit1
>>  #define R0T0    bit0

>>  /* OPTION bit definitions 0x39 */
>>  #define IRQE    bit5
>>  #define DLY     bit4
>>  #define CME     bit3
>>  #define CR1     bit1
>>  #define CR0     bit0

>>  /* PPROG bit definitions 0x3B
>>   * MC68HC711D3 only
>>   */
>>  #define MBE     bit7
>>  #define ELAT    bit5
>>  #define EXCOL   bit4
>>  #define EXROW   bit3
>>  #define PGM     bit0

>>  /* HPRIO bit definitions 0x3C */
>>  #define RBOOT   bit7
>>  #define SMOD    bit6
>>  #define MDA     bit5
>>  #define IRVNE   bit4
>>  #define PSEL3   bit3
>>  #define PSEL2   bit2
>>  #define PSEL1   bit1
>>  #define PSEL0   bit0

>>  /* INIT  bit definitions 0x3D */
>>  #define RAM3    bit7
>>  #define RAM2    bit6
>>  #define RAM1    bit5
>>  #define RAM0    bit4
>>  #define REG3    bit3
>>  #define REG2    bit2
>>  #define REG1    bit1
>>  #define REG0    bit0

>>  /* TEST1 bit definitions 0x3E */
>>  #define TILOP   bit7
>>  #define OCCR    bit5
>>  #define CBYP    bit4
>>  #define DISR    bit3
>>  #define FCM     bit2
>>  #define FCOP    bit1
>>  #define TCON    bit0

>>  /* CONFIG bit definitions 0x3F */
>>  #define NOCOP   bit2
>>  #define ROMON   bit1    /* MC68HC11D3 only */
>>  #define EPON    bit1    /* MC68HC711D3 only */

DISCLAIMER: Motorola reserves the right to make changes without further 
notice to any products herein.  Motorola makes no warranty, representation 
or guarantee regarding the suitability of its products for any particular 
purpose, nor does Motorola assume any liability arising out of the 
application or use of any product or circuit, and specifically disclaims 
any and all liability, including without limitation consequential or 
incidental damages.  "Typical" parameters can and do vary in different 
applications.  All operating parameters, including "Typicals" must be 
validated for each customer application by customer's technical experts.  
Motorola does not convey any license under its patent rights nor the rights 
of others. Motorola products are not designed, intended, or authorized for 
use as components in systems intended for surgical implant into the body, 
or other applications intended to support or sustain life, or for any other 
application in which the failure of the Motorola product could create a 
situation where personal injury or death may occur.  Should Buyer purchase 
or use Motorola products for any such unintended or unauthorized 
application, Buyer shall indemnify and hold Motorola and its officers, 
employees, subsidiaries, affiliates, and distributors harmless against all 
claims, costs, damages, and expenses, and reasonable attorney fees arising 
out of, directly or indirectly, any claim of personal injury or death 
associated with such unintended or unauthorized use, even if such claim 
alleges that Motorola was negligent regarding the design or manufacture of 
the part.  Motorola is a registered trademark of Motorola, Inc.  Motorola, 
Inc. is an Equal Opportunity/Affirmative Action Employer.
