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 = 0;
spi_chip_select(true);
spi_byte_transfer(0x9F);
byte0 = spi_byte_transfer(0xA5);
byte1 = spi_byte_transfer(0xA5);
byte2 = spi_byte_transfer(0xA5);
spi_chip_select(false);
return ((byte0 << 16) | (byte1 << 8) | (byte2 << 0));
}
void flash_erase_sector(uint32_t SectorAddr)
{
flash_enable_write();
spi_chip_select(true);
spi_byte_transfer(0x20);
spi_byte_transfer((SectorAddr >> 16) & 0xFF);
spi_byte_transfer((SectorAddr >> 8) & 0xFF);
spi_byte_transfer((SectorAddr >> 0) & 0xFF);
spi_chip_select(false);
flash_wait_write();
}
/**
* 启动SPI DMA通道
* buffer 缓冲区指针
* length 缓冲区数据长度,
* 如果 isread = true 表示需要从 flash 中读取多少个字节。
* 如果 isread = false 表示需要向 flash 写入多少个字节。
* isread true = 读,false = 写
*
*/
void flash_start_dma(uint8_t *buffer, uint32_t length, uint8_t isread)
{
uint32_t temp = 0xffffffff;
DMA_InitTypeDef DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
DMA_DeInit(DMA1_Stream0);
DMA_DeInit(DMA1_Stream7);
while(DMA_GetCmdStatus(DMA1_Stream0) != DISABLE);
while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE);
/* DMA1 channel 0 stream0 --- 配置 SPI3-RX DMA */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI3->DR;
if (isread == true)
{
/* 读方式下回读数据放到 buffer 中*/
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
}
else
{
/* 写方式下回读数据丢弃 */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&temp;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
}
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = length;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream0, &DMA_InitStructure);
/* DMA1 channel 0 stream7 --- 配置 SPI3-TX DMA */
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI3->DR;
if (isread == true)
{
/* 读方式下发送 0xff */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&temp;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
}
else
{
/* 写方式下发送 buffer 数据*/
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
}
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = length;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream7, &DMA_InitStructure);
/* 1.开启 DMA 数据流传输完成中断 */
DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);
/* 2.使能 DMA 数据流 */
DMA_Cmd(DMA1_Stream0, ENABLE);
DMA_Cmd(DMA1_Stream7, ENABLE);
/* 3.使能 SPI DMA 请求 */
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx, ENABLE);
/* 5.等待 DMA 传输完成 */
spi_wait_tx();
spi_wait_rx();
}
void DMA1_Stream7_IRQHandler(void)
{
if (DMA_GetFlagStatus(DMA1_Stream7, DMA_FLAG_TCIF7) != RESET)
{
/* 1.清中断标志 */
DMA_ClearFlag(DMA1_Stream7, DMA_FLAG_TCIF7);
/* 2.禁能 DMA 传输完成中断 */
DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, DISABLE);
/* 3.禁能 SPI TX DMA 请求 */
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, DISABLE);
/* 4.禁能 DMA Stream */
DMA_Cmd(DMA1_Stream7, DISABLE);
/* 5.通知应用程序 TX 传输完成 */
spi_post_tx();
}
}
void DMA1_Stream0_IRQHandler(void)
{
if (DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_TCIF0) != RESET)
{
/* 1.清中断标志 */
DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0);
/* 2.禁能 DMA 传输完成中断 */
DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, DISABLE);
/* 3.禁能 SPI TX DMA 请求 */
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx, DISABLE);
/* 4.禁能 DMA Stream */
DMA_Cmd(DMA1_Stream0, DISABLE);
/* 6.通知应用程序 RX 传输完成 */
spi_post_rx();
}
}
void flash_write_page(uint8_t* buffer, uint32_t addr)
{
flash_enable_write();
spi_chip_select(true);
spi_byte_transfer(0x02);
spi_byte_transfer((addr >> 16) & 0xFF);
spi_byte_transfer((addr >> 8) & 0xFF);
spi_byte_transfer((addr >> 0) & 0xFF);
flash_start_dma(buffer, FLASH_PAGE_SIZE, false);
spi_chip_select(false);
flash_wait_write();
}
void flash_read_page(uint8_t *buffer, uint32_t addr)
{
spi_chip_select(true);
spi_byte_transfer(0x03);
spi_byte_transfer((addr >> 16) & 0xFF);
spi_byte_transfer((addr >> 8) & 0xFF);
spi_byte_transfer((addr >> 0) & 0xFF);
flash_start_dma(buffer, FLASH_PAGE_SIZE, true);
spi_chip_select(false);
}
void flash_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
SPI_InitTypeDef SPI_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_4;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI3, &SPI_InitStructure);
SPI_Cmd(SPI3, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream0_IRQn;
NVIC_Init(&NVIC_InitStructure);
spi_chip_select(false);
}
uint8_t wbuffer[512];
uint8_t rbuffer[512];
int main(void)
{
int i = 0;
flash_init();
/* 初始化测试数据 */
for (i = 0; i < 512; i++)
{
wbuffer[i] = (uint8_t)(i+9);
}
flash_erase_sector(0);
flash_read_page(rbuffer, 0); /* 在此处打断点查看数据 */
flash_write_page(wbuffer, 0);
flash_read_page(rbuffer, 0); /* 在此处打断点查看数据 */
while(1);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)