CHAPTER 10. Starting with serial
An essential activity within any microprocessor system is the movement of data, between say CPU and memory. Equally important is the transfer of data between subsystems, say computer and keyboard. Data is sent by ordering bits into words (often bytes, but not always) and then sending those words.
Broadly speaking, there are two ways of transferring the data. In parallel transfer, all the bits of the word are transmitted at the same time, each bit over its own connection. The alternative is to send each bit in turn, over a single connection. This is called serial communication. It is easy to see the first relative advantages. Parallel takes more wires and connections, but is faster. Serial needs fewer wires, is slower, and generally requires more complex hardware to transmit and receive.
Therefore, in the past, over short distances data transfer has been mainly parallel. Over long distances, where running a large number of wires would be bulky and expensive, it has been serial. Now, however, that distinction has been challenged, and nowhere more so than in the field of embedded systems, where things must be very small. The advantage of serial transmission, with its fewer wire links, has in many situations become overwhelming. Serial communication has therefore become very important and great ingenuity has been applied to overcoming its main apparent disadvantages – its low speed and more complex hardware.
This chapter introduces the main ideas of serial data communication, both in principle and practice. This includes:
• Describing the principles of synchronous serial communication.
• Exploring the implementation of synchronous serial communication with the PIC 16F873A, notably with the SPI (Serial Peripheral Interface) and I2C (Inter-Integrated Circuit) protocols.
• Describing the principles of asynchronous serial communication.
• Exploring the implementation of asynchronous serial communication with the PIC 16F873A.
As always, a good proportion of the material is illustrated with example code. This is written for the Derbot AGV and its hand controller board, and will be of interest whether or not one has the hardware to run the programs. A number of oscilloscope traces of serial data are also included. At the time of writing it is effectively not possible to simulate the programs in this chapter with the MPLAB simulator, as the serial ports are not supported in the simulator.
10.1. The main idea – introducing serial
The introduction above identified one of the main advantages of serial communication, the fact that it saves space. Figure 10.1 shows one way that this happens. Both of the memory ICs pictured can store the same amount of data. However, the one with parallel interconnect needs thirteen address lines and eight for data, which dominate the chip size. The one using serial interconnect has two lines (SCL – serial clock; SDA – serial data) for data address and three (S0, , S2) for address. This incidentally is an example of an I2C chip, of which we shall learn much more soon. The space saving at the IC level is clearly dramatic. To this is added the space saving in PCB tracks, ribbon cable and so on.
While serial communication has a number of clear advantages, it is important to recognise the challenges it also presents. With just a single wire to carry the data how do we know when one bit starts or ends, or where a word starts or ends? These questions are resolved in a number of interesting ways. Two different ways are used to identify the individual bits. The simple way is to send a clock signal to accompany the data; every clock cycle is used to indicate one bit of data. This is called ‘synchronous’ serial data communication. Instead of sending a clock signal everywhere, certain timing requirements can be placed on the data itself. In this case, it can be possible to do without the clock and the data bits can still be properly identified. This is called ‘asynchronous’ serial data communication. We look at both of these in some detail during this chapter.
To identify the start and end of a whole word, it is common to package the data in a certain format. Data synchronisation and formatting implies certain sets of rules will be needed, in order to ensure coherent communication. These sets of rules are called ‘protocols’ and are very important in the serial world. Some are comparatively simple, while others are very complicated. We will come across a number in this chapter.
In a serial link, we generally use the idea of a ‘transmitter’, the device outputting data onto a serial link, and ‘receiver’, the device receiving the data. In general terms, any device on a serial link is sometimes called a ‘node’.
To illustrate our study of serial communication, we will be looking at the serial capabilities of the 16F873A. This has two serial ports, as mentioned in Chapter 7. Both are extremely flexible and can be configured in different ways. Therefore, both are quite complex! The Master Synchronous Serial Port (MSSP) is designed for different forms of serial communication, while the Addressable Universal Synchronous Asynchronous Receiver Transmitter (USART) can operate in both synchronous and asynchronous modes.
10.2. Simple serial links – synchronous data communication
10.2.1. Synchronous basics
To understand how data can be sent serially, it is helpful to explore the underlying hardware. Data within a microprocessor or memory is still likely to be used and formatted in parallel. Therefore, a serial transmitter needs to be able to accept data in parallel format, but then transmit it serially; a serial receiver needs to be able to do the reverse. The classic way of doing this is with a shift register.
A simple 8-bit shift register is shown in Figure 10.2. It is made up of eight flip-flops connected together so that the Q-output of one becomes the data input of the next. All are driven from the same clock, and on every clock cycle the data is moved one flip-flop to the right. If a new bit of data appears at the DIN input on every clock cycle, then in eight clock cycles one byte will be clocked through such that it can be read as a parallel word from outputs QA to QH. This simple circuit can act as a ‘receiver’ of serial data.
It is not difficult to enhance the circuit so that parallel data can not only be read from the shift register, it can also be ‘loaded’ with a parallel word. It's not worth drawing the full logic diagram of such a shift register, but instead we can represent it in block diagram form, as in Figure 10.3. With this general-purpose shift register, we can clock serial data into it or out of it, and can read parallel data or load parallel data.
At this point we already have the basis for a serial communication link. If two of the shift registers shown in Figure 10.3 are taken and clocked from the same source, then data from one can be transferred serially to the other using the connection shown in Figure 10.4. Effectively, the two 8-bit shift registers act as one 16-bit shift register, with output connected back to input. After eight clock cycles the data in one shift register is moved to the other. Therefore, either can be viewed as the transmitter and either as the receiver. The action of data transfer is actually controlled by the clock. The link is called a ‘synchronous’ link because the data transfer is synchronised to a common clock signal.
10.2.2. Implementing synchronous serial I/O in the microcontroller
The synchronous serial link just described can be readily implemented in a microcontroller, as shown in Figure 10.5. The clock source is placed in the microcontroller, and as the clock controls data flow, this node is called the ‘master’. The other node is called the ‘slave.’ The slave device could be another microcontroller, a memory device or one of a range of other peripherals.
This sort of connection is the basis of many simple embedded serial links. The shift register is memory mapped, and can be read from and written to.
10.2.3. Microwire and Serial Peripheral Interface
In the late 1970s and early 1980s, National Semiconductor, Motorola and others were developing microprocessors and microcontrollers that had built-in synchronous serial capability. They needed to define the associated operating characteristics so that other manufacturers could make devices that could interface reliably with their products. Both National and Motorola were producing serial ports that worked in the way described above. From their designs, two standards were produced. National called theirs Microwire and Motorola called theirs Serial Peripheral Interface (SPI). These are similar to and can communicate with each other. Each has the flexibility to adjust its characteristics, for example to determine whether data is transferred on the rising or falling edge of the clock. Both have now been going for many years and are well established, with new chips still being produced which interface with them. We will see an implementation of SPI in the following sections.
10.2.4. Introducing multiple nodes
The diagram of Figure 10.5 gives an effective serial link, but it only connects two nodes. How could we extend it? The answer is simple. If a means is introduced of selecting which slave device the master is to communicate with, then more than one slave can be connected to the serial data lines, as shown in Figure 10.6. Each slave input now requires a means of enabling it, sometimes labelled ‘Slave Select’ (SS) or ‘Chip Select’. The exact function of the SS line varies somewhat from one device to another, but to a greater or lesser extent it causes the slave to disconnect all or part of itself from the serial connection. The master now has to have a dedicated line for each slave with which it communicates; these can be port bit outputs.
10.3. The 16F87XA Master Synchronous Serial Port module in SPI mode
The MSSP module is designed for synchronous communication and can be configured as a simple synchronous port (called SPI mode, but compatible with both SPI and Microwire), or as an I2C port (Inter-Integrated Circuit). It has three SFRs dedicated to it, SSPCON1, SSPCON2 and SSPSTAT, which can be found in the register file map diagram of Figure 7.6. It also has a register for data transfer, SSPBUF, and is the source of an interrupt, as seen in Figure 7.10. In this section we look at the module in SPI mode.
10.3.1. Port overview
Figure 10.7 shows the MSSP configured as an SPI port. It can be configured as master or slave, with a variety of clock speeds if master. Let us see how it builds on the simple serial concepts we have discussed above. At the heart of the serial port is the shift register SSPSR. When clocked, it transfers serial data to pin SDO (if the output buffer gate is enabled) and transfers serial data in from pin SDI. If the port is set up as a slave, it will receive the clock from the system master through pin SCK. If the port is set up as master, it will generate the clock, which it now outputs through the SCK pin. This clock is derived either from the internal clock oscillator, or from Timer 2.
An important enhancement to our earlier simple serial port is the addition of the buffer register SSPBUF. This holds a data byte on its way to or from the shift register, and is actually the addressable register that the program writes to or reads from. This makes the serial port much more flexible in use. Data can be moved to or from the buffer while the shift register is in operation. This, for example, allows a received byte to be held temporarily, while the next one is already being clocked in.
10.3.2. Port configuration
The two SFRs that control the action of the port in SPI mode are SSPCON1 and SSPSTAT. Their use differs somewhat between the SPI and I2C modes. They are shown, when used in SPI mode, in Figure 10.8 and Figure 10.9 respectively. In them there are bits to do the following:
• Enable and configure the port.
• Sett clock rate and clock characteristics.
• Manage data transfer and buffering.
The port is enabled with bit 5 (SSPEN) of SSPCON1, and its operating mode selected with the lower four bits of the same register. It can be seen that these bits determine whether the port is to work as master or slave. If in Master mode, four clock sources are available. As can be seen, these are either the clock oscillator signal divided by 4, 16 or 64, or the Timer 2 output, as described in Chapter 9 and seen in Figure 9.4.
If in Slave mode, the Slave Select input pin can be enabled, through the four lower bits of SSPCON1. In this case, an external signal can control the tristate buffer that drives the SDO pin and the clock to the shift register. The input then effectively enables the serial port action and the port can be used in a multi-node configuration, such as in Figure 10.6.
For all pins through which data or clock transfer is to take place, the data direction bits must be set as needed. Therefore, for the SDO pin, which is shared with Port C bit 5, bit 5 of TRISC must be cleared to make the pin an output. Similarly, for SCK, in Master mode bit 3 of TRISC must be cleared (to make it an output), while in Slave mode it should be set (to make it an input). The SDI pin, however, is under the direct control of the MSSP module.
10.3.3. Setting the clock
Figure 10.10 shows the relationship between clock and data waveforms available when the module is in Master mode. If bit CKP is set to 1, then the clock idles at Logic 1. The clock edge on which data is transmitted is determined by bit CKE. For incoming data, the instant when data is sampled is determined by bit SMP. The way these are set may be determined by the particular requirements of the slave device that is being used. It is, of course, essential to maintain consistency throughout a single interconnected system.
10.3.4. Managing data transfer
A synchronous serial port such as the one we are looking at can be set as master or slave. Within either of these, the application software can use it as receiver or transmitter, or both. Whatever the application, data is always clocked out from one end of the shift register and in at the other. It is up to the user to determine which data is to be used.
Use of a serial port therefore brings with it some interesting challenges in terms of timing and control. If the port is set as Slave, then an external device causes the transfer, but the slave port must be alerted to this. It must move data into and/or out of the port buffer, according to which direction data is moving. If it is a master, it initiates the transfer and must also move data to and/or from the buffer. In either case, the serial port hardware can be undertaking a data transfer while the program is doing something completely different. To assist in managing the process, the port has a number of Status bits in its SFRs, as well as the interrupt.
If the port is set as Master, a write to the buffer register SSPBUF automatically starts a transfer, clocking out whatever data has been loaded into SSPBUF and clocking in whatever data is present at the SDI pin. On completion of eight clock cycles, the interrupt flag SSPIF is set and data in the shift register SSPSR is automatically transferred to the buffer SSPBUF. The SSPIF flag can be used as an interrupt to alert the CPU that the transfer is complete. If there is a write to SSPBUF before the previous word has been completely sent, then the write collision bit WCOL is set.
If it is set as Slave, then, when the SCK input starts switching, the port clocks data into the SSPSR shift register through the SDI pin. At the same time, data is clocked out of it from the other end through the SDO pin. It is, of course, up to the system designer to ensure that valid data is ready in the SSPSR register and/or is available at the SDI input, according to the requirement. When eight cycles are complete, the interrupt flag SSPIF is set and, again, data in SSPSR is automatically transferred to the buffer SSPBUF. If the previous byte has not been read from SSPBUF, then the SSPOV bit is set, indicating a receive overflow.
10.4. A simple Serial Peripheral Interface example
The Derbot AGV, in the version described in this book, does not use SPI data communication. Nevertheless, Program Example 10.1 provides a simple example program that runs on the Derbot hardware. As always, a full listing appears on the book's companion website, while only the features of direct interest are shown in the example. In this case, it is such a short program that almost all of it is reproduced. It should be possible to cross-check all initialisation settings with the control registers in Figure 10.8 and Figure 10.9.
The program enables the Derbot microcontroller SPI by writing to SSPCON1 (for reasons of backward compatibility the Assembler Include File calls this SSPCON) and sets it up as a master, with clock frequency Fosc/16. Clock control bits SMP and CKE are both set to zero here. Clock and data output pins are set up as outputs via TRISC. The program then transmits two bytes in turn repeatedly on the serial link, with a 40 μs delay in between.
|Program Example 10.1.|
|Serial Peripheral Interface demonstration program|
Figure 10.11 shows oscilloscope traces of the data and clock lines of Program Example 10.1, for CKE = 1 and CKE = 0. These are a practical confirmation of some of the waveforms of Figure 10.10. With the horizontal scale set at 10 μs per division, the clock period can be seen to be exactly 4 μs, i.e. a frequency of 250 kHz. This corresponds with the clock setting made in SSPCON1, of Fosc (4 MHz) divided by 16. The two data bytes 11010101, followed by 00101010, can clearly be seen, being transmitted MSB first. With bit CKP (in SSPCON1) in both cases set high, the clock is seen to idle at Logic 1. When bit CKE (in SSPSTAT) is set high, we see the output data changing on the positive-going edge of the clock, i.e. from its ‘active’ (Logic 0 in this case) to its idle state. The reverse is true when CKE is zero. Notice that the idle state of the data line is not fixed.
The timing between bytes is also of interest. Notice that the program calls a delay of 40 μs between sending bytes, but that the apparent gap is less than 20 μs. This is because the data transmission process is initiated by the program when it writes to SSPBUF. The delay subroutine is then called by the program and much of it runs while the data transmission is taking place.
10.5. The limitations of Microwire and Serial Peripheral Interface, and of simple synchronous serial transfer
From what we have seen so far, synchronous links like Microwire and SPI provide a simple and reliable data connection, yet they have limitations. These include:
• They don't cater well for situations where more than one master may be required.
• They don't address.
• They don't acknowledge – the transmitter simply doesn't know whether the message has been received.
• They are not very flexible – it may not be that easy to add another node, even just one more slave, as for each new slave (at least in the configuration of Figure 10.6) an extra Slave Select line is needed.
10.6. Enhancing synchronous serial and the Inter-Integrated Circuit bus
The Inter-Integrated Circuit (I2C) protocol was developed by Philips to provide a serial communication standard to overcome some of the shortcomings of Microwire or SPI. As its name suggests, it is meant to provide communication between ICs within a single system. It is intended to be flexible and tolerant of different technologies and speeds. Like all good standards, it has been exploited well beyond its original intended application. The full I2C specification can be found in Ref. 10.1, with a useful commentary on it in Ref. 10.2.
10.6.1. Main Inter-Integrated Circuit features and physical interconnection
Like SPI or Microwire, I2C is based on a master–slave relationship between nodes. The master controls all bus usage. The current specification [Ref. 10.1] names four bus speeds: Standard-mode (with bit rate up to 100 kbps), Fast-mode (with bit rate to 400 kbps), Fast-mode Plus (with bit rate to 1 Mbps) and High-speed mode (with maximum bit rate of 3.4 Mbps).
The I2C bus uses only two lines for all interconnection, called SDA (serial data) and SCL (serial clock). The output of each node connects to the bus using an Open Drain or Open Collector output, as shown in Figure 10.12, while the node input is through a standard logic buffer. The two interconnect lines each have a pull-up resistor. Both lines are bi-directional, but the SCL clock signal is always generated by the current master.
When no node is accessing the bus the Open Drain outputs are all inactive and the lines idle at Logic 1. The number of nodes connected to the bus is limited just by the number of addresses that are available (see below) and the loading capacitance that each adds. Too much capacitance ultimately will mean that the clock or data rise time will exceed the specified maximum value.
10.6.2. The pull-up resistor
With neither line having an active pull-up, it is the pull-up resistor in conjunction with the line capacitance that determines the rise time. The specification states a maximum line capacitance of 400 pF and a maximum rise time (from Logic 0 to Logic 1) in standard mode of 1000 ns. The value of the resistor is chosen to achieve the rise time requirement, dependent on this line capacitance. A low value of resistor reduces the rise time but increases current consumption. A value of 4.7 kΩ is widely used; the value must, however, be lowered if the line capacitance is high or can be increased if line capacitance is low. Reference 1.1 gives example calculations for this.
10.6.3. Inter-Integrated Circuit signal characteristics
The I2C protocol follows a very clear format for data transfer, as shown in Figure 10.13. It is initiated by a Start condition, in which the SDA line is taken low, while the SCL line stays high. It is terminated by a Stop condition, in which the SDA line goes high while the clock is held high. The Start and Stop conditions are asserted by the current master, as is the clock.
Between the Start and the Stop, data is transferred in bytes. During this time, the SDA value can only change when SCL is low; data must remain stable when the clock line is high. This allows data transfer and Start or Stop to be distinguished. The first byte of any transfer contains address information. The standard allows for either a 7-bit address, within a single byte, or a 10-bit address spread across two bytes. The figure shows the 7-bit version. In either mode the eighth bit of the first byte is a Read/Write bit. This determines direction of data flow for the message that follows. At the end of every byte, the transmitter releases the SDA line and the receiver must send an acknowledge bit, pulling the SDA line low. Any number of bytes can be sent within one message (i.e. between single Start and Stop bits).
There are two slight exceptions to the pattern just described. A ‘general call’ address is allowed, for which all address bits are zero. This is used to address all nodes on the bus simultaneously. If a master wants to start a new message when it is still within a message, then a ‘Repeated Start’ condition is available.
Importantly, the I2C protocol allows for more than one master, and a node can switch from being a slave to being a master. If the bus is idle, then any of the potential masters can take control of it. If two try to take control of the bus at the same time, an arbitration process is applied, as described in Ref. 10.1.
10.7. The Master Synchronous Serial Port configured for Inter-Integrated Circuit
The 16F873A MSSP can be configured for I2C operation. In this case the SCL line is shared with bit 3 of Port C and SDA with bit 4 of Port C. In I2C mode the port is significantly more complex than when in SPI mode, and care needs to be taken to understand it. The first indication of the increased complexity is the whole extra control register, SSPCON2, needed for I2C mode.
We will aim to introduce this complex but interesting serial application incrementally, and illustrate it with programs for the Derbot AGV.
10.7.1. The MSSP Inter-Integrated Circuit registers and their preliminary use
As with the MSSP in SPI mode, the two registers central to the module hardware are the shift register SSPSR and the buffer SSPBUF. To these are added an address register, SSPADD. This is used to hold the slave address when in Slave mode; while in Master mode it forms part of the baud rate generator. Block diagrams of the module hardware, one for each of the slave and master, follow shortly.
When in I2C mode, the MSSP uses the two control registers already introduced, SSPCON1 and SSPSTAT. Most bits in these are, however, used for different functions, so they must effectively be viewed almost as different SFRs, from the point of view of learning about them. They are reproduced in Figure 10.14 and Figure 10.15. To cope with the greater I2C complexity, there is a further control register, SSPCON2, shown in Figure 10.16. There is thus a total of six registers that the programmer uses directly for I2C operation, in addition to the registers relating to Port C and interrupts.
As in SPI mode, the MSSP is enabled for I2C by setting the SSPEN bit in the SSPCON1 register. The mode of operation, notably whether master or slave, and the address length used, is then determined by the setting of the least significant four bits of SSPCON1. It can be seen from Figure 10.14 that there are six possible I2C modes of operation.
While the bits of the SSPSTAT register mostly give information about the current status of the port, the bits in the new SSPCON2 register (Figure 10.16) initiate one or other of the I2C activities. Setting SEN, for example, initiates a Start condition, PEN a Stop condition and RSEN a Repeated Start. We shall see examples of this soon.
To gain an insight into how these bits are used and their timing, it is more or less essential to study the timing diagrams that appear in the data sheets. There are many of these, one for each of the possible modes of operation. Two of these are shown a little later in this chapter. The art of developing software to drive the MSSP in I2C mode is very much a case of ensuring that these diagrams are satisfied – completely. That does not mean that every bit displayed in the diagram has to be used; sometimes one does not need to use them all. The flow of events depicted must, however, be followed. The diagrams are not entirely simple and in many cases it is preferable to use or adapt software already written, rather than to start from scratch.
10.7.2. The Master Synchronous Serial Port in Inter-Integrated Circuit Slave mode
When configured in I2C Slave mode, the MSSP operates as shown in Figure 10.17. This diagram is not too complex and indeed has many similarities to the SPI mode diagram of Figure 10.7. The central features of the SSPSR shift register and the SSPBUF buffer are there. The shift register clock is provided by the external pin SCL and data is shifted out or in via the SDA pin.
The role of the slave is brutally simple, to wait until it is addressed and then to do what it is told to do. Therefore, a special logic circuit detects when a Start condition occurs, and an address match comparator indicates whether the address that follows matches the internal address of the node, held in the SSPADD control register. If there is an address match, then the MSSP interrupt flag SSPIF, in register PIR1, is set. The programmer uses this to initiate the slave response. This will depend primarily on the value of the bit in the address word, which is transferred to the bit in the SSPSTAT register, and can be tested in the program.
If a Write is detected, the slave is to act as receiver. The relevant timing diagram, for a 7-bit address, is shown in Figure 10.18(a). The buffer full flag BF, set because the address byte has been received, must be cleared by a dummy read of SSPBUF. If used, the SSPIF flag should be cleared. The slave then clocks in a byte of data, under control of the master clock. If all is operating correctly, an Acknowledge is automatically generated by the slave. Figure 10.18(a) goes on to illustrate the case when the first data byte is not read from SSPBUF. The BF flag (in SSPSTAT) remains high, leading to the overflow flag, SSPOV, being set. An Acknowledge is then not sent by the slave, and the master terminates the message with a Stop condition.
If a Read is detected in the first byte of the message, the slave must act as a transmitter. The sequence is shown in Figure 10.18(b). When the slave recognises that it has been addressed and a Read demanded, it must write a byte of data into the SSPBUF register, which automatically sets the BF flag high. Of course, it may take a little time to respond to this, so it holds the clock line low until this transfer is complete. This blocks any further action on the serial link – the slave has power at last! It releases the serial line, in the software, by setting bit CKP high. The hardware automatically returns this low (if BF is low) on completion of nine bits of transmission. This is an example of ‘clock stretching’ – one of the few ways that a slave can influence the activity of the serial link. It is automatically implemented in Transmit mode, and optionally implemented in Receive mode, by the setting of the SEN bit in the SSPCON2 register.
With the SCK released, the master clocks the data out and should generate an Acknowledge in response. Further status information can be derived from the state of flags in the Status register SSPSTAT. The I2C message is terminated when a stop bit from the master is detected. It should be possible to follow this full sequence in the figure.
10.7.3. The Master Synchronous Serial Port in Inter-Integrated Circuit Master mode
The MSSP in Master mode is altogether more complex, as can be seen in Figure 10.19. The master must after all control all bus transactions. At the heart of things, however, we still find the SSPSR shift register and the SSPBUF buffer. Electrical interface with the two serial lines shows the classic I2C connection already seen, with Open Drain for output and Schmitt trigger for input. The clock is now internally generated, by the baud rate generator. It is routed both to the shift register and to the external bus via the SCL pin. The node must be able to generate and detect Start, Stop and Acknowledge conditions. It also, by means of the Exclusive OR gate connected to the SDA output, detects a bus collision. This occurs when the master is transmitting but the logic state on the bus does not accord with the intended transmitted value. A collision sets the bus collision interrupt flag, BCLIF (Figure 7.10). The master port can also engage in arbitration if it finds itself in contention with another master.
The baud rate generator, which appears at the top right of Figure 10.19, is shown in further detail in Figure 10.20. It consists of a Down Counter that is reloaded with the value held in the SSPADD register when it has counted down to zero. Note clearly that the SSPADD register has nothing to do with addresses when the module is in Master mode – masters don't have addresses. The user selects the desired baud rate by the value placed in SSPADD. The formula which determines the value, quoted from Ref. 10.3, is:
where [SSPADD] is the value loaded into the SSPADD register, Fosc is the microcontroller clock frequency and FSCL is the desired I2C clock frequency.
Figure 10.21 shows the timing diagram for the port as I2C master, when transmitting a byte of data. The SEN bit is seen being used to initiate a Start condition and the PEN bit to initiate a Stop. Both are in the SSPCON2 register. The R/W bit, in SSPSTAT, is used to indicate that transmission is in progress. This sequence of events will be illustrated in the forthcoming Derbot example.
10.8. Inter-Integrated Circuit applied in the Derbot Autonomous Guided Vehicle
10.8.1. The Derbot hand controller as a serial node
The Derbot AGV is designed to interface with its hand controller via an I2C link, with the AGV being set as master and the hand controller as slave. Many data transfers are, however, initiated by the hand controller when the user presses a key on the keypad. An I2C slave cannot, however, initiate a transfer! Therefore, an interrupt line is connected from controller to AGV which forms the external interrupt input of the AGV microcontroller. The full interaction is programmed so that when a keypad press is detected, the controller sends an interrupt to the AGV, which then requests data via the I2C link.
The two program examples that follow, Program Example 10.2 and Program Example 10.3, are written respectively for the Derbot AGV acting as master and the hand controller acting as slave. When working together, a keypad press on the hand controller causes an interrupt to be sent to the AGV. This then initiates an I2C message in which the AGV as master requests a byte of data (the character) from the hand controller. The AGV then echoes the character back to the controller, which sends it to the display. Full program versions can be found on the book's companion website. The subroutines and ISRs can be used as the basis of any communication between hand controller, AGV and any other I2C peripheral the user may wish to design. It is worth noting, however, that they are comparatively simple routines and do not test or respond to all possible fault conditions.
10.8.2. The Autonomous Guided Vehicle as an Inter-Integrated Circuit master
Program Example 10.2 runs on the Derbot AGV and applies the I2C port as a master. The key SFR settings are Port C (where I2C port bits must be set as inputs), SSPADD (which determines the clock frequency) and SSPCON1 (which determines the overall setting). Equation (10.1) is used to determine the value for SSPADD. The detail of the SSPCON1 setting should be explored by comparing it with the register details in Figure 10.14.
All major I2C actions in the program are undertaken with the use of subroutines and it is instructive to look at these. The program starts, from comment ;send opening string, by transmitting the character message ‘Derbot’ to the hand controller. This is done in a single multiple-byte message. First the address is sent, using subroutine I2C_send_add. The address 52H is arbitrarily chosen; this must be shifted left by one to fit into the address word. With set to 0, the transmitted word becomes A4H.
|Program Example 10.2.|
|Derbot Inter-Integrated Circuit interchange Autonomous Guided Vehicle to hand controller – master (excerpts)|
Within the ongoing I2C message, the characters are then read in turn from Table 1 (not shown, but on the book's companion website) and sent serially, using subroutine I2C_send_word. This transfer applies the timing diagram of Figure 10.21. A delay is called between each character, to allow time for the hand controller to write to the LCD display. The end of the character string is marked with the code FFH. When this is detected, the Stop condition is asserted with subroutine I2C_send_stop.
All subsequent program activity is in the ISR, which is initiated by receipt of an external interrupt from the hand controller. The ISR starts an I2C message, addressed to the hand controller, requesting a read. This is done with subroutines I2C_send_add and I2C_rec_word. With the bit now set to 1, the address word is A5H. It should be possible to follow the sequence of the subroutines and their use of the control registers. This message ends with a Stop condition, implemented by subroutine I2C_send_stop. The return message, where the received word is echoed back to the hand controller, is done with the subroutine sequence I2C_send_add, followed by I2C_send_word, followed by I2C_send_stop.
10.8.3. The hand controller as an Inter-Integrated Circuit slave
Program Example 10.3 runs on the Derbot hand controller. It is an extension of the program keypad_test, which appeared in Program Example 8.1, with the I2C transfer to the AGV now inserted. Notice first the way the control registers are used, compared to the Master mode.
|Program Example 10.3.|
|Derbot Inter-Integrated Circuit interchange Autonomous Guided Vehicle to hand controller – slave (excerpts)|
SSPCON1 sets the node as slave and SSPADD is now used to hold the slave address. SSPADD holds the slave address, 52H, rotated left by one bit. The I2C bits of Port C again must be set as input. Two interrupts are enabled – Port B interrupt on change, to detect the keypad being pressed, and the MSSP interrupt, to alert the microcontroller to the arrival of the first byte of an I2C message. Interrupt control bits GIE, PEIE, SSPIE and RBIE are accordingly set.
An MSSP interrupt occurs when an address match is detected on an address byte. The interrupt routine first determines the interrupt source. If it is an I2C interrupt, the bit in SSPSTAT is first tested, to determine whether the byte just received was address or data. If address, the SSPBUF register (which will be holding the address byte) is read – simply to clear the BF flag in SSPSTAT. A test is then made of the bit in SSPSTAT. If the master is requesting a Write, then the ISR is quit. The program waits for the next interrupt, which will indicate the expected incoming data byte. If the master is requesting a Read, then program execution stays in the ISR and goes to the label Send_I2C. The timing diagram of Figure 10.18(b) is followed. The byte held in kpad_char is moved to SSPBUF, the CKP bit in SSPCON1 is set high to release the clock, and the interrupt flag is monitored to determine completion.
If in the test of the bit an incoming data byte had been detected, then program execution moves to the label ISR1. The data will by then already be in SSPBUF. This is accordingly read and the character is sent to the display, using the lcd_write subroutine. A subroutine dig_pntr_set is also invoked, seen only in the full listing on the book's companion web site. This manages the LCD pointer, ensuring that characters are not sent to positions which do not appear on the size of display used.
10.8.4. Evaluation of the Derbot Inter-Integrated Circuit programs
Figure 10.22 shows some of the waveforms of the I2C exchange, when the programs above are running. In (a), we see the characteristic nine clock cycles per word of an I2C data exchange. The clock frequency can be seen to be just a little lower than the expected frequency of 125 kHz. The master starts a message, with the address byte 10100100B (i.e. A4H) being sent. As we know, the LSB of this is the bit, indicating a Write is requested. The slave then replies with the word 00110111B (i.e. 37H, or the ASCII character 7, meaning that the keypad key ‘7’ has just been pressed). The master is seen to Acknowledge and then exert a Stop condition.
The detail of Figure 10.22(b) is characteristic of an Open Drain output driving a logic line. The transition from Logic 1 to 0 is fast, and caused by the transistor output switching on. When it switches off, however, the line only rises to Logic 1 through the action of the pull-up resistor, and the slower, exponential rise of this is clearly seen.
The two programs just discussed are useful and show the use of I2C in an application that is reasonably constrained. It's worth noting that they don't take account of every state an I2C node can get into, nor do they take corrective action if the serial link is not working properly. In the master program, for example, if no Acknowledge is received, the program simply loops indefinitely.
10.9. Evaluation of synchronous serial data communication and an introduction to asynchronous serial data communication
Synchronous serial communication, as discussed, is an incredibly useful way of moving data around, but the question remains: do we really need to send that clock signal wherever the data goes? Although it allows an easy way of synchronising the data, it does have these disadvantages:
• An extra line is needed to go to every data node.
• The bandwidth needed for the clock is always twice the bandwidth needed for the data; therefore, it is demands of the clock which limit the overall data rate.
• Over long distances, clock and data themselves could lose synchronisation.
10.9.1. Asynchronous principles
For the reasons just listed, a number of serial standards have been developed which do not require a clock signal to be sent with the data. This is generally called ‘asynchronous’ serial communication. It is now up to the receiver to extract all timing information directly from the signal itself. This has the effect of laying new and different demands on the signal, and making transmitter and receiver nodes somewhat more complex than comparable synchronous nodes.
A common approach (but not the only one – the diversity of asynchronous links has been limited only by human ingenuity) to resolving the challenges of asynchronous communication is based on this:
• Data rate is predetermined – both transmitter and receiver are preset to recognise the same data rate. Hence each node needs an accurate and stable clock source from which the baud rate can be generated. Small variations from the theoretical value can, however, be accommodated.
• Each byte or word is ‘framed’ with a Start and Stop bit. These allow synchronisation to be initiated before the data starts to flow.
An asynchronous data format, of the sort used by such standards as RS-232, is shown in Figure 10.23. The line idles in a predetermined state. The start of a data word is initiated by a Start bit, which has polarity opposite to that of the idle state. The leading edge of the Start bit is used for synchronisation. Eight data bits are then clocked in. A ninth bit, for parity checking, is also sometimes used. The line then returns to the idle state, which forms a Stop bit. A new word of data can be sent immediately, following the completion of a single Stop bit, or the line may remain in the idle state until it is needed again.
10.9.2. Synchronising serial data – without an incoming clock
In order to correctly receive an incoming data stream with no accompanying clock, the receiver must be able to detect the start of the byte or word and the moment in each bit when the data is valid. With the data rate predetermined, one might think that this is not a difficult problem, but it is impossible for different microcontrollers to have clock frequencies that are precisely the same.
The principle of how this timing can be done is shown in Figure 10.24. The receiver runs an internal clock whose frequency is an exact multiple of the anticipated bit rate. Usually, a multiple of 16 is chosen, but this is not essential. The receiver monitors the state of the incoming data on the serial receive line. When a Start bit is detected, a counter begins to count clock cycles until the midpoint of the anticipated Start bit is reached, i.e. eight clock cycles when a ×16 clock is being used. It tests the state of the incoming data line again, to confirm a Start bit is present. If not, the receive is aborted. If the Start bit is confirmed as present, the clock counter counts a further 16 cycles, to the middle of the first data bit. At this point, it clocks that bit into the main receive shift register. In this manner it continues to clock in bits, waiting each time for a bit width before clocking in the next. Depending on the setting of the receiver, it clocks in eight or nine bits (or whatever the expected word length is). After a further bit width, it tests for a Stop bit. If this is of the correct value, then a valid reception can be flagged and the received data can be latched into a buffer.
If the Stop bit is not present, then a ‘framing error’ is flagged. The receiver can then be readied to receive the next word.
10.10. The 16F87XA Addressable Universal Synchronous Asynchronous Receiver Transmitter (USART)
10.10.1. Port overview
The second serial port that the 16F87XA family has is an Addressable Universal Synchronous Asynchronous Receiver Transmitter (USART). This rather forbidding title tells us that it can operate in both synchronous and asynchronous modes, and that it can receive and transmit. The inclusion of the word ‘Universal’ reflects traditional titles and simply implies that it can be configured in all major operating modes needed. The ‘Addressable’ term indicates a mode of use whereby an incoming byte can be designated and interpreted as an address.
The USART can be configured as synchronous master, synchronous slave or in asynchronous mode. In the latter case it is full duplex – that is, it can transmit and receive at the same time. Thus, it has both a receive shift register and a transmit shift register, which can operate simultaneously. Both sections share the same baud rate generator and have the same data format. As can be seen from Figure 7.10, it has interrupt sources for both receive and transmit. The USART shares pins with Port C, the Receive line being on bit 7 and the Transmit on bit 6.
Operation of the USART is controlled by two registers, TXSTA (Figure 10.25) and RCSTA (Figure 10.26). The port is enabled by the SPEN bit of RCSTA, and selection of synchronous or asynchronous modes is by the SYNC bit of the TXSTA register.
We will consider each operating mode in turn, with a small example from the Derbot AGV.
10.10.2. The USART asynchronous transmitter
The block diagram of the USART transmitter section is shown in Figure 10.27. It is controlled mainly by the TXSTA control register. To start with the familiar, we see in the block diagram that central feature of a serial port – a shift register, ‘TSR register’. Notice that data is transmitted LSB first, unlike the MSSP port. The shift register is buffered by the TXREG register, an addressable SFR linked to the data bus. It is to this register that the program writes. The shift register is driven by a clock, ‘baud rate CLK’, which is enabled by the TXEN bit. The clock frequency is set by the baud rate generator, depending on the value held in the SPBRG register. The output of the shift register is connected to the microcontroller pin via the ‘Pin Buffer and Control’ circuit. This is enabled by the Serial Port Enable bit, SPEN, in the RCSTA control register.
Data to be transmitted must be loaded into the TXREG buffer by the program. It is transferred immediately to the TSR shift register if no transmission is taking place, or after the Stop bit if a transmission is already under way. Status information is provided by two bits, the interrupt flag TXIF and the TMRT bit. The former indicates the status of TXREG. When the data transfer between TXREG and the shift register occurs, then the interrupt flag TXIF (in register PIR1, Figure 7.12) is set. This cannot be cleared in the software and is only cleared when TXREG is reloaded. The bit TRMT monitors the state of the shift register and can be polled by the program. It is set when the shift register is empty, i.e. a transmit has been completed.
A ninth data bit, TX9D, enabled by bit TX9, can be inserted into the transmitted word. Both these bits appear in the TXSTA control register. This ninth bit can be used as a parity bit. Unlike some serial ports, however, the parity value is not generated automatically in the hardware – it is up to the programmer to do this within the program. If the ninth bit is to be used, it should be set up before its associated data word is written to TXREG. If this is not done, then a transfer to TXREG will start a serial data transfer before the ninth bit is in place. An alternative use for the ninth bit is to indicate an address in the accompanying byte, as described in Section 10.10.6.
10.10.3. The USART baud rate generator
The baud rate generator is used in both synchronous and asynchronous modes of the USART. It is built round a free-running 8-bit counter, controlled by the SPBRG register. The counter is clocked by the internal microcontroller oscillator frequency, and the action of the counter is effectively to divide this frequency down by the amount predetermined by the value in SPBRG. The division rate is further modified in asynchronous mode by a prescaler bit, BRGH, in register TXSTA. The resulting baud rate frequencies are as follows, where [SPBRG] is the value in the register of the same name:
10.10.4. The USART asynchronous receiver
The block diagram of the USART receiver section is shown in Figure 10.28. It is controlled mainly by the RCSTA register (Figure 10.26). In some ways the diagram is a mirror image of the transmitter diagram of Figure 10.27. Some features are, however, distinctly different due to the differing requirements of the receiver and transmitter. Data enters the Port C bit 7 pin of the microcontroller. The data recovery circuit is included to minimise interference. Every time a data value is to be determined three samples are taken and the majority value transferred. Central to the receiver we see a shift register, ‘RSR register’. This is driven by a clock from the baud rate generator. The shift register is double-buffered by a FIFO (first in, first out) buffer. The upper byte in this is the RCREG register, an addressable SFR. This double-buffer can hold the most recent two data bytes that have been received and thereby allow a third incoming byte to be clocked in to the shift register. The port is enabled overall by the SPEN bit. Subservient to this is a Single Receive Enable bit, SREN (not to be confused with SPEN!), or a Continuous Receive Enable bit, CREN. This allows choice between accepting a single incoming word or a continuous series.
When a complete word has been received correctly, including the Stop bit, the main eight data bits are transferred to the FIFO, if it is clear to receive, and interrupt flag bit RCIF is set. If a ninth bit is used (determined by the state of RX9), then it is transferred to bit RX9D. This bit has the same level of buffering as the main incoming data bytes.
If an incoming data byte is clocked in, but the Stop bit is detected as Logic 0, then a framing error is indicated by bit FERR. As with RCREG and RX9D, this bit is double-buffered, so the framing status of each buffered bit can be tested. If both buffers of RCREG are full and the RSR register has received a further complete byte, then the overrun error bit, OERR, is set. The word in the RSR register is lost and further transfers from the RSR register to RCREG are then blocked. The OERR flag must be cleared in the software before further reception can take place. When reading a data value, the action of reading RCREG causes the FERR and RX9D bits to be updated with new values. These bits should therefore be read first.
10.10.5. An asynchronous example
In this section we extend Program Example 10.2, described earlier in this chapter, to include an asynchronous communication link. Now when the keypad is pressed on the Derbot hand controller, the keypad character is sent to the AGV, which then sends it out on its asynchronous transmitter. This is looped back to its asynchronous receiver and the word is finally echoed back to the hand controller. While this extra serial link provides no extra functionality whatsoever, it does give a good opportunity to develop a simple test program and look at more serial data! Program Example 10.4 shows the detail relating to the asynchronous communication. The full program is on the book's companion website.
It should be possible to follow the initial setting of the TXSTA and RCSTA registers as shown, by reading the program comments and comparing with the control registers in Figure 10.25 and Figure 10.26. The baud rate of 50 kbps was chosen arbitrarily.
As with Program Example 10.2, all data transfer occurs within the main ISR. For this reason the asynchronous interrupts are not used. The ISR starts with a byte being read from the hand controller on the I2C port and stored in I2C_RX_word. The point where data is sent on the asynchronous transmitter is shown. The word just received is transferred to the TXREG register. As it transfers out, the asynchronous receiver will simultaneously begin to clock it in. The program simply waits for the receive interrupt flag to be set, indicating that a word has been received and a transfer is complete. The received word is then echoed back to the hand controller, via the I2C link.
Waveforms from this program example can be seen in Figure 10.29. Panel (a) shows a byte of asynchronous data, with the display in oscilloscope mode. With the horizontal time base at 50 μs/division, a bit period of exactly 20 μs can be seen, relating exactly to the selected baud rate of 50 kbps. The idle state of Logic 1 and the opening Start bit at Logic 0 can clearly be seen. The data runs ‘backwards’, LSB first, and can be seen to be 00110101B, or 35 in hexadecimal. This is ASCII character 5, indicating that this was the keypad button pressed. The Stop bit merges into the next idle period, being simply its first 20μs, so it cannot be seen explicitly.
Figure 10.29(b) shows the same asynchronous word, but now with part of the preceding and following I2C messages. The oscilloscope is here in logic analyser mode. The first I2C message
shows just the data byte, again 00110101B, which is repeated by the asynchronous link, although of course in its own format. The following I2C message is just the address byte of the hand controller, which can be read as 10100100B. The bit is low (i.e. the master will write to the slave) and an Acknowledge can just be seen on the ninth clock cycle.
|Program Example 10.4.|
|Asynchronous data transfer on the Derbot|
10.10.6. Using address detection with the USART receive mode
The USART may be used in a way that allows an address to be embedded in the received data. Multiple nodes can then be connected to the serial line and a node can recognise its own address. The USART receiver must be set in 9-bit mode (bit RX9 = 1) and the address enable bit ADDEN, in RCSTA, should be set to 1. Once in this mode, a Logic 1 in the ninth bit indicates that the accompanying byte is an address. Initially, all data whose ninth bit is 0 is ignored. When a byte is detected whose ninth bit is 1, the program can read the accompanying byte and determine (in software) whether an address match has occurred. If this is the case, the program can revert the port to normal reception by setting ADDEN to 0, and further words will be read as data. This continues until a further address word is detected, which may be for another node.
10.10.7. The USART in synchronous mode
Aside from its essential asynchronous capability, the USART can also be used in synchronous mode, which is selected by setting the SYNC bit in the TXSTA register. The port must be enabled with RCSTA bit SPEN. Port C bit 7 is then used for serial data and bit 6 for serial clock. Given an understanding of the SPI mode of the MSSP port, as described earlier in this chapter, the underlying concepts of this mode of USART operation will not present any major difficulty. It is therefore left to the reader to read the data on this, if you wish to use it.
10.11. Implementing serial without a serial port – ‘bit banging’
The foregoing pages seem to imply that, to make use of serial communication, it is absolutely essential to use a microcontroller with one or more serial ports. This is not absolutely true, as it is possible to generate and receive serial data streams in software only, using standard port bits for input/output. This can be a comparatively simple, even attractive (from a cost-saving point of view), option for a simple synchronous link, especially if it is only occasionally used. It remains a possibility for more advanced protocols like I2C, but becomes increasingly difficult to implement. Chapter 6 of Ref. 1.1 gives further information and an example for the PIC 16F84 microcontroller.
10.12. Building the Derbot
To run most of the programs used as examples in this chapter, you will need to have a working LCD version of the hand controller. The ‘bus’ connector on the AGV will have to be in place, as well as the I2C pull-up resistors. The circuit will then be very close to that shown in Figure A3.1, but without the light-dependent resistors and the ultrasound detector.
• Serial communication is an increasingly important aspect of embedded systems. A good understanding is essential to the aspiring designer.
• There are two broad types of serial communication: synchronous and asynchronous.
• There are a very large number of different standards and protocols for serial communication, ranging from the very simple to the seriously complicated. It is important to match the right protocol with the right application.
• The 16F873A microcontroller has two extremely flexible serial ports. The cost of flexibility is a significant level of complexity in grasping their use. Therefore, it is often worth adapting publicly available routines to use, rather than starting from scratch in writing new code.
Note: Note: Reference 10.2 remains useful, even though reference titles seem to indicate that it is superseded by Reference 10.1, published later.
10.1. The I2C Bus Specification and User Manual, Rev. 03 (2007). NXP Semiconductors, Document no. UM10204.
10.2. I2C Manual (2003). Philips Semiconductors, Application Note AN10216–01.
10.3. Using the PICmicro MSSP Module for Master I2C Communications (2000). Microchip Technology Inc., Application Note AN735, Ref. no. DS00735A.
10.4. Using the PICmicro SSP Module for Slave I2C Communications (2000). Microchip Technology Inc., Application Note AN734, Ref. no. DS00734A.
10.5. Asynchronous Communications with the PICmicro USART (2003). Microchip Technology Inc., Application Note AN774, Ref. no. DS00774A.
2. Two 16F873A microcontrollers are to be connected together with a synchronous serial link, operating in SPI (Serial Peripheral Interface) mode. One is to act as Master, the other as Slave. No other nodes are required. Data needs to be sent in both directions. A serial bit rate of 2MHz is required. Each microcontroller is running with an 8 MHz crystal oscillator.
(i) Draw a simple block diagram, showing the two microcontrollers and indicating how the serial connection is made. Clearly label the pins being used. Show on your diagram which is Master and which Slave. You need show only the connections necessary for the serial link; no other connections need be shown.
(ii) For each microcontroller, indicate how SSPCON1 should be configured. Consider only bits 0 to 5, and use X to show ‘don't care’ for bits which have no impact on this particular requirement.
(iii) Briefly explain each selection made.
(b) Explain briefly the disadvantages of a simple serial protocol like this, for example in situations where multiple nodes and high reliability are required.
3. Pin and timing diagrams of an 8-bit serial Digital to Analogue Converter (DAC) are shown in Figure 10.30. It is intended to connect it to the Master Synchronous Serial Port (MSSP) module of a PIC 16F873A microcontroller, when configured in SPI mode. Draw a simple block diagram that shows how the digital interconnection can be made. Show only the detail necessary to complete this interconnection, and nothing else.
4. In a development of the application described in Question 3, four of the same DACs are now required. All are driven from the same 16F873A serial port, but each must be enabled individually. Draw a simple diagram to show how the interconnection can be achieved.
5. In a prototype embedded system, the capacitance to ground of the serial lines and master microcontroller are estimated as 90 pF per line. To satisfy the I2C standard, the time constant of either serial line should not exceed 830 ns.
(a) What value of pull-up resistor should be connected to each I2C line, if this condition is just satisfied?
(b) The PCF8574 is an I2C compatible serial to parallel converter integrated circuit. A number of PCF8574s are to be connected to the I2C bus described above. Each PCF8574 places a further load capacitance on each serial line of 15 pF. For power supply and dissipation considerations, the pull-up resistors should not be less than 4.7 kΩ. What is the maximum number of PCF8574s that can be added to the bus?
6. Three 16F873A microcontrollers are interconnected on an I2C bus. Each is running from a 10 MHz clock oscillator. Some of their control register settings are shown below. Deduce what effect each microcontroller is having on the bus, and its relevant settings.
|Microcontroller 1||Microcontroller 2||Microcontroller 3|
|SSPADD||0011 0010||0000 0111||46H|