赞
踩
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);
- }
-

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。