STM32 使用DMA读写FLASH数据需要注意以下几点:
1.SPI全双工模式下,无论读写FLASH数据均需要同时使能RX/TX DMA。
2.写数据时回读数据应当丢弃,读数据时应当发送0xff来启动SPI读周期。
3.使用DMA时应当使能DMA Stream,然后再使能SPI DMA请求。
以下为测试代码,为省事,没启动串口提供打印信息,可在读出FLASH数据后通过断点查看数据。
#include <stdbool.h>
#include <stm32f4xx_dma.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_spi.h>
#define FLASH_PAGE_SIZE 256
static volatile int g_rx_flag = 0;
static volatile int g_tx_flag = 0;
static void spi_wait_rx(void)
{
while(!g_rx_flag);
g_rx_flag = 0;
}
static void spi_post_rx(void)
{
g_rx_flag = 1;
}
static void spi_wait_tx(void)
{
while(!g_tx_flag);
g_tx_flag = 0;
}
static void spi_post_tx(void)
{
g_tx_flag = 1;
}
static void spi_do_delay(uint16_t n)
{
uint16_t t = n;
while (-- t);
}
uint8_t spi_byte_transfer(uint8_t Dat)
{
while ((SPI3->SR & SPI_I2S_FLAG_TXE) == 0);
SPI3->DR = Dat;
while ((SPI3->SR & SPI_I2S_FLAG_RXNE) == 0);
return ((uint8_t)(SPI3->DR));
}
uint8_t spi_readbyte(void)
{
return spi_byte_transfer(0xA5);
}
/* 使用 GPIO6 作为 CS 信号
*/
static void spi_chip_select(bool select)
{
spi_do_delay(5);
if (select == true)
{
GPIOB->BSRRH = GPIO_Pin_6;
}
else
{
GPIOB->BSRRL = GPIO_Pin_6;
}
spi_do_delay(5);
}
void flash_wait_write(void)
{
uint8_t status = 0;
spi_chip_select(true);
spi_byte_transfer(0x05);
do
{
status = spi_byte_transfer(0xA5);
} while (status & 0x01);
spi_chip_select(false);
}
void flash_enable_write(void)
{
spi_chip_select(true);
spi_byte_transfer(0x06);
spi_chip_select(false);
}
void flash_write_status(uint8_t value)
{
flash_enable_write();
spi_chip_select(true);
spi_byte_transfer(0x01);
spi_byte_transfer(value);
spi_chip_select(false);
flash_wait_write();
}
void flash_disable_write(void)
{
flash_write_status(0);
}
uint32_t flash_read_identify(void)
{
uint8_t byte0 = 0, byte1 = 0, byte2 =