Файл: Programming Microcontrollers in C, 2-nd edit (Ted Van Sickle, 2001).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 4043
Скачиваний: 1
294 Chapter 6 Large Microcontrollers
program counter in this location will provide proper initialization of the program counter.
In the example above, the interrupt service routine OC3_Isr is placed in the address 0x46. Unfortunately, there is no easy way to accomplish this placement. The structure address must be counted by hand and the pointer placed at the correct location. The structure members are initialized only up to the vector with the highest ad dress. Note that the structure is global, so that its members will all be initialized to zero unless otherwise assigned. Notice also that the vectors up to vector number 0x18 are initialized. These vectors in clude all of the program-generated exceptions. These areas are where one would expect most of the problems to occur in debugging a pro gram. The vector numbers 0x19 through 0xff are left initialized to 0. These vectors are all accessed by either the internal modules or from external interrupts. If there are no hardware problems with the system, it is unlikely that external devices will cause uncalled-for interrupts, and if one of the internal modules causes an interrupt with an uninitialized vector, the CPU16 will access the uninitialized inter rupt vector.
One other problem can arise when debugging programs that involve user-specified interrupts. In the event that the isr address is improperly placed in the vector table, the program will become lost whenever the interrupt occurs. If such a program exhibits bizarre behavior, a good trick is to place a break point at the address 0. If the vector is wrong, an interrupt will take the proper vector which will contain a 0 and attempt to execute the code at the address 0. The break point at this location will stop execution and give you a clue as to the program error. A break point at _init_vector can also be useful to determine where the program is when an unexplained exception occurs.
If a compiler provides a mechanism that complies to the ANSI standard and one that does not, it is better to choose the ANSI stan dard mechanism rather than the nonstandard approach. For example, ANSI states nothing about how to establish a vector table. The above approach is but one of several that can be used to handle the place ment of the vectors in the vector table. Another approach is to use the vector macro that is found in hc16.h . The disadvantage to the vector macro is that it can place a vector into RAM only. Often with
The MC68HC16 295
embedded controls, it is necessary to place the vectors into ROM. In that case, the use of the routine vector.c is the best approach.
The use of the @port command is certainly not found in the ANSI standard. It is possible to create a complete interrupt service routine without the use of the @port. However, if C is used to the maximum, the isr will have some built-in inefficiencies. For ex ample, the language has no direct register commands so it is necessary to create a function that saves the status of the computer on entry to the routine, and another to restore the machine status prior to the return from the interrupt. Also, a special function must be created to execute the RTI instruction at the end of the interrupt service rou tine. These assembly routines can be created as function calls and saved in the header file. When they are used, it is wise to study care fully the code generated by the compiler to make certain that there are no errors in the code. For example, if a function should happen to clear some space on the stack for local storage, the placement of an RTI instruction in the C code sequence would cause the return op eration to be executed before the stack is restored. Such an error will cause serious problems in system performance if not corrected.
Both the @far and the @port commands are not in compliance with the ANSI standard. It is recommended that you use these com mands sparingly because their use causes nonportable code to be generated with the compiler. So far in this text, we have used two significantly different compilers. Each compiler manufacturer claims that their compiler complies to ANSI. In the case of the C6805 com piler from Byte Craft, it probably conforms as closely as can be expected for such a primitive machine. Both the MC68HC11 and the MC68HC16 compilers comply more closely to the standard than the C6805. Both of these machines are so much more computer that one should expect very close compliance. Any extension to the basic lan guage should be used with care. The above two commands are desirable and provide useful functions for the embedded control field.
The Cosmic compilers also have an extension that has not been used in this text. The way in which they define the internal registers to the machine is not standard, and it does not permit very efficient use of bit manipulation by the compiler. The approach used here is shown in the various header files written for the parts. The compiler writer assumes that the use of a construct like
296 Chapter 6 Large Microcontrollers
#define ABLE (*(Register *) 0x2000)
is too complicated for most programmers to understand. The ap proach that they use is nonportable, and the latter approach is completely portable among ANSI compliant compilers. It is recom mended that, even though the header files contain some code that might be difficult to explain, you should use the approach presented here to create code that is as portable as possible.
Some of the sections that follow will show how portable code can be used. Examples from both the MC68HC11 and the MC68HC05 will be used on the MC68HC16, and you will see that much of the code will be transferred with little change. Where would you expect changes? Recall the recommendation that each program be broken into three sections: the initialization section, the applications section, and the asynchronous service section. Each section will be subject to some change when moving from one machine to another, but the ap plications section will probably suffer little change and the other two sections will see the most changes when the code is moved. For ex ample, you will see that the initialization of theMC68HC16 is somewhat different from that of the MC68HC11, but the interrupt service rou tines will be nearly the same. In fact, in some cases the isr for the two parts is identical. On the other hand, the way that things are handled on the MC68HC05 is so different that the initialization and isr will probably have to be completely rewritten when moving code to one of the larger machines. However, here the machine-independent portions of the applications routine can be moved with little change.
System Integration Module (SIM)
A brief examination of the names of most of the modules will reveal their use. There is one notable exception—what is a system integration module (SIM)? The SIM is sort of the interface between the IMB and the outside world. It is very useful, and contains much of the circuitry that a hardware designer would have to incorporate to make a computer out of a microprocessor. The object of the chip designer with the introduction of the SIM was to make it possible to use the MC68HC16 in a system with a minimum of external cir cuitry. This section is not to provide you with a complete description of the SIM. The SIM Reference Manual is a 200-page document, and I’m not intending to duplicate that manual here. The following
System Integration Module (SIM) 297
paragraphs each contain a brief description of the several blocks found within the SIM. The set up and control of these blocks are all con trolled by the registers described in the SIM book on the CD-ROM.
System Configuration and Protection
This module monitors many of the things that can go wrong with the operation of the MC68HC16. Internal and external signals can be generated that signal an error has occurred. Reset signals can be originated from several sources. The reset status monitor keeps track of the source of the latest reset to help with debug operations. The halt monitor responds to a HALT signal on the internal bus. This monitor, if properly enabled, can request a reset. The bus monitor and the spurious interrupt monitor can each request a bus error. The bus monitor responds primarily to an unanswered asynchronous bus transfer request. Such a sequence is usually the result of a program access to unimplemented memory. If properly enabled, the spurious interrupt monitor can initiate a bus error.
There are two time-based functions in the system configuration and protection section of the SIM. The first is a software watchdog timer. This timer requires that the program access a memory location with a code sequence. This access resets a timer. With a proper pro gram, the special location in memory is accessed routinely in the normal execution of the program and the timer should never overflow. If it does, there is probably a system error that is corrected by a system reset. The periodic interrupt timer is used whenever a simple clocking sequence is needed. We will see use of this timer in a later section.
System Clock
The system clock provides timing signals for the IMB and all of the internal modules of the microcontroller. The time base for the microcontroller can be a 32768-kHz reference crystal , a 4.194-MHz crystal, or an external clock signal. If either of the crystal oscillators are used there is an internal phase-locked loop frequency multiplier that will multiply the operating frequency to the final system clock frequency.
External Bus Interface
The external bus interface transfers information between the IMB and external devices. This interface supports a 16-bit data bus, up to a
298 Chapter 6 Large Microcontrollers
24-bit address bus, a three-line function control signal bus, control sig nals for dynamic bus sizing, and handshaking for external bus arbitration.
Interrupts
The CPU16 contains a three-wire, seven-level interrupt system. These interrupts are interfaced to the SIM through the IMB. The outside world is interfaced into the SIM as seven individual interrupt lines which are multiplexed onto the three-wire line within the SIM. There are also two sources of interrupt from within the SIM itself. These interrupts are from the periodic interrupt timer and the soft ware watchdog timer.
Chip Selects
There are many signal lines on the microcontroller that might not be needed with a typical system. For example, address lines 20 through 23 all follow the condition of address line 19. Perhaps not all of the external interrupt lines are needed. Often the function con trol lines that can be used to decode the nature of a bus cycle—i.e., either data or program access—are not used. Altogether there are 12 signal lines that can be implemented as chip selects. This line will assert when there is an access within a memory range specified.
Reset and System Initialization
The microcontroller has several sources of reset. The reset and system initialization section directs the several resets to the proper operation, and records the source of the resets. Also, when the sys tem is reset initially, the state of several pins on the system bus is analyzed to determine the mode of the part when it exits the reset sequence.
General Purpose I/O
There are 16 SIM pins that can be configured as general-purpose input/output signals. These ports are ports E and F, and the pins are all multiply assigned. Port E pins, for example, are bus control pins, and Port F pins have a second use as the external interrupt inputs to the system.
A Pulse Width Modulation Program 299
A Pulse Width Modulation Program
While the MC68HC16 has a built-in pulse width modulation (PWM) system, it is sometimes desired to achieve more flexible reso lution than can be obtained with the built-in system. Therefore, it is not unreasonable that one would want to use the general-purpose timer to create a PWM. Prior to writing the code for a PWM in this manner, we should look at the basic time period of the processor. Unless otherwise directed, all of the timers in the GPT are driven by the system clock. This signal is passed through a prescaler controlled by the bits CPR2 through CPR0 in the register TMSK2. The default prescaler value will cause a clock rate to the GPT of the system clock divided by four.
The question now is the clock rate. Recall that the clock control is a portion of the SIM. Within the SIM there is a register named SYNCR. The clock frequency is controlled by the three bit fields named W, X, and Y in this register. When operating at a low crystal frequency—between 25 and 50 kHz—the formula for the system frequency is given by
s r |
(y +1) |
( |
22w+x |
) |
F = F 4 |
where y has a value between 0 and 63, and both w and x can have values of 0 or 1. With a frequency f of 32767 and the W, X, and Y default values of 0, 0, and 63, respectively, the device will come out of reset with a system frequency of 8.388 MHz. To be able to get the finest resolution for our timing functions, let us plan to operate the system clock frequency at its maximum value by changing the value of X from its default value of 0 to 1. This change will cause the system frequency to be 16.776704 MHz. The frequency of the input into the GPT is one-fourth this value or 4.194176 MHz. The time period for this frequency is 238 nanoseconds.
The code for a PWM on the MC68HC11 was shown in Chapter 5. A program that implements a PWM on the MC68HC16 is shown below.
/* This program provides a pwm output to OC3. The period will be the integer value found in pwm_period, and the on time will be the integer value found in pwm_count.
Keep pwm_count less than pwm_period. */
300Chapter 6 Large Microcontrollers
#include “hc16.h” #include “gpt.h” #include “sim.h”
#define PERIOD 0x1000 #define ON_TIME 0x0800 #define GPT_IARB 5 #define GPT_IRL 6 #define GPT_VBA 4
/* function prototypes */
@port void OC3_Isr( void); /* the PWM isr */
WORD pwm_period=PERIOD, pwm_count=ON_TIME;
main()
{
/* The initialization portion of the program */
SYNCR.X=ON; /* set the clock freq to 16.78 MHz */ SYPCR.SWE=OFF; /* disable the watchdog */
GPT_MCR.IARB=GPT_IARB; |
/* pick an IARB for the Timers */ |
||
ICR.IRL=GPT_IRL; |
/* |
interrupt level 6 */ |
|
ICR.VBA=GPT_VBA; |
/* |
vectors start at 0x40 */ |
|
OCONM.OCONM3=ON; |
/* |
sent OC1 out to pin */ |
|
CONM.OCONM5=ON; |
/* |
couple OC1 to OC3 */ |
|
TMSKON.OC3I=ON; |
/* |
enable the OC3 interrupt */ |
|
OCOND.OCOND5=ON; |
/* |
turn on OC3 when OC1 |
occurs */ |
TCTLON.OL3=ON; /* toggle OC3 when OC3 occurs |
*/ |
||
TOC1=TCNT+pwm_period;/* |
set OC1 to the period */ |
||
TOC3=TOC1+pwm_count; /* |
set OC3 time on */ |
||
cli(); /* enable the system interrupts */
/* the applications portion of the program */
FOREVER
{
}
}
/* The asynchronous service portion of the program */
@port void OC3_Isr( void) /* the PWM isr */
A Pulse Width Modulation Program 301 |
|
{ |
|
TFLG1.OC1F=OFF; |
/* reset OC1 interrupt flag */ |
if(OC1D.OC1D3==ON) /* compliment OC1D3 */ |
|
OC1D.OC1D3=OFF; |
|
else |
|
OC1D.OC1D3=ON; |
|
TFLG1.OC3F=OFF; |
/* reset OC3 interrupt flag */ |
TOC1+=pwm_period; |
|
TOC3=TOC1+pwm_count;
}
Listing 6-2: Elementary PWM Program For The MC68HC16
In keeping with the new usage of header files for writing code for the MC68HC16, the header files hc16.h, gpt.h, and sim.h are included in the above program. These files contain definitions of all registers needed for the implementation of this program.You should include hc16.h with every program or function that you write for this part. In this case, most of the program involves registers within the general purpose timer, so gpt.h is included. There is one regis ter accessed from the system integration module. Therefore, the header sim.h is also included.
The MC68HC16 contains a software watchdog. The part comes out of reset with the watchdog enabled. Therefore, unless a program periodically accesses the watchdog, the part will execute a watchdog reset. This periodic reset will make debugging of timing operations difficult. The watchdog is disabled in the first instruction of the ini tialization of the program. The next three instructions are MC68HC16-specific instructions.
The MC68HC16 has a seven-level interrupt system similar to the MC68000 family of parts. The seventh level is the highest priority and is the only nonmaskable interrupt for the part. The remaining levels are progressively lower priority until the level 0 is found. At level zero, no interrupt is being processed, and this level is where the processor usually operates. When an interrupt occurs, the hardware level of the interrupt is placed in the interrupt priority field of the code register. Further interrupts of the designated level or lower will remain pending until a RTI instruction restores the IP field to a lower level. This approach provides for priority selection among several internal or external interrupt sources.
302 Chapter 6 Large Microcontrollers
Another potential problem occurs when two internal modules are assigned the same priority level. In this case, a second level of arbitration is set up to choose among these several modules, in the event that more than one module requests an interrupt at the same time. The module control register of each module has a field called IARB. This 4-bit field is assigned by the programmer and it is an arbitration level that will be applied when the processor must select between two equal priority interrupts that occur simultaneously. The interrupting module with the largest IARB value will be given con trol of the processor. The IARB field can contain values from 0 to 15. When the module is being used, its IARB field must be assigned a non-zero value, and no two modules can contain the same IARB value. The code line
GPT_MCR.IARB=GPT_IARB;/* pick an IARB for the Timers */
places a value 5 into the IARB of the general purpose timer. The interrupt level 6 is assigned to the GPT by the code line
ICR.IRL=GPT_IRL; |
/* |
interrupt level 6 */ |
and the vector base address is assigned a value of 40 by the code line |
||
ICR.VBA=GPT_VBA; |
/* |
vectors start at 0x40 */ |
The means by which the vector assignment is accomplished in the GPT is different from that for the remaining modules in the MC68HC16. For the GPT, a 4-bit vector base address field is found in the interrupt configuration register. A vector is an 8-bit value.
The vector assignment is accomplished when the value placed in the VBA field of the ICR is used as the high nibble of an 8-bit num ber. The lower four bits are specified by the contents of Table 6-2. There you will note that the vector address of OC3 is at 0xV6. When the contents of the VBA field is 4, then the vector for OC3 is 0x46. The vector address is twice the value of the vector or 0x8c in this case. That is the reason that the address OC3_Isr is placed in the address 0x8c in the vector initialization routine.
You will note that each interrupt in the timer will be assigned a vector with the most significant nibble of the value placed in the VBA field of the ICR. There is a prearranged priority among these several interrupts. One interrupt can be moved to the highest priority among the several timer interrupts if desired. The priority adjust bits