谈谈对HC32F460芯片的QSPI理解
扫描二维码
随时随地手机看文章
网站:bbs.21ic.com
近在学习华大的HC32F460这个芯片,今天想说说我对QSPI的理解
一、定义
QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。
在SPI协议的基础上,Motorola公司对其功能进行了增强,增加了队列传输机制,推出了队列串行外围接口协议(即QSPI协议)。 QSPI 是一种专用的通信接口,连接单、双或四(条数据线)SPI Flash 存储介质。
二. 六种读指令的方式
1. 标准读指令
1.1串行总线周期开始
1.2串行闪存选择信号被置为有效状态
1.3从QSIO0管脚输出该指令的指令代码(03h/13h)*
1 1.4输出目标地址,该地址的宽度可以通过 QSFCR 寄存器中的AWSL[1:0]位来设置
1.5接收数据,QSPI 的初始状态选择的指令就是标准读指令。
2. 快速读指令
2.1 串行总线周期开始
2.2 串行闪存选择信号被置为有效状态
2.3 从QSIO0管脚输出该指令的指令代码(0Bh/0Ch)
2.4 输出目标地址,地址宽度可以通过 QSFCR 寄存器中的 AWSL[1:0]位来设置
2.5 地址输出后是一定数量的虚拟周期,其具体数量由 QSFCR 寄存器中的 DMCYCN[3:0]决定。
2.6 数据接收
3. 二线式输出快速读指令 二线式输出快速读是一种使用两根信号线进行数据接收的读指令。
3.1 总线周期开始
3.2 串行闪存选择信号被置为有效状态
3.3 从QSIO0管脚输出该指令的指令代码(3Bh/3Ch)和目标地址,地址宽度可以通过 QSFCR 寄存器中的AWSL[1:0]位来设置。
3.4 一定数量的虚拟周期,其具体数量由 QSFCR 寄存器中的 DMCYCN[3:0]决定
3.5 通过 QSIO0 和 QSIO1 两根管脚进行数据接收。偶位数据在 QSIO0 接收,奇位在 QSIO1。
4. 二线式输入输出快速读指令 二线式输入输出快速读是一种使用两根信号线进行地址发送和数据接收的读指令。
4.1 串行总线周期开始
4.2 串行闪存选择信号被置为有效状态
4.3 QSIO0 管脚输出该指令的指令代码(BBh/BCh)。
4.4 从 QSIO0 和 QSIO1两个管脚输出目标地址,地址宽度可以通过 QSFCR 寄存器中的 AWSL[1:0]位来设置。
4.5 一定数量的虚拟周期,其具体数量由 QSFCR 寄存器中的 DMCYCN[3:0]决定。
4.6 通过 QSIO0 和 QSIO1 两根管脚进行数据接收。偶数位的地址和虚拟周期(包括 XIP 模式选择信息)的传输及数据接收使用 QSIO0 管脚,奇数位使用 QSIO1管脚。
5. 四线式输出快速读指令 四线式输出快速读是一种使用四根信号线进行数据接收的读指令。
5.1 当一个串行总线周期开始的时候
5.2 串行闪存选择信号被置为有效状态
5.3 QSIO0 管脚输出该指令的指令代码(6Bh/6Ch)和目标地址,地址宽度通过 QSFCR 寄存器中的AWSL[1:0]位来设置
5.4 在这之后是一定数量的虚拟周期,其具体数量由 QSFCR 寄存器中的 DMCYCN[3:0]决定
5.5 通过 QSIO0,QSIO1,QSIO2 和 QSIO3 四根管脚进行数据接收。
6. 四线式输入输出快速读指令 四线式输入输出快速读是一种使用四根信号线进行地址发送和数据接收的读指令。
6.1 串行总线周期开始
6.2 串行闪存选择信号被置为有效状态
6.3 从QSIO0 管脚输出该指令的指令代码(EBh/ECh)
6.4 从 QSIO0,QSIO1,QSIO2 和 QSIO3 四个管脚输出目标地址,地址宽度可以通过 QSFCR 寄存器中的AWSL[1:0]位来设置。
6.5 一定数量的虚拟周期,具体数量由 QSFCR 寄存器中的 DMCYCN[3:0]决定
6.6 通过 QSIO0,QSIO1,QSIO2 和 QSIO3 四根管脚进行数据接收。
通过以上的介绍,大家应该能看的很清楚各种的数据读取方式的共同点和不同点是什么 共同点都是需要同步时钟和片选信号
不同点就是发送数据的时用的是几个引脚发送的,接收数据的时候是用的几个引脚
三 .示例解析
数据读取方式大家都清楚了,下面贴一个4线输入输出快速读取的初始化函数配置过程,首先代码如下 :
/* QSPCK Port/Pin definition */ /* QSNSS Port/Pin definition */ /* QSIO0 Port/Pin definition */ /* QSIO1 Port/Pin definition */ /* QSIO2 Port/Pin definition */ /* QSIO3 Port/Pin definition */
引脚的功能如上图所示
如果是SPI通讯的话是4根线,一个时钟线,一个片选线,两个数据线MISO和MOSI
引脚既然比SPI多那么传输的速度肯定也要比SPI速度快,所以在应用上可以来与片外的ROM RAM FLASH等进行通讯
宏定义大家都看到了对吧,下面是配置部分代码如下 :
static void QspiFlash_Init(void){ stc_qspi_init_t stcQspiInit; /* configuration structure initialization */ MEM_ZERO_STRUCT(stcQspiInit); /* Configuration peripheral clock */ PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_QSPI, Enable); /* Configuration QSPI pin */ PORT_SetFunc(QSPCK_PORT, QSPCK_PIN, Func_Qspi, Disable); PORT_SetFunc(QSNSS_PORT, QSNSS_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO0_PORT, QSIO0_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO1_PORT, QSIO1_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO2_PORT, QSIO2_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO3_PORT, QSIO3_PIN, Func_Qspi, Disable); /* Configuration QSPI structure */ stcQspiInit.enClkDiv = QspiHclkDiv3; stcQspiInit.enSpiMode = QspiSpiMode3; stcQspiInit.enBusCommMode = QspiBusModeRomAccess; stcQspiInit.enPrefetchMode = QspiPrefetchStopComplete; stcQspiInit.enPrefetchFuncEn = Disable; stcQspiInit.enQssnValidExtendTime = QspiQssnValidExtendSck32; stcQspiInit.enQssnIntervalTime = QspiQssnIntervalQsck8; stcQspiInit.enQsckDutyCorr = QspiQsckDutyCorrHalfHclk; stcQspiInit.enVirtualPeriod = QspiVirtualPeriodQsck8; stcQspiInit.enWpPinLevel = QspiWpPinOutputHigh; stcQspiInit.enQssnSetupDelayTime = QspiQssnSetupDelay1Dot5Qsck; stcQspiInit.enQssnHoldDelayTime = QspiQssnHoldDelay1Dot5Qsck; stcQspiInit.enFourByteAddrReadEn = Disable; stcQspiInit.enAddrWidth = QspiAddressByteThree; stcQspiInit.stcCommProtocol.enReadMode = QspiReadModeFourWiresOutput; stcQspiInit.stcCommProtocol.enTransInstrProtocol = QspiProtocolExtendSpi; stcQspiInit.stcCommProtocol.enTransAddrProtocol = QspiProtocolExtendSpi; stcQspiInit.stcCommProtocol.enReceProtocol = QspiProtocolExtendSpi; stcQspiInit.u8RomAccessInstr = QSPI_3BINSTR_FOUR_WIRES_OUTPUT_READ; QSPI_Init(&stcQspiInit);} 其实这部分配置代码特别好理解咱们分开来看 stc_qspi_init_t stcQspiInit;//首先是定义了一个stc_qspi_init_t 类型的局部变量stcQspiInit MEM_ZERO_STRUCT(stcQspiInit);//对stcQspiInit初始化清零操作 PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_QSPI, Enable);//开启QSPI电源,也就是要用到这个功能了 //功能定义引脚名称功能 PORT_SetFunc(QSPCK_PORT, QSPCK_PIN, Func_Qspi, Disable); PORT_SetFunc(QSNSS_PORT, QSNSS_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO0_PORT, QSIO0_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO1_PORT, QSIO1_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO2_PORT, QSIO2_PIN, Func_Qspi, Disable); PORT_SetFunc(QSIO3_PORT, QSIO3_PIN, Func_Qspi, Disable); //下面是重点了,对参数进行配置,我们来看看都配置了哪些寄存器 stcQspiInit.enClkDiv = QspiHclkDiv3; //QspiHclkDiv3 = 2u, //Clock source: HCLK/3 //串行接口基准时钟选择 // b5 b4 b3 b2 b1 b0 // 0 0 0 0 0 0:2个HCLK周期 // 0 0 0 0 0 1:2个HCLK周期* // 0 0 0 0 1 0:3个HCLK周期 // 0 0 0 0 1 1:4个HCLK周期* stcQspiInit.enSpiMode = QspiSpiMode3;//QspiSpiMode3 = 1u, PI模式选择 0:SPI模式0 1:SPI模式3 stcQspiInit.enBusCommMode = QspiBusModeRomAccess; //访问模式QspiBusModeRomAccess = 0u, Rom access mode //QSPI总线通信模式选择 //0:ROM访问模式 //1:直接通信模式 stcQspiInit.enPrefetchMode = QspiPrefetchStopComplete; //QspiPrefetchStopComplete = 0u, //Stop after prefetch data complete //选择重置预读取动作的位置 //0:当前的预读取动作在字节边界中止 //1:当前的预读取动作即时中止 stcQspiInit.enPrefetchFuncEn = Disable; //预读取功能有效/无效选择 //0:预读取功能无效 //1:预读取功能有效 stcQspiInit.enQssnValidExtendTime = QspiQssnValidExtendSck32; // QspiQssnValidExtendSck32 = 1u, // QSSN valid time extend 32 QSCK cycles // QSPI总线访问后QSSN有效时间延长功能选择 // b5 b4 // 0 0:不延长QSSN有效时间0 // 0 1:将QSSN有效时间延长32个QSCK 周期1 // 1 0:将QSSN有效时间延长128个QSCK 周期2 // 1 1:将QSSN有效时间无限延长3 stcQspiInit.enQssnIntervalTime = QspiQssnIntervalQsck8; //QspiQssnIntervalQsck8 = 7u, //QSSN signal min interval time 8 QSCK //QSSN信号最小无效时间选择 // b3 b2 b1 b0 //0 0 0 0:1个QSCK周期 //0 0 0 1:2个QSCK周期 stcQspiInit.enQsckDutyCorr = QspiQsckDutyCorrHalfHclk; //QspiQsckDutyCorrHalfHclk = 1u, //QSCK's rising edge delay 0.5 HCLK cycle when Qsck select HCLK is odd //QSCK输出波形占空比补正 //0:不进行占空比补正 //1:将QSCK的上升沿滞后0.5个HCLK周期 //(当QSCK选择的频率是HCLK的奇数倍时有效) stcQspiInit.enVirtualPeriod = QspiVirtualPeriodQsck8; QspiVirtualPeriodQsck8 = 7u,Virtual period select 8 QSCK //使用快速读指令时虚拟周期数量选择 //b3 b2 b1 b0 //0 0 0 0:3个QSCK周期*1 //0 0 0 1:4个QSCK周期 //0 0 1 0:5个QSCK周期 stcQspiInit.enWpPinLevel = QspiWpPinOutputHigh; //QspiWpPinOutputHigh = 1u, //WP pin(QIO2) output high level //WP管脚(QIO2)电平设置 //0:低电平 //1:高电平 stcQspiInit.enQssnSetupDelayTime = QspiQssnSetupDelay1Dot5Qsck; //QspiQssnSetupDelay1Dot5Qsck = 1u, //QSSN setup delay 1.5 QSCK output than QSCK first rising edge //QSSN信号输出时序选择 //0:比QSCK第一个上升沿提前0.5个QSCK输出QSSN //1:比QSCK第一个上升沿提前1.5个QSCK输出QSSN stcQspiInit.enQssnHoldDelayTime = QspiQssnHoldDelay1Dot5Qsck; //QspiQssnHoldDelay1Dot5Qsck = 1u, //QSSN hold delay 1.5 QSCK release than QSCK last rising edge //QSSN信号释放时序选择 //0:比QSCK最后一个上升沿滞后0.5个QSCK释放QSSN //1:比QSCK最后一个上升沿滞后1.5个QSCK释放QSSN stcQspiInit.enFourByteAddrReadEn = Disable; // 当地址宽度为4字节时的读指令代码选择 //0:不使用4字节地址读指令代码 //1:使用4字节地址读指令代码 stcQspiInit.enAddrWidth = QspiAddressByteThree; //QspiAddressByteThree = 2u, Three byte address //串行接口地址宽度选择 //b1 b0 //0 0:1字节 //0 1:2字节 //1 0:3字节 //1 1:4字节 stcQspiInit.stcCommProtocol.enReadMode = QspiReadModeFourWiresOutput; // QspiReadModeFourWiresIO = 5u, // Four wires input/output fast read //串行接口读取模式选择 //b2 b1 b0 //0 0 0:标准读0 //0 0 1:快速读1 //0 1 0:二线式输出快速读2 //0 1 1:二线式输入输出快速读3 //1 0 0:四线式输出快速读4 //1 0 1:四线式输入输出快速读5 //1 1 0:自定义标准读6 //1 1 1:自定义快速读7 stcQspiInit.stcCommProtocol.enTransInstrProtocol = QspiProtocolExtendSpi; stcQspiInit.stcCommProtocol.enTransAddrProtocol = QspiProtocolExtendSpi; stcQspiInit.stcCommProtocol.enReceProtocol = QspiProtocolExtendSpi; QspiProtocolExtendSpi = 0u, Extend spi protocol 指令发送阶段SPI协议选择。 地址发送阶段SPI协议选择 数据接收阶段SPI协议选择 b1 b0 0 0:扩展式SPI协议 0 1:二线式SPI协议 1 0:四线式SPI协议 1 1:设定禁止 stcQspiInit.u8RomAccessInstr = QSPI_3BINSTR_FOUR_WIRES_OUTPUT_READ; //0xEBu //替换指令代码 用于替代默认指令的串行闪存指令代码 QSPI_Init(&stcQspiInit); 以上就是我总结的QSPI的初始化部分 因为HC32F460有自己QSPI库函数,在应用的时候大家可以根据需要来调用库函数进行通讯 四. 库函数
/*********************************************************************************** \brief De-Initialize QSPI unit**** \param [in] None**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_DeInit(void)
/*********************************************************************************** \brief Initialize QSPI unit**** \param [in] pstcQspiInitCfg Pointer to qspi configuration** \arg See the struct #stc_qspi_init_t**** \retval Ok Process successfully done** \retval Error Parameter error********************************************************************************/en_result_t QSPI_Init(const stc_qspi_init_t *pstcQspiInitCfg)
/*********************************************************************************** \brief Config communication protocol structure**** \param [in] pstcCommProtocol Pointer to qspi communication protocol configuration** \arg See the struct #stc_qspi_comm_protocol_t**** \retval Ok Process successfully done** \retval Error Parameter error********************************************************************************/en_result_t QSPI_CommProtocolConfig(const stc_qspi_comm_protocol_t *pstcCommProtocol)
/*********************************************************************************** \brief Enable or disable prefetch function**** \param [in] enNewSta The function new state** \arg Disable Disable prefetch function** \arg Enable Enable prefetch function**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_PrefetchCmd(en_functional_state_t enNewSta)
/*********************************************************************************** \brief Set clock division**** \param [in] enClkDiv Clock division** \arg QspiHclkDiv2 Clock source: HCLK/2** \arg QspiHclkDiv3 Clock source: HCLK/3** \arg QspiHclkDiv4 Clock source: HCLK/4** \arg QspiHclkDiv5 Clock source: HCLK/5** \arg QspiHclkDiv6 Clock source: HCLK/6** \arg QspiHclkDiv7 Clock source: HCLK/7** \arg QspiHclkDiv8 Clock source: HCLK/8** \arg QspiHclkDiv9 Clock source: HCLK/9** \arg QspiHclkDiv10 Clock source: HCLK/10** \arg QspiHclkDiv11 Clock source: HCLK/11** \arg QspiHclkDiv12 Clock source: HCLK/12** \arg QspiHclkDiv13 Clock source: HCLK/13** \arg QspiHclkDiv14 Clock source: HCLK/14** \arg QspiHclkDiv15 Clock source: HCLK/15** \arg QspiHclkDiv16 Clock source: HCLK/16** \arg QspiHclkDiv17 Clock source: HCLK/17** \arg QspiHclkDiv18 Clock source: HCLK/18** \arg QspiHclkDiv19 Clock source: HCLK/19** \arg QspiHclkDiv20 Clock source: HCLK/20** \arg QspiHclkDiv21 Clock source: HCLK/21** \arg QspiHclkDiv22 Clock source: HCLK/22** \arg QspiHclkDiv23 Clock source: HCLK/23** \arg QspiHclkDiv24 Clock source: HCLK/24** \arg QspiHclkDiv25 Clock source: HCLK/25** \arg QspiHclkDiv26 Clock source: HCLK/26** \arg QspiHclkDiv27 Clock source: HCLK/27** \arg QspiHclkDiv28 Clock source: HCLK/28** \arg QspiHclkDiv29 Clock source: HCLK/29** \arg QspiHclkDiv30 Clock source: HCLK/30** \arg QspiHclkDiv31 Clock source: HCLK/31** \arg QspiHclkDiv32 Clock source: HCLK/32** \arg QspiHclkDiv33 Clock source: HCLK/33** \arg QspiHclkDiv34 Clock source: HCLK/34** \arg QspiHclkDiv35 Clock source: HCLK/35** \arg QspiHclkDiv36 Clock source: HCLK/36** \arg QspiHclkDiv37 Clock source: HCLK/37** \arg QspiHclkDiv38 Clock source: HCLK/38** \arg QspiHclkDiv39 Clock source: HCLK/39** \arg QspiHclkDiv40 Clock source: HCLK/40** \arg QspiHclkDiv41 Clock source: HCLK/41** \arg QspiHclkDiv42 Clock source: HCLK/42** \arg QspiHclkDiv43 Clock source: HCLK/43** \arg QspiHclkDiv44 Clock source: HCLK/44** \arg QspiHclkDiv45 Clock source: HCLK/45** \arg QspiHclkDiv46 Clock source: HCLK/46** \arg QspiHclkDiv47 Clock source: HCLK/47** \arg QspiHclkDiv48 Clock source: HCLK/48** \arg QspiHclkDiv49 Clock source: HCLK/49** \arg QspiHclkDiv50 Clock source: HCLK/50** \arg QspiHclkDiv51 Clock source: HCLK/51** \arg QspiHclkDiv52 Clock source: HCLK/52** \arg QspiHclkDiv53 Clock source: HCLK/53** \arg QspiHclkDiv54 Clock source: HCLK/54** \arg QspiHclkDiv55 Clock source: HCLK/55** \arg QspiHclkDiv56 Clock source: HCLK/56** \arg QspiHclkDiv57 Clock source: HCLK/57** \arg QspiHclkDiv58 Clock source: HCLK/58** \arg QspiHclkDiv59 Clock source: HCLK/59** \arg QspiHclkDiv60 Clock source: HCLK/60** \arg QspiHclkDiv61 Clock source: HCLK/61** \arg QspiHclkDiv62 Clock source: HCLK/62** \arg QspiHclkDiv63 Clock source: HCLK/63** \arg QspiHclkDiv64 Clock source: HCLK/64**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_SetClockDiv(en_qspi_clk_div_t enClkDiv)
/*********************************************************************************** \brief Set WP Pin level**** \param [in] enWpLevel WP pin level** \arg QspiWpPinOutputLow WP pin(QIO2) output low level** \arg QspiWpPinOutputHigh WP pin(QIO2) output high level**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_SetWPPinLevel(en_qspi_wp_pin_level_t enWpLevel)
/*********************************************************************************** \brief Set communication address width**** \param [in] enAddrWidth Communication address width** \arg QspiAddressByteOne One byte address** \arg QspiAddressByteTwo Two byte address** \arg QspiAddressByteThree Three byte address** \arg QspiAddressByteFour Four byte address**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_SetAddrWidth(en_qspi_addr_width_t enAddrWidth)
/*********************************************************************************** \brief Set extend address value**** \param [in] u8Addr Extend address value** \arg 0~0x3F**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_SetExtendAddress(uint8_t u8Addr)
/*********************************************************************************** \brief Set rom access instruction**** \param [in] u8Instr Rom access instruction** \arg 0~0xFF**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_SetRomAccessInstruct(uint8_t u8Instr)
/*********************************************************************************** \brief Read direct communication value**** \param [in] None**** \retval uint8_t Direct communication read value********************************************************************************/uint8_t QSPI_ReadDirectCommValue(void)
/*********************************************************************************** \brief Enable or disable xip mode**** \param [in] u8Instr Enable or disable xip mode instruction** \arg 0~0xFF**** \param [in] enNewSta The function new state** \arg Disable Disable xip mode** \arg Enable Enable xip mode**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_XipModeCmd(uint8_t u8Instr, en_functional_state_t enNewSta)
/*********************************************************************************** \brief Enter direct communication mode**** \param [in] None**** \retval Ok Process successfully done**** \note If you are in XIP mode, you need to exit XIP mode and then start direct communication mode.********************************************************************************/en_result_t QSPI_EnterDirectCommMode(void)
/*********************************************************************************** \brief Exit direct communication mode**** \param [in] None**** \retval Ok Process successfully done********************************************************************************/en_result_t QSPI_ExitDirectCommMode(void)
/*********************************************************************************** \brief Get prefetch buffer current byte number**** \param [in] None**** \retval uint8_t Current buffer byte number********************************************************************************/uint8_t QSPI_GetPrefetchBufferNum(void)
/*********************************************************************************** \brief Get flag status**** \param [in] enFlag Choose need get status's flag** \arg QspiFlagBusBusy QSPI bus work status flag in direct communication mode** \arg QspiFlagXipMode XIP mode status signal** \arg QspiFlagRomAccessError Trigger rom access error flag in direct communication mode** \arg QspiFlagPrefetchBufferFull Prefetch buffer area status signal** \arg QspiFlagPrefetchStop Prefetch action status signal**** \retval Set Flag is set** \retval Reset Flag is reset********************************************************************************/en_flag_status_t QSPI_GetFlag(en_qspi_flag_type_t enFlag)
/*********************************************************************************** \brief Clear flag status**** \param [in] enFlag Choose need get status's flag** \arg QspiFlagRomAccessError Trigger rom access error flag in direct communication mode**** \retval Ok Process successfully done** \retval ErrorInvalidParameter Parameter error********************************************************************************/en_result_t QSPI_ClearFlag(en_qspi_flag_type_t enFlag) 以上就是库函数部分,大家可以来调用库函数进行编程,如果技术好的可以直接调用寄存器来写 ^_^本文系21ic论坛网友 binoo7原创
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!