This project introduces you to the synthesis and analysis tools for producing microprocessor C code using the MPLAB® X integrated development environment (IDE) on the chipKIT™ Pro MX7 processor board.
The purpose of this project is to familiarize you with the methods of reading from and writing to the input and output (I/O) pins of the PIC™32 microcontroller.
The purpose of this project is to investigate methods of creating software time delays to pace processor operations.
The purpose of this project is to investigate the application of software-based state machines to controlling the speed, direction of rotation, and operational mode of stepper motors.
The purpose of this project is to understand the operation of PIC™32 timers so that they can be used to implement a synchronized multi-rate periodic control system by polling the timer interrupt flag.
Explore detecting events using interrupts or by using preemption that implements a nested interrupt management scheme.
Investigate concepts involving parallel communications and handshaking.
Learn about asynchronous communications and communicate with a microcontroller using a terminal emulation program to implement a point to point serial link between the chipKIT™ PRO MX7 and a PC.
Investigate concepts involving synchronous communications using a basic master-slave multi-drop network communications and use the I2C protocol to communicate with the 24LC256 I2C™ CMOS Serial EEPROM.
Investigate synchronous communications with the SPI master-slave serial bus
Generate a proportional output using the output compare resource on the PIC®32MX processor to implement digital-to-analog conversion with pulse width modulation (PWM), thus controlling the speed of a DC motor.
Use the PIC™ 32 input capture to measure frequency to determine the speed of a DC motor.
The purpose of this project is to investigate synchronous communications with the SPI master-slave serial bus. The project uses the Digilent® PmodJSTK™ joy stick module that has two LED outputs and three button inputs as well as a two axis joystick. Project 8a provides an alternative or supplement to Project 8 that investigates the I2C serial protocol.
Qty | Description | |
---|---|---|
1 | Digilent chipKIT™Pro MX7 processor board with USB cable | ![]() |
1 | Microchip MPLAB® X IDE | ![]() |
1 | Microchip MPLAB® XC32 Compiler | |
1 | Digilent PmodCLP™ Parallel Character LCD | ![]() |
1 | Digilent PmodJSTK 2-axis joystick with buttons and LEDs | ![]() |
1 | Digilent PmodTPH™ 6-pin test header | ![]() |
1 | Logic analyzer (Digilent Analog Discovery™) | ![]() |
As discussed in Project 7, serial communications involve sending data one bit at a time as opposed to Project 6 where eight bits of data was sent at a time to the LCD. One of the biggest motivations for implementing serial communications is to minimize the number of processor pins and wires needed to pass data between two points. The longer the physical distance between the end points, the more expensive the communications media becomes.
This project will focus on the Serial Peripheral Interface (SPI) protocol, which is only one out of a list of many interfaces. As supplemental information for project 8, the Serial Protocols list provides a partial list of the available serial protocols. You may ask, “Why so many serial protocols?” The simple answer is that the protocols are optimized for data rates, physical media, physical distance, and connectivity. Some protocols are strictly for point-to-point communications, such as the asynchronous serial communications used in Project 7. Other protocols are for multi-drop applications where many senders can be connected to many receivers—an Ethernet network is an example.
As the term implies, a transmitter communicates between a sender and a receiver using a synchronizing clock. The synchronizing clock can be a separate signal or a transition embedded into the data waveform.
The handshaking theory behind asynchronous and synchronous communication is essentially the same: Point B needs to know when a transmission from Point A begins, when it ends, and if it was processed correctly. However, the difference lies in how the transmission is broken down. Think of the difference in terms of a friendly chat. With asynchronous communication you would need to stop after every word to make sure the listener understood your meaning, and knew that you were about to speak the next word. With synchronous communication, you would establish with your listener that you were speaking English, that you will be speaking words at measured intervals, and that you would utter a complete sentence, or paragraph, or extended soliloquy, before pausing to confirm understanding. Further, you would establish with your listener beforehand that any extraneous noises you make during the speech or between speeches (coughing, burping, hiccupping, etc.) should be ignored. Clearly, the second approach is much faster, even though initializing communication may take slightly longer. In fact, by replacing the start, stop, and parity bits around individual words as used for asynchronous communications with start, stop, and control (processing instructions and error checking) sequences around large continuous data blocks, synchronous communication is about 30% faster than asynchronous communication, before any other factors are considered. See the Synchronous Serial Communication Overview1 for more information.
There are two kinds of operating modes for multi-drop or network configurations; master–slave and peer-to-peer. Master-slave operates similarly to the microprocessor-LCD communication considered in Project 6. The microprocessor is the master and it dictates the data direction and the timing of the data exchange between the master and slave units. I2C (inter-integrated circuit communications—also sometimes written as I2C) and SPI are examples of master-slave networks supported directly by hardware in many microprocessors. I2C is a half-duplex scheme where the slave devices are enabled or selected by encoding data in a message sent by the master. SPI uses master-controlled dedicated device select signals along with separate data send and receive signals to enable simultaneous communications (full-duplex) between the master and a specific slave device.
Peer-to-peer communications on the other hand allows data exchange at any time and between any two communications nodes. Full-duplex UART communications is one example of peer-to-peer communications. RS-232, CAN, and Ethernet communications are additional examples of peer-to-peer communications.
The SPI serial protocol has a higher data rate than does I2C because it can generally operate higher clock rates and is not limited to 8-bits per word. Although I2C requires only two wires (thus conserving processor pins—see Project 8) rather than four wires required by SPI, I2C has bandwidth overhead due to the time required for device selection by sending the ID as a serial byte. Unlike I2C, SPI has no device acknowledge capability.
SPI is a full-duplex synchronous serial communications bus protocol developed by Motorola, and it has become a de facto standard that has not been adopted by any national or international standards organizations. The SPI bus implements a master-slave communications scheme where the master device alone controls data that is exchanged with slave devices. The master device has exclusive control of the serial clock (SCK) signal that is used to clock the data to and from a slave device.
SPI requires four wires for full-duplex operation and supports only one master but multiple slave devices. The master writes data to the slave using the master-out-slave-in (MOSI) line. The slave devices are able to send data to the master over the master-in-slave-out (MISO) line. Other than the clock signal, all handshaking is handled by an explicit slave select (SS) or chip select (CS) signal.
Figures 1 and 2 illustrate the two common SPI bus connection configurations. Figure 1 shows that the multiple slave devices share SCK, MOSI, MISO signals. For this connection configuration, the slave devices are explicitly selected by multiple dedicated SS microprocessor outputs. This is the more common SPI connection configuration.
Figure 2 shows a daisy-chain configuration where slave devices share the SCK and SS signals. However, the MOSI and MISO signals are routed through a series of slave devices. Using this configuration, data intended for the last device in the chain must be clocked through the preceding slave devices. Data that is to be read from the first slave device in the chain must also be clocked through the slave devices that follow it in the chain. This additional data transfer time is the cost of conserving processor I/O pins used for enabling slave devices. Due to the excessive data transfer time for systems with many slave devices, this configuration is seldom used.
When the microprocessor is connected to a slave device that has both input and output capability using SPI, as data is clocked out of the master, data is clocked in from the slave device. This results in efficient data transfers for some slave devices. The loosely defined SPI interface does require careful consideration of the slave clock-data timing as well as using a microprocessor that can be configured to support various timing requirements. Figure 3 shows the clock-data time timing for the four SPI operating modes. The clock polarity (CPOL) controls the idle level of the SCK output from the master. If CPOL is high then the idle level of SCK is high. The clock phase (CPHA) specifies when the data is to be changed or written to MOSI by the master and MISO by the slave device. When CPHA is low, the data signal (MISO for master and MOSI for the slave) is sampled by the receiving device when SCK makes a transition from the idle level to the active level.
Table 1 provides to correlation between the conventional definitions of SPI mode CPHA and CPOL to the PIC®32 settings for clock edge (CKE) and clock polarity (CKP). It is important to match the master processor operation to what the slave device is expecting. For some designs, it is possible for different slave devices to expect the master to operate in modes that are not the same. The PIC32 operations modes can be changed during program execution but the modes should not be changed when the processor is actively clocking data on the SPI bus.
Table 1. SPI SCK operational modes.
SPI Mode | Active Level | Sample Transition | CPOL | CPHA | PIC32 CKP | PIC32 CKE |
---|---|---|---|---|---|---|
0 (or 0,0) | HIGH | Idle to Active | 0 | 0 | 0 | 1 |
1 (or 0,1) | HIGH | Active to Idle | 0 | 1 | 0 | 0 |
2 (or 1,0) | LOW | Idle to Active | 1 | 0 | 1 | 1 |
3 (or 1,1) | LOW | Active to Idle | 1 | 1 | 1 | 0 |
SPI master-slave communications can be operated in either simplex or full-duplex modes. Simplex communications occur when the slave device can only send or receive data. Regardless of which device, master or slave, is sending the data, the master always provides the SCK signal. Although the phase and sample timing can differ between devices using SPI, the data is always active high (a high level represents a logical 1).
Data is sent and received by transferring the most significant bit (MSB) on the first clock pulse. We will define a transfer transaction as the exchange of data while the SS signal is continuously asserted in the active state (usually a low level.) For a specific transaction, if multiple bytes are to be transferred, the byte counter in the slave device is reset when the SS signal is asserted. There is no start and stop sequence or byte acknowledge like used with I2C. Data can be transferred as 8-, 16-, or 32-bit words. There is no limit to how much data can be transferred in a single transaction.
A data bit is shifted into the receiving device at the same time as the data bit is shifted out. Hence, once a word of data has been sent, the device has also received the next word. The SPI uses SCK clock edges to implement each bit transfer. At one SCK edge, each data sends a bit of data on the send line. The opposite clock edge a half of SCK clock cycle later, a data bit on the receive line is clocked into the receiving device. The specific clock edges are specified by the SPI mode of operation. The SCK signal can be asymmetrical as long as the period of the high or low state is greater than the inverse of two times the maximum data rate.
We will be using the C32 peripheral library functions to set up the SPI hardware in the PIC32 processor. The SPI control register will be initialized for the case when the PIC32 is the master processor and the PmodJSTK is the slave device. The hardware configuration for this design is shown in Fig. 7 of the first tab on the right. The pin assignment uses SPI channel 1. A picture and functional block diagram of the PmodJSTK joystick module are shown in Figs. 8 and 9 of the orange tab as well as the pin assignments listed in Table 7. The PmodJSTK provides access to a two-axis joystick with a switch that is activated when the joystick control is pressed as well and two momentary contact push buttons. The joystick position is indicated with a 10-bit reading, where a value of roughly 512 indicates the center joystick position. There are two LEDs provided on the PmodJSTK that can be used to output status indication.
Reading the joystick positions and button status of the PmodJSTK requires a 5-byte data exchange, as shown in Table 2. The joystick position for the X and Y axis is indicated by combination of the low byte with the least significant two bits of the high byte. The status of the three buttons provided by the fifth byte is assigned to the bit positions shown in Table 3. The LEDs can be controlled with a single byte data exchange by setting the bits of the LED control byte, as shown in Table 4. Note that the most significant bit of the LCD Control byte is always set to a one.
Table 2. The SPI data format for reading and writing to PmodJSTK.
Byte Number | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
Read Byte | X axis — low byte | X axis — high byte | Y axis — low byte | Y axis — high byte | Button Status |
Write Byte | LED Control | Not Used | Not Used | Not Used | Not Used |
Table 3. PmodJSTK button status byte.
Bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Assignment | 0 | 0 | 0 | 0 | 0 | BTN2 | BTN1 | Joystick |
Table 4. PmodJSTK LED control byte.
Bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Assignment | 1 | 0 | 0 | 0 | 0 | 0 | LED2 | LED1 |
The reference manual for the PmodJSTK suggests that the clock speed be restricted to less than 1 MHz. The PmodJSTK byte counter is reset each time the SS signal is asserted low. The manual also suggests that there be a 15 μs delay inserted after the SS signal is asserted and when the SCK begins to clock the data transfer. It also suggests that a 10 μs delay be used between transferring data bytes.
As discussed above, a microprocessor must be able to support numerous SPI mode configurations. Although it is possible and frequently done, the SPI protocol can be implemented by any microprocessor using the method of bit-banging I/O pins. The PIC32 processor provides a hardware implementation of the SPI protocol that results in reduced software and faster data transfers. The SPIxCON register controls the SPI functionality where “x” ranges from 1 to 4, indicating the SPI channel. For this project, we will focus only on the SPI channel 1 configuration where the PIC32 processor is the SPI master.
The reader is referred to the Section 23 of the PIC32 reference manual for a complete description of the PIC32 SPI operation. The approach to configuring the SPI control register will be to identify the control bits that need to be set to configure the PIC32 processor as the SPI master for 8-bit operation. Neither SPI interrupts nor SPI extended buffers will be used. The SPI control register bit definitions mnemonics are listed in the ppic32mx.h system header file, as shown in Table 5. Shaded rows in Table 5 are not used in the configuration for this design. After reset, the default state of all SPIxCON bits is zero.
Table 5. SPIxCON control bit definitions.
Functionality | Mnemonic |
---|---|
SPI CPU select 0 — CPU is Slave : 1 — CPU is Master |
SPICON_MSTEN |
SPI clock polarity 0 — Low idle state : 1 — High idle state |
SPICON_CKP |
Slave Select Enable | SPICON_SSEN |
SPI clock edge select for data change 0 — idle to active state : 1 — active to idle state |
SPICON_CKE |
Input sampled time relative to data output time 0 — middle of interval : 1 — end of interval |
SPICON_SMP |
[Mode16:Mode32] [00]–8 bit, [10]–16 bit, [01]-32 bit | SPICON_MODE16 |
[Mode16:Mode32] [00]–8 bit, [10]–16 bit, [01]-32 bit | SPICON_MODE32 |
Disable SDO pin | SPICON_DISSDO |
Stop SPI when CPU is idle | SPICON_SIDL |
Freeze SPI operation for CPU exception | SPICON_FRZ |
SPI peripheral On/Off control 0 — OFF : 1 — ON |
SPICON_ON |
Frame Sync pulse edge | SPICON_SPIFE |
Frame Sync polarity active high | SPICON_FRMPOL |
Frame Sync pulse input control on SS pin | SPICON_FRMSYNC |
Frame Support enable | SPICON_FRMEN |
The C32 peripheral library documentation specifies three arguments to be passed by the SpiChnOpen function. The first argument selects the SPI channel and is set to either 1 or 2. The second argument is a 32-bit value that programs the SPI1CON register to select the SPI operating mode. The configuration argument is generated using the mnemonics listed in Table 5 that are joined with the logical OR operation. Including the mnemonic in the configuration declaration sets the associated bit position to a one. The last argument is a value that is divided into the PIC32 peripheral clock to set the SPI clock rate. An example statement to open SPI channel 1 is:
Brg = PBCLK/(2 * MAX_SPI_CLOCK); // SPI bit rate generator - PBCLK = peripheral bus clock
SpiChnOpen(1, config, Bgr);
For this example, config equals (SPICON_ON | SPICON_MSTEN)|(SPICON_ON | SPICON_MSTEN) and brg is the peripheral bus clock divider for twice the maximum SPI clock rate. The SPI configuration explicitly turns on SPI1 operation as a SPI master. By default, the SPI setting is for 8-bit data transfers, SPI mode 1 (Table 1), data is sampled at the middle of to the transmission period, and the SDO (MOSI) pin is enable.
Exchanging data between the PIC processor and the slave device requires two C instructions: one instruction to send the data word out on the MOSI signal line and one C instruction to recover the data word just clocked in on the MISO signal. The C program code in Listing 1 shows one method to exchange data with the PmodJSTK. The DelayUs instruction is a call to a microsecond software delay function needed to implement a 10 μs delay as recommended in the joystick reference manual. The C instruction, SpiChnPutC(1),(BYTE) data_out), sends the single byte of data that is passed to this function by the calling function. It will wait until the data byte has been completely sent before returning to the JSTK_xfer function. Thus, the data that was shifted in from the MISO line is waiting to be read by the SpiChnGetC(1) function. The argument shown as “1” in both functions indicates SPI channel 1.
Listing 1. SPI single data byte exchange function for the PmodJSTK.
int JSTK_xfer(int data_out)
{
DelayUs(10);
SpiChnPutC(1,(BYTE) data_out);
return SpiChnGetC(1);
}
The JSTK_xfer function would need to be called five times, as shown in Listing 2, to exchange all five bytes needed to read the PmodJSTK position and button status. Note that the SS signal, named JSTK_SEL, is asserted low followed by a 15 μs delay before transferring the first data byte. The byte sent to the PmodJSTK for the first exchange contains the LED setting control as described in Table 4. The value of the bytes sent on successive exchanges is not important as that data is ignored by the joystick controller.
Listing 2. SPI five data byte exchange function for the PmodJSTK.
void JSTK_getAll(int ledSt, BYTE *recv)
{
JSTK_SEL = 0;
DelayUs(15);
*recv++ = JSTK_xfer(ledSt | 0x80);
*recv++ = JSTK_xfer(0);
*recv++ = JSTK_xfer(0);
*recv++ = JSTK_xfer(0);
*recv++ = JSTK_xfer(0);
JSTK_SEL = 1;
}
Figure 5 is a screen capture of the first of the five-byte SPI communications with the joystick controller. Since the PIC32 was programmed to operate in SPI mode 1, the MISO signal line is sampled on the negative SCK transitions. This byte is sent to set the joystick LED 2 on and read the X-axis low byte as 0xF2.
Move the joystick and observe the changes in values displayed on the LCD. Record the values display for the joystick in the positions listed in Table 6.
Table 6. X- and Y-axis position values.
X-axis position | X-axis value | Y-axis position | Y-axis value |
---|---|---|---|
Center | Center | ||
Up | Right | ||
Down | Left |
List the strengths of SPI communications over I2C.
List the weaknesses of SPI communications.
Why is SPI considered a communications bus and not a network?
Why does SPI normally have higher data transfer rates?
Is it necessary for the SPI SCK signal to have a 50% duty cycle?