Chapter 9.2: Store Lots of Data in an SPI Flash – Part 2: Connecting and Reading the JEDEC ID
01/26/2016 | 06:33 PM
This is a five part series on the SPI communication protocol. In the first section, we learned all about SPI and how to make a SPI flash breakout board from a bare chip. In this section, we will connect the SPI flash to the EFM32 Starter Kit and then write some code with the help of the USART library to fetch the JEDEC ID from the register on the part. We will continue to rely on the Spansion flash chip’s spec to accomplish this.
Flash Chip to MCU Connections
The SPI bus requires either three or four wires, depending on the mode.
I will demonstrate the use of SPI using the four-wire mode, which is more common in my experience than the three-wire mode. The EFM32 USART supports the three-wire mode and calls this mode Synchronous Half Duplex Communication. In that case, the MISO line is not used and the MOSI line becomes a bidirectional signal. You can read more about it in the Reference Manual.
In SPI terminology, a SPI device can be a master or a slave device, at any given moment in time. The USART peripheral in the EFM32 can be configured as either one. One device has to be the master and the other a slave for a single SPI transaction. We will configure the MCU as master since the MCU is driving the interaction with the flash chip. We might someday configure the MCU as a slave if we have another MCU in a system and intend to share information between the two of them. But we could configure our USART in the MCU dynamically to be a slave on one cycle, then a master on the next cycle.
The Master In Slave Out (MOSI) terminology is an improvement over the RX/TX nomenclature of the serial port connections. Now, a master device’s MOSI output pin connects directly to a slave’s MOSI input pin, and MISO pin to MISO pin. This is great, because the connections are made between like-named, or at least similarly-named pins. Unfortunately the Data Sheet tables for the USART pins don’t specifically list MOSI/MISO, and you still need to know to map the USART TX pins to MOSI and the USART RX pins to MISO. This information is covered in the Reference Manual for the USART peripheral. In addition, some devices don’t use the MOSI/MISO naming and instead use SDI, DI, SI, etc. for an input. If you can find the one that says input, attach that to the master’s MOSI and you will do fine.
The flash chip breakout board has additional signals that must be attached to your Starter Kit. The first thing to look for are the power and ground connections. Whenever you are connecting your MCU to an external device, you need to take a look at the voltage requirements in the spec for that device. This is listed in the Electrical section for the Spansion chip.
The Supply Voltage (also known as Vcc and sometimes called Vdd) requires between 2.7V and 3.8V. Sometimes you will find chips that require 1.8V or 2.8V, which would then need an external power supply to be provided. In this case, the chip can be powered directly from the Starter Kit’s 3.3V supply pins that are labeled as 3V3. Connect the signals as shown in the table below. We are using specific pins of USART1 location 1 for the SPI signals, since those are brought out to pins on the Starter Kit, and just any old GPIO’s for the other signals.
Signal
Spansion Flash Breakout Pin
Wonder Gecko GPIO Pin
CS# (Chip Select, active low)
1 – top left
PD3 – USART CS
SO (MISO)
2
PD1 – USART RX (MISO)
WP# (Write Protect, active low)
3
PD4 – Chosen at random
GND
4 – bottom left
GND
SI/SO (MOSI)
5 – bottom right
PD0 – USART TX (MOSI)
SCK (Clock)
6
PD2 – USART CLK
HOLD# (active low)
7
PD5 – Chosen at random
VCC
8 – top right
V3V
SPI Software Configuration
Now that everything is wired up, it is time to communicate with the flash memory chip from the MCU with software. You can use Simplicity Configurator to configure the part like we did in the last lesson, or manually configure your USART to connect to the SPI signals CLK, CS, MOSI (TX in the USART) and MISO (RX in the USART). I will demonstrate how to do it manually for this chapter.
There is a decision to be made about the clock mode when configuring the clock signal in the USART software setup. With SPI, very little is set in stone. It is up to the chip designers to determine exactly how the electrical signals should operate. The USART provides configuration registers that handle the polarity and phase in order to work with all devices. These are referred to as CPOL or CLKPOL (depending on the chip) for the clock polarity and CPHA or CLKPHA for the clock phase. The clock polarity can be set to either 0 or 1, which determines the idle state of the clock line. The clock phase can also be 0 or 1, which determines whether data is latched on the rising or falling edge of the clock signal. This gives four possible choices for clock modes 0 through 3, which make up the four clock modes. There are diagrams in the Reference Manual that describe all four modes.
All that really matters to us at this point is that we pick the right mode for the Spansion chip. If we look in the spec for the Spansion flash chip, we see that it can operate in either clock mode 0 or clock mode 3.
When configuring the CS line, there is a decision to be made about whether or not the USART peripheral will control the CS line automatically, known as AUTOCS, or if the software will explicitly control the CS line to the slave SPI device. We will need to control the CS line explicitly, because if we were to pick AUTOCS mode and fail to feed the USART the two bytes of data fast enough, the USART-controlled CS line will go high in the middle of the above waveform, and the device will essentially forget all about the command we requested. We need to drive the CS line low for the entire time as shown in the diagram. The AUTOCS mode is better used when we are sending bytes to the USART through another hardware mechanism rather than software.
We will leave the SPI bus frequency at the default of 1MHz. The table in the Spansion spec states that the chip supports SPI bus frequencies up to at least 44MHz, but you should be aware that the maximum that the EFM32 chip can reach is about one half of the HFPER clock frequency. With the default HFRCO clock setup, that means it can only reach about 7MHz. Plus, our breadboard setup is more likely to see noise that could cause glitches at higher frequencies.
void usart_setup()
{
// Set up the necessary peripheral clocks
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_USART1, true);
// Enable the GPIO pins for the USART, starting with CS
// This is to avoid clocking the flash chip when we set CLK high
GPIO_PinModeSet(gpioPortD, 3, gpioModePushPull, 1); // CS
GPIO_PinModeSet(gpioPortD, 0, gpioModePushPull, 0); // MOSI
GPIO_PinModeSet(gpioPortD, 1, gpioModeInput, 0); // MISO
GPIO_PinModeSet(gpioPortD, 2, gpioModePushPull, 1); // CLK
// Enable the GPIO pins for the misc signals, leave pulled high
GPIO_PinModeSet(gpioPortD, 4, gpioModePushPull, 1); // WP#
GPIO_PinModeSet(gpioPortD, 5, gpioModePushPull, 1); // HOLD#
// Initialize and enable the USART
USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
init.clockMode = usartClockMode3;
init.msbf = true;
USART_InitSync(USART1, &init);
// Connect the USART signals to the GPIO peripheral
USART1->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN |
USART_ROUTE_CLKPEN | USART_ROUTE_LOCATION_LOC1;
}
All of that work and we still don’t have anything that we can test to see if we did it right. We still need some code to actually initiate a SPI cycle and we need to find a destination for that cycle that will yield a meaningful result to prove that the SPI command worked or not. For this purpose, I turn to identification registers. The chip designers of SPI parts will usually give you a softball register that always returns a non-zero fixed value to let you test basic connectivity and signs of life. In this case, that register in the Spansion SPI Flash is the JEDEC ID at address 0x9F. It actually has three distinct, non-zero fixed values that it can return one after another. So we can test to make sure that we find the first value, then expand our test case to make sure that we find all three values.
#include "utilities.h" // Re-used from earlier lesson for delay function
#define JEDEC_ID_CMD 0x9F
int main(void)
{
CHIP_Init();
usart_setup();
setup_utilities();
delay(100);
uint8_t result[3];
uint8_t index = 0;
GPIO_PinModeSet(gpioPortD, 3, gpioModePushPull, 0);
// Send the command, discard the first response
USART_SpiTransfer(USART1, JEDEC_ID_CMD);
// Now send garbage, but keep the results
result[index++] = USART_SpiTransfer(USART1, 0);
result[index++] = USART_SpiTransfer(USART1, 0);
result[index++] = USART_SpiTransfer(USART1, 0);
GPIO_PinModeSet(gpioPortD, 3, gpioModePushPull, 1);
// Check the result for what is expected from the Spansion spec
if (result[0] != 1 || result[1] != 0x40 || result[2] != 0x13)
{
DEBUG_BREAK
}
while (1)
;
}
Execute the code shown and break in on the while loop. You should see a value of 1 in the result array at the 0 position. This proves to a 1/254 chance that we are reading the register that we think we are reading. Had this register’s default been zero or 0xff, we could not be sure that we were reading the right register because 0xff is the default state of flash memory at reset and zero is the usual default state for most configuration registers. But since the default value for this Manufacturer ID is 1, we can be confident that this SPI driver is beginning to work.
You should notice something funny going on in this code. We read a single value from the USART_SpiTransfer function and don’t do anything with the return value, then we read another value before storing the return value. That is because a four-wire SPI bus is ALWAYS bidirectional. When a master drives a cycle out on MOSI, the slave is required to drive something on MISO for every clock edge, even on the first clock. But since the slave doesn’t even know what is being asked until after that first clock, the slave device will either send back a useless value, or sometimes slave devices will use this first bit time as a chance to send back a status message. You have to examine the SPI chip’s spec to find out what it will do. Once the command from the first bit time is latched and processed by the slave, it can respond with the necessary information on the second SPI transfer.
The code verifies that all three values from the JEDEC ID command are as expected, which gives us near certainty that we have indeed read from the Flash SPI device properly and the USART driver is working well so far.
In the next section, we will take a look at these SPI waveforms on the oscilloscopes and learn about more advanced SPI topology.
Chapter 9.2: Store Lots of Data in an SPI Flash – Part 2: Connecting and Reading the JEDEC ID
This is a five part series on the SPI communication protocol. In the first section, we learned all about SPI and how to make a SPI flash breakout board from a bare chip. In this section, we will connect the SPI flash to the EFM32 Starter Kit and then write some code with the help of the USART library to fetch the JEDEC ID from the register on the part. We will continue to rely on the Spansion flash chip’s spec to accomplish this.
Flash Chip to MCU Connections
The SPI bus requires either three or four wires, depending on the mode.
I will demonstrate the use of SPI using the four-wire mode, which is more common in my experience than the three-wire mode. The EFM32 USART supports the three-wire mode and calls this mode Synchronous Half Duplex Communication. In that case, the MISO line is not used and the MOSI line becomes a bidirectional signal. You can read more about it in the Reference Manual.
In SPI terminology, a SPI device can be a master or a slave device, at any given moment in time. The USART peripheral in the EFM32 can be configured as either one. One device has to be the master and the other a slave for a single SPI transaction. We will configure the MCU as master since the MCU is driving the interaction with the flash chip. We might someday configure the MCU as a slave if we have another MCU in a system and intend to share information between the two of them. But we could configure our USART in the MCU dynamically to be a slave on one cycle, then a master on the next cycle.
The Master In Slave Out (MOSI) terminology is an improvement over the RX/TX nomenclature of the serial port connections. Now, a master device’s MOSI output pin connects directly to a slave’s MOSI input pin, and MISO pin to MISO pin. This is great, because the connections are made between like-named, or at least similarly-named pins. Unfortunately the Data Sheet tables for the USART pins don’t specifically list MOSI/MISO, and you still need to know to map the USART TX pins to MOSI and the USART RX pins to MISO. This information is covered in the Reference Manual for the USART peripheral. In addition, some devices don’t use the MOSI/MISO naming and instead use SDI, DI, SI, etc. for an input. If you can find the one that says input, attach that to the master’s MOSI and you will do fine.
The flash chip breakout board has additional signals that must be attached to your Starter Kit. The first thing to look for are the power and ground connections. Whenever you are connecting your MCU to an external device, you need to take a look at the voltage requirements in the spec for that device. This is listed in the Electrical section for the Spansion chip.
The Supply Voltage (also known as Vcc and sometimes called Vdd) requires between 2.7V and 3.8V. Sometimes you will find chips that require 1.8V or 2.8V, which would then need an external power supply to be provided. In this case, the chip can be powered directly from the Starter Kit’s 3.3V supply pins that are labeled as 3V3. Connect the signals as shown in the table below. We are using specific pins of USART1 location 1 for the SPI signals, since those are brought out to pins on the Starter Kit, and just any old GPIO’s for the other signals.
Signal
Spansion Flash Breakout Pin
Wonder Gecko GPIO Pin
CS# (Chip Select, active low)
1 – top left
PD3 – USART CS
SO (MISO)
2
PD1 – USART RX (MISO)
WP# (Write Protect, active low)
3
PD4 – Chosen at random
GND
4 – bottom left
GND
SI/SO (MOSI)
5 – bottom right
PD0 – USART TX (MOSI)
SCK (Clock)
6
PD2 – USART CLK
HOLD# (active low)
7
PD5 – Chosen at random
VCC
8 – top right
V3V
SPI Software Configuration
Now that everything is wired up, it is time to communicate with the flash memory chip from the MCU with software. You can use Simplicity Configurator to configure the part like we did in the last lesson, or manually configure your USART to connect to the SPI signals CLK, CS, MOSI (TX in the USART) and MISO (RX in the USART). I will demonstrate how to do it manually for this chapter.
There is a decision to be made about the clock mode when configuring the clock signal in the USART software setup. With SPI, very little is set in stone. It is up to the chip designers to determine exactly how the electrical signals should operate. The USART provides configuration registers that handle the polarity and phase in order to work with all devices. These are referred to as CPOL or CLKPOL (depending on the chip) for the clock polarity and CPHA or CLKPHA for the clock phase. The clock polarity can be set to either 0 or 1, which determines the idle state of the clock line. The clock phase can also be 0 or 1, which determines whether data is latched on the rising or falling edge of the clock signal. This gives four possible choices for clock modes 0 through 3, which make up the four clock modes. There are diagrams in the Reference Manual that describe all four modes.
All that really matters to us at this point is that we pick the right mode for the Spansion chip. If we look in the spec for the Spansion flash chip, we see that it can operate in either clock mode 0 or clock mode 3.
When configuring the CS line, there is a decision to be made about whether or not the USART peripheral will control the CS line automatically, known as AUTOCS, or if the software will explicitly control the CS line to the slave SPI device. We will need to control the CS line explicitly, because if we were to pick AUTOCS mode and fail to feed the USART the two bytes of data fast enough, the USART-controlled CS line will go high in the middle of the above waveform, and the device will essentially forget all about the command we requested. We need to drive the CS line low for the entire time as shown in the diagram. The AUTOCS mode is better used when we are sending bytes to the USART through another hardware mechanism rather than software.
We will leave the SPI bus frequency at the default of 1MHz. The table in the Spansion spec states that the chip supports SPI bus frequencies up to at least 44MHz, but you should be aware that the maximum that the EFM32 chip can reach is about one half of the HFPER clock frequency. With the default HFRCO clock setup, that means it can only reach about 7MHz. Plus, our breadboard setup is more likely to see noise that could cause glitches at higher frequencies.
All of that work and we still don’t have anything that we can test to see if we did it right. We still need some code to actually initiate a SPI cycle and we need to find a destination for that cycle that will yield a meaningful result to prove that the SPI command worked or not. For this purpose, I turn to identification registers. The chip designers of SPI parts will usually give you a softball register that always returns a non-zero fixed value to let you test basic connectivity and signs of life. In this case, that register in the Spansion SPI Flash is the JEDEC ID at address 0x9F. It actually has three distinct, non-zero fixed values that it can return one after another. So we can test to make sure that we find the first value, then expand our test case to make sure that we find all three values.
Execute the code shown and break in on the while loop. You should see a value of 1 in the result array at the 0 position. This proves to a 1/254 chance that we are reading the register that we think we are reading. Had this register’s default been zero or 0xff, we could not be sure that we were reading the right register because 0xff is the default state of flash memory at reset and zero is the usual default state for most configuration registers. But since the default value for this Manufacturer ID is 1, we can be confident that this SPI driver is beginning to work.
You should notice something funny going on in this code. We read a single value from the USART_SpiTransfer function and don’t do anything with the return value, then we read another value before storing the return value. That is because a four-wire SPI bus is ALWAYS bidirectional. When a master drives a cycle out on MOSI, the slave is required to drive something on MISO for every clock edge, even on the first clock. But since the slave doesn’t even know what is being asked until after that first clock, the slave device will either send back a useless value, or sometimes slave devices will use this first bit time as a chance to send back a status message. You have to examine the SPI chip’s spec to find out what it will do. Once the command from the first bit time is latched and processed by the slave, it can respond with the necessary information on the second SPI transfer.
The code verifies that all three values from the JEDEC ID command are as expected, which gives us near certainty that we have indeed read from the Flash SPI device properly and the USART driver is working well so far.
In the next section, we will take a look at these SPI waveforms on the oscilloscopes and learn about more advanced SPI topology.
PREVIOUS I NEXT
Hello,
Where can I find your utilities routine that you mention you developed in an earlier exercise ?