Chapter 5 - The Serial Peripheral Interface (SPI)
The Serial Peripheral Interface, SPI, is a fast synchronous serial interface. It provides a convenient means of connecting the QED Board 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 QED Board's optional on-board 12 bit A/D and 8 bit D/A converters communicate with the processor via the SPI.
The SPI can transfer data much more rapidly than an asynchronous serial link. If the QED Board is clocked at 8 MHz, the SPI can transfer data at up to 1 Megabit/second; with a 16 MHz clock the SPI's maximum rate doubles to 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 the SPI for maximum speed data transfer using a format that is compatible with the on-board D/A and 12 bit A/D. 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 four PORTD pins named /SS, SCK, MOSI, and MISO brought out to pins 11 through 14 on the Digital I/O connector (see Appendix A). The SCK (serial clock) pin is a configurable synchronous data clock output. This signal synchronizes the exchange of bytes between the 68HC11 processor and the 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) signal enables data transfers by slave devices when it is active low. A ground connection is also necessary to ensure that the communicating devices have a common voltage reference.
When the 68HC11 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.
The /SS pin can be configured as either an input or an output. Initializing the 68HC11 as a slave (by clearing the MSTR bit in the SPCR control register as explained below) automatically configures the /SS pin as an input. If the /SS input to a slave is inactive (high), the slave ignores the SCK input, does not transmit or receive data, and keeps its MISO output in a high-impedance state so that it does not interfere with the SPI bus. If the /SS input to a slave is active (low), the slave transfers data in response to the SCK clock input that is initiated by the master.
If the 68HC11 is initialized as a master (by setting the MSTR bit in the SPCR control register as explained below) then bit 5 of the Port D data direction register (DDRD) determines whether /SS is an input or an output. If bit 5 of DDRD is 1, then /SS is a general purpose output that operates independently of the SPI. This allows the processor that is master to control the input /SS pins of other CPU's, for example. If bit 5 of DDRD is 0, then /SS is an input. In this situation, if the /SS input is pulled low while the 68HC11 is the master, the processor detects a "mode fault" (by setting a bit in the SPI status register) meaning that there is more than one master device on the SPI bus.
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 68HC11 as a master or slave device. In this chapter we will consider the most general and simple configurations.
SPI Network Connections
Configured as a master device, the 68HC11 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 68HC11 and a slave 68HC11 would be connected to exchange data:
Master 68HC11 | Slave 68HC11 | |
---|---|---|
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 68HC11 has only one input, MISO, which is the slave QED Board'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 QED Board'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 QED Board 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 QED Board connected to a serial A/D converter might have these connections:
Master QED Board | Slave Serial A/D | |
---|---|---|
MOSI | ||
MISO | < —————– | Conversion Output |
SCK | —————–> | CLK |
/SS | —————–> | /CS |
GROUND | —————– | GROUND |
In this example, the QED Board 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 68HC11 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 QED Board's SPI.
Configuring the SPI
The SPI is configured and accessed via four registers:
Name | Description | Reference |
---|---|---|
SPCR | SPI control register | F1 p.10-3 |
SPSR | SPI status register | F1 p.10-5 |
SPDR | SPI data register | F1 p.10-5 |
PORTD.DIRECTION | Port D data direction (DDRD) | F1 p. 4-5 |
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 by setting the appropriate bits in the Port D data direction register which is named PORTD.DIRECTION in the QED-Forth kernel.
Initializing the SPI Control Register
The SPI control register, SPCR, contains 8 bits which must be initialized for proper control of the QED Board's SPI (HC11 p.8-7). 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 68HC11 as a master, and clearing the MSTR bit initializes it as a slave. Clearing the MSTR bit in the SPCR control register automatically configures the /SS (slave select) pin as an input. The /SS input in turn determines whether the slave responds to the SCK input, as described in a previous section. If the 68HC11 is initialized as a master by setting the MSTR bit, then bit 5 of the Port D data direction register (PORTD.DIRECTION) determines whether /SS is an input or an output. If the /SS pin of the master is an output, it can be controlled independently of the SPI system. 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 |
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 68HC11, determine the device's requirements for clock phase and polarity and configure the 68HC11'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 (HC11 p.8-3). 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:
With 8 MHz crystal | With 16 MHz crystal | ||
---|---|---|---|
SPR1 | SPR0 | SPI Frequency (bits/s) | SPI Frequency (bits/s) |
0 | 0 | 1.0 MHz | 2.0 MHz |
0 | 1 | 500 kHz | 1.0 MHz |
1 | 0 | 125 kHz | 250 kHz |
1 | 1 | 62.5 kHz | 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 (F1 p.10-5) exists on the network as explained above in connection with the /SS input. When a mode fault is detected, the processor:
- disables the SPI outputs by clearing the bits in the Port D data direction register (DDRD),
- clears the MSTR bit in the SPCR to configure the SPI as a slave,
- clears the SPE bit to disable the SPI, and
- 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.
SPI Configuration Utilities in the QED-Forth Kernel
The kernel routines INIT.SPI and SPI.OFF are available to configure and disable the serial peripheral interface. An additional routine named INIT.A/D12&DAC executes INIT.SPI and performs other actions to initialize the onboard 12 bit A/D and 8 bit DAC.
INIT.SPI turns on the SPI, sets the data transfer frequency to the maximum achievable rate, configures the 68HC11 as the master, and specifies a clock polarity and phase that accommodates many serial peripheral devices. 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. 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). This is the clock configuration established by INIT.SPI. The description of this routine is as follows:
Stack: ( -- )
Configures and enables the serial peripheral interface (SPI). The SPI uses bits 2-5 of PORTD
. INIT.SPI
initializes the 68HC11 as the SPI master with 1 MHz data transfer (2 MHz if a 16 MHz processor crystal is used), with valid data present/sampled on the rising leading edge of the SPI clock. It initializes the contents of PORTD.DIRECTION
to be compatible with being the master of the SPI (that is, PD2/MISO
= input, PD3/MOSI
= output, PD4/SCK
= output, PD5/SS
= output). Note that this configuration is compatible with data transfers with the onboard 12 bit A/D and 8 bit DAC. INIT.SPI
also initializes the resource variable SPI.RESOURCE
to 0\0
.
The resource variable SPI.RESOURCE controls access to the SPI in multitasking environments. Proper use of this resource variable (as described in the "Multitasking" chapter in the QED Software Manual) ensures that there is no contention among multiple tasks that access the SPI.
The QED-Forth routine SPI.OFF disables the SPI by clearing the SPI enable (SPE) bit in the SPI control register (SPCR). After execution of this routine, PORTD pins PD2 through PD5 may be used as standard digital I/O subject to the data direction specified in the PORTD.DIRECTION register.
The SPI Interface to the Onboard Analog Converters
The SPI provides a data pathway for communications with serial devices including the onboard 12 bit analog to digital (A/D) converter and 8 bit digital to analog converter (DAC). These analog converters are described in detail in the next chapter; this section summarizes their interface with the processor via the SPI.
The connections of the 68HC11 processor to the onboard 12 bit A/D can be represented as:
68HC11 (master) | 12 bit A/D (slave) | |
---|---|---|
MOSI | ————- > | Data In |
MISO | < ————- | Data Out |
SCK | ————- > | SCK |
A/D./CS | ————- > | /CS |
GROUND | ———— | GROUND |
Notice that the /SS (active-low slave select) signal is not used. Rather, the A/D is selected by an active low chip select signal named A/D./CS which is generated by the top bit of port PPB (PPB7). The QED Forth routines A/D12.SAMPLE, A/D12.MULTIPLE, (A/D12.SAMPLE), and (A/D12.MULTIPLE) manage the data transfer between the 68HC11 and the 12 bit A/D. Data transfer occurs at the maximum 1 MHz baud rate (2 MHz if a 16 MHz processor crystal is used), with valid data present/sampled on the rising leading edge of the SPI clock.
The connections of the 68HC11 processor to the onboard 8 bit DAC can be represented as:
68HC11 (master) | 8 bit DAC (slave) | |
---|---|---|
MOSI | ————- > | Serial Data In |
SCK | ————- > | CLK |
DAC.CS | ———— > | LOAD |
GROUND | ———— | GROUND |
Notice that the MISO (master in/slave out) signal is not used, as there is no need for the DAC to send data to the 68HC11 processor. Likewise, the /SS (active-low slave select) signal is not used; rather, the DAC is selected by an active low chip select signal named DAC.CS which is generated by an onboard programmable logic device. The QED Forth routines >DAC and (>DAC) manage the data transfer from the 68HC11 to the DAC. Data transfer occurs at the maximum 1 MHz baud rate (2 MHz if a 16 MHz processor crystal is used), with valid data present/sampled on the rising leading edge of the SPI clock.
Note that the 12 bit A/D and 8 bit DAC share the SPI bus. You may interface other peripherals via the SPI as long as each peripheral has its own unique chip select signal.
The best general purpose initialization routine for the 12 bit A/D and 8 bit DAC is the QED-Forth word
INIT.A/D12&DAC (--)
which calls INIT.SPI and also ensures the PIA is configured with PPB as an output port so that a valid chip select signal is generated for the 12 bit A/D. This routine should be executed before using the 12 bit A/D or 8 bit DAC.
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.
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:
- 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
- Determine, within the constraints of your application, whether the QED Board 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
- 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 QED Board 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.
- Having completed the configuration of the SPI, you may now enable it by executing SPI.ON and disable it using SPI.OFF.
- 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 routines defined in this chapter make it 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.