你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F7-discovery QSPI接口使用心得  

[复制链接]
feiting94 发布时间:2015-9-8 22:09
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
总结一下特点:
(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
这里主要说明quad-spi flash代码流程分析
论坛可以下载STM32Cube_FW_F7_V1.1.0压缩包,我也是从里面的例程中学习的。
选择STM32Cube_FW_F7_V1.1.0/project/STM32746G-Discovery/example/QSPI/QSPI_ExecuteInPlace例程
(1)Flash配置寄存器初始化
  1.   /* Initialize QuadSPI ------------------------------------------------------ */
  2.   QSPIHandle.Instance = QUADSPI;         
  3.   HAL_QSPI_DeInit(&QSPIHandle);
  4.         
  5.   /* ClockPrescaler set to 2, so QSPI clock = 216MHz / (2+1) = 72MHz */
  6.   QSPIHandle.Init.ClockPrescaler     = 2;                                                                // <span style="background-color: rgb(255, 255, 255);">查阅手册可知,最大频率108MHz,这里为什么不用1呢??</span>
  7.   QSPIHandle.Init.FifoThreshold      = 4;                                                                 // FIFO的阈值为4bytes,
  8.   QSPIHandle.Init.SampleShifting     = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  9.   QSPIHandle.Init.FlashSize          = POSITION_VAL(0x1000000) - 1;                         //0x1000000=16MB,
  10.   QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;        //nCS stay high for at least 2 clock cycles between commands
  11.   QSPIHandle.Init.ClockMode          = QSPI_CLOCK_MODE_0;                                    //Clk stays low while nCS is released
  12.   QSPIHandle.Init.FlashID            = QSPI_FLASH_ID_1;                                               //选择第1片flash
  13.   QSPIHandle.Init.DualFlash          = QSPI_DUALFLASH_DISABLE;
  14.   
  15.   if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
  16.   {
  17.     Error_Handler();
  18.   }
复制代码
(2)使能写操作
  1.   /* Enable write operations ------------------------------------------ */
  2.   sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;            
  3.   sCommand.Instruction       = WRITE_ENABLE_CMD;
  4.   sCommand.AddressMode       = QSPI_ADDRESS_NONE;
  5.   sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  6.   sCommand.DataMode          = QSPI_DATA_NONE;
  7.   sCommand.DummyCycles       = 0;
  8.   sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
  9.   sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  10.   sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

  11.   if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  12.   {
  13.     Error_Handler();
  14.   }
  15.   
  16.   /* Configure automatic polling mode to wait for write enabling ---- */
  17.   sConfig.Match           = 0x02;
  18.   sConfig.Mask            = 0x02;
  19.   sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  20.   sConfig.StatusBytesSize = 1;
  21.   sConfig.Interval        = 0x10;
  22.   sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

  23.   sCommand.Instruction    = READ_STATUS_REG_CMD;
  24.   sCommand.DataMode       = QSPI_DATA_1_LINE;

  25.   if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  26.   {
  27.     Error_Handler();
  28.   }
复制代码
首先使用indrect mode,使用1bit instruction传输,命令是 WRITE_ENABLE_CMD,无其他4个阶段
源码中定义   #define WRITE_ENABLE_CMD                     0x06;
这里要查阅芯片手册
5.png
确实是一致的。
接着使用automatic polling mode,命令是READ_STATUS_REG_CMD,读status register
automatic polling mode有如下功能,它将查询的得到的值和设置的Match值比较,只比较Mask中bit=1的位,设置可以为AND或者OR模式,
查阅手册:

6.png
确实是bit1,即mask=0x02,当该位为1时,说明写使能,故match=0x02;
(3)擦除flash的第一个sector
  1.         /* Erasing Sequence -------------------------------------------------- */
  2.         sCommand.Instruction = SECTOR_ERASE_CMD;   //块擦除,64KB one sector
  3.         sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
  4.         sCommand.Address     = qspi_addr;                          //qspi_addr=0
  5.         sCommand.DataMode    = QSPI_DATA_NONE;
  6.         sCommand.DummyCycles = 0;

  7.         if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
  8.         {
  9.           Error_Handler();
  10.         }
复制代码
(4)等待擦除完毕,使用automatic polling mode查询,这里还是读status register,但读的是bit0位,而且预期值bit0=0;查阅手册
7.png
  1.   /* Configure automatic polling mode to wait for memory ready ------ */  
  2.   sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
  3.   sCommand.Instruction       = READ_STATUS_REG_CMD;
  4.   sCommand.AddressMode       = QSPI_ADDRESS_NONE;
  5.   sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  6.   sCommand.DataMode          = QSPI_DATA_1_LINE;
  7.   sCommand.DummyCycles       = 0;
  8.   sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
  9.   sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  10.   sCommand.SIOOMode         = QSPI_SIOO_INST_EVERY_CMD;

  11.         //bit0:write in progress 0:ready 1:busy
  12.   sConfig.Match           = 0x00;
  13.   sConfig.Mask            = 0x01;
  14.   sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  15.   sConfig.StatusBytesSize = 1;
  16.   sConfig.Interval        = 0x10;
  17.   sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

  18.   if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }
复制代码
(5)写使能并且写数据
  1. /* Enable write operations ----------------------------------------- */
  2.           QSPI_WriteEnable(&QSPIHandle);

  3.                                         //QUAD INPUT FAST PROGRAM Data In:DQ[3:0];Address In:DQ0
  4.           /* Writing Sequence ------------------------------------------------ */
  5.           sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
  6.           sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
  7.           sCommand.Address     = qspi_addr;                                              //qspi_addr=0
  8.           sCommand.DataMode    = QSPI_DATA_4_LINES;
  9.           sCommand.NbData      = size;                                                         //size = QSPI_PAGE_SIZE = 256

  10.           if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  11.           {
  12.             Error_Handler();
  13.           }

  14.           if (HAL_QSPI_Transmit_DMA(&QSPIHandle, flash_addr) != HAL_OK)         //flash_addr = (uint8_t *)(&Load$QSPI$Base);
  15.           {
  16.             Error_Handler();
  17.           }
复制代码
看到这里就不得不提一下scatter file文件
8.png
打开这个文件,STM32746G-DISCOVERY.sct
  1. ; *************************************************************
  2. ; *** Scatter-Loading Description File generated by uVision ***
  3. ; *************************************************************

  4. LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  5.   ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
  6.    *.o (RESET, +First)
  7.    *(InRoot$Sections)
  8.    .ANY (+RO)
  9.   }
  10.   RW_IRAM1 0x20000000 0x00050000  {  ; RW data
  11.    .ANY (+RW +ZI)
  12.   }
  13.   QSPI 0x90000000 0x00100000  {
  14.    *.o (.qspi)
  15.   }
  16. }
复制代码
可以看到和一般的scatter file(分散加载描述文件)相比,多了一个QSPI执行域,
学过的都知道,这里表示链接时,将所有目标文件的.qspi段放在QSPI执行域,
再看一下F7的内存映射
9.png
在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
  1. /* Configure Volatile Configuration register (with new dummy cycles) */
  2.             QSPI_DummyCyclesCfg(&QSPIHandle);

  3.             /* Reading Sequence ------------------------------------------------ */
  4.             sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
  5.             sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;

  6.             sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;

  7.             if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK)
  8.             {
  9.               Error_Handler();
  10.             }
复制代码
(9)执行.qspi段的代码
  1. /* Execute the code from QSPI memory ------------------------------- */
  2.           GpioToggle();
复制代码
注意
  1. #if defined(__CC_ARM)
  2. #pragma arm section code = ".qspi"
  3. #pragma no_inline
  4. static void GpioToggle(void)
  5. #elif defined(__ICCARM__)
  6. static void GpioToggle(void) @ ".qspi"
  7. #elif defined(__GNUC__)
  8. static void __attribute__((section(".qspi"), noinline)) GpioToggle(void)
  9. #endif

  10. {
  11.   BSP_LED_Toggle(LED1);
  12.   /* Insert delay 200 ms */
  13.   HAL_Delay(200);
  14. }
复制代码

我的问题:
学完之后,我一直对一个问题感到困惑,再用st-link烧写程序时,这个.qspi段是不是放在内部flash中,只有在执行时,MCU才会到0x9000 0000处执行,这时MCU读flash,但是对我们来说是屏蔽的,我们可以直接当内部flash使用。如果前面没有执行DMA将0x9000 0000处数据传递到flash,后面是不是就不对了。这个时候为什么0x9000 0000处会有数据呢,实际上这里并没有flash啊,希望有人能帮忙解答一下
收藏 8 评论21 发布时间:2015-9-8 22:09

举报

21个回答
feiting94 回答时间:2015-9-9 12:00:44
netlhx 发表于 2015-9-9 09:14
这个位置就是映射到4G空间的FLASH的地址

请问一下,这个位置实际上并没有flash,那程序在执行步骤5,6,7,将这个位置的内容通过DMA写入到实际的flash上时,MCU是怎么怎么知道要传输数据的内容,毕竟映射的地址那里并没有flash。还有程序烧写进去时 .qspi段是放在哪里呢
党国特派员 回答时间:2015-9-9 09:35:02
学习了。。。 blank.png blank1.png blank2.png blank3.png blank4.png
feiting94 回答时间:2016-3-13 09:28:04
狂奔的小冉 发表于 2016-3-11 17:46
我想问一下,WRIRE ENABLE这些参数的说明是那份文档,我最近做F446,但是user manual没有Instruction的具体 ...

n25q_128mb_3v_65nm.pdf (1.11 MB, 下载次数: 133)
moyanming2013 回答时间:2015-9-8 23:30:21
先学习下。。。
你好我好大家好! 回答时间:2015-9-8 23:43:28
学习下                     
netlhx 回答时间:2015-9-9 09:14:44
这个位置就是映射到4G空间的FLASH的地址
yanhaijian 回答时间:2015-9-9 12:37:42
研究的比较细。
埃斯提爱慕 回答时间:2015-9-10 23:23:52
提示: 作者被禁止或删除 内容自动屏蔽
anny 回答时间:2015-9-17 15:03:36

支持楼主的原创分享
yanhaijian 回答时间:2015-9-17 15:21:05
学习了,顶顶。
狂奔的小冉 回答时间:2016-3-11 17:45:52
我想问一下,WRIRE ENABLE这些参数的说明是那份文档,我最近做F446,但是user manual没有Instruction的具体说明。谢谢
狂奔的小冉 回答时间:2016-3-11 17:46:10
我想问一下,WRIRE ENABLE这些参数的说明是那份文档,我最近做F446,但是user manual没有Instruction的具体说明。谢谢
狂奔的小冉 回答时间:2016-3-13 10:01:09

原来是在EEPROM的 datasheet里。。。谢谢了!
绝影 回答时间:2016-8-26 13:37:49
今天也在研究Qspi 在keil添加FLASH的界面可以添加外部的Qspi存储器,应该可以将程序下载进去
11223.png
12下一页

所属标签

相似分享

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版