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 Mosaic Handheld

Table of Contents

PART 1 GETTING STARTED

Introduction. How to Use This Manual

Chapter 1: Getting to Know Your Handheld Instrument

Chapter 2: Powering Your Handheld

PART 2 PROGRAMMING THE MOSAIC HANDHELD

Chapter 3: Your First Program

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

Chapter 5: Making Effective Use of Memory

Chapter 6: Real Time Programming

Chapter 7: Failure and Run-Time Error Recovery

Chapter 8: Programming the Graphical User Interface

PART 3 COMMUNICATIONS, MEASUREMENT, AND CONTROL

Chapter 9: Digital and Timer-Controlled I/O

Chapter 10: Data Acquisition

Chapter 11: Serial Communications

RS-232 and RS-485 Communications

Serial Protocols

Serial Connectors and Configuration Options

Using the Serial Ports

Setting Baud Rates

Multi-Drop Communications Using RS-485

Synchronous Serial Peripheral Interface (SPI)

SPI Bus Pins

SPI Network Connections

Configuring the SPI

Summary

Chapter 12: The Battery-Backed Real Time Clock

Chapter 13: Customizing the Handheld's I/O

PART 4: REFERENCE DATA

Appendix A: GUI Function Reference

Appendix B: Handheld Schematics

Chapter 11

<< Previous | Next>>

Serial Communications

RS-232 and RS-485 Communications

The Handheld has two serial communications ports: a primary serial port called Serial 1 that supports both RS232 and RS485 protocols, and a secondary serial port called Serial 2 that supports RS232. The Serial 1 port is implemented with the 68HC11's on-chip hardware UART (Universal Asynchronous Receiver/Transmitter).  Serial 2 is implemented by a software UART in the controller’s QED-Forth Kernel that uses two of the processor’s PortA I/O pins to generate a serial communications channel.

Table 11‑1    Serial Communications Channels

Channels

Type

Port Address

Comments / Alternate Uses

1

Serial 1: RS232/485 hardware UART at up to 19.2 KBaud

PD 0-1, PD 5 used for RS-485. 

 

1

Serial 2: RS232 software UART at up to 4800 Baud

PA 3-4

PA 3-4 may be used as timer-controlled I/O (one input-capture and one output-compare) if Serial 2 is not used.  PA 3-4 may also be used for hardware handshaking for Serial 1.

1

Synchronous Serial Peripheral Interface at 2 MBaud

PD 2-5

 

3

Serial communications channels

The primary channel’s UART translates the bit-by-bit data on the serial cable into bytes of data that can be interpreted by the QED-Forth Kernel or by your application program.  It controls the serial-to-parallel and parallel-to-serial conversion and performs all of the timing functions necessary for asynchronous serial communications.  The communications is asynchronous because no synchronizing clock signal is transmitted along with the data.  Rather, the UART deduces the correct time to sample the incoming signal based on the start and stop bits in the signal itself.  (The Handheld also supports fast synchronous serial communications via the Serial Peripheral Interface described later in this Chapter.)

The secondary channel is very useful for debugging application programs that communicate with other computers or I/O via the primary channel.  Since both channels can operate simultaneously and independently, debugging can be performed while the application program is communicating via its primary channel.  The dual communications channels also provide an easy way to link systems that communicate using different serial protocols.

Serial Protocols

There are several protocols that govern the format of exchanged data, with the RS232 protocol used primarily by personal computers, and the RS485 protocol used in industrial control systems.  The Serial 1 port can be configured for either RS232 or RS485 communications at up to 19200 baud.  The Serial 2 port is dedicated to RS232 communications at up to 4800 baud.

RS232

RS232 is by far the most common protocol.  It is supported by virtually all personal computers, and is the default protocol for both of the Handheld’s serial ports.  Its simplest implementation requires only three wires: one to transmit serial data, a second to receive serial data, and a third to provide a common ground reference.  RS232 allows both communicating parties to transmit and receive data at the same time; this is referred to as full duplex communications.  RS232’s greatest benefit is its universality; practically all personal computers can use this protocol to send and receive serial data.  If your computer does not have an RS-232 serial port, low cost USB-to-RS-232 serial cables are available; contact Mosaic Industries for details.

RS232 uses inverse logic; that is, a positive bit at the 68HC11 UART is inverted by the onboard RS232 driver chip and appears as a negative signal on the serial cable.  The terminal’s serial receiver chip re-inverts the signal to its positive sense.  The data bits are also transmitted in reverse order, with the least significant bit transmitted first, after a start bit.  The specified signal levels of approximately +/- 9 Volts are derived from the Handheld’s +5 Volt supply by a dual RS232 driver chip that has a built-in charge pump voltage multiplier.

RS485

RS485 is another protocol supported by the primary serial port on the Handheld.  It is a half duplex protocol, meaning that only one party at a time may transmit data.  Unlike the standard RS232 protocol, RS485 allows many communicating parties to share the same 3-wire communications cable.  Thus RS485 is the standard protocol of choice when multi-drop communications are required.

Like RS232, the data bits are transmitted in reverse order, with the least significant bit transmitted first.  The RS485 protocol uses differential data signals for improved noise immunity; thus RS485 can communicate over greater distances than RS232.  An RS485 transceiver is present on the Handheld, and its data direction is controlled by pin 5 of port D of the 68HC11.

Serial Connectors and Configuration Options

The primary and secondary serial communications ports are accessible through the Handheld's 10 pin, dual row Communications Header (H4) on the Processor Board.  Several serial communications cables are also supplied with Handheld Starter Kits.

The pinout of the Handheld’s Communications Header (H4) is shown in the following table.

Although the RS232 protocol specifies functions for as many as 25 pins, each communications channel requires only three for simple serial interfaces: TxD1 (transmit data), RxD1 (receive data), and DGND (digital ground).  The RS232 protocol specifies the use of two separate grounds, a signal ground and a protective (or “chassis”) ground.  The Handheld does not differentiate between these.  To provide a convenient means of attaching two grounds to the serial cable, there are several pins (labeled DGND) on the communications connector that are connected to the controller’s ground plane.

Table 11‑2  Serial Communications Header, H4

Signal

 

Pins

 

Signal

/TxD1

1

2

/RxD1

DGND

3

4

/MOD1.CS

RS485 XCVR-

5

6

RS485 XCVR+

/TxD2

7

8

/RxD2

DGND

9

10

+VBAT

Given the availability of ready-made communications cables, it is not necessary to study or understand the following descriptions of cable connections.  These detailed signal descriptions and cable diagrams are presented to provide complete information for those who have special communications requirements and for those who wish to make their own application-specific communications cables.  Most computers conform to IBM PC AT-compatible RS232 interfaces which use 9-pin D-Type connectors, consequently the Handheld brings out its serial ports to two female 9-pin D-Type connectors on the PowerDock.  Table 11‑3  shows the connection diagram for a standard 9-pin serial cable.

Table 11‑3    Serial Cable Connections.

Cable Pin

PC AT or Terminal

Handheld

1

NC

DTR1/DSR1

2

RxD

TxD1

3

TxD

RxD1

4

DTR

DSR1/DCD1

5

GND

GND

6

DSR

DTR1/DCD1

7

RTS

CTS1

8

CTS

RTS1

9

NC

NC

We can gain insight into the operation of the RS232 protocol by examining the signal connections used for the primary serial port in Table 11‑3.  The transmit and receive data signals carry the messages being communicated between the Handheld and the PC or terminal.  The Handheld’s transmit data signal TxD1 (pin 2 on the 9-pin serial connector) is connected to the terminal’s receive data signal RxD (pin 2 on its 9-pin connector). Likewise, the terminal’s transmit signal TxD is connected to the Handheld’s receive signal RxD1.  Chassis and signal grounds are connected together to the digital ground (DGND) signal.

From the Handheld’s point of view, these three signals (TxD, RxD, and ground) are the only connections required to perform serial communications.  While these signals provide a data path, they do not provide hardware handshaking that allows the two communicating parties to let each other know when they are ready to send or receive data. 

The RS232 protocol provides for four handshaking signals called ready to send (RTS), clear to send (CTS), data set ready (DSR), and data terminal ready (DTR) to coordinate the transfer of information.  The Handheld, however, does not implement hardware handshaking.  Rather, it relies on software handshaking via transmission of XON/XOFF characters to coordinate data transfer and ensure that information is not lost when one of the communicating parties is busy.

Many terminals and PCs, however, do rely on hardware handshaking to determine when the other party (in this case the Handheld) is ready to accept data.  By connecting pairs of these handshaking signals together, the terminal or PC can be made to think that the Handheld is always ready to send and receive data.  Thus in Table 11‑3 , RTS1 is connected to CTS1, and DSR1 is connected to DTR1 and DCD1 onboard the Handheld using zero ohm shorting resistors.  These signals may alternatively be redirected to the digital inputs and outputs used by the second serial port if hardware handshaking is required.

The secondary serial port is connected similarly except that the onboard connection of RTS to CTS, and DSR to DTR are permanent.

Enabling RS485 Communications

If your application requires RS485, use the primary serial port (serial1) for RS485 communications, and use the secondary serial port (Serial 2) to program and debug your application code using the RS232 protocol.  The default serial routines used by the onboard kernel assume that full duplex communications are available, so you cannot use the RS485 protocol to program the controller.  You can use it to communicate with other devices.

A jumper, J9 on the Processor Board, configures the primary serial port for either RS232 or RS485 operation.

For RS232 operation: Remove the jumper shunt from J9. In this case, cable connections may be made to Serial 1 on either the 10-pin Serial Communications Header or the DB25 Connector if jumpers J1-J3 are configured appropriately on the Personality Board. 

For RS485 operation: Install the jumper shunt onto J9. In this case, cable connections must be made to Serial 1 at pins 5 and 6 of the 10-pin Serial Header.

Using the Serial Ports

Using the primary serial port is easy.  In fact, you have been using it all along as you worked through the examples in this document.  The standard C serial I/O routines such as printf(), scanf(), putchar(), and getchar() give you high level access to the serial ports.  All high level routines call the following low level revectorable serial primitives to access the currently active serial port:

 

int   AskKey(void)   // returns a flag that is true if an input char is waiting

char  Key(void)      // waits for and returns the next input char

void  Emit(char)     // outputs the specified char to the serial port

 

EMIT ( char -- )     \ outputs the specified char to the serial port

?KEY ( -- flag )     \ returns a flag that is true if an input char is waiting

KEY  ( -- char )     \ waits for and returns the next input char

Because all of the serial I/O routines on the Handheld are revectorable, it is very easy to change the serial port in use without modifying any high level code. 

Let’s do a quick experiment to see how easy it is.  We’ll use code from the GETSTART.C program.  If you have already downloaded the program, you are ready to go.  If your board is presently running a multitasking application, type

WARM

to stop the program now.

If you have not yet compiled the GETSTART program and you want to do the exercises here, open GETSTART.C in your TextPad editor, click on the Make Tool, and after the compilation is done, enter Mosaic Terminal by clicking on the terminal icon and use the “Send File” menu item to send GETSTART.DLF to the Handheld.  

Switching the Default Serial Port

Before running the program, let’s switch to the secondary serial port. The secondary serial port is implemented by a software UART that controls two pins on PortA.  Pin 3 of PortA is the Serial2 input, and pin 4 of PortA is the Serial2 output.  To switch to the secondary serial port running at 1200 baud, simply type from the terminal the following QED-Forth commands:

DECIMAL

1200  BAUD2

USE.SERIAL2

You can operate the port at any baud rate up to 4800 baud; just specify the rate you want before the BAUD2 command.  Now select the “Comm” item in the “Settings” menu of the Terminal program, and click on 1200 baud (or whatever baud rate you selected in the command above).  Move the serial cable from the “Serial Port 1” connector to the “Serial Port 2” connector on the PowerDock.  Typing a carriage return at the terminal should now produce the familiar “ok” response via the Serial2 port.

Now type:

main

and you’ll see the familiar starting message of the GETSTART.C program:

Starting condition:

The radius is      0; the circular area is      0.

ok

In fact, the program works the same as it did before, but now it is using the secondary serial port instead of the primary port -- and you didn’t even have to recompile the code! 

For those of you interested in the details, here’s how it works: The low-level serial driver routines named KEY, ?KEY and EMIT Key(), AskKey() and Emit() are revectorable routines that can be redirected to use either of the serial ports.  By interactively executing the QED-Forth function

USE.SERIAL2

before calling main, we revectored these serial primitives to use the Serial2 port.

You can invoke the C version of this routine by calling

 

UseSerial2()

anywhere within your C program’s source code file.  Function prototypes for this function and other versatile serial I/O routines are defined in the COMM.H header file, and are described in detail in the Control-C Glossary.

To return to using the primary serial port, simply type from the active terminal the QED-Forth command:

USE.SERIAL1

which transfers control back to serial port 1 running at the prior established baud rate (typically 19200 baud).  A hardware reset (pressing down on the reset switch) has the same effect.  If you do this now, remember to move the Handheld’s serial connector back to Serial Port 1, and to change the terminal’s baud rate back to 19200 baud using the “Comm” item under the terminal’s “Settings” menu.

If you always want the Handheld to start up using the secondary serial port as the default serial communications link, you can type at your terminal:

1200  SERIAL2.AT.STARTUP

where 1200 is the baud rate that you choose; you can specify any standard baud rate up to 4800 baud.  The complementary routine is:

 

SERIAL1.AT.STARTUP

which makes the primary serial port the default startup serial link.  We recommend that you keep the faster Serial1 port as the default serial link as you work through the exercises in this book.

All of these functions that we are calling interactively via the operating system can also be called from C in your program source code; their C function prototypes are as follows:

 

void UseSerial1( void );

void UseSerial2( void );

void Baud2( int baud );

void Serial1AtStartup( void );

void Serial2AtStartup( int baud );

In summary, the code provided for implementing the second serial port is very flexible and can be used to support dual concurrent communications ports.  Data translation between different machines can be performed with ease, and applications that communicate via the primary serial port can be debugged using the secondary channel. 

Timing Considerations and Multitasking

In multitasking systems using both serial ports Serial1 and Serial2, the application code should include one of the commands

 

RELEASE.ALWAYS SERIAL.ACCESS !

RELEASE.NEVER SERIAL.ACCESS !

 

SERIAL_ACCESS = RELEASE_ALWAYS;

SERIAL_ACCESS = RELEASE_NEVER;

before building the tasks.  This prevents contention that can occur if the default RELEASE.AFTER.LINE RELEASE_AFTER_LINE option is installed in the SERIAL.ACCESS SERIAL_ACCESS user variable.

The primary serial port, Serial1, is supported by the 68HC11's on-chip hardware UART, and does not require interrupts to work properly.  On the other hand, the secondary serial port (Serial2) is implemented using hardware pins PA3 (input) and PA4 (output), and is controlled by the associated interrupts IC4/OC5 and OC4, respectively.  The Handheld’s kernel software contains a complete set of high level driver routines for the Serial2 port, and these functions are summarized in the QED-Forth Control-C Glossary.

The maximum Serial2 communications rate is 4800 baud. Because the software UART is interrupt based, competing interrupts that prevent timely servicing of the Serial2 interrupts can cause communications errors on the secondary serial channel.  For example, at 4800 baud (bits per second), each bit lasts about 200 microseconds (µs), and if communications are full duplex (e.g., if the Handheld echoes each incoming character), then there is a serial interrupt every 100 µs or so.  In the middle of a character, each interrupt service routine takes about 35 µs.  At the end of a received character, the service routine takes about 45 µs.  At the start of a transmitted character, the service routine takes about 65 µs.  Thus, as a rough approximation, operating at 4800 baud full duplex requires about 40 to 50% of the 6811's CPU time (that is, an average of approximately 40 to 50 µs service time every 100 µs). 

If you are running Serial2 at 4800 baud, the rest of your application must be able to function properly using the remaining portion of the CPU time.  Moreover, if Serial2 is running full duplex at 4800 baud, any other interrupt service routine that takes longer than 100 µs is likely to cause a problem.  If an interrupt service routine takes longer than 200 µs, then an entire serial bit will be missed, causing a communications error. Also, several non-serial interrupts can stack up; if they have higher priority than the serial interrupts, they will be serviced before the Serial2 interrupt routine, and again a serial input or output bit may be lost.

Routines that temporarily disable interrupts for significant periods of time can also interfere with the Serial2 port.  The Control-C QED-Forth Glossary contains a list of functions that temporarily disable interrupts, and the glossary entries give further information regarding how long interrupts are disabled.  In most cases the times are less than 25 µs which does not pose a problem.  However, note that the functions that write to EEPROM disable interrupts for 20 msec. per programmed byte.  Be sure to account for these effects when designing your application.

We have built sophisticated instruments using the Handheld that operate very reliably using multiple interrupts in addition to the software UART.  If your application requires use of the secondary serial port as well as other interrupt routines, the key is to keep the interrupt service routines short and fast.  You might also consider operating the secondary serial port at a lower baud rate to relax the timing constraints.

Setting Baud Rates

The rate of data transmission is expressed in bits per second, or baud.  The primary serial channel can operate at standard speeds up to 19200 baud and can be configured for either RS232 (the default) or RS485 operation.  The Serial2 channel is always configured for RS232 communications, and can sustain baud rates up to 4800 baud.

The routines

 

void Baud1AtStartup( int baud );

void Serial2AtStartup( int baud );

 

SERIAL1.AT.STARTUP

SERIAL2.AT.STARTUP

make it easy to establish a standard baud rate at which the board will communicate each time it starts up.  Although the maximum standard baud rate of the primary serial port is 19200 baud, nonstandard baud rates of over 80 Kbaud can be attained by the 68HC11's on-chip UART and the onboard RS232 driver.  The maximum sustainable baud rate on the secondary serial port is 4800 baud.

Multi-Drop Communications Using RS-485

Connecting computers together in multi-drop networks is common in factories and laboratories.  In these distributed processing networks, a variety of machines and instruments work locally, but communicate and share data or resources with one another globally using a single serial link. You can use the Handheld’s RS485 link to create such a multi-drop serial network.

In the most common multi-drop RS-485 protocol, one computer is designated as a “master” and the rest of the computers or devices on the serial bus are designated as “slaves”.  At any given time, only the master and a single “active” slave communicate.  The remaining “inactive” slaves may actively receive, or listen to, data on the communications line, but only one slave at a time can transmit a message.  If more than one slave tried to drive the transmit line simultaneously, their serial drivers would fight with each other for control of the bus.  To ensure that no two devices drive the network at the same time, it is necessary that each slave device be able to disable it’s own RS-485 data transmitter.

Software Implementation of an RS485 Network

Because the requirements of every multi-drop application are so unique, it is difficult to specify or design a software protocol that meets everyone’s needs.  This section describes the QED-Forth routines that control the RS485 transceiver, and presents some ideas that may prove useful in designing a multi-drop data exchange protocol.

The Handheld controls the RS485 transceiver with bit 5 of Port D of the processor.  When this bit is high, the transceiver is in transmit mode.  When it is low, the transceiver is in receive mode.  QED-Forth includes three built-in routines to facilitate control of the RS485 transceiver.  They are:

 

void InitRS485( void );

void RS485Receive( void );

void RS485Transmit( void );

 

INIT.RS485

RS485.RECEIVE

RS485.TRANSMIT

INIT.RS485 InitRS485() configures Port D to ensure that bit 5 is an output.  RS485.RECEIVE RS485Receive() clears bit PD5 to place the transceiver in receive mode, and RS485.TRANSMIT RS485Transmit() sets bit PD5 to place the transceiver in transmit mode.

To use a Handheld as a slave in a multi-drop network, simply define a word, (named SILENCESilence(void), for example) that when executed calls RS485.RECEIVE RS485Receive() to wait for any pending character transmission to complete, then disable the transmitter, and then execute a QED-Forth routine such as KEY Key() or EXPECT to listen to the communications on the serial bus.  The SILENCE Silence() routine searches the incoming serial characters for a pre-determined keyword (for example, the ascii “name” of this particular slave).  When the network master wants to talk to this particular slave, it outputs the slave’s ascii name onto the serial bus.  When the keyword name is received by the SILENCE Silence() routine running in the slave, the slave Handheld executes RS485.TRANSMIT RS485Transmit() to send an acknowledgment to the master (which should now be listening to the serial bus to accept the acknowledgment). The master and slave can then exchange data. 

The data exchange format may be a line of ascii text or Intel or Motorola hex dump formats (see the glossary entries for DUMP.INTEL, DUMP.S1, and DUMP.S2 for descriptions of these formats). The master and slave could even exchange ascii QED-Forth commands.  When the exchange is complete, the slave can again execute the SILENCE Silence() routine to disable its transmitter and begin listening for its name.

Synchronous Serial Peripheral Interface (SPI)

The Serial Peripheral Interface, SPI, is a fast synchronous serial interface.  It provides a convenient means of connecting the Handheld to a variety of peripheral devices, including analog to digital and digital to analog converters, real time clocks, and other computers which use high speed communication.

The SPI can transfer data much more rapidly than an asynchronous serial link – its maximum rate is 2 Megabits/second.

After configuring the SPI system to communicate on a properly connected network of devices, sending and receiving data is as simple as writing and reading a register.  The QED-Forth kernel includes pre-coded drivers that configure and control the SPI for maximum speed data transfers. This chapter describes those drivers, and presents code that makes it easy to configure the SPI for different data transfer rates and formats.

SPI Bus Pins

Hardware is interfaced to the SPI via three PORTD pins named SCK, MOSI, and MISO brought out to pins 7, 8, and 10 on the Wildcard Port Header (see Appendix B).  The SCK (serial clock) pin is a configurable synchronous data clock output.  This signal synchronizes the exchange of bytes between the Handheld and its peripherals.  The byte-sized messages are transmitted and received via the MOSI (master out/slave in) and MISO (master in/slave out) pins.  The /SS (active-low slave select) is typically used to enable data transfers by slave devices when it is active low.  For the Handheld, /SS is not used for SPI communication because it is used to control the direction of the RS485 transceiver; you can use any digital I/O line as a /SS signal.  A ground connection is also necessary to ensure that the communicating devices have a common voltage reference.

When the Handheld controls the network, it is referred to as a “master”; otherwise, it is a “slave”.  The distinction between master and slave is an important one.  The device that initiates a data transfer is the master, and all other devices on the network are slaves.  Only one active master may control the network at a time; however, the device that assumes the role of master may change according to an appropriate protocol.

If you are using the Handheld as a slave device and require the /SS signal for your external SPI hardware, configure one of the Port A pins on the Field Header as an input pin.  By polling the Port A pin or by setting up an interrupt service routine, you can configure the Handheld to ignore the SCK input when /SS is high and keep MISO in a high-impedance state so that it does not interfere with the SPI bus.  When the /SS input goes low, the slave (or Handheld in this case) transfers data in response to the SCK clock input that is initiated by the master.

If you are using the Handheld as a master device, each external SPI device will require a separate select line (/SS).  You can implement the slave select lines by configuring Port A pins as outputs. Remember that the /SS is active low so to select a device you need to set the pin low; otherwise the pin should idle high.

There are many possible configurations of master/slave networks.  Regardless of the network, however, there are only four signals used: SCK provides a synchronized clock, MOSI and MISO signals are used for data transmission and reception, and /SS configures the Handheld as a master or slave device.  In this section we will consider the most general and simple configurations.

SPI Network Connections

Configured as a master device, the Handheld transmits bytes via the “master out/slave in” pin, MOSI.  It receives bytes sent by a slave device via the “master in/slave out” pin, MISO.  Transmissions are always initiated by the master device, and consist of an exchange of bytes.  As the master transmits a byte to an active slave (that is, a slave with its /SS input active low), the master receives a byte from the slave.  It may be that only the byte sent from the master to the slave is meaningful; nevertheless, each device simultaneously transmits and receives one byte.  The only difference between the master and slave devices is that the master initiates the transmission.

Slave devices use the master in/slave out pin, MISO, for transmitting, and the master out/slave in pin, MOSI, for receiving data.  The following wiring diagram illustrates how the MOSI, and MISO pins of a master and a slave would be connected to exchange data:

 

Master

 

Slave

MOSI

®

MOSI

MISO

¬

MISO

SCK

®

SCK

/SS

®

/SS

GROUND

«

GROUND

The status of a device as master or slave determines how the various pins must be configured.  The arrows in the diagram point to pins configured as inputs, and originate from output pins.  Thus, the master has only one input, MISO, which is the slave’s only output.  Note that the master device outputs the clock synchronization signal SCK to the slave’s SCK which is configured as an input.  Also, in the diagram, the master’s /SS (slave select) is configured as an output.  By setting this output LOW, the slave’s input /SS is pulled LOW.  The GROUND line serves as a common voltage reference for the master and slave.

There are a variety of ways the MOSI, MISO, SCK and /SS pins on your Handheld can be connected.  The one you choose depends on the specific device, or devices you will be connecting to.  In some circumstances a one-way data flow may suffice.  For example, a Handheld connected to a serial A/D converter might have these connections:

 

Master
Handheld

 

Slave
Serial A/D Device

MOSI

®

not connected

MISO

¬

Conversion Output

SCK

®

CLK

/SS  (Port A pin)

®

/CS

GROUND

«

GROUND

In this example, the Handheld selects the serial A/D by outputting a LOW signal on /SS.  Even though the MOSI pin is not connected to anything, the master initiates a transmission using a “dummy” byte.  The SCK pin clocks the serial A/D’s CLK input which causes the A/D’s conversion result to be transferred to the master via the MISO line.

The Handheld allows the details of the synchronous communications protocol to be customized for compatibility with a variety of peripherals.  The next section describes the registers that configure and control the Handheld’s SPI.

Configuring the SPI

The SPI is configured and accessed via four registers:

 

Name

Description

Reference

SPCR

SPI control register

MC68HC11F1 Technical Data Manual,  p.8-5

SPSR

SPI status register

MC68HC11F1 Technical Data Manual, p.8-7

SPDR

SPI data register

MC68HC11F1 Technical Data Manual, p.8-7

DDRD

Port D data direction

MC68HC11F1 Technical Data Manual,p. 6-4

Given a properly wired network and a properly configured SPCR control register, a master device may transmit a message by simply storing the byte to the SPDR data register.  This automatically activates the SCK clock which synchronously transmits the data.  As the master transmits its data, 8 bits of data are simultaneously received.  The received data byte is accessed by reading SPDR data register.  This ability to exchange messages means that the SPI is capable of full duplex communication.  Once the data has been exchanged, a flag bit in the SPSR status register is set to indicate that the transfer is complete.  If the programmer has enabled the local interrupt mask for the SPI, an interrupt is recognized at this point.  Any required SPI output signals must be configured as outputs, either by calling InitSPI() or by setting the appropriate bits in the Port D data direction register DDRD.

The InitSPI() function provides a convenient way to initialize the SPI as the master at a 2MHz baud rate.  This function properly configures the directions of the SPI I/O pins, and configures the data transfer such that data is valid on the falling trailing edge of the clock, with the clock idling in the low state.  This configuration works for many SPI devices, including the optional battery-backed real-time clock.  Consult the data sheets for any peripheral devices that you are interfacing to the SPI and, if a different configuration is needed, follow the instructions below to set up the appropriate SPI data transfer protocol.

The BufferToSPI() function implements fast data transfer from a specified buffer in the controller’s memory to an SPI device.  This function cannot accept incoming data; consult its glossary entry for details.

Multitasking applications with more than one SPI device should control access to the SPI bus using the resource variable SPI_RESOURCE and the access control functions GET() and RELEASE().  Consult their glossary entries for details.

Initializing the SPI Control Register

The SPI control register, SPCR, contains 8 bits which must be initialized for proper control of the Handheld’s SPI (M68HC11 Reference Manual, Section 8.6.2).  These bits are:

 

Bit Name

Description

SPIE

SPI interrupt enable

SPE

SPI system enable

DWOM

Port D wired-or mode

MSTR

Master

CPOL

Clock polarity

CPHA

Clock phase

SPR1

SPI clock rate select bit1

SPR0

SPI clock rate select bit0

The DWOM bit (port D wired-or mode) should always be set to 0.  Setting DWOM to 1 takes away the processor’s ability to pull the Port D signals high unless there is a pull-up resistor on each bit of the port. Setting this bit to 1 without installing pull-up resisters corrupts the operation of the serial communications interface which uses bits 0 and 1 of Port D. 

Setting SPE (SPI enable) to 1 turns on the SPI system. This bit should be set only after all other SPI configuration is complete. 

SPIE is a local interrupt mask that allows an interrupt to be recognized when an SPI data transfer has completed, or if a write collision or mode fault is detected. 

Setting the MSTR bit initializes the Handheld as a master, and clearing the MSTR bit initializes it as a slave.  If the /SS pin of the master is an input and if a low input level is detected, the processor sets the MODF bit in the SPI status register a “mode fault” condition.  This detects the presence of more than one master on the SPI bus.

The CPOL, CPHA, SR1 and SPR0 configure the SCK pin’s clock polarity, clock phase, and clock rate.  These signals are described in detail below.

SPI Clock Signal Configuration

The SCK pin’s synchronous clock signal has configurable phase, polarity and baud rate so that it can interface to a variety of synchronous serial devices.  In general, all devices on a network should use the same phase, polarity, and baud rate clock signal.  In some cases, however, a sophisticated network may have device groups on a network that use different clock configurations.  Although the devices would share the same network, communications would only be understandable by members of the same group.

The clock’s polarity is controlled by a bit named CPOL (clock polarity) and its phase is controlled by CPHA (clock phase).  CPOL determines whether the clock idles in the low state (CPOL = 0) or the high state (CPOL = 1).  If the clock idles in the low state, the leading edge of the clock is a rising edge.  If the clock idles in the high state, the leading edge of the clock is a falling edge.  The CPHA bit determines whether data is valid on the leading or trailing edge of the clock.  Note that the data is changed by the transmitting device one half clock cycle before it is valid.

The following table summarizes the combinations of CPHA and CPOL settings:

 

CPOL

CPHA

Data is valid on the:

0

0

Rising, leading edge

0

1

Falling, trailing edge

= default set by InitSPI()

1

0

Falling, leading edge

1

1

Rising, trailing edge

Many serial devices require a clock that idles in the low state (CPOL = 0), and expect valid data to be present on rising clock edges. Thus in this common configuration the transmitting device outputs the data when the clock goes low, and the receiving device samples the valid data when the clock goes high (CPHA = 0).  In other words, data is valid on the “rising leading edge” of the clock.

To interface devices that support synchronized serial interfaces, but are not configurable like the Handheld, determine the device’s requirements for clock phase and polarity and configure the Handheld’s CPHA and CPOL accordingly.  It is important to note that when the CPHA bit is 0, the /SS line must be de-asserted and re-asserted between each successive data byte exchange (68HC11 Reference Manual, Section 8.3.2).  If the CPHA bit is 1, the /SS line may be tied low between successive transfers.

SPI Baud Rate

The two lowest order bits in the SPCR control register, named SPR1 and SPR0, determine the data exchange frequency expressed in bits per second; this frequency is also known as the baud rate.  This setting is only relevant for the master device, as it is the master’s clock which drives the transfer.  SPR1 and SPR0 determine the baud rate according to the following table:

 

SPR1

SPR0

SPI Frequency (bits/s)

0

0

2.0 MHz

= default set by InitSPI()

0

1

1.0 MHz

1

0

250 kHz

1

1

125 kHz

Summary of the SPCR Control Register

The SPIE bit in the SPCR (SPI control register) enables SPI interrupt handling.  The SPE bit turns on the SPI system.  The DWOM bit determines whether Port D needs pull-up resistors; it should be set to 0.  The MSTR bit determines whether the device is a master or slave.  The CPOL and CPHA bits configure the synchronous clock polarity and phase and specify when valid data is present on the MISO and MOSI data lines.  Finally, for master devices, the SPR1 and SPR0 bits determine the baud rate at which data is exchanged.

SPI Status Register Flags

There are three flag bits implemented in the SPSR (SPI status register).  They are:

 

Flag

Condition

SPIF

SPI transfer complete

WCOL

Write collision

MODF

Mode fault

Any of these conditions may generate an interrupt if the SPIE (SPI interrupt enable) bit in the SPCR control register is set. 

The SPIF is set when a data transfer is complete, and is cleared by a read of the SPSR status register, followed by a read or write to the SPDR data register.  Thus, resetting the SPIF flag is very simple.  After a data transfer is initiated by writing to the SPDR data register, the processor may poll the SPSR status register until the SPIF flag is set.  Then reading the data that was received (by reading the SPDR) or initiating a new data transfer (by writing to the SPDR) automatically clears the SPIF flag.  Alternatively, the if the SPI interrupts are enabled, the SPI interrupt handler determines what caused the interrupt by reading the SPSR register to see which of the three status bits is set.  If SPIF is set, reading the received data or initiating a new data transfer automatically clears the SPIF bit.

A write collision occurs when a byte is written to the SPI data register, SPDR, while data is being exchanged.  The WCOL flag is set when a write collision occurs.  The data transfer that is in process when the write collision occurs is completed.  WCOL is cleared by a read to the SPSR followed by a read or write to the SPDR.

A mode fault occurs when the SPI senses that a multimaster conflict (MC68HC11F1 Technical Data Manual, p.8-7) exists on the network as explained above in connection with the /SS input.  When a mode fault is detected, the processor:

    1. disables the SPI outputs by clearing the bits in the Port D data direction register (DDRD),

    2. clears the MSTR bit in the SPCR to configure the SPI as a slave,

    3. clears the SPE bit to disable the SPI, and

    4. generates an interrupt if the SPIE bit in the SPCR is enabled  

These steps greatly reduce the chance that the communicating devices might be damaged by contention on the SPI bus.  The MODF bit is cleared by a read of the SPSR followed by a write to the SPCR.

SPI Data Transfers

A data transfer is initiated by a master device when it stores a message byte into its SPDR register.  If a slave device has already stored a byte into its SPDR register, that byte will be exchanged with the master’s byte.  Once the bytes have been exchanged, the master may write a new byte to initiate another byte exchange.  Although data byte transfers are easily executed once the network has been wired and configured properly, a carefully executed software protocol may be required to ensure data integrity.

An SPI Example

The following words should assist the configuration of master and slave devices.  Complete implementation of a particular software protocol, however, is beyond the scope of this hardware guide.

Listing 110   Enter your Listing Caption here.

HEX

8028  REGISTER: SPCR        \ define the location of the SPI control reg

8029  REGISTER: SPSR        \ name the SPI status reg

802A  REGISTER: SPDR        \ name the SPI data reg

 

80 CONSTANT SPI.INTERRUPTS    \ mask for SPIE bit in SPCR

40 CONSTANT SPI.ENABLE        \ mask for SPE bit in SPCR

10 CONSTANT SPI.MASTER        \ mask for MSTR bit in SPCR

 

80 CONSTANT SPI.TRANSFER.COMPLETE \ mask for SPIF bit in SPSR

 

\ Port D data direction register masks for configuring pins

\ as inputs or outputs to accommodate master or slave configurations

38 CONSTANT DDRD.MASTER.SPI      \ master pin configurations

04 CONSTANT DDRD.SLAVE.SPI \ slave pin configurations

 

\ Data clock configuration masks:

0  CONSTANT RISING.LEADING.EDGE  \ mask for rising, leading edge

4  CONSTANT FALLING.TRAILING.EDGE   \ mask for falling, trailing edge

8  CONSTANT FALLING.LEADING.EDGE \ mask for falling, leading edge

C  CONSTANT RISING.TRAILING.EDGE \ mask for rising, trailing edge

 

\ the following 4 constants assume an 8 MHz crystal frequency:

0  CONSTANT 1MHZ.SPI       \ mask for 1 MHz baud

1  CONSTANT 500KHZ.SPI        \ mask for 500 KHz baud

2  CONSTANT 125KHZ.SPI        \ mask for 125 KHz baud

3  CONSTANT 62.5KHZ.SPI       \ mask for 62.5 KHz baud

 

: SET.SPI.CLOCK ( data.latch.edge.mask\baud.mask --  )

   0F SPCR CLEAR.BITS     \ clear current edge and baud settings

   OR             \ combine the latch mask with the baud mask

   SPCR  SET.BITS \ set bits for desired latching edge and baud rate

;

 

: I.AM.THE.MASTER  ( -- | configures the 68HC11 to be master )

   SPI.MASTER  SPCR SET.BITS

   DDRD C@ 03 AND    \ get settings of PD0, PD1 which are used for SCI

   DDRD.MASTER.SPI   OR \ maintain direction of PD0 and PD1 while

   DDRD C!        \ making    PD2/MISO an input

               \ PD3/MOSI an output

               \ PD4/SCK an output

               \  and PD5//SS an output

;

 

: I.AM.THE.SLAVE  ( -- | configures the 68HC11 to be slave )

   SPI.MASTER  SPCR CLEAR.BITS

   DDRD C@ 03 AND    \ get settings of PD0, PD1 which are used for SCI

   DDRD.SLAVE.SPI OR \ maintain direction of PD0 and PD1 while

   DDRD C!        \ making    PD2/MISO an output

               \ PD3/MOSI an input

               \ PD4/SCK an input

               \  and PD5//SS an input

;

 

: ENABLE.SPI.INTERRUPTS    ( -- )

   SPI.INTERRUPTS SPCR SET.BITS

;

 

: DISABLE.SPI.INTERRUPTS   ( -- )

   SPI.INTERRUPTS SPCR CLEAR.BITS

;

 

: SPI.ON ( -- | enable the SPI )

   0\0 SPI.RESOURCE X! \ initialize the resource variable

   SPI.ENABLE  SPCR SET.BITS

;

 

\ SPI.OFF ( -- ) is pre-defined in the QED-Forth kernel

 

CODE POLL ( mask\addr --  )   \ addr must be in common memory!

   \ waits until the bits set in the mask are also set in the byte stored at addr.

   \ this routine is assembly coded for speed

   BEGIN,         \ begin wait loop

      0 IND,Y LDX    \ X <- addr

      0 IND,X LDAB   \ B <- byte contents of addr

      3 IND,Y ANDB   \ AND contents of addr with the mask

      3 IND,Y CMPB   \ loop until the result equals the mask

   EQ UNTIL,

   4 IMM LDAB

   ABY            ( -- ) \ drop 2 items to clear stack

   RTS

END.CODE

 

: TRANSFER.SPI.DATA  ( outgoing.data.byte -- incoming.data.byte )

   \ writes data to a slave device, and accepts an incoming data byte;

   \ assumes that the slave is ready to receive and transmit data

   SPI.RESOURCE GET \ wait for access to the SPI 

SPI.TRANSFER.COMPLETE SPSR DROP POLL   \ wait til SPI can accept new data

   SPDR C!     \ write data.byte to data register

SPI.TRANSFER.COMPLETE SPSR DROP POLL   \ wait til new data is received

   SPDR C@     ( -- incoming.data.byte )

   SPI.RESOURCE RELEASE    \ release control of the resource

;

With these words, using the SPI is accomplished in 5 steps:

   4.   Determine the clock phase and polarity and the data transfer frequency you intend to use.  Select the appropriate masks and then execute SET.SPI.CLOCK.  For example, if you specify that data must be valid at the rising trailing edge with a frequency of 1 MHz, execute the following statement:

RISING.TRAILING.EDGE 1MHZ.SPI  SET.SPI.CLOCK

   4.   Determine, within the constraints of your application, whether the QCard Controller should be initialized as a master or slave.  If the device is to be a master, execute I.AM.THE.MASTER, otherwise execute I.AM.THE.SLAVE.  For this example, we’ll execute

I.AM.THE.MASTER

   4.   If you intend to have interrupts handle data transfers, write collisions, and mode faults, use ATTACH to configure your interrupt handler and then execute ENABLE.SPI.INTERRUPTS.  Note that all maskable interrupts are automatically disabled every time the QCard Controller resets or performs a COLD or WARM restart.  If interrupts are not used, the data transfer words should avoid overwriting the data register by polling the SPIF flag in the SPSR status register as shown in the TRANSFER.SPI.DATA routine.

   4.   Having completed the configuration of the SPI, you may now enable it by executing SPI.ON and disable it using SPI.OFF.

   4.   Initiate data transfer.  For this example, we assume that the protocol has been arranged to ensure that the slave is ready to transmit and receive data; the master could then write the byte 08 and fetch the incoming data byte by executing

08 TRANSFER.SPI.DATA

which leaves the incoming byte on the data stack.

Summary

The flexibility and power of the 68HC11’s serial peripheral interface supports high speed communication between the 68HC11 and other synchronous serial devices.  The interface can be used to support analog to digital and digital to analog converters, networks of many computers controlled by a single master, or networks of devices controlled by several coordinated masters.  Pre-coded device drivers configure the SPI for a standard data format, and it is easy to customize a data format and baud rate for your application.   With careful design, many peripherals can communicate via the SPI, and powerful multi-processor systems can be linked using this high speed bus.

<< Previous | Next>>


Home|Site Map|Products|Manuals|Resources|Order|About Us
Copyright (c) 2012 Mosaic Industries, Inc.
Your source for single board computers, embedded controllers, and operator interfaces for instruments and automation