manufacturer of I/O-rich SBCs, operator interfaces, handheld instruments, and development tools for embedded control low cost single board computers, embedded controllers, and operator interfaces for scientific instruments & industrial control development tools for embedded control order our low cost I/O-rich embedded control products embedded controller manufacturer profile single board computers & embedded controllers development tools & starter kits for your embedded design operator interfaces with touchscreens and graphical user interface plug-in expansion modules for digital & analog I/O C language & Forth language integrated development tools, IDE single board and embedded computer accessories embedded controller enclosures, bezels, environmental gaskets

The C Programmer’s Guide to the QVGA Controller

Table of Contents

PART 1 GETTING STARTED

Introduction. How to Use This Manual

Chapter 1: Getting to Know Your QVGA

PART 2 PROGRAMMING THE QVGA CONTROLLER

Chapter 2: Your First Program

Chapter 3: The IDE: Writing, Compiling, Downloading and Debugging Programs

Chapter 4: Making Effective Use of Memory

Chapter 5: Programming the Graphical User Interface

Chapter 6: Real Time Programming

Chapter 7: Failure and Run-Time Error Recovery

PART 3 COMMUNICATIONS, MEASUREMENT, AND CONTROL

Chapter 8: Digital and Timer-Controlled I/O

Overview of Available Digital I/O

Using the Digital I/O Ports on the 68HC11 Chip

Using the PIA

Using the High Current Drivers

Connecting Hardware to the Digital Outputs

The Processor’s Output Compare Functions

Pulse and PWM Generation Techniques

Chapter 9: Data Acquisition Using the QVGA Controller

Chapter 10: Outputting Voltages with Digital to Analog Conversion

Chapter 11: Serial Communications

Chapter 12: The Battery-Backed Real Time Clock

PART 4: PUTTING IT ALL TOGETHER

Chapter 13: A Turnkeyed Application

PART 5: REFERENCE DATA

Appendix A: QVGA Electrical Specifications

Appendix B: Connector Pinouts

Appendix C: Physical Dimensions

Appendix D: Schematics (pdf)

Chapter 8

<< Previous | Next>>

Chapter 8: Digital and Timer-Controlled I/O

Overview of Available Digital I/O

The QVGA Controller provides 30 digital I/O lines, 24 analog I/O lines, and three communications channels.  The digital I/O lines originate in four ports on the CPU (68HC11), designated PORTA, PORTB, PORTC, and PORTD, and three additional ports provided by a peripheral interface adapter (PIA) chip (82C55A), designated PPA, PPB and PPB.  Table 8‑1 summarizes the digital I/O available, its alternate uses, and port assignments.

Table 8‑1   The QVGA Controller’s Digital I/O

I/O Lines

Type

Port Address

Comments / Alternate Uses

8

Configurable either as all digital inputs or outputs

PPA 0-7

Initialized on start-up and resets as inputs.

5

Digital outputs

PPB 0-4

Initialized as outputs, but if the high-current drivers that use PPB 5-7 are not needed, PPB may be software reconfigured to all inputs.

4

Open-drain high-current outputs

PPB 5-7 and PAL bit

 

4

Digital inputs

PPC 0-3

Initialized on start-up and resets as inputs, but may be reconfigured as all outputs.

3

Configurable either as all digital inputs or outputs

PPC 5-7

Initialized as inputs but if RS485 is used PPC5-7 must be reconfigured as outputs.

6

Timer-controlled inputs or outputs including 3 input-capture, 3 output-compare, and pulse accumulator

PA 0-2, 5-7

Bit-by-bit configured by the application as inputs or outputs, including:
          Timed inputs:   PA 0-2
       Timed outputs:   PA 5-7
Pulse accumulator:  PA 7

30

Digital I/O lines

 

 

There are a total of 30 fully uncommitted digital I/O lines for your use.  After initialization or reset these are configured as 21 digital inputs and 9 digital outputs, but as Figure 8‑1 shows many of these I/O lines are reconfigurable.  Up to 21 of these I/O lines can be configured as inputs, all can be configured as outputs. 

In addition to these I/O lines there are several committed to other services on the controller; these are summarized in Table 8‑2.

Table 8‑2      Committed I/O pins

Service

Port

Pins

RS-485

PIA PPC

PPC 4

8-bit A/D

CPU PORTE

PE 0-7

Serial 2

CPU PORTA

PA 3-4

SPI

CPU PORTD

PD 2-5

For applications requiring even more digital I/O, I/O lines usually committed to the 8-bit A/D, the RS485 port, the secondary serial port or the SPI may be redirected as general purpose digital I/O if these other services are not needed, providing up to 15 additional digital I/O lines.  Table 8‑3 summarizes the digital I/O lines gained if other services are not used.  The services uses are ordered from the least-used (the RS485) to the most frequently used (the SPI).  Note that the SPI is required to use the 12-bit A/D and any Wildcard I/O expansion modules.  The five of the 9 output lines that originate on PPB (PPB 0-4) may be converted to input lines if the high current drivers are not needed.  In that case, PPB can be reconfigured as all inputs, 9 outputs can be traded for 5 inputs, for a loss of 4 total lines but a gain of 5 more inputs.

Table 8‑3      Additional digital I/O lines made available if other services are forfeited and their committed I/O pins freed.

Services Used

Digital I/O Available

RS485

8-bit A/D

Serial 2

SPI

Inputs

Outputs

Total

Initial

Max

Initial

Max

Yes

Yes

Yes

Yes

21

21

9

30

30

No

Yes

Yes

Yes

22

22

9

31

31

No

No

Yes

Yes

30

30

9

39

39

No

No

No

Yes

32

32

9

41

41

No

No

No

No

36

36

9

45

45

Many of these 57 I/O lines are digital inputs and outputs.  Including the high current drivers the maximum number of digital inputs and outputs is 41 (up to 32 can be configured as inputs, up to 29 as outputs) if none are used for the 8-bit A/D, the RS485, or the secondary serial port.  Table 8‑1  summarizes the digital I/O and alternate use of some of the I/O pins.

Digital inputs and outputs are very useful in data acquisition, monitoring, instrumentation and control applications.  A low voltage (approximately 0 Volts) is established on a digital output pin when the processor writes a logical 0 to the corresponding bit in a data register associated with the digital output port.  A high voltage (approximately 5 Volts) is established on the digital output pin when the processor writes a 1 to a corresponding bit in the port’s data register.  This allows software to control external events and processes.  For example, an application program can use digital outputs to activate solenoids and turn switches and lights on and off, or to interface the QVGA Controller with a wide variety of digital accessories.

A digital input allows the processor to monitor the logical state of an external voltage by reading a data register associated with the port.  External voltages near 0 Volts connected to a digital input cause the corresponding bit in the port’s data register to be read as a logical 0, and external voltages near 5 Volts connected to a digital input are read as a logical 1.  Application programs can use digital inputs to read switches and keypads or to interface to digital devices such as A/D converters and real-time clocks.

In addition, there are four high current drivers available.  These N-channel MOSFET outputs can sink 150 mA continuously, and up to 1 amp on an intermittent basis.  Onboard snubber diodes allow control of inductive loads.  They are particularly useful for driving relays, solenoids, and low power stepper motors.

Using digital I/O is very easy: simply configure the output port as input or output as explained below, and then use functions or assignment statements to read from or write to the port.  The names of the data and direction registers and all required initialization routines are pre-defined in the header files so you don’t have to worry about hexadecimal register addresses in your code. 

The following sections describe the available digital I/O ports and how to use them.

The digital I/O signals on the QVGA Controller originate from a Motorolla 68HC11 processor chip and an 82C55A peripheral interface adapter (PIA) chip.  The 68HC11 provides two 8 bit ports named PORTA and PORTE, and 4 available bits on PORTD (PD2 through PD5).  The PIA supplies three 8 bit digital I/O ports named PPA, PPB, and PPC.

Table 8‑4  summarizes the digital input/output available on the QVGA Controller including the names, addresses, and number of signals associated with the digital ports on the 68HC11 and PIA.  The “configurable as” column specifies whether the direction of the port may be changed on a bit-by-bit, nibble-by-nibble, or byte basis (or in the case of PORTE, configured as digital or analog input). The final column lists alternate uses (other than standard digital I/O), the signal pins and the number of signals associated with the alternate uses.  Note that a fourth High Current driver output is controlled by the onboard PAL.

Table 8‑4      Digital I/O Port Addresses and Configurability.

Port Name

Address (HEX)

I/O Line

Configurable As

     Alternate Use    (Signals Used)

68HC11:

 

 

 

 

PORTA

8000

8

Bitwise I/O

                     Serial2:   PA3 & PA4  (2)
Pulse accumulator:  PA7              (1)
          Timed inputs:   PA0-3       (3 or 4)
       Timed outputs:   PA3-7       (4 or 5)

PORTD

8008

4

Bitwise I/O

SPI controls AD12 & DAC             (4)

PORTE

800A

8

Bytewise digital or analog input

                   8 bit A/D:   PE0-7          (8)

PIA:

 

 

 

 

PPA

8080

8

Bytewise I/O

 

PPB

8081

8

Bytewise I/O

High Current Outs:   PPA5-7        (3)

PPC lower

8082

4

Nibblewise I/O

        Keypad Inputs:   PPC0-3       (4)

PPC upper

8082

4

Nibblewise I/O

                     RS485:   PPC4           (1)

Table 8‑5  specifies the named data direction register which controls the input/output direction, or specifies the functions that configure each digital I/O port.

Table 8‑5      Digital I/O port data direction registers and configuration functions.

Port Name

Configured By

68HC11:

 

PORTA

DDRAPORTA.DIRECTION

PORTD

DDRDPORTD.DIRECTION

PORTE

AD8On()
AD8Off()
A/D8.ON
A/D8.OFF

PIA:

 

PPA

InitPIA()INIT.PIA

PPB

InitPIA()INIT.PIA

PPC lower

InitPIA()INIT.PIA

PPC upper

InitPIA()INIT.PIA

Alternate Uses of the Digital I/O Ports

Some of these port signals have alternative uses as summarized in Table 8‑4 .  The 68HC11’s I/O ports and the PIA ports can serve a variety of selectable functions: 

[[[Figure  1.2 summarizes the digital and analog I/O available on the QED Board.  It specifies the origin of the signals, their type and configurability, and the number of signals dedicated to alternate uses. The following text explains the contents of Figure 1.2.

The 24 I/O lines originating at the PIA are named Peripheral Port A (PPA), Peripheral Port B (PPB), and Peripheral Port C (PPC).  PPA is an 8 bit digital I/O port available for the user’s application; it can be configured as either input or output. 

PPB is an 8 bit digital port dedicated to the built-in keypad/display interface (PPB0 to PPB6) and to the generation of the chip select signal for the optional 12 bit A/D (PPB7).  It is configured as an output port by QED-Forth. 

PPC is split into two 4 bit digital I/O ports called lower PPC (PPC0 to PPC3) and upper PPC (PPC4 to PPC7).  Lower PPC is used to scan the keypad.  If RS485 communications is not in use, all of upper PPC is available for the user’s application; it can be configured as either input or output.  If RS485 is being used, one bit in upper PPC (PPC4) is dedicated to controlling the direction of data transfer, and the remaining three output bits (PPC5 to PPC7) are available for the user’s application.

As shown in Figure 1.2, the 68HC11’s PORTA is an 8 bit digital I/O port configurable as input or output on a bit by bit basis.  These signals can also be used to implement input captures (PA0 to PA3), output compares (PA3 to PA7), and a pulse accumulator (PA7).  The secondary serial port, if used, ties up two of the PORTA lines (PA3 and PA4) to implement the receive and transmit signals.

PORTD on the 68HC11 contains 4 digital I/O bits (PD2 to PD5) that implement the fast serial peripheral interface (SPI).  If the SPI is not in use (which implies that the 12 bit A/D and 8 bit DAC are not on the board), these four lines are available as general purpose inputs or outputs.

The final three entries in the table in Figure 1.2 present the analog I/O ports on the QED Board.  PORTE on the 68HC11 implements the 8 channel 8 bit A/D.  If this A/D is not in use, PORTE can be configured as an 8 bit digital input port.  The optional 8 channel (or 4 channel differential) 12 bit A/D provides 8 analog inputs, and the optional 8 channel 8 bit DAC provides 8 analog outputs.  As explained in Chapter 6, pairs of DACs may be combined to achieve higher resolution digital to analog conversion.]]]

PORTA

PORTA may be used as bit-configurable digital input/output.  The data direction (input or output) of each bit in PORTA is determined by writing to the DDRA register as described below.  If any bits in PORTA are not being used for simple digital I/O, they may be used to implement a variety of counting and timing functions including input captures, output compares, and pulse accumulation.  In addition, the QED Board provides an optional software UART that supports a secondary RS232 serial port (called serial2) using pins 3 and 4 of PORTA. 

PORTD

PORTD is a 6 bit port that is typically dedicated to serial I/O (PD0 and PD1) and to the Serial Peripheral Interface (PD2-PD5).  The SPI is a fast synchronous serial link which is used to communicate with the optional onboard 12 bit analog to digital converter (A/D12) and 8 bit digital to analog converter (DAC).  The SPI is turned on by executing InitSPI() or InitAD12andDAC() and is turned off by executing SPIOff().  The SPI is initially off after a reset or restart.  If you have ordered a custom board with no 12 bit A/D or DAC, you may use PD2-PD5 as 4 general purpose digital I/O bits whose data direction is set by register DDRD and whose contents are accessible at register PORTD.

PORTE

PORTE provides 8 input lines.  They may be used as the analog inputs to the 68HC11’s built-in 8 bit A/D converter, or they may be used as general purpose digital inputs if the 8 bit A/D converter is turned off.  The AD8On() function turns the 8 bit A/D on, and AD8Off() turns it off.  The 8 bit A/D is initially off after a reset or restart.

PPA

PPA has no alternate functions and is available as a general purpose digital input port or output port. 

PPB

Three bits of PPB are dedicated to controlling three of the open-drain high-current drivers.  The remaining 5 lines are available for your use .

PPC

The upper 4 bits of PPC are available as digital input or output if RS485 communications are not being used.  If RS485 communications are used, bit 4 of PPC (that is, the lowest bit in the upper nibble of PPC) controls the direction of the RS485 transceiver, and the upper half of PPC must be configured as an output (see the Glossary entry for InitRS485).

Using the Digital I/O Ports on the 68HC11 Chip

This section describes how to configure and access the PORTA and PORTE digital ports in the 68HC11 chip on the QED Board. 

As you work through the examples in the remaining sections of the chapter, you can use a voltmeter to verify that the outputs are behaving as you expect.  You can also connect the input signals through a 1 kOhm resistor to +5V or GND to verify that you can digitally read their values. (The 1 kOhm resistor is just a safety precaution to minimize the chance that you’ll “blow out” a port bit by mistakenly connecting an output bit to a supply voltage; even if you make this mistake, the resistor would limit the current to safe levels.)

Digital inputs and outputs are very useful in data acquisition, monitoring, instrumentation and control applications.  A low voltage (near 0 Volts) is established on a digital output pin when the processor writes a logical 0 to the corresponding bit in a data register associated with the digital output port.  A high voltage (near 5 Volts) is established on the digital output pin when the processor writes a 1 to a corresponding bit in the port’s data register.  This allows software to control external events and processes.  For example, an application program can use digital outputs to activate solenoids and turn switches and lights on and off, or to interface the QVGA Controller with a wide variety of digital accessories such as D/A converters, displays, etc.

A digital input allows the processor to monitor the logical state of an external voltage by reading a data register associated with the port.  External voltages near 0 Volts connected to a digital input cause the corresponding bit in the port’s data register to be read as a logical 0, and external voltages near 5 Volts connected to a digital input are read as a logical 1.  Application programs can use digital inputs to read switches and keypads or to interface to digital devices such as A/D converters and real-time clocks.

Using digital I/O is very easy:

   0.   Configure the direction of the digital I/O port.  This is accomplished by writing to a named data direction port (in the case of PORTA and PORTD) to set the directions of individual bits within a port, or by executing an initialization routine such as INIT.PIA.

   0.   To change the state of an output port, write to the port’s data register (whose address is left on the stack by simply stating the name of the port) using C!, SET.BITS, CLEAR.BITS, or other pre-defined operators.

   0.   To read the state of an input port, read the port’s data register with a C@ command; the result is left on the data stack.

The names of the data and direction registers and all required initialization routines are pre-defined in the QED-Forth kernel so you don’t have to hassle with hexadecimal register addresses in your code.  The following sections describe the available digital I/O ports and how to use them.

QED-Forth Provides Named Registers and Pre-coded Configuration Routines

The ports are addressed in common memory .  The 68HC11 ports are associated with data and direction registers in the processor’s 96 byte block of “Control and Status Registers” located at 8000H-805FH; Appendix B summarizes the contents of all of these registers.  The PIA ports are associated with data registers addressed at 8080H-8082H and a control register at address 8083H.

QED-Forth names the digital I/O ports, and when the name is executed the 32 bit extended address of the port’s data register is left on the stack.  This makes it easy to access the port; simply state the port’s name and use the standard byte fetch and store operations C@ and C! to read or write to the port.  Individual bits in the digital ports can also be modified with operators such as SET.BITS, CLEAR.BITS, TOGGLE.BITS, and CHANGE.BITS

The names of the digital I/O ports and the respective hexadecimal addresses left on the stack are as follows:

 

PORTA ( -- 8000\0 )

PORTD ( -- 8008\0 )

PORTE ( -- 800A\0 )

PPA   ( -- 8080\0 )

PPB   ( -- 8081\0 )

PPC   ( -- 8082\0 )

QED-Forth also makes it easy to configure the data direction (input or output) of the I/O ports.  The directions of the individual bits in PORTA and PORTD are controlled by direction registers which are named in QED-Forth.  The direction register names and the respective hexadecimal addresses left on the stack are as follows:

 

PORTA.DIRECTION   ( -- 8001\0 )

PORTD.DIRECTION   ( -- 8009\0 )

Writing a 1 to a bit in the data direction register sets the corresponding port bit to an output, and writing a 0 configures the bit as an input.  The commands C!, SET.BITS, or CLEAR.BITS can be used to modify the contents of the data direction registers.  Any combination of input and output bits may be specified for these ports.

The data direction of the PIA ports are set by the routine INIT.PIA which is described later in this chapter and in the glossary. 

PORTE on the 68HC11 can be configured as an 8 channel 8 bit analog to digital converter by executing A/D8.ON, and it reverts to its default condition as an 8 channel digital input port after execution of A/D8.OFF.

Setting the Data Direction of PORTA and PORTD

Two named registers control the direction of the bits in PORTA and PORTD, respectively:

 

PORTA.DIRECTION

PORTD.DIRECTION

Writing a 1 to a bit in the direction register sets the corresponding port bit as an output, and writing a 0 to a bit in the direction register sets the corresponding port bit as an input.  A one-to-one correspondence exists between bits in the data direction register and its corresponding port.  These two ports are configurable on a bit-by-bit basis, so any combination of inputs and outputs can be specified.

For example, to set PORTA as all input, execute

 

00  PORTA.DIRECTION C!

To set the lower 4 bits of PORTA as input and the upper 4 bits as outputs, execute

 

HEX F0 PORTA.DIRECTION C!

To set the least significant bit of PORTA as an input while leaving the direction of all other bits unchanged, execute

 

01 PORTA.DIRECTION CLEAR.BITS

which clears the least significant bit in PORTA.DIRECTION to 0.

 

The direction of PORTD is controlled in the same way.  Recall that PORTD is a 6 bit port, and the two least significant bits are used by the primary serial channel.  This leaves the four bits PD2 through PD5 available for digital I/O if they are not used for the SPI.  For example, to set the four available bits PD2 through PD5 to all outputs, execute

 

HEX 3C PORTD.DIRECTION C!

The command

 

HEX FF PORTD.DIRECTION C!

has the exact same effect; the two least significant bits in PORTD are not affected by the PORTD.DIRECTION register, and the two most significant bits in PORTD do not exist.

Configuring PORTE as a Digital Input Port

PORTE is always an input port.  After each reset and restart, it is configured as an 8 channel digital input port.  Executing

 

A/D8.ON

turns on the 8 bit analog converter and configures PORTE as an 8 channel 8 bit analog input port (see Chapter 6).  Executing

 

A/D8.OFF

turns off the 8 bit A/D and configures PORTE as an 8 channel digital input port.

(For experts and the curious:  A/D8.OFF turns the 8 bit analog converter off by clearing the A/D power up bit named ADPU in the OPTION register; A/D8.ON sets the ADPU  bit; see MC68HC11F1 Technical Data Manual, p.6-4.)

For Experts: Fast Port Accesses

The following comments may help those who need maximum speed when accessing a port from within a Forth definition. 

Because all of the named digital I/O ports are located in common memory, the fast page-less operator (C@) can be used to access the ports.  For example, the command

 

PORTE DROP (C@)   ( -- byte )

returns the same result as the command PORTE C@(C@) executes more rapidly than C@ because it does not change pages during the read operation.  But this time savings is mostly offset by having PORTE place the full extended address including page on the data stack at runtime, and then calling DROP to remove the page from the stack.  A more efficient method is to instruct the compiler to place only the 16 bit address on the stack at runtime, and then call (C@) to read the contents.  The following definition shows how this can be accomplished:

 

: READ.PORTE   ( -- )

   [ PORTE DROP ] LITERAL (C@)            \ this is a very fast fetch

   CR .” The contents of PORTE = “ .      \ display the result

;

The [ is an immediate word that invokes the execution mode.  PORTE DROP places the 16 bit address of the port on the data stack, and  ] re-enters the compilation mode.  LITERAL removes the 16 bit address of the port from the data stack and compiles it as a literal that will be placed on the stack at runtime so that (C@) may fetch its contents.  The rest of the definition prints the result.  This same technique may be used to read, modify, or write to any location in common memory.  A wide variety of fast page-less operators are available in the kernel, including (@), (!), (F@), (F!), (SET.BITS), (CLEAR.BITS), (TOGGLE.BITS), and (CHANGE.BITS).

Of course, the fastest way to access the contents of a port in common memory is to use assembly code.  The following routine leaves the contents of PORTE on the data stack:

 

CODE FETCH.PORTE.CONTENTS ( -- byte )

   PORTE DROP EXT LDAB \ B gets contents of portE

   CLRA \ zero upper byte of double accumulator

   DEY DEY \ make room on data stack

   0 IND,Y STD \ put result on data stack

   RTS

END.CODE

Because all of the named port addresses are located in the common memory, it is safe to DROP the page and use an assembly coded “load” operation such as LDAB to fetch the contents of the port.  Note that when assembly coding accesses to locations that are not in common memory, it is best to call the pre-coded memory access routines in the QED-Forth kernel (such as C@) which properly handle the page changes.

Port Initialization

The PORTA bits PA0 through PA7 are configured as inputs after a reset or restart, unless the serial2 port is specified as the default startup port (see the glossary entry for SERIAL2.AT.STARTUP).  If the secondary serial port is automatically initialized at startup, then PA4 is initialized as the serial output and PA3 is configured as the serial input.  The remaining PORTA pins are configured as digital inputs after the reset or restart.

PORTD bits PD2 through PD5 are configured as digital inputs after a reset or restart.  PORTE bits PE0 through PE7 are configured as digital inputs after a reset or restart; the default state of the 8 bit A/D converter is OFF.

Summary of Port Access

This chapter describes how to configure and access the 68HC11 digital I/O ports A, D and E and the PIA ports PPA, PPB, and PPC.  To use the digital I/O ports, follow these three simple steps.

   0.   Configure the direction of the digital I/O port.

      To configure PORTA, write to the PORTA.DIRECTION register using C! or a bit manipulation routine such as SET.BITS or CLEAR.BITS.  Writing a 1 to a bit position in PORTA.DIRECTION configures the corresponding port bit as an output, and writing a 0 to a bit position configures the corresponding bit as an input.  PORTA is configurable on a bit-by-bit basis.

      To configure PORTD, write to the PORTD.DIRECTION register.  PORTD is a 6 bit port, and the two least significant bits are used by the primary serial channel.  This leaves the four bits PD2 through PD5 available for digital I/O if they are not used for the SPI.  The available PORTD pins are configurable on a bit-by-bit basis.

      To configure PORTE for analog input, execute A/D8.ON.  To configure PORTE for digital input, execute A/D8.OFF. PORTE is configured as a digital input after a reset or restart.

      To configure the PIA, place two flags on the stack and execute INIT.PIA.  The first flag specifies the direction of PPA, and the second flag (top flag on the stack) specifies the direction of the upper nibble of PPC.  A true flag specifies output and a FALSE flag specifies input.  INIT.PIA configures PPB as an output and lower PPC as an input to ensure compatibility with the keypad/display drivers.

   0.   To change the state of an output port, write to the port’s data register (whose address is left on the stack by simply stating the name of the port) using C!, SET.BITS, CLEAR.BITS, or other pre-defined operators.

   0.   To read the state of an input port, read the port’s data register with a C@ command; the result is left on the data stack.

PORTA

PORTA is configurable as input or output on a bit-by-bit basis. To configure PORTA, use an assignment statement to write to the DDRA (Data Direction Register A) register.  DDRA and all 68HC11 register names are defined in the QEDREGS.H file in the \FABIUS\INCLUDE\MOSAIC directory.  Writing a 1 to a bit position in DDRA configures the corresponding port bit as an output, and writing a 0 to a bit position configures the corresponding bit as an input. For example, the following C statement configures PORTA as all outputs:

 

DDRA = 0xFF;

To configure PORTA as all inputs, use the statement:

 

DDRA = 0x00;

If we want to configure bits 0-6 as inputs, and bit 7 as output, we can execute:

 

DDRA = 0x80;

To change the state of an output bit on PORTA of the 68HC11 chip, use an assignment statement with PORTA on the left hand side to write to the port’s data register named PORTA.  For example, if PORTA is configured as all outputs, the following C statement sets all PORTA bits high:

 

PORTA = 0xFF;

To read the state of PORTA, use an assignment statement with PORTA on the right hand side to read the port’s data register. For example, the following code fragment reads PORTA and places the results in the variable named latest_porta_state:

 

static unsigned char latest_porta_state;

latest_porta_state = PORTA;

PORTE

PORTE (named in the QEDREGS.H file) is an 8 bit analog or digital input port.  PORTE is configured as a digital input after a reset or restart, and is read in the same way that PORTA is read: simply use it as the right hand side of an assignment statement.  For example, to read the digital state of PORTE, your program could execute the statements:

 

static unsigned char latest_porte_state;

latest_porte_state= PORTE;

To configure PORTE for analog input, use the function:

 

AD8On()

To turn off the 8 bit A/D and revert to a digital input port, use:

 

AD8Off() 

(For experts and the curious:  AD8Off() turns the 8 bit analog converter off by clearing the A/D power up bit named ADPU in the OPTION register; AD8On() sets the ADPU bit.)

Using the PIA

This section describes how to configure and access the available I/O ports of the Peripheral Interface Adapter (PIA) on the QED Board.

PIA Initialization

The QED-Forth word

 

INIT.PIA ( flag1\flag2 -- | flag1 = ppa.output?, flag2 = upper.ppc.output?)

writes to the peripheral interface adapter (PIA) configuration register to set the data direction for PPA and the upper 4 bits of PPC.  If flag1 is true, INIT.PIA configures PPA as output, and if flag 1 is false, it configures PPA as input.  Likewise, if flag2 is true, INIT.PIA configures upper PPC as output, and if flag 2 is false, it configures upper PPC as input.  INIT.PIA sets the direction of PPB as output and lower PPC as input to ensure compatibility with the built-in keypad and display interfaces.  It clears bit 6 of PPB and sets bit 7 of PPB high so that the display.enable and 12 bit A/D chip select signals are inactive.  If the specified input/output configuration of the PIA is the same as the prior configuration, INIT.PIA does not modify the PIA configuration register, and thus does not change the state of any output pins in PPA or upper PPC.  If the specified PIA configuration is different than the prior configuration, INIT.PIA writes to the PIA’s configuration register and this automatically zeros any outputs in PPA or upper PPC.  Consult the PIA data sheet in Appendix C for details of the PIA operation. 

The function

 

void InitPIA( int ppa_output_flag, int upper_ppc_output_flag)

writes to the PIA configuration register to set the data direction for PPA and the upper 4 bits of PPC.  If ppa_output_flag is true (non-zero), InitPIA() configures PPA as output, and if ppa_output_flag is false (zero), it configures PPA as input.  Likewise, if upper_ppc_output_flag is true, InitPIA() configures the upper four bits of PPC as output, and if upper_ppc_output_flag is false, it configures upper PPC as input.  InitPIA() sets the direction of PPB as output and lower PPC as input to ensure compatibility with the built-in keypad and high current driver interfaces . It clears bits 5, 6 and 7 of PPB which control high current driver outputs HC1, HC2, and HC3.

Warning!

There may be a short transient ON condition on the three high current outputs during power-up and reset.  The state of the PIA chip can not be controlled when it is initially turned on or reset.  A consequence of this is that in the interval of time between power-up and the operating system’s initialization of the output to an OFF condition, there may be a short transient ON.  You may need to take appropriate precautions in critical applications.

Additionally, if the specified PIA configuration is different than the prior configuration, INIT.PIAInitPIA() writes to the PIA’s configuration register and this automatically zeros any outputs in PPA or upper PPC, even if the direction of PPA or PPC was not changed!

If the specified input/output configuration of the PIA is the same as the prior configuration, INIT.PIAInitPIA() does not modify the PIA configuration register, and thus does not change the state of any output pins in PPA or upper PPC.  But, if the specified PIA configuration is different than the prior configuration, INIT.PIAInitPIA() writes to the PIA’s configuration register and this automatically zeros any outputs in PPA or upper PPC, even if the direction of PPA or PPC was not changed!  Consequently, INIT.PIAInitPIA() may disrupt in-progress operations involving the 12 bit A/D, keypad, or display.  INIT.PIA is called by INIT.A/D12&DAC, INIT.DISPLAY, and INIT.RS485Consult the PIA data sheet for details of the PIA operation. 

When designing your application, the safest course is to perform all required initializations in an autostart routine as soon as the application program begins.  This avoids the problem of a late initialization that disturbs an in-progress I/O operation.

Upon each reset or restart, the PIA is configured as follows:

 

Port

Direction

PPA

input

PPB

output

lower PPC

input

upper PPC

input

Accessing PIA Ports PPA, PPB and PPC

The PIA (ports PPA, PPB, and PPC) uses as special set of routines to input or output values. These routines employ clock stretching to slow down the access of the on-board PIA to ensure that its timing criteria are met. 

 

For example, to set all the bits of PPA to zero you would execute,

   0   PPA PIA.C!

The PIA.C! routine performs clock stretching (in other words, inserts wait states) during the access to PPA to guarantee that the timing conditions of the PIA are met.  It also disables interrupts for 27 cycles (less than 7 microseconds) during the memory access.

Similarly, PIA port bits can be read, set, cleared, toggled, and changed using the routines PIA.C@, PIA.SET.BITS, PIA.CLEAR.BITS, PIA.TOGGLE.BITS, and PIA.CHANGE.BITS, respectively.  Full descriptions for these routines are in the attached Glossary.

Because the timing of the PIA chip are slightly too slow for simple assignment-statement accesses to be “guaranteed by design” at a 16 MHz clock speed, a set of access functions has been defined that inserts a wait state while the PIA is being accessed.  This guarantees reliable performance over all device variations and temperature extremes.  To access the ports of the PIA (Peripheral Interface Adapter) chip, use the following functions defined in the PIA.H file and described in the Control-C Glossary:

 

void  PIAStore( uchar c, xaddr address )

uchar PIAFetch( xaddr address )

void  PIAChangeBits( uchar data, uchar mask, xaddr address )

void  PIAClearBits( uchar mask, xaddr address )

void  PIASetBits( uchar mask, xaddr address )

void  PIAToggleBits( uchar mask, xaddr address )

The three PIA port addresses are also defined as macros in the PIA.H file:

 

#define PPA_ADDRESS  ((xaddr) 0x8080)

#define PPB_ADDRESS  ((xaddr) 0x8081)

#define PPC_ADDRESS  ((xaddr) 0x8082)

where “xaddr” is a 32-bit extended address type specifier defined in the TYPES.H file.

These functions are easy to use, as illustrated by the following brief examples.  If your program has called InitPIA() to configure PPA as an output port, it can store the value 0x55 to the port by executing the C statement:

 

PIAStore(0x55, PPA_ADDRESS);

You can set the least significant bit in PPA by calling:

 

PIASetBits(0x01, PPA_ADDRESS);

where 0x01 is a mask; the 1’s in the mask specify which bits are to be set.

Your program can invert the state of the lower 4 output bits in PPA using the statement:

 

PIAToggleBits(0x0F, PPA_ADDRESS);

Again, 0x0F is a mask; the 1’s in the mask specify which bits are to be toggled, and the 0’s in the mask specify bits that are to be left unchanged.

If you’ve configured upper PPC as an input port, you can read its value with the statements:

 

static unsigned char  nibble_contents;

nibble_contents = PIAFetch(PPC_ADDRESS);

The upper 4 bits of nibble_contents will then contain the upper PPC input values.

Characteristics of the PIA’s I/O Ports

The 82C55A peripheral interface adapter (PIA) chip is the industry standard part for providing digital I/O ports.  This brief summary is intended to clarify some of the features of this chip.

The PIA is configured by writing to a control register at address 8083H.  The pre-defined routine INIT.PIAInitPIA() described earlier writes to this register.  It configures the PIA for simple digital I/O (“mode 0”) and sets the data direction of ports PPA and upper PPC according to user-supplied flags.  INIT.PIAInitPIA() configures PPB as an output and the lower half of PPC as an input. 

Whenever the PIA is configured by writing to the control register, all outputs are set to the logic low state.  This is true whether or not the new configuration is different from the prior configuration.  The INIT.PIAInitPIA() routine tries to minimize the impact of this (often undesirable) “feature” by checking the control register before writing to it.  If the PIA configuration requested by the programmer is the same as the existing configuration, the PIA’s control register is not modified.  In general, it is best to use a static configuration for the PIA; dynamically changing the direction of PIA ports while the application is running can cause troublesome glitches on the PIA output pins.

The PIA has another unusual “feature” called “bus hold circuitry”.  The PIA tries to maintain specified logic levels on pins that are configured as inputs (rather than the standard approach of leaving the input pins in a “floating” high impedance state).  After a reset or change in configuration, the PIA holds all inputs high by sourcing between 50 and 400 microamps into the external load attached to the input pin.  If your design requires that the inputs settle to a voltage near ground, you will need to pull the pins low with external pull-down resistors that connect each input pin to ground.  The resistors should have a value less than 1 K-ohm; the manufacturer suggests that the pull-down should be 640 ohms to ensure a logical 0 under worst-case conditions.  Port PPA also has bus hold circuitry that can hold an input in the low condition.  If your design requires that PPA inputs be held at a logical high state, install external pull-up resistors of less than 3 K-ohms from the PPA input pins to the +5 Volt supply.

PIA output pins have good current drive capabilities.  The data sheet states that the chip can maintain an output high voltage of at least 3.0 Volts while sourcing up to 2.5 mA.  The manufacturer’s technical support staff claims that the typical performance is much better; they say that a typical chip can maintain 3.0 Volts or higher while sourcing up to 20 mA.  In the worst case the PIA outputs can sink up to 2 mA while maintaining the output voltage below 0.4 Volts.  There is no internal current limiting on the outputs, so your custom circuitry should include current-limiting resistors if significant current will be required from the output pins.

Using the High Current Drivers

Four N-channel MOSFET high current drivers are available at the Supplementary I/O connector.  Each driver can sink up to 150 mA continuously, or up to 1 amp on an intermittent basis at voltages as great as 60 V.  Onboard snubber diodes suppress inductive kickback, so the drivers can be used to control solenoids, motors, and other inductive loads. 

Figure 8‑1 shows how to connect a DC load (a DC motor is shown) to the MOSFETs.

Figure 8‑1    Connecting a DC load (for example, a DC motor) to the high current drivers using onboard power (left) and using external power (right).

HC0 is controlled by a PAL signal and HC1 - HC3 are controlled by the PIA port bits PPB5 - PPB7 respectively.  NOTE: Upon power-up and reset, the high current MOSFETs, HC1 - HC3, may momentarily sink current until the QED-Forth startup software initializes them.  The PAL-controlled HC0 output does not exhibit this transient turn-on behavior at startup.

Two simple functions control these four high current drivers:

 

void  ClearHighCurrent( uchar mask )SET.HIGH.CURRENT

void  SetHighCurrent( uchar mask )CLEAR.HIGH.CURRENT

SET.HIGH.CURRENT SetHighCurrent()  accepts a 4-bit mask and turns on the drivers that correspond to "1"s in the mask.  CLEAR.HIGH.CURRENT ClearHighCurrent() accepts a 4-bit mask and turns off the drivers that correspond to "1"s in the mask.  Note that "turning on" a driver allows it to sink current, thereby pulling the voltage at the output pin towards ground.  "Turning off" a driver prevents it from sinking current. For example, to turn on all four high current drivers, execute

 

      SetHighCurrent( 0x0F )

 

      HEX   0F SET.HIGH.CURRENT

Then, if you execute

 

ClearHighCurrent( 0x01 )

 

01  CLEAR.HIGH.CURRENT

you will turn off driver number 0 while leaving the state of the other three drivers unchanged.

 

You can verify the operation of the high current outputs by connecting a pullup resistor (say, 1 kOhm) from the output to +5V and measuring the output voltage with a voltmeter.  Note that the output voltage goes LOW when the output is ON (sinking current to ground), and the voltage goes HIGH when the output is OFF (no current flowing in the load resistor).

Using Uninterruptable Operators

The Importance of Uninterruptable Operators

Sometimes it is necessary to set, clear, toggle, or change one or more bits in a port while leaving other bits unaffected.  QED-Forth provides convenient read/modify/write routines called SET.BITS, CLEAR.BITS, TOGGLE.BITS, and CHANGE.BITS to accomplish these functions.  The corresponding fast page-less operators named (SET.BITS), (CLEAR.BITS), (TOGGLE.BITS), and (CHANGE.BITS) can also be used to modify the contents of addresses in common memory.  The glossary entries provide detailed descriptions of these operations. 

For example, if upper PPC has been configured as an output using INIT.PIA, the top 4 bits in PPC can be cleared to zeros by executing

 

HEX F0 PPC CLEAR.BITS

F0 is a bit mask with the top 4 bits equal to ones; this tells CLEAR.BITS that only the top 4 bits should be cleared. The bottom 4 bits of PPC are unaffected.

SET.BITS, CLEAR.BITS, TOGGLE.BITS, and CHANGE.BITS (and the corresponding page-less operators) globally disable interrupts just before reading the memory contents and restore the prior state of the interrupt flag (enabled or disabled) after writing to the specified address.  This makes these routines robust with respect to interrupts and timesliced multitasking when two or more concurrently executing routines are modifying bits in the same memory location.

The following scenario illustrates the importance of these uninterruptable operators when more than one task or interrupt routine is writing to a memory location.  Let’s assume that two different tasks are controlling the bits of the upper nibble of PPC.  Assume that TASK1 is controlling the state of bit 4 in PPC (perhaps to set the direction of the RS485 transceiver), and TASK2 controls bit 7 in PPC.  Let’s assume that bit 4 is low when TASK2