STM32 SPI interface read and write SPI flash experiment

Publisher:王大雷Latest update time:2018-09-19 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

STM32 SPI flash read and write test experiment report

1. Experimental Purpose

1. Learn the basic working principle of SPI

2. Deepen your understanding of STM32SPI through experiments

3. Use STM32's SPI11 and SPI interface flash chip to communicate, read and write tests, and print the test results through the serial port

2. Experimental Principle

1. SPI Basics

SPI Features

● 3-wire full-duplex synchronous transmission

● Two-wire simplex synchronous transmission with or without a third bidirectional data line

● 8 or 16 bit transmission frame format selection

● Master or slave operation

● Support multi-master mode

● 8 master mode baud rate pre-scaling factors (maximum fPCLK/2)

● Slave mode frequency (maximum fPCLK/2)

● Fast communication between master mode and slave mode

● NSS management can be performed by software or hardware in both master and slave modes: Dynamic change of master/slave operation mode

● Programmable clock polarity and phase

● Programmable data order, MSB first or LSB first

● Dedicated transmit and receive flags that can trigger interrupts

● SPI bus busy status flag

● Hardware CRC to support reliable communication

─ In transmit mode, the CRC value can be sent as the last byte

─ Automatic CRC check on the last byte received in full-duplex mode

● Master mode fault, overload and CRC error flags that can trigger interrupts

● 1-byte transmit and receive buffer supporting DMA function: generates transmit and receive requests

 

Slave Select (NSS) Foot Management

There are 2 NSS modes:

Figure 211 ● Software NSS mode: This mode can be enabled by setting the SSM bit in the SPI_CR1 register (see ).

In this mode, the NSS pin can be used for other purposes, and the internal NSS signal level can be driven by writing the SSI bit of SPI_CR1.

● Hardware NSS mode, divided into two situations:

─NSS output is enabled: When the STM32F10xxx works as the master SPI, and the NSS output has been registered via SPI_CR2

The SSOE bit of the SPI master is enabled, and the NSS pin is pulled low. All NSS pins are connected to the NSS pin of the master SPI.

SPI devices configured as hardware NSS will automatically become slave SPI devices.

When an SPI device needs to send broadcast data, it must pull down the NSS signal to notify all other devices that it is the master.

device; if it cannot pull NSS low, it means that there is another master device communicating on the bus, and a

Hardware failure error (Hard Fault).

─NSS output is disabled: allows operation in a multi-master environment.

 

 

The phase and polarity of the clock signal can be combined into four different modes. The following are two of them.

Data frame format

The data bits can be output MSB first or LSB first, depending on the LSBFIRST bit in the SPI_CR1 register.

Each data frame can be 8 or 16 bits depending on the DFF bit in the SPI_CR1 register. The selected data frame format is valid for both transmission and/or reception.

 

Configure SPI to master mode

In master configuration, a serial clock is generated on the SCK pin.

Configuration steps

1. Define the serial clock baud rate by the BR[2:0] bits in the SPI_CR1 register.

2. Select the CPOL and CPHA bits to define the phase relationship between the data transmission and the serial clock (see Figure 212).

3. Set the DFF bit to define 8-bit or 16-bit data frame format.

4. Configure the LSBFIRST bit of the SPI_CR1 register to define the frame format.

5. If the NSS pin is required to work in input mode, in hardware mode, the NSS pin should be connected to

to high level; in software mode, the SSM bit and SSI bit of the SPI_CR1 register need to be set.

In output mode, just set the SSOE bit.

6. The MSTR bit and the SPE bit must be set (these bits will only remain set if the NSS pin is tied high).

In this configuration, the MOSI pin is the data output and the MISO pin is the data input.

 

 

The SPI module can operate in simplex mode in two configurations:

● 1 clock line and 1 bidirectional data line;

● 1 clock line and 1 data line (receive only or send only);

 

SPI communication can use CRC by following the steps below:

● Set the values ​​of CPOL, CPHA, LSBFirst, BR, SSM, SSI, and MSTR;

● Enter the polynomial in the SPI_CRCPR register;

● Enable CRC calculation by setting the CRCEN bit in the SPI_CR1 register. This operation will also clear the SPI_RXCRCR register.

and SPI_TXCRC;

● Set the SPE bit of the SPI_CR1 register to start the SPI function;

● Start communication and maintain communication until only the last byte or half word remains;

● When writing the last byte or half word into the transmit buffer, set the CRCNext bit of SPI_CR1 to instruct the hardware to

After sending the last data, send the CRC value. Stop CRC calculation during sending the CRC value.

● After the last byte or half word is sent, the SPI sends the CRC value and the CRCNext bit is cleared.

The CRC of the SPI_RX is compared with the SPI_RXCRCR value and if the comparison does not match, the CRCERR flag on the SPI_SR is set

When the ERRIE bit of the SPI_CR2 register is set, an interrupt is generated.

Personal understanding: CRC check, the sender calculates the CRC value, the receiver calculates the CRC value, and then the sender sends the calculated CRC value. After receiving it, the receiver compares it with the value calculated by the receiver. If they are different, an error flag is returned

 

 

SPI communication using DMA

In order to achieve the maximum communication speed, the SPI transmit buffer needs to be filled with data in a timely manner, and the data in the receive buffer must also be filled in a timely manner.

To facilitate high-speed data transfer, SPI implements a DMA that uses a simple request/response

mechanism.

When the corresponding enable bit in the SPI_CR2 register is set, the SPI module can issue a DMA transfer request.

The receive buffers also have their own DMA requests (see ).

● When sending, a DMA request is issued every time TXE is set to '1', and the DMA controller writes data to the SPI_DR register.

The TXE flag is cleared.

● When receiving, a DMA request is issued each time RXNE is set to '1', and the DMA controller reads the data from the SPI_DR register.

According to the RXNE flag, it is cleared.

When only using SPI to send data, you only need to enable the SPI's transmit DMA channel. At this time, because there is no received data to read,

OVR is set to '1' (Translator's note: software does not need to pay attention to this flag).

When only using SPI to receive data, you only need to enable the SPI receive DMA channel.

 

SPI Registers

SPI Control Register 1 SPI_CR1

(For the function of each bit, refer to page 486 of the data sheet)

 

SPI Control Register 2 (SPI_CR2)

SPI Status Register (SPI_SR)

SPI Data Register (SPI_DR)

SPI CRC Polynomial Register

SPI Rx CRC Register (SPI_RXCRCR)

When CRC calculation is enabled, RXCRC[15:0] contains the CRC value calculated based on the received bytes.

This register is reset when the CRCEN bit is written to '1'. The CRC calculation uses the polynomial in SPI_CRCPR.

When the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method; when the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method;

When it is 16 bits, all 16 bits in the register are involved in the calculation and follow the CRC16 standard.

 

SPI Tx CRC Register (SPI_TXCRCR)

When CRC calculation is enabled, TXCRC[15:0] contains the CRC value calculated based on the bytes to be transmitted.

This register is reset when the CRCEN bit in SPI_CR1 is written as '1'. The CRC calculation uses multiple bits in SPI_CRCPR.

Mode.

When the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method; when the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method;

When the bit is 16, all 16 bits in the register are involved in the calculation and follow the CRC16 standard.

 

2. Experimental circuit diagram

W25X16 has 8192 programmable pages, each with 256 bytes. You can program 256 bytes at a time using the "page programming instruction". You can erase 16 pages at a time using the "sector instruction", 256 pages at a time using the "block erase instruction", and the entire chip can be erased using the "whole chip erase instruction". W25X16 has 512 erasable sectors or 32 erasable blocks.

W25X16 supports standard SPI interface with a maximum transmission rate of 75MHz.

 

Dual output SPI mode

W25X16 supports SPI dual output mode, which requires the use of "fast read dual output command 0x3B". At this time, the transmission rate is equivalent to twice the standard SPI rate. This command is very suitable for situations where you need to quickly download code to memory as soon as power is turned on or when you need to cache code segments to memory for operation. After using the "fast dual output command", the DIO pin becomes an output pin.

Instructions: Write Enable, Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register

 

3. Experimental Content

software design

Configure the STM32 SPI as master mode to read the SPI flash to implement read and write functions.

The SPI1 part is configured below.

In master mode, the SCK pin outputs the serial clock.

 

Configuration steps:

1) Configure the SPI serial clock bit rate

2) Define the phase relationship between data transmission and serial

3) Set 8-bit or 16-bit data frame format

4) If the NSS pin is required to work in input mode, in hardware mode, the NSS pin should be connected to a high level during the entire data frame transmission. In software mode, the SSM bit and SSI bit of SPI1_CR1 need to be set. If the NSS pin works in output mode, the SSOE bit needs to be set.

5) The MSTR and SPE bits must be set (these bits will only remain set if the NSS pin is tied high)

//Initialization of the serial peripheral interface SPI, SPI is configured into master mode                                                          

//This example uses SPI1 to read and write W25X16, and initializes SPI1

void SPIx_Init(void)

{

        SPI_InitTypeDef SPI_InitStructure;

        GPIO_InitTypeDef GPIO_InitStructure;

        

        /* Enable SPI1 and GPIOA clocks */

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOC|RCC_APB2Periph_SPI1|RCC_APB2Periph_AFIO, ENABLE);

        

        /* Configure SPI1 pins: NSS, SCK, MISO and MOSI */

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

        GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        //SPI1 NSS

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

 

        GPIO_SetBits(GPIOC, GPIO_Pin_4);

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_SetBits(GPIOA, GPIO_Pin_4);   

 

        /* SPI1 configuration */

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1 is set to two-line full-duplex

        SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Set SPI1 to master mode

        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI sends and receives 8-bit frame structure

        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //When the serial clock is not in operation, the clock is high

        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //Start sampling data at the second clock edge

        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS signal is managed by software (using SSI bit)

        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //Define the baud rate prescaler value: the baud rate prescaler value is 8

        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //Data transmission starts from the MSB bit

        SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC value calculation polynomial

        SPI_Init(SPI1, &SPI_InitStructure);

        /* Enable SPI1 */

        SPI_Cmd(SPI1, ENABLE); //Enable SPI1 peripheral

}   

 

 

 

SPI interface reads and writes Flash one byte

//SPIx read and write a byte

//Return value: the bytes read

u8 SPIx_ReadWriteByte(u8 TxData)

{                

        u8 retry=0;                                

        while((SPI1->SR&1<<1)==0)//Wait for the send area to be empty        

        {

                retry++;

                if(retry>200)return 0;

        }                          

        SPI1->DR=TxData; //Send a byte

        retry=0;

        while((SPI1->SR&1<<0)==0) //Wait for receiving a byte  

        {

                retry++;

                if(retry>200)return 0;

        }                                                             

        return SPI1->DR; //Return received data                                   

}

 

 

Get SPI flash ID

//Read chip ID W25X16 ID: 0XEF14

u16 SPI_Flash_ReadID(void)

{

        u16 Temp = 0;          

        SPI_FLASH_CS=0;                                   

        SPIx_ReadWriteByte(0x90); //Send read ID command           

        SPIx_ReadWriteByte(0x00);            

        SPIx_ReadWriteByte(0x00);            

        SPIx_ReadWriteByte(0x00);                                     

        Temp|=SPIx_ReadWriteByte(0xFF)<<8;  

        Temp|=SPIx_ReadWriteByte(0xFF);        

        SPI_FLASH_CS=1;                                   

        return Temp;

}  

 

 

Start reading data of the specified length at the specified position

//Read SPI FLASH  

//Start reading data of the specified length at the specified address

//pBuffer: data storage area

//ReadAddr: start reading address (24bit)

//NumByteToRead: the number of bytes to read (maximum 65535)

void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   

{

        u16 i;                                                                                                       

        SPI_FLASH_CS=0; //Enable device   

    SPIx_ReadWriteByte(W25X_ReadData); //Send read command   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>16)); //Send 24-bit address   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>8));   

    SPIx_ReadWriteByte((u8)ReadAddr);   

    for(i=0;i

        {

        pBuffer[i]=SPIx_ReadWriteByte(0XFF); //Loop reading  

    }

        SPI_FLASH_CS=1; //Cancel chip select                   

}  

 

 

Write data of specified length at specified location

 

//Write SPI FLASH  

//Start writing data of the specified length at the specified address

//This function has erase operation!

//pBuffer: data storage area

//WriteAddr: start writing address (24bit)

//NumByteToWrite: the number of bytes to be written (maximum 65535)                     

u8 SPI_FLASH_BUF[4096];

void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   

{

        u32 secpos;

        u16 secoff;

        u16 secremain;           

        u16 i;  

        secpos=WriteAddr/4096; //sector address 0~511 for w25x16

        secoff=WriteAddr%4096; //Offset within the sector

        secremain=4096-secoff; //Sector remaining space size   

        if(NumByteToWrite<=secremain)secremain=NumByteToWrite; //No more than 4096 bytes

        while(1)

        {        

                SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//Read the contents of the entire sector

                for(i=0;i

                {

                        if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//need to erase            

                }

                if(i

                {

                        SPI_Flash_Erase_Sector(secpos); //Erase this sector

                        for(i=0;i

                        {

                                SPI_FLASH_BUF[i+secoff]=pBuffer[i];          

                        }

                        SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//Write the entire sector  

 

                }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//Write the erased content and directly write to the remaining area of ​​the sector.                                    

                if(NumByteToWrite==secremain)break;//Writing is finished

                else //Writing is not finished

                {

                        secpos++; //sector address increment by 1

                        secoff=0; //Offset position is 0         

 

                           pBuffer+=secremain; //Pointer offset

                        WriteAddr+=secremain; //write address offset           

                           NumByteToWrite-=secremain; //Number of bytes decreases

                        if(NumByteToWrite>4096)secremain=4096; //The next sector still cannot be written

                        else secremain=NumByteToWrite; //The next sector can be written

                }        

        };                 

}

 

 

 

In the main function, first write the data of the specified length into the Flash, then read and print it to the serial port, compare the read and written data, and display the result to the serial port.

int main(void)

{

        u8 i=0;

        u8 datatemp[SIZE];

        

        GPIO_Configuration();

        USART_Configuration();

        GPIO_SetBits(GPIOF, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);

        

        

        

        SPI_Flash_Init();   

        

        while(SPI_Flash_ReadID()!=FLASH_ID) //Cannot detect W25X16

        {           

                i=SPI_Flash_ReadID();

                printf("\n\r ID:%d",i);

                printf("\n\rThe correct W25X16 chip ID was not read, please check the hardware connection");

                Delay(0xaFFFF);

                Delay(0xaFFFF);

                GPIO_ResetBits(GPIOF, GPIO_Pin_7);

                GPIO_SetBits(GPIOF, GPIO_Pin_7);

        

        }

        

        printf("\n\rStart writing to W25X16 SPI FLASH chip....");

        SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE);//Starting from 1000 bytes, write data of SIZE length

        printf("\n\rWrite completed!"); //Prompt that the transfer is completed

        printf("\n\r");

        Delay(0xFFFFFF);

        printf("\n\r");

        

        printf("\n\rStart reading data from W25X16 SPI FLASH chip.... ");

        SPI_Flash_Read(datatemp,1000,10000); //Start from address 1000 and read SIZE bytes

        printf("\n\rReading completed, the data read is: %s ",datatemp); //Prompt that the transmission is completed

        

        while(1)

        {

                

                i++;

                Delay(0xFFFF);

                if(i>0&& i<100)

                {

                        GPIO_SetBits(GPIOF, GPIO_Pin_6); //Prompt that the system is running        

                }

                else if(i >= 100 && i < 200)

                {

                        GPIO_ResetBits(GPIOF, GPIO_Pin_6); //Prompt that the system is running        

                }        

                i = i % 200;           

                }

        

        }


Keywords:STM32 Reference address:STM32 SPI interface read and write SPI flash experiment

Previous article:STM32CubeMX learning tutorial 1: GPIO output marquee
Next article:STM32CubeMX tutorial introduction and basic use

Recommended ReadingLatest update time:2024-11-16 15:04

[STM32] Incompatibility and solutions when opening MDK4 project with MDK5
Problem Description I recently found a problem when using MDK5. Let's take a look at the existing MDK version information: When opening an MDK4 version project with MDK5, a window "Using an MDK Version 4 Project" will usually pop up: This is an MDK version 4 project ,require Device support for Cortex-M based de
[Microcontroller]
[STM32] Incompatibility and solutions when opening MDK4 project with MDK5
Verify that STM32 is little-endian storage
I recently wrote an STM32 program and used a union, which caused a question.  For example, 0x12345678 is stored in a U32 type variable. The big endian and little endian are stored like this.  Big-endian storage:        Low address ... High address        0x   12      34      56      78 Little endian storage:        Lo
[Microcontroller]
Issues that need to be paid attention to when jumping STM32 programs
Note: The .axf or .elf files generated by keil are executable image files. IAP - User Program issues that need attention To set the interrupt vector properly, assuming that the starting address of the User Program is (0x08008000), then the interrupt vector must be set at 0x08008000. The interrupt vector must be set to
[Microcontroller]
Detailed explanation of FSMC usage of STM32
LCD has the following control lines: CS: Chip Select, low level valid RS: Register Select WR: Write write signal, low level valid RD: Read read signal, low level valid RESET: Reset signal, low level valid DB0-DB15: Data line Suppose all these lines are controlled by ordinary IO ports. According to the LCD control chip
[Microcontroller]
Understanding of R15 register in stm32
This morning I read the "stm32 Authoritative Guide" and didn't understand some of the content about the R15 register. I checked the information and found out that this is the case.   Here is someone else's question.     I copied a function code data in Nor Flash (the function's first address is: 0x6400EC10)
[Microcontroller]
Understanding of R15 register in stm32
STM32 Getting Started Learning Experience Summary
    1. Why spend time on "hesitation"?     Experience summary: Whenever we get started (ARM is like this, DSP is the same), there will always be many questions and concerns. We are eager to know what the prospects of learning STM32 are? What foundation is needed? Is it difficult? Is it suitable for me? But when can
[Microcontroller]
STM32 uses analog IIC to operate EEPROM
Post the code of stm32f103vet6 using simulated IIC to operate EEPROM:   Header file part i2c.h #ifndef _i2c_H_ #define _i2c_H_ #include "stm32f10x.h" #define countof(a) (sizeof(a)/sizeof(*(a))) #define GPIOA_IDR_Addr (GPIOA_BASE + 8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE + 8) // /*Bit-b
[Microcontroller]
Temperature monitoring system based on STM32 and CAN bus
Abstract: This paper introduces the hardware design and software design of the temperature monitoring system based on STM32 and CAN bus. Through the communication between the upper computer and the lower computer, the temperature data can be monitored. Keywords: STM32; CAN bus; Delphi; PT100; SD card; FATFS file
[Industrial Control]
Temperature monitoring system based on STM32 and CAN bus
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号