来源:项目中需要用stm32对外部spi flash(m25p16 2MB)进行快速读取,主要是图像数据。
平台:stm32f407---168MHz,FreeRTOS V7.3.0
主要参考:http://blog.csdn.net/sinat_20598829/article/details/44408125
貌似发现了其中的一个小问题,未使用中断!!!见图
期间还参考帖子:http://blog.csdn.net/chenwei2002/article/details/49722373,本人不才,未能实现文中使用的方法。对于文中所讲:我们把SPI模式配置成只读模式,如上面程序中的样子,这个时候就可以直接读取数据,而不需要在发送无效数据0xff,大大提高了性能。SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly; 然而在配置为只读模式后没有spi时钟驱动flash进行数据输出,故放弃此方法。
代码来源:st 官方spi flash驱动文件
(STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Examples\SPI\SPI_FLASH)
在官方文件的基础上进行修改(注意修改红色部分):
/**
******************************************************************************
*
* +-----------------------------------------------------------+
* | Pin assignment |
* +-----------------------------+---------------+-------------+
* | STM32 SPI Pins | sFLASH | Pin |
* +-----------------------------+---------------+-------------+
* | sFLASH_CS_PIN | ChipSelect(/S)| 1 |
* | sFLASh_SPI_MISO_PIN / MISO | DataOut(Q) | 2 |
* | | VCC | 3 (3.3 V)|
* | | GND | 4 (0 V) |
* | sFLASH_SPI_MOSI_PIN / MOSI | DataIn(D) | 5 |
* | sFLASH_SPI_SCK_PIN / SCK | Clock(C) | 6 |
* | | VCC | 7 (3.3 V)|
* | | VCC | 8 (3.3 V)|
* +-----------------------------+---------------+-------------+
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "spi_dma_flash.h"
#include
/** @addtogroup STM32F4xx_StdPeriph_Examples
* @{
*/
/** @addtogroup SPI_FLASH
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define USE_SPI_DMA
#define SET_SPI1_ENABLE SPI_Cmd(sFLASH_DMA_SPI, ENABLE);
#define DMA2_TX_STREAM DMA2_Stream3
#define DMA2_TX_CHANNEL DMA_Channel_3
#define DMA2_RX_STREAM DMA2_Stream0
#define DMA2_RX_CHANNEL DMA_Channel_3
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DMA_InitTypeDef DMA2_Tx_InitStructure;
static DMA_InitTypeDef DMA2_Rx_InitStructure;
/* Private function prototypes -----------------------------------------------*/
void sFLASH_DMA_LowLevel_DeInit(void);
void sFLASH_DMA_LowLevel_Init(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief DeInitializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_DMA_DeInit(void)
{
sFLASH_DMA_LowLevel_DeInit();
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_DMA_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
sFLASH_DMA_LowLevel_Init();
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
/*!< SPI configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
DMA_Configuration_SPI1();
SPI_Init(sFLASH_DMA_SPI, &SPI_InitStructure);
SET_SPI1_ENABLE;
}
/**
* @brief Erases the specified FLASH sector.
* @param SectorAddr: address of the sector to erase.
* @retval None
*/
void sFLASH_DMA_EraseSector(uint32_t SectorAddr)
{
/*!< Send write enable instruction */
sFLASH_DMA_WriteEnable();
/*!< Sector Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send Sector Erase instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_SE);
/*!< Send SectorAddr high nibble address byte */
sFLASH_DMA_SendByte((SectorAddr & 0xFF0000) >> 16);
/*!< Send SectorAddr medium nibble address byte */
sFLASH_DMA_SendByte((SectorAddr & 0xFF00) >> 8);
/*!< Send SectorAddr low nibble address byte */
sFLASH_DMA_SendByte(SectorAddr & 0xFF);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_DMA_WaitForWriteEnd();
}
/**
* @brief Erases the entire FLASH.
* @param None
* @retval None
*/
void sFLASH_DMA_EraseBulk(void)
{
/*!< Send write enable instruction */
sFLASH_DMA_WriteEnable();
/*!< Bulk Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send Bulk Erase instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_BE);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_DMA_WaitForWriteEnd();
}
/**
* @brief Writes more than one byte to the FLASH with a single WRITE cycle
* (Page WRITE sequence).
* @note The number of byte can't exceed the FLASH page size.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH, must be equal
* or less than "sFLASH_DMA_PAGESIZE" value.
* @retval None
*/
void sFLASH_DMA_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
/*!< Enable the write access to the FLASH */
sFLASH_DMA_WriteEnable();
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send "Write to Memory " instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_WRITE);
/*!< Send WriteAddr high nibble address byte to write to */
sFLASH_DMA_SendByte((WriteAddr & 0xFF0000) >> 16);
/*!< Send WriteAddr medium nibble address byte to write to */
sFLASH_DMA_SendByte((WriteAddr & 0xFF00) >> 8);
/*!< Send WriteAddr low nibble address byte to write to */
sFLASH_DMA_SendByte(WriteAddr & 0xFF);
/*!< while there is data to be written on the FLASH */
while (NumByteToWrite--)
{
/*!< Send the current byte */
sFLASH_DMA_SendByte(*pBuffer);
/*!< Point on the next byte to be written */
pBuffer++;
}
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_DMA_WaitForWriteEnd();
}
/**
* @brief Writes block of data to the FLASH. In this function, the number of
* WRITE cycles are reduced, using Page WRITE sequence.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH.
* @retval None
*/
int sFLASH_DMA_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % sFLASH_DMA_SPI_PAGESIZE;
count = sFLASH_DMA_SPI_PAGESIZE - Addr;
NumOfPage = NumByteToWrite / sFLASH_DMA_SPI_PAGESIZE;
NumOfSingle = NumByteToWrite % sFLASH_DMA_SPI_PAGESIZE;
if (Addr == 0) /*!< WriteAddr is sFLASH_DMA_PAGESIZE aligned */
{
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_DMA_PAGESIZE */
{
sFLASH_DMA_WritePage(pBuffer, WriteAddr, NumByteToWrite);
}
else /*!< NumByteToWrite > sFLASH_DMA_PAGESIZE */
{
while (NumOfPage--)
{
sFLASH_DMA_WritePage(pBuffer, WriteAddr, sFLASH_DMA_SPI_PAGESIZE);
WriteAddr += sFLASH_DMA_SPI_PAGESIZE;
pBuffer += sFLASH_DMA_SPI_PAGESIZE;
}
sFLASH_DMA_WritePage(pBuffer, WriteAddr, NumOfSingle);
}
}
else /*!< WriteAddr is not sFLASH_DMA_PAGESIZE aligned */
{
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_DMA_PAGESIZE */
{
if (NumOfSingle > count) /*!< (NumByteToWrite + WriteAddr) > sFLASH_DMA_PAGESIZE */
{
temp = NumOfSingle - count;
sFLASH_DMA_WritePage(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
sFLASH_DMA_WritePage(pBuffer, WriteAddr, temp);
}
else
{
sFLASH_DMA_WritePage(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /*!< NumByteToWrite > sFLASH_DMA_PAGESIZE */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / sFLASH_DMA_SPI_PAGESIZE;
NumOfSingle = NumByteToWrite % sFLASH_DMA_SPI_PAGESIZE;
sFLASH_DMA_WritePage(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
sFLASH_DMA_WritePage(pBuffer, WriteAddr, sFLASH_DMA_SPI_PAGESIZE);
WriteAddr += sFLASH_DMA_SPI_PAGESIZE;
pBuffer += sFLASH_DMA_SPI_PAGESIZE;
}
if (NumOfSingle != 0)
{
sFLASH_DMA_WritePage(pBuffer, WriteAddr, NumOfSingle);
}
}
}
return 0;
}
/**
* @brief Reads FLASH identification.
* @param None
* @retval FLASH identification
*/
uint32_t sFLASH_DMA_ReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send "RDID " instruction */
sFLASH_DMA_SendByte(0x9F);
/*!< Read a byte from the FLASH */
Temp0 = sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE);
/*!< Read a byte from the FLASH */
Temp1 = sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE);
/*!< Read a byte from the FLASH */
Temp2 = sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
/**
* @brief Reads a byte from the SPI Flash.
* @note This function must be used only if the Start_Read_Sequence function
* has been previously called.
* @param None
* @retval Byte Read from the SPI Flash.
*/
uint8_t sFLASH_DMA_ReadByte(void)
{
return (sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE));
}
/**
* @brief Sends a byte through the SPI interface and return the byte received
* from the SPI bus.
* @param byte: byte to send.
* @retval The value of the received byte.
*/
uint8_t sFLASH_DMA_SendByte(uint8_t byte)
{
/*!< Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(sFLASH_DMA_SPI, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_I2S_SendData(sFLASH_DMA_SPI, byte);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(sFLASH_DMA_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(sFLASH_DMA_SPI);
}
/**
* @brief Enables the write access to the FLASH.
* @param None
* @retval None
*/
void sFLASH_DMA_WriteEnable(void)
{
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send "Write Enable" instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_WREN);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
}
/**
* @brief Polls the status of the Write In Progress (WIP) flag in the FLASH's
* status register and loop until write operation has completed.
* @param None
* @retval None
*/
void sFLASH_DMA_WaitForWriteEnd(void)
{
uint8_t flashstatus = 0;
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send "Read Status Register" instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_RDSR);
/*!< Loop as long as the memory is busy with a write cycle */
do
{
/*!< Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in FLASH_Status variable */
flashstatus = sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE);
}
while ((flashstatus & sFLASH_DMA_WIP_FLAG) == SET); /* Write in progress */
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_DMA_LowLevel_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< Enable the SPI clock */
sFLASH_DMA_SPI_CLK_INIT(sFLASH_DMA_SPI_CLK, ENABLE);
/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(sFLASH_DMA_SPI_SCK_GPIO_CLK | sFLASH_DMA_SPI_MISO_GPIO_CLK |
sFLASH_DMA_SPI_MOSI_GPIO_CLK | sFLASH_DMA_CS_GPIO_CLK, ENABLE);
/*!< SPI pins configuration *************************************************/
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_UP;
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_SCK_PIN;
GPIO_Init(sFLASH_DMA_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_MOSI_PIN;
GPIO_Init(sFLASH_DMA_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_MISO_PIN;
GPIO_Init(sFLASH_DMA_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Connect SPI pins to AF5 */
GPIO_PinAFConfig(sFLASH_DMA_SPI_SCK_GPIO_PORT, sFLASH_DMA_SPI_SCK_SOURCE, sFLASH_DMA_SPI_SCK_AF);
GPIO_PinAFConfig(sFLASH_DMA_SPI_MISO_GPIO_PORT, sFLASH_DMA_SPI_MISO_SOURCE, sFLASH_DMA_SPI_MISO_AF);
GPIO_PinAFConfig(sFLASH_DMA_SPI_MOSI_GPIO_PORT, sFLASH_DMA_SPI_MOSI_SOURCE, sFLASH_DMA_SPI_MOSI_AF);
/*!< Configure sFLASH_DMA Card CS pin in output pushpull mode ********************/
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(sFLASH_DMA_CS_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief DeInitializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_DMA_LowLevel_DeInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< Disable the sFLASH_DMA_SPI ************************************************/
SPI_Cmd(sFLASH_DMA_SPI, DISABLE);
/*!< DeInitializes the sFLASH_DMA_SPI *******************************************/
SPI_I2S_DeInit(sFLASH_DMA_SPI);
/*!< sFLASH_DMA_SPI Periph clock disable ****************************************/
sFLASH_DMA_SPI_CLK_INIT(sFLASH_DMA_SPI_CLK, DISABLE);
/*!< Configure all pins used by the SPI as input floating *******************/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_SCK_PIN;
GPIO_Init(sFLASH_DMA_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_MISO_PIN;
GPIO_Init(sFLASH_DMA_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_SPI_MOSI_PIN;
GPIO_Init(sFLASH_DMA_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_DMA_CS_PIN;
GPIO_Init(sFLASH_DMA_CS_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief Clear DMA transfer flags.
* @param None
* @retval None
*/
void ClrDmaFlag(void)
{
DMA_ClearFlag(DMA2_RX_STREAM, DMA_FLAG_TCIF0);
DMA_ClearFlag(DMA2_TX_STREAM, DMA_FLAG_TCIF3);
}
/**
* @brief Reads a block of data from the FLASH.
* @param pBuffer: pointer to the buffer that receives the data read from the FLASH.
* @param ReadAddr: FLASH's internal address to read from.
* @param NumByteToRead: number of bytes to read from the FLASH.
* @retval None
*/
void sFLASH_DMA_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
/*!< Select the FLASH: Chip Select low */
sFLASH_DMA_CS_LOW();
/*!< Send "Read from Memory " instruction */
sFLASH_DMA_SendByte(sFLASH_DMA_CMD_READ);
/*!< Send ReadAddr high nibble address byte to read from */
sFLASH_DMA_SendByte((ReadAddr & 0xFF0000) >> 16);
/*!< Send ReadAddr medium nibble address byte to read from */
sFLASH_DMA_SendByte((ReadAddr& 0xFF00) >> 8);
/*!< Send ReadAddr low nibble address byte to read from */
sFLASH_DMA_SendByte(ReadAddr & 0xFF);
#ifdef USE_SPI_DMA //ʹÓÃDMA
while (DMA_GetCmdStatus(DMA2_RX_STREAM) != DISABLE){};
/* ÖØÐÂÅäÖÃDMAÔ´µØÖ· ¼°´«ÊäÏîÄ¿Êý */
DMA2_Rx_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pBuffer;
DMA2_Rx_InitStructure.DMA_BufferSize = NumByteToRead;
DMA_Init(DMA2_RX_STREAM, &DMA2_Rx_InitStructure);
/* ʹÄÜDMA·¢Ë͵ÄÄ¿µÄÊÇÔÚ½ÓÊÕflashÊý¾ÝʱÐèÒªÌṩ½ÓÊÕʱÖÓ */
while (DMA_GetCmdStatus(DMA2_TX_STREAM) != DISABLE){};
DMA2_Tx_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&pBuffer;
DMA2_Tx_InitStructure.DMA_BufferSize = NumByteToRead;
DMA_Init(DMA2_TX_STREAM, &DMA2_Tx_InitStructure);
/* ʹÄÜSPI DMA ½ÓÊպͷ¢ËÍÇëÇó */
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx, ENABLE);
/* ʹÄÜÒ»´ÎDMA ´«Êä */
DMA_Cmd(DMA2_RX_STREAM, ENABLE);
DMA_Cmd(DMA2_TX_STREAM, ENABLE);
/*µÈ´ýDMA ´«ÊäÍê³É */
while(DMA_GetFlagStatus(DMA2_RX_STREAM, DMA_FLAG_TCIF0) == RESET){};
/* ±ØÐëÇå³ý ½ÓÊÕ¡¢·¢ËÍÍê³É±ê־λ */
ClrDmaFlag();
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx, DISABLE);
sFLASH_DMA_CS_HIGH();
#else //²»Ê¹ÓÃDMA
while (NumByteToRead--) /*!< while there is data to be read */
{
/*!< Read a byte from the FLASH */
*pBuffer = sFLASH_DMA_SendByte(sFLASH_DMA_DUMMY_BYTE);
/*!< Point to the next location where the byte read will be saved */
pBuffer++;
}
/*!< Deselect the FLASH: Chip Select high */
sFLASH_DMA_CS_HIGH();
#endif
}
/*******************************************************************************
* Function Name : DMA_Configuration_SPI1
* Description : SPI1 DMAÊý¾Ý´«ÊäÅäÖã¬ÊÊÓÃÓÚstm32F4ϵÁÐ
* Input : none
* Output : None
* Return : None
*******************************************************************************/
void DMA_Configuration_SPI1(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2 ʼÖÕ³õʼ»¯
DMA_DeInit(DMA2_TX_STREAM);
DMA2_Tx_InitStructure.DMA_Channel = DMA2_TX_CHANNEL;
DMA2_Tx_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;
DMA2_Tx_InitStructure.DMA_Memory0BaseAddr = 0;
DMA2_Tx_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA2_Tx_InitStructure.DMA_BufferSize = 0;
DMA2_Tx_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA2_Tx_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA2_Tx_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA2_Tx_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA2_Tx_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA2_Tx_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA2_Tx_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA2_Tx_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA2_Tx_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA2_Tx_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* DMA2 stream0 --- SPI1-RX configuration */
DMA_DeInit(DMA2_RX_STREAM);
DMA2_Rx_InitStructure.DMA_Channel = DMA2_RX_CHANNEL;
DMA2_Rx_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;
DMA2_Rx_InitStructure.DMA_Memory0BaseAddr = 0;
DMA2_Rx_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA2_Rx_InitStructure.DMA_BufferSize = 0;
DMA2_Rx_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA2_Rx_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA2_Rx_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA2_Rx_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA2_Rx_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA2_Rx_InitStructure.DMA_Priority = DMA_Priority_High;
DMA2_Rx_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //FIFOģʽ¹Ø±Õ
DMA2_Rx_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA2_Rx_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // ÄÚ´æÍ»·¢µ¥´Î´«Êä
DMA2_Rx_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //ÍâÉèÍ»·¢µ¥´Î´«Êä
}
/**
* @brief M25P16д²âÊÔ: 32¸öÉÈÇø £¬Ã¿¸öÉÈÇø64KB
* @param None
* @retval 0: true, 1:flase
*/
uint8_t dmaFlashWrite_Test(void)
{
uint8_t flashData[256];
uint32_t i=0;
sFLASH_DMA_EraseBulk();
// sFLASH_DMA_EraseSector(0x0);
for (i=0x0;i<0x100;i++)
{
flashData[i]= i;
}
for (i=0;i<8192;i++)
{
sFLASH_DMA_WriteBuffer(flashData, i*256, 256);
}
printf("spi flash write done!\r\n");
return 0;
}
/**
* @brief M25P16¶Á²âÊÔ
* @param None
* @retval 0: true, 1:flase
*/
u8 Rx_Buffer[65535];
uint8_t dmaFlashRead_Test(void)
{
uint32_t i,j=0;
for(i=0; i<16; i++)
{
sFLASH_DMA_ReadBuffer(Rx_Buffer, i*65535, 0xFFFF);
if(i==10)
{
for(j=1; j<0x100; j++)
{
// printf("0x%02x ",Rx_Buffer[j]);
}
// memset(Rx_Buffer, 0, 0xffff);
}
else if(i==15)
{
for(j=1; j<0x100; j++)
{
// printf("0x%02x ",Rx_Buffer[j]);
}
}
// printf("\rspi flash read 65k count:%d \r\n", i);
}
return 0;
}
/**
* @}
*/
/**
* @}
*/
/*****END OF FILE****/
调试信息:
上图的关键信息在于不使用DMA接收完成中断时,需要再次进行DMA传输时要及时手动清接收及发送完成FLAG。
参考测试结果:总共读取1MB数据,每次数据量65536,总共16次。
可用宏USB_SPI_DMA 使能DMA传输功能
开启DMA传输后用时约260 ticks(1S = 1000ticks)
未开启用时约900 ticks
貌似性能提升也不是很高,有童鞋测试结果明显的,分享下优化方法吧。