1. Hardware Connection
W25Q64 divides the 8M capacity into 128 blocks, each block is 64K bytes, each block is divided into 16 sectors, each sector is 4K bytes. The minimum erase unit of W25Q64 is one sector, which means that 4K bytes must be erased each time. The operation requires a cache area of at least 4K for W25Q64, which has high requirements for SRAM. The chip must have more than 4K SRAM to operate well.
The W25Q64 has an erase and write cycle of up to 10W times, a data retention period of 20 years, and supports a voltage of 2.7~3.6V. The W25Q64 supports standard SPI and dual-output/quad-output SPI. The maximum SPI clock can reach 80Mhz (equivalent to 160Mhz for dual output and 320Mhz for quad output).
1.1 Hardware Connection
The pin connections with STM32 are as follows: SPI1 configuration is used here.
STM32 pins corresponding to SPI functions
PA2 Chip Select CS
PA5 clock SCK
PA6 MISO
PA7 MOSI
The SPI function of STM32 is very powerful. The SPI clock can reach up to 18Mhz, supports DMA, and can be configured as SPI protocol or I2S protocol (only supported by large-capacity models).
1.2 SPI communication timing
The SPI protocol defines the communication start and stop signals, data validity, clock synchronization and other aspects.
This is a communication sequence of a host. NSS, SCK, and MOSI signals are all generated by the host, while the MISO signal is generated by the slave. The host reads the data of the slave through this signal line. The MOSI and MISO signals are only valid when NSS is low. MOSI and MISO transmit one bit of data in each clock cycle of SCK.
1. Communication start and stop signals
At the number 1 in the figure, the NSS signal line changes from high to low, which is the start signal of SPI communication. NSS is a signal line that each slave has its own. When the slave detects the start signal on its own NSS line, it knows that it has been selected by the host and begins to prepare to communicate with the host. At the number 6 in the figure, the NSS signal changes from low to high, which is the stop signal of SPI communication, indicating that this communication is over and the selected state of the slave is cancelled.
2. Data Validity
SPI uses MOSI and MISO signal lines to transmit data, and uses SCK signal line for data synchronization. MOSI and MISO data lines transmit one bit of data in each clock cycle of SCK, and data input and output are performed simultaneously. There is no hard and fast rule for MSB first or LSB first when transmitting data, but to ensure that the same protocol is used between two SPI communication devices, the MSB first mode shown in the figure is generally adopted.
Observe the 2345 mark in the figure. The data of MOSI and MISO changes and outputs during the rising edge of SCK, and is sampled at the falling edge of SCK. That is, at the falling edge of SCK, the data of MOSI and MISO is valid, and the high level indicates data "1", and the low level indicates data "0". At other times, the data is invalid, and MOSI and MISO prepare for the next data representation. Each SPI data transmission can be 8 bits or 16 bits per unit, and the number of units transmitted each time is not limited.
1.3 STM32 SPI peripherals
The SPI peripheral of STM32 can be used as the master and slave of communication, and supports the highest SCK clock frequency of fpclk/2 (the default fpclk1 of STM32F103 chip is 72MHz, and fpclk2 is 36MHz), fully supports the 4 modes of SPI protocol, the data frame length can be set to 8 bits or 16 bits, and the data can be set to MSB first or LSB first. It also supports two-line full-duplex (this mode is described in the previous section), two-line unidirectional and single-line mode.
SPI architecture:
Communication pins:
All the hardware architecture of SPI is developed from the MOSI, MISO, SCK and NSS lines on the left side of the figure. The STM32 chip has multiple SPI peripherals, and their SPI communication signals are led out to different GPIO pins. When used, they must be configured to these designated pins.
2. Software Configuration
Here we use the master mode of STM32's SPI1. The SPI-related library functions and definitions are distributed in the file stm32f10x_spi.c and the header file stm32f10x_spi.h.
2.1 Configure the multiplexing function of related pins and enable SPI1 clock
The first step is to enable the clock of SPI1, which is set by the 12th bit of APB2ENR. Secondly, the relevant pins of SPI1 should be set as multiplexed outputs, so that they can be connected to SPI1. Otherwise, these IO ports are still in the default state, that is, standard input and output ports. Here we use PA5, 6, and 7 (SCK, MISO, MOSI, CS uses software management), so these three are set as multiplexed IO.
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2P%riphGPHOA|RCC_APB2Periph_SPI1%r52C%521ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplex push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
2.2 Initialize SPI1 and set SPI1 working mode
Next, initialize SPI1, set SPI1 to host mode, set the data format to 8 bits, and then set the SCK clock polarity and sampling mode. Set the SPI1 clock frequency (maximum 18Mhz) and the data format (MSB first or LSB first). This is achieved in the library function through the SPI_Init function.
Function prototype:
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
The first parameter is the SPI number, and the second parameter structure type SPI_InitTypeDef is used to set the related properties.
The definition of SPI_InitTypeDef is as follows:
typedef struct
{
uint16_t SPI_Direction;
uint16_t SPI_Mode;
uint16_t SPI_DataSize;
uint16_t SPI_CPOL;
uint16_t SPI_CPHA;
uint16_t SPI_NSS;
uint16_t SPI_BaudRatePrescaler;
uint16_t SPI_FirstBit;
uint16_t SPI_CRCPolynomial;
}SPI_InitTypeDef;
Parameter Explanation
SPI_Direction sets the SPI communication mode, which can be selected as half-duplex, full-duplex, and serial transmission and serial reception.
SPI_Mode sets the master and slave modes of SPI, master mode (SPI_Mode_Master), slave mode (SPI_Mode_Slave).
SPI_DataSiz Data is 8-bit or 16-bit frame format selection item. SPI_DataSize_8b (8 bits), SPI_DataSize_16b (16 bits)
SPI_CPOL sets the clock polarity
SPI_CPHA sets the clock phase, that is, selects the first or second edge of the serial synchronous clock at which the data is sampled.
SPI_NSS Sets whether the NSS signal is controlled by hardware (NSS pin) or software
SPI_BaudRatePrescaler sets the SPI baud rate prescaler value, which is the parameter that determines the SPI clock. There are 8 optional values from no channel division to 256 division. Select the 256 division value SPI_BaudRatePrescaler_256, and the transmission speed is 36M/256=140.625KHz.
SPI_FirstBit sets the data transmission order to be MSB first or LSB first. SPI_FirstBit_MSB (high bit first)
SPI_CRCPolynomial sets the CRC check polynomial to improve communication reliability. It can be greater than 1.
The sample format of initialization is:
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Set SPI unidirectional or bidirectional data mode: SPI is set to two-line bidirectional full-duplex
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Set SPI working mode: set to master SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //Set the SPI data size: SPI sends and receives 8-bit frame structure
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //Select the steady state of the serial clock: the clock is floating high
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //Data capture (sampling) at the second clock edge
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS signal is managed by hardware (NSS pin) or software (using SSI bit): internal NSS signal is controlled by SSI bit
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //Define the baud rate prescaler value: the baud rate prescaler value is 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //Specify whether data transmission starts from the MSB bit or the LSB bit: Data transmission starts from the MSB bit
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC value calculation polynomial
SPI_Init(SPI1, &SPI_InitStructure); //Initialize the peripheral SPIx registers according to the parameters specified in SPI_InitStruct
2.3 Enable SPI1
After initialization is completed, enable SPI1 communication. After enabling SPI1, you can start SPI communication. The method to enable SPI1 is:
SPI_Cmd(SPI1, ENABLE); //Enable SPI peripheral
2.4 SPI Data Transmission
The communication interface needs to have functions for sending and receiving data. The prototype of the sending data function provided by the firmware library is:
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
Write data to the SPIx data register to achieve transmission.
The prototype of the data receiving function provided by the firmware library is:
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;
This reads the received data from the SPIx data register.
2.5 Check SPI transmission status
During SPI transmission, it is necessary to determine whether the data transmission is completed, whether the sending area is empty, etc. This is achieved through the function SPI_I2S_GetFlagStatus. The method to determine whether the transmission is completed is:
SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);
3. Software Design
3.1 SPI Implementation
SPI_InitTypeDef SPI_InitStructure;
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplex push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Set SPI unidirectional or bidirectional data mode: SPI is set to two-line bidirectional full-duplex
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Set SPI working mode: set to master SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //Set the SPI data size: SPI sends and receives 8-bit frame structure
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //Select the steady state of the serial clock: the clock is floating high
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //Data capture (sampling) at the second clock edge
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS signal is managed by hardware (NSS pin) or software (using SSI bit): internal NSS signal is controlled by SSI bit
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //Define the baud rate prescaler value: the baud rate prescaler value is 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //Specify whether data transmission starts from the MSB bit or the LSB bit: Data transmission starts from the MSB bit
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC value calculation polynomial
SPI_Init(SPI1, &SPI_InitStructure); //Initialize the peripheral SPIx registers according to the parameters specified in SPI_InitStruct
SPI_Cmd(SPI1, ENABLE); //Enable SPI peripheral
SPI1_ReadWriteByte(0xff); //Start transmission
}
/************************************************/
//SPI speed setting function
//SpeedSet:
//SPI_BaudRatePrescaler_2 2分频 (SPI 36M@sys 72M)
//SPI_BaudRatePrescaler_8 8分频 (SPI 9M@sys 72M)
//SPI_BaudRatePrescaler_16 16分频 (SPI 4.5M@sys 72M)
//SPI_BaudRatePrescaler_256 256分频 (SPI 281.25K@sys 72M)
void SPI1_SetSpeed(u8 SpeedSet)
{
SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1,ENABLE);
}
/************************************************/
//SPIx read and write a byte
//TxData: Bytes to be written
//Return value: the bytes read
u8 SPI1_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) // Check if the specified SPI flag is set: send buffer empty flag
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI1, TxData); //Send a data through peripheral SPIx
retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) // Check whether the specified SPI flag is set: receive buffer not empty flag
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI1); //Return the data most recently received via SPIx
}
3.2 Flash Read and Write
u16 SPI_FLASH_TYPE=W25Q64; //The default is 25Q64
//4Kbytes is a Sector
//16 sectors make up 1 Block
//W25X16
//The capacity is 2M bytes, with a total of 32 blocks and 512 sectors
//Initialize the SPI FLASH IO port
void SPI_Flash_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //SPI CS
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //Multiplexed push-pull output
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);
SPI1_Init(); //Initialize SPI
SPI1_SetSpeed(SPI_BaudRatePrescaler_4); //Set to 18M clock, high speed mode
SPI_FLASH_TYPE=SPI_Flash_ReadID();//读取FLASH ID.
}
/************************************************/
//Read the status register of SPI_FLASH
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR: default 0, status register protection bit, used with WP
//TB,BP2,BP1,BP0: FLASH area write protection setting
//WEL: Write Enable Lock
//BUSY: busy flag (1, busy; 0, idle)
//Default: 0x00
u8 SPI_Flash_ReadSR(void)
{
u8 byte=0;
SPI_FLASH_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_ReadStatusReg); //Send the read status register command
byte=SPI1_ReadWriteByte(0Xff); //Read a byte
SPI_FLASH_CS=1; //Cancel chip select
return byte;
}
/************************************************/
//Write SPI_FLASH status register
//Only SPR, TB, BP2, BP1, BP0 (bit 7, 5, 4, 3, 2) can be written!!!
void SPI_FLASH_Write_SR(u8 sr)
{
SPI_FLASH_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteStatusReg); //Send the command to write the status register
SPI1_ReadWriteByte(sr); //Write a byte
SPI_FLASH_CS=1; //Cancel chip select
}
/************************************************/
//SPI_FLASH write enable
//Set WEL
void SPI_FLASH_Write_Enable(void)
{
SPI_FLASH_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteEnable); //Send write enable
SPI_FLASH_CS=1; //Cancel chip select
}
/************************************************/
//SPI_FLASH write disabled
// Clear WEL
void SPI_FLASH_Write_Disable(void)
{
SPI_FLASH_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteDisable); //Send write disable command
SPI_FLASH_CS=1; //Cancel chip select
}
/************************************************/
//Read chip ID W25X16 ID: 0XEF14
u16 SPI_Flash_ReadID(void)
{
u16 Temp = 0;
SPI_FLASH_CS=0;
SPI1_ReadWriteByte(0x90); //Send read ID command
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
Temp|=SPI1_ReadWriteByte(0xFF)<<8;
Temp|=SPI1_ReadWriteByte(0xFF);
SPI_FLASH_CS=1;
return Temp;
}
/************************************************/
//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 and;
SPI_FLASH_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_ReadData); //Send read command
SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //Send 24-bit address
SPI1_ReadWriteByte((u8)((ReadAddr)>>8));
SPI1_ReadWriteByte((u8)ReadAddr);
for(i=0;i { pBuffer[i]=SPI1_ReadWriteByte(0XFF); //Loop reading } SPI_FLASH_CS=1; //Cancel chip select } /************************************************/ //SPI writes less than 256 bytes of data in one page (0~65535) //Start writing data up to 256 bytes at the specified address //pBuffer: data storage area //WriteAddr: start writing address (24bit) //NumByteToWrite: The number of bytes to be written (maximum 256), this number should not exceed the remaining bytes of the page!!! void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16 and; SPI_FLASH_Write_Enable(); //SET WEL SPI_FLASH_CS=0; //Enable device SPI1_ReadWriteByte(W25X_PageProgram); //Send write page command SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //Send 24-bit address SPI1_ReadWriteByte((u8)((WriteAddr)>>8)); SPI1_ReadWriteByte((u8)WriteAddr); for(i=0;i { SPI1_ReadWriteByte(pBuffer[i]);//Loop write data } SPI_FLASH_CS=1; //Cancel chip select SPI_Flash_Wait_Busy(); //Wait for writing to end } /************************************************/ //Write SPI FLASH without checking // Make sure that all data in the address range you write is 0XFF, otherwise data written at non-0XFF will fail! //With automatic page change function //Start writing data of the specified length at the specified address, but make sure the address does not cross the boundary! //pBuffer: data storage area //WriteAddr: start writing address (24bit) //NumByteToWrite: the number of bytes to be written (maximum 65535) //CHECK OK void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16 pageremain; pageremain=256-WriteAddr%256; //Number of bytes remaining in a single page if(NumByteToWrite<=pageremain) pageremain=NumByteToWrite; //No more than 256 bytes while(1) { SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain); if(NumByteToWrite==pageremain) break; // Writing is finished else //NumByteToWrite>pageremain { pBuffer+=pageremain; WriteAddr+=pageremain; NumByteToWrite-=pageremain; //Subtract the number of bytes already written if(NumByteToWrite>256) pageremain=256; //256 bytes can be written at a time else pageremain=NumByteToWrite; //Not enough 256 bytes } }; } /************************************************/ //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]; //Size of a sector void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u32 secpos; u16 secoff; u16 secremain; u16 and; 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 what has been erased, 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 } }; } /************************************************/ // Erase the entire chip //Whole chip erase time: //W25X16:25s //W25X32:40s //W25X64:40s //Waiting time is too long... void SPI_Flash_Erase_Chip(void) { SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //Enable device SPI1_ReadWriteByte(W25X_ChipErase); //Send chip erase command SPI_FLASH_CS=1; //Cancel chip select SPI_Flash_Wait_Busy(); //Wait for chip erasure to end } /************************************************/ // Erase a sector //Dst_Addr: sector address 0~511 for w25x16 //Minimum time to erase a mountain area: 150ms void SPI_Flash_Erase_Sector(u32 Dst_Addr) { Dst_Addr*=4096; SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //Enable device SPI1_ReadWriteByte(W25X_SectorErase); //Send sector erase command SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //Send 24-bit address SPI1_ReadWriteByte((u8)((Dst_Addr)>>8)); SPI1_ReadWriteByte((u8)Dst_Addr); SPI_FLASH_CS=1; //Cancel chip select SPI_Flash_Wait_Busy(); //Wait for erasing to complete } /************************************************/ //Wait for free time void SPI_Flash_Wait_Busy(void) { while ((SPI_Flash_ReadSR()&0x01)==0x01); // Wait for BUSY bit to clear } /************************************************/ //Enter power-down mode void SPI_Flash_PowerDown(void) { SPI_FLASH_CS=0; //Enable device SPI1_ReadWriteByte(W25X_PowerDown); //Send power-down command SPI_FLASH_CS=1; //Cancel chip select delay_us(3); //Wait for TPD } /************************************************/ //wake void SPI_Flash_WAKEUP(void) { SPI_FLASH_CS=0; //Enable device SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB SPI_FLASH_CS=1; //Cancel chip select delay_us(3); //Wait for TRES1 } reference: 1. Atomic library function manual 2.SPI—Read and write serial FLASH --------------------- Author:wwt18811707971 Source: CSDN Original text: https://blog.csdn.net/wwt18811707971/article/details/77756312 Copyright Statement: This article is an original article by the blogger. Please attach the blog link when reprinting!
Previous article:STM32 learning notes one by one input capture
Next article:IIC Topic 2 - STM32 driving AT24C02
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- How haptic technology can enhance driving safety
- Let’s talk about the “Three Musketeers” of radar in autonomous driving
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Three steps to govern hybrid multicloud environments
- Three steps to govern hybrid multicloud environments
- 【Qinheng Trial】Four overall system designs (1/2)——Function integration of ch549 modules
- Share: Solution to BQ40Z80's constant hiccups
- Altium Designer v21.2.0.30
- Pre-registration for the celebrity live show | Arrow-ADI multi-parameter optical water quality analysis platform
- LM2575, DC24V to DC12V, there is a howling sound during debugging?
- Raspberry Pi high-resolution square display PIMORONI HYPERPIXEL 4.0 SQUARES
- Easy-to-use nine-channel RGB LED driver
- [Application development based on NUCLEO-F746ZG motor] 10. Parameter configuration - GPIO port configuration
- Magnetic Hall Sensor Omnipolar MH251
- Flexible vibration plate machine operation demonstration diagram