stm32qspi内存映射_STM32F7-discovery QSPI接口使用心得
STM32電機培訓online,大佬帶你玩電機
FMC和QSPI引腳沖突的解決
分享一個 QSPI N25Q256A的讀寫程序,支持QUAD, 4字節模式
1.QuadSPI接口的特點。與普通的SPI Flash接口相比,quadSPI可以接四位數據線,傳輸速率大大提高
STM32F7的quad-spi接口有三種模式
(1)indirect mode(間接模式):所有操作都是用的QUADSPI寄存器,通常在對FLASH寄存器配置時用這種模式
(2)status polling mode(狀態輪詢模式):外部Flash的狀態寄存器查詢使用的是這種模式,如果開啟中斷,可以產生中斷信號
(3)memory-mapped mode(內存映射模式):外部flash映射到MCU的地址空間,可以視為內部閃存,讀寫數據用的這種模式
STM32F7的quad-spi接口主要特點:
(1)三種工作模式
(2)Dual-Flash模式,可以同時接兩片Flash,共用CLK和CS片選線。這樣可以最多同時傳輸8位數據(4+4)
(3)支持SDR和DDR
(4)間接模式的DMA通道
(5)內嵌接收和發送FIFO
(6)支持FIFO threshold, timeout, operation complete, access error四種中斷
Quad-spi完整的命令格式由5部分組成,分別是Instruction,Address,Alternate-bytes,dummy-cycles和Data這5個階段,時序圖如圖所示
3.png (42.97 KB, 下載次數: 30)
2015-9-8 20:19 上傳
總結一下特點:
(1)每個階段都可以選擇是 1bit(SO/SI線 single SPI mode),2bit(IO0/IO1線 dual SPI mode),和4bit(IO0/IO1/IO2/IO3線 quad SPI mode)傳輸,
(2)寫數據時,dummy cycle可以為0;讀數據時,為了保證足夠的轉換時間,因為之前是寫數據,現在要變成讀,至少要1個dummy cycle
(3)這5個階段都不是必須的,可以沒有
(4)indirect mode模式,數據讀取時通過QUADSPI_DR寄存器;memory-mapped mode模式,數據直接返回和輸出通過AHB總線或者DMA
(5)SDR和DDR模式的區別:兩者的instruction階段都是CLK信號的下降沿數據傳輸;在DDR模式中,Address,Alternate-bytes和Data這3個階段都是上升沿和下降沿都有數據傳輸
(6)F7有32-byte FIFO,可以設置threshold(閾值),接收數據數目超過該值時,FTF(FIFO threshold flag)=1
3.STM32F7-Discovery的quad-spi flash使用的是micron公司的N25Q128A系列,有128Mbit容量,后面附上數據手冊,原理圖如圖所示
1.png (29.91 KB, 下載次數: 25)
2015-9-8 19:45 上傳
這里主要說明quad-spi flash代碼流程分析
論壇可以下載STM32Cube_FW_F7_V1.1.0壓縮包,我也是從里面的例程中學習的。
選擇STM32Cube_FW_F7_V1.1.0/project/STM32746G-Discovery/example/QSPI/QSPI_ExecuteInPlace例程
(1)Flash配置寄存器初始化
/* Initialize QuadSPI ------------------------------------------------------ */
QSPIHandle.Instance = QUADSPI;
HAL_QSPI_DeInit(&QSPIHandle);
/* ClockPrescaler set to 2, so QSPI clock = 216MHz / (2+1) = 72MHz */
QSPIHandle.Init.ClockPrescaler? ???= 2;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? // 查閱手冊可知,最大頻率108MHz,這里為什么不用1呢??
QSPIHandle.Init.FifoThreshold? ?? ?= 4;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???// FIFO的閾值為4bytes,
QSPIHandle.Init.SampleShifting? ???= QSPI_SAMPLE_SHIFTING_HALFCYCLE;
QSPIHandle.Init.FlashSize? ?? ?? ? = POSITION_VAL(0x1000000) - 1;? ?? ?? ?? ?? ?? ?? ?? ? //0x1000000=16MB,
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;? ?? ???//nCS stay high for at least 2 clock cycles between commands
QSPIHandle.Init.ClockMode? ?? ?? ? = QSPI_CLOCK_MODE_0;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//Clk stays low while nCS is released
QSPIHandle.Init.FlashID? ?? ?? ?? ?= QSPI_FLASH_ID_1;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//選擇第1片flash
QSPIHandle.Init.DualFlash? ?? ?? ? = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
{
Error_Handler();
}復制代碼(2)使能寫操作
/* Enable write operations ------------------------------------------ */
sCommand.InstructionMode? ?= QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction? ?? ? = WRITE_ENABLE_CMD;
sCommand.AddressMode? ?? ? = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode? ?? ?? ? = QSPI_DATA_NONE;
sCommand.DummyCycles? ?? ? = 0;
sCommand.DdrMode? ?? ?? ???= QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle??= QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode? ?? ?? ? = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match? ?? ?? ???= 0x02;
sConfig.Mask? ?? ?? ?? ?= 0x02;
sConfig.MatchMode? ?? ? = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval? ?? ???= 0x10;
sConfig.AutomaticStop? ?= QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction? ? = READ_STATUS_REG_CMD;
sCommand.DataMode? ?? ? = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}復制代碼首先使用indrect mode,使用1bit instruction傳輸,命令是WRITE_ENABLE_CMD,無其他4個階段
源碼中定義? ?#define WRITE_ENABLE_CMD? ?? ?? ?? ?? ?? ?? ?0x06;
這里要查閱芯片手冊
5.png (21.35 KB, 下載次數: 20)
2015-9-8 21:14 上傳
確實是一致的。
接著使用automatic polling mode,命令是READ_STATUS_REG_CMD,讀status register
automatic polling mode有如下功能,它將查詢的得到的值和設置的Match值比較,只比較Mask中bit=1的位,設置可以為AND或者OR模式,
查閱手冊:
6.png (120.57 KB, 下載次數: 31)
2015-9-8 21:21 上傳
確實是bit1,即mask=0x02,當該位為1時,說明寫使能,故match=0x02;
(3)擦除flash的第一個sector
/* Erasing Sequence -------------------------------------------------- */
sCommand.Instruction = SECTOR_ERASE_CMD;? ?//塊擦除,64KB one sector
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.Address? ???= qspi_addr;? ?? ?? ?? ?? ?? ?? ?? ???//qspi_addr=0
sCommand.DataMode? ? = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
{
Error_Handler();
}復制代碼(4)等待擦除完畢,使用automatic polling mode查詢,這里還是讀status register,但讀的是bit0位,而且預期值bit0=0;查閱手冊
7.png (27.46 KB, 下載次數: 18)
2015-9-8 21:30 上傳
/* Configure automatic polling mode to wait for memory ready ------ */
sCommand.InstructionMode? ?= QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction? ?? ? = READ_STATUS_REG_CMD;
sCommand.AddressMode? ?? ? = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode? ?? ?? ? = QSPI_DATA_1_LINE;
sCommand.DummyCycles? ?? ? = 0;
sCommand.DdrMode? ?? ?? ???= QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle??= QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode? ?? ?? ?= QSPI_SIOO_INST_EVERY_CMD;
//bit0:write in progress 0:ready 1:busy
sConfig.Match? ?? ?? ???= 0x00;
sConfig.Mask? ?? ?? ?? ?= 0x01;
sConfig.MatchMode? ?? ? = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval? ?? ???= 0x10;
sConfig.AutomaticStop? ?= QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)
{
Error_Handler();
}復制代碼(5)寫使能并且寫數據
/* Enable write operations ----------------------------------------- */
QSPI_WriteEnable(&QSPIHandle);
//QUAD INPUT FAST PROGRAM Data In:DQ[3:0];Address In:DQ0
/* Writing Sequence ------------------------------------------------ */
sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.Address? ???= qspi_addr;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //qspi_addr=0
sCommand.DataMode? ? = QSPI_DATA_4_LINES;
sCommand.NbData? ?? ?= size;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//size = QSPI_PAGE_SIZE = 256
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_QSPI_Transmit_DMA(&QSPIHandle, flash_addr) != HAL_OK)? ?? ?? ?//flash_addr = (uint8_t *)(&Load$QSPI$Base);
{
Error_Handler();
}復制代碼看到這里就不得不提一下scatter file文件
8.png (48.16 KB, 下載次數: 17)
2015-9-8 21:38 上傳
打開這個文件,STM32746G-DISCOVERY.sct
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000??{? ? ; load region size_region
ER_IROM1 0x08000000 0x00100000??{??; load address = execution address
*.o (RESET, +First)
*(InRoot$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00050000??{??; RW data
.ANY (+RW +ZI)
}
QSPI 0x90000000 0x00100000??{
*.o (.qspi)
}
}復制代碼可以看到和一般的scatter file(分散加載描述文件)相比,多了一個QSPI執行域,
學過的都知道,這里表示鏈接時,將所有目標文件的.qspi段放在QSPI執行域,
再看一下F7的內存映射
9.png (17.12 KB, 下載次數: 26)
2015-9-8 21:43 上傳
在0x8000 0000到0x9FFF FFFF有一個Quad SPI,這就是memory-mapped mode的由來。
因此上面flash_addr = (uint8_t *)(&Load$$QSPI$$Base) = 0x9000 0000; DMA傳輸就是將 0x9000 0000處開始的size = 256bytes的數據傳遞到flash,模式是indrect read mode
(6)判斷傳輸是否完成,判斷的方法同步驟4
(7)重復5、6步直到傳輸完max_size = (uint32_t)(&Load$$QSPI$$Length)=??0x00100000
(8)設置dummy-cycle的值,配置為memory-mapped mode,命令是QUAD_OUT_FAST_READ_CMD=0x6B,就是說映射完后,相對于內部flash
/* Configure Volatile Configuration register (with new dummy cycles) */
QSPI_DummyCyclesCfg(&QSPIHandle);
/* Reading Sequence ------------------------------------------------ */
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK)
{
Error_Handler();
}復制代碼(9)執行.qspi段的代碼
/* Execute the code from QSPI memory ------------------------------- */
GpioToggle();復制代碼注意
#if defined(__CC_ARM)
#pragma arm section code = ".qspi"
#pragma no_inline
static void GpioToggle(void)
#elif defined(__ICCARM__)
static void GpioToggle(void) @ ".qspi"
#elif defined(__GNUC__)
static void __attribute__((section(".qspi"), noinline)) GpioToggle(void)
#endif
{
BSP_LED_Toggle(LED1);
/* Insert delay 200 ms */
HAL_Delay(200);
}復制代碼
我的問題:
學完之后,我一直對一個問題感到困惑,再用st-link燒寫程序時,這個.qspi段是不是放在內部flash中,只有在執行時,MCU才會到0x9000 0000處執行,這時MCU讀flash,但是對我們來說是屏蔽的,我們可以直接當內部flash使用。如果前面沒有執行DMA將0x9000 0000處數據傳遞到flash,后面是不是就不對了。這個時候為什么0x9000 0000處會有數據呢,實際上這里并沒有flash啊,希望有人能幫忙解答一下
總結
以上是生活随笔為你收集整理的stm32qspi内存映射_STM32F7-discovery QSPI接口使用心得的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 物流设计大赛优秀作品_独家!亲历全国大学
- 下一篇: workbench设置单元坐标系_Wor