An article explaining the SPI serial peripheral interface in detail
INDUSTRIAL LCD DISPLAYS / IGBT MODULES DISTRIBUTOR

Infineon / Mitsubishi / Fuji / Semikron / Eupec / IXYS

An article explaining the SPI serial peripheral interface in detail

Posted Date: 2024-01-19

SPI is also one of the most common external communication ports of MCU. It was developed by Motorola in the 1980s and is used for short-distance data communication between devices in embedded systems. The standard mode uses four signal lines. Currently, common application devices include: LCD modules, Ethernet modules, SPI serial Flash and many sensors, etc. Most SD cards have SPI operating mode.

The characteristics of SPI are master-slave structure, simple protocol, low cost, serial transmission, etc. It has synchronous clock signal and the transmission rate can reach several megabytes to more than ten megabytes (recently, there are also devices with speeds of 20 to 30 megabytes), which is suitable for Medium data volume, point-to-point transmission environment.

1.1 SPI communication protocol

SPI is a point-to-point, full-duplex serial communication protocol used for communication between two devices. The basic wiring method is four signal lines, as shown below:

Figure 1. SPI signal line connection diagram

There are two data lines among the four signal lines, which are used for the master to send data to the slave (MOSI: Master OutSlave In), and the slave to send data to the host (MISO: MasterIn Slave Out).

The host device outputs a clock to the slave through the SCK clock signal line, and at the same time the host outputs the SSEL signal as the slave's chip select.

1.1.1 SPI data transmission

The data transmission process of SPI is very simple. There are the following operations in each SCK clock cycle:

▲The master sends a data bit to the slave in MOSI;

▲The slave receives a data bit on MOSI;

▲The slave sends a data bit to the master at MISO;

▲The host receives one data bit on MISO.

Generally, the SPI master and slave each use a shift register to send and receive data. The schematic diagram is as follows:

Figure 2. SPI data shifting diagram

Driven by the same clock signal, the shift registers of the master and the slave shift in the same direction at the same time. After n shifts of n clock cycles, the data of the master and the data of the slave are exactly exchanged.

Usually the length of each character data is n=8 or n=16. LPC800 allows each data length to be any value from 1 to 16.

1.1.2 SPI clock signal

In addition to the frequency characteristics of the SPI clock signal SCK, its polarity and phase also need to be considered, which are represented by CPOL and CPHA respectively, and have the following meanings:

▲Clock polarity:

CPOL=0: When idle, the clock signal is '0'. The leading edge of the clock signal is the rising edge, and the trailing edge is the falling edge.

CPOL=1: When idle, the clock signal is '1'. The leading edge of the clock signal is the falling edge, and the trailing edge is the rising edge.

▲Clock phase:

CPHA=0: The sender changes the output signal on the trailing edge of the previous clock cycle; the receiver samples the input signal on the leading edge of the clock cycle.

CPHA=1: The sender changes the output signal on the leading edge of the clock cycle; the receiver samples the input signal on the trailing edge of the clock cycle.

Usually four combinations of CPOL and CPHA are defined as four modes, as shown in the following table:

Figure 3. Waveform diagram of four operating modes of SPI

Before the first clock edge of SCK in mode 0 and mode 2, the SPI master uses the internal clock to output the first data bit (the highest bit) on MOSI, and the SPI slave uses the last edge of the previous data frame to output the first data bits (highest bit).

1.1.3 Interconnection of SPI devices

The interconnection between SPI devices is a master-slave relationship. One master device can connect to multiple slave devices. The master device communicates with which slave device through the slave device chip select signal.

Figure 4. Schematic diagram of interconnection between SPI devices

The number of slaves that can be connected to a host device is limited by the number of chip select signals (SSELn) that can be output and the driving capabilities of the MOSI and SCK signal lines.

1.2 SPI characteristics of LPC800

The SPI of LPC800 is very simple, but rich in configuration and easy to use.

▲The length of each data frame can be directly configured to be any one from 1 to 16 bits, and data frames of any length can also be supported through software operation.

▲Supports host mode or slave mode.

▲The host can ignore the data returned by the slave when sending data. This helps optimize the operation of the software, such as when refreshing the LCD module (in reality, many LCD modules are unreadable), or when writing to SPI memory.

▲Control information can be written to the register together with the sent data, so that various flexible operation requirements can be achieved.

▲There are up to four directly controlled slave chip select signals, and the polarity can be configured.

▲Support DMA operation.

▲Various timings in each data frame can be flexibly controlled.

1.3 SPI Flash read and write routines Below are several routines to demonstrate the use of SPI to read and write SPI Flash.

These routines are all on LPC824-Lite, and operate the W25Q32BV on the board. Below, we will copy some of the command formats of this memory chip to facilitate the understanding of the routines. The following routines use the shaded commands in the table.

Table 1.W25Q32BV partial command list

Figure 5. SPI Flash circuit diagram on the development board

1.3.1 SPI polling mode operation

All following SPI routines use the same initializer.

Code snippet 1. SPI host initialization function

The initialization function is very simple and direct. Like the initialization process of all other modules, it is "turn on the clock → map the pin → reset the module → configure parameters.

The figure below shows the configuration bits of all SPI configuration registers.

Figure 6. SPI configuration register (CFG) overview

In code snippet 1, only bits 0 and 2 of the CFG register are set, and the other bits are all '0'.

The SPI transmit data/control register of LPC800 is very unique.

Figure 7. List of SPI transmit data and control registers

The picture above shows all the bits of the complete transmit data control register. The user can use the TXDATCTL register to write data and all control bits at the same time, or use TXCTL to write the control bits alone, or use TXDAT to write the data bits alone.

For the SSEL chip select signal output to the slave, the user can output the corresponding level at any time as needed, and can even control the SSEL level individually by character.

If you need to use a data frame with more than 16 bits, you can use the EOF control bit. For example, if each data frame needs to be 24 bits long, you can output two 12-bit characters. When outputting the first 12-bit character, configure EOF=0. When outputting the second 12-bit character, configure EOF. =1; you can also output three 8-bit characters, and configure EOF=1 when outputting the third character.

As can be seen from Figure 2, while SPI is sending data, it will also receive data from the other party, but many times during the sending process, the program does not need to care about what data is received, such as when outputting data to the LCD screen. In this case, setting RXIGNORE=1 will prevent the SPI module from generating the receive status bit, and will not cause errors such as receive overflow because the received data is not read out.

Let's look at the code below to see how to use these registers flexibly.

Two macros are defined below for judging sending and receiving status:

Define two more macros for sending control bit settings:

In line 08 of code snippet 1, SSEL0 is mapped to pin P0_15. In Figure 5, we see that P0_15 is the chip select signal of SPI Flash. Therefore, the SSEL control bits are set in these two macros so that only the output SSEL0 is valid, and other SSEL chip selects are invalid (unselected).

OUT_CTL will be used to send commands and data. At this time, there is no need to relate the input data, so set RXIGNORE=1.

IN_DATA is used to send a series of clock pulses to the slave when data needs to be received. At this time, the SPI Flash ignores the received data and can send any value.

Combined with the above initialization code and macro definition, the following code is used to read in the manufacturer code and chip code.

Code snippet 2. Polling function to read manufacturer ID and memory capacity

There is no WaitForSPI0txRdy statement before lines 11 and 15 of the above code. This is because valid data has been received previously, which means that the previous transmission has been completed and there is no need to wait for the transmission register to be ready and can be transmitted directly.

The following code is used to read out the device ID. The only difference between the process and the above is that when sending the command string, TXDAT and TXCTL are operated respectively.

Code snippet 3. Polling function to read manufacturer ID and device ID

Finally, there is a very simple main function, code snippet 4.SPI polling routine main function

01 int main(void) 02 { 03 SPI0_init(); // SPI initialization 04 Read_JEDEC_ID(); 05 Read_Device_ID(); 06 07 while (1) { 08 } 09 }

1.3.2 SPI interrupt mode operation

The following is a simple interrupt mode operation routine.

Take the read manufacturer ID and memory capacity command as an example. Here we use the TXDATCTL register to write the transmission control word and the data to be sent at the same time each time, and save the content to be written to TXDATCTL each time in an array in advance. Then in the interrupt handler, the data in the array is output to the register one by one.

The array is defined as follows:

const uint32_t CMD_JedecID() = { OUT_CTL | 0x9F, // Read the manufacturer ID and memory capacity command IN_DATA | 0xFF, // Send a pulse of one character and read back the manufacturer ID MF7~MF0 IN_DATA | 0xFF, // Send a Character pulse, read back the memory ID IN_DATA | 0xFF, CTL_EOT // Send a character pulse, read back the memory capacity};

Then through several variables, the entire operation process is controlled.

uint32_t Tx_Cnt; // Used to control the progress of the current array sending uint32_t Tx_Num; // Used to record the length of the above array uint32_t *Tx_Buf; // A pointer to the sending array uint32_t Rx_Cnt; // Used to control the progress of the current receiving data uint8_t Rx_Buf(10); // used to store received data

The interrupt handler and preparation function are as follows:

Code snippet 5. Interrupt mode reads manufacturer ID and memory capacity

Line 06 in the above code is to prevent frequent interrupts caused by the failure to clear the transmission ready state of the STAT register due to no data being sent.

In lines 20 and 21, there are two loop statements respectively, waiting for the entire sending and receiving process to end. After the data is sent to the transmit register, the transmission has not ended. The hardware is still shifting bit by bit. You need to wait until SSEL returns to high level to confirm that the transmission on the signal line has ended. Note that the order of these two statements cannot be reversed, otherwise the statement waiting for SSEL will be ineffective because SSEL has not yet become valid (low level) before entering the interrupt handler.

Before these two lines of wait statements, the user program can do other things to make efficient use of CPU time.

The above code is very simple and efficient, but it is not suitable for processing long data blocks. Another method is used below to implement read and write operations on the SPIFlash memory unit using interrupts.

1.3.3 Complete routine for accessing SPI Flash in interrupt mode

Focusing on the command list of W25Q32BV (see Table 1), all commands can be summarized into the following four categories:

1. Only send commands (if there is a 24-bit address, it is also classified as a command word, the same below), such as "write enable", "whole chip erase", "sector erase" and other commands.

2. Send commands and send data buffers, such as "page program" commands.

3. Send commands and receive data strings, such as "read manufacturer and device ID", "read data" and other commands.

4. Send commands and receive status words, and wait for a specified status.

The "write status register" command can be either type 1 or type 2 above.

The following structure will be used to pass commands and data buffers to four different interrupt handlers respectively. Each component in the structure has different meanings in different interrupt programs.

According to different command classes, four interrupt handlers are used to handle different processes respectively, and the IRQHandler in the structure is used to specify which process to use.

Below are four different interrupt handlers.

1. Only send command process

Code snippet 6. Only send command buffer processing flow

Since there is only a sending process in the send command buffer processing flow, you only need to enable the send ready interrupt when using it, so there is no need to judge the status register to distinguish between sending and receiving in the above processing.

The usage of this processing flow is introduced as follows with the "Write Enable" command.

Code snippet 7. Implement the "write enable" command using send-only command buffer processing flow

In the above function, after all variables, status registers and interrupt registers are configured and interrupts are enabled on line 10, all generated SPI0 interrupt processing will be directed to the preset SPI0_Cmd_IRQHandler() handler on line 02.

The function of line 12 is the same as that of lines 20 and 21 of code snippet 5. They first wait for the completion of the sending command buffer, and then wait for the end of all processes, that is, SSEL returns to high level.

2. Sending command and data buffer process

Code snippet 8. Send command and send data buffer processing flow

The first half of the processing flow is very simple, sending the data in the command buffer one by one until all the data is sent.

The process of sending the data buffer is the same as the process of sending only the command buffer, so the second half of code snippet 8 copies the parameters of the data buffer to the control variable of the command buffer, and then transfers to the previous only Send command buffer processing flow and complete sending data buffer.

The "page programming" command is a typical send command and send data buffer processing flow. The settings of the transmission structure are as follows.

Code snippet 9. Use the send command and send data buffer processing flow to implement the "page programming" command

Use the page address to be programmed, the data buffer pointer and the data length to call this function. Configure each variable of the transmission structure item by item in the function, then configure the corresponding register through the Execution() function of code snippet 7, and wait for the end of the transfer process. .

3. Process of sending commands and receiving data strings

Code snippet 10. Processing flow of sending commands and receiving data strings

The process of sending commands and receiving data strings has an additional data receiving part compared to the previous two processes. The processing of the send ready (TXRDY) interrupt part is divided into two stages. The first stage is to send the command buffer. The second stage is to send any character (0xFF here), which is used to generate the clock signal for the slave output data; when there is only one data to be received, while sending the last arbitrary character, the send ready interrupt is disabled. This interrupt will no longer be generated thereafter to achieve the purpose of controlling the number of received data.

In processing the receive ready (RXRDY) interrupt, the received data is directly read and saved to the data buffer.

"Read data", "Read chip unique ID" and other commands all execute this process, and the read data is stored in the buffer indicated by Data_Buf.

Code snippet 11. Use the sending command and receiving data string processing flow to implement "read data"

The parameters of the Page_Read() function are basically the same as the previous Page_Program(): three parameters: the read data area address, the data buffer pointer and the data length.

4. The process of sending commands and receiving status words

This process requires sending the command word first, then reading the status word, and detecting the specified bit of the status word. If the status bit of concern is not the desired value, repeat the process of reading the status word and detecting the status word until the status of concern is reached. bit reaches the desired value.

Code snippet 12. Send command and receive status word processing process

The processing flow of sending commands and receiving status words is the same as the previous processing flow of sending commands and receiving data strings. The processing of sending ready (TXRDY) interrupt is also divided into two stages. The first stage is the sending command buffer. The second stage is to send any character (here 0xFF), which is used to generate the clock signal for the slave output status word; when the received status word matches the required value, then another arbitrary character is sent, Make SSEL inactive (high).

In processing the receive ready (RXRDY) interrupt, the received data is directly read and saved as a status word, leaving it to be detected by line 11 and the predetermined matching value.

After "page programming" and several erase commands, you need to use the send command and receive status word processing flow, send "read status register 1" and then repeatedly detect the "busy" flag until the programming or erase command is completed, "busy" "flag becomes '0'.

Code snippet 13. Use send command and receive status word processing process to wait for the "busy" flag

The Wait_Status1() function has two parameters. mask is a mask word. The corresponding bit of the status word that needs to be detected is '1', and the corresponding bit that does not need to be detected is '0'; value is the expected value of the status word that needs to be detected. The read status word and the mask word are processed The result after the "AND" operation needs to be the same as value.

For example, the calling method to wait for the "busy" flag to change to '0' is:

5. Test the main function of SPI Flash

After introducing all the interrupt handling processes, the final main function is very simple:

Code snippet 14. Test SPI Flash main function

After running this program, the reader can check the front and rear halves of the Buffer. The data should be the same, indicating successful writing and reading.

1.4 The timing control of signals generated by the host first clarifies a concept - characters and data frames. Character refers to the data bits contained in the TXDAT, TXDATCTL or RXDAT register at one time when SPI transmits or receives. A data frame can directly correspond to a character, or it can be a combination of multiple consecutive characters. The SPI module of LPC800 can introduce frame delays between data frames, but cannot insert delays between characters unless the data frame and character length are the same.

Figure 8. Relationship between characters and data frames

The upper line in the above figure shows that when the length of a data frame is less than 16 bits, one character is a data frame. The lower line of the figure shows that when the length of a data frame is greater than 16 bits, a data frame contains several characters.

When sending the last character of each data frame, set the EOF bit of the sending control register (see Figure 7) to indicate the end of the frame. Using the EOF control bit, data frames of any length can be supported.

There is a delay register in the SPI module that can provide users with a variety of timing delay controls. The various control bits of the delay register are as shown below.

Figure 9. SPI delay register (DLY) control bits

1.4.1 Interval control between chip select signal and data frame signal

The PRE_DELAY and POST_DELAY fields each have 4 bits and can be configured to insert delays of 0 to 15 clock cycles respectively.

PRE_DELAY indicates the delay time that needs to be inserted between SSEL becoming valid and data transmission starting.

POST_DELAY indicates the delay time that needs to be inserted between the end of data transmission and SSEL becoming invalid.

The following two figures show the role of PRE_DELAY and POST_DELAY.

Figure 10. Diagram of the action positions of PRE_DELAY and POST_DELAY (CPHA=0)

Figure 11. Diagram of the action positions of PRE_DELAY and POST_DELAY (CPHA=1)

The figure shows that a delay of 2 clock cycles is inserted after SSEL goes low (PRE_DELAY=2); a delay of 1 clock cycle is inserted after the last bit (LSB) is sent (POST_DELAY=1).

1.4.2 Interval control between data frames

FRAME_DELAY has 4 bits. When the sent character control bit EOT=1, a delay of 0~15 clock cycles is inserted after the last bit of the character. This delay is beneficial for some devices to have enough time to receive the next frame after receiving a data frame.

The function of FRAME_DELAY is as shown below

Figure 12. Schematic diagram of the role of FRAME_DELAY

1.4.3 Interval control between two transmissions

TRANSFER _DELAY has 4 bits. When the sent character control bit EOF=1, after SSEL becomes invalid (high level), there needs to be a delay of at least 1 to 16 clock cycles before the next transmission can start, that is, SSEL must be at least It remains high for one clock cycle before changing to low again. This delay is beneficial for some devices to have enough time to enter the reception of the next transmission after receiving the last data frame of a transmission.

TRANSFER _DELAY only gives the lower limit of the length for which SSEL remains invalid (high level). This time may become longer due to software reasons. For example, the software needs time to prepare the next transmitted data.

The function of TRANSFER _DELAY is as shown below

Figure 13. Schematic diagram of the role of TRANSFER_DELAY

Review Editor: Tang Zihong


#article #explaining #SPI #serial #peripheral #interface #detail