上回我们说到了MG32F02A的UART0通过DMA方式进行串口接收。
这次我们来看一下SPI应该如何使用。
由于标准四线制SPI是全双工的双向总线,所以在你发送的同时也发生了接收,因此读写的方式是不一样的,需要用不同的办法来进行主从机的通讯。
首先发主机的发送程序:
- #include "MG32x02z_DRV.H"
- typedef uint8_t u8;
- typedef uint16_t u16;
- typedef uint32_t u32;
- typedef uint64_t u64;
- #define Dummy_Data 0xFFFFFFFF
- #define SPI_NSS PB0 // SPI_NSS
- void CSC_Init (void)
- {
- CSC_PLL_TyprDef CSC_PLL_CFG;
- UnProtectModuleReg(MEMprotect); // Setting flash wait state
- MEM_SetFlashWaitState(MEM_FWAIT_ONE); // 50MHz> Sysclk >=25MHz
- ProtectModuleReg(MEMprotect);
- UnProtectModuleReg(CSCprotect);
- CSC_CK_APB_Divider_Select(APB_DIV_1); // Modify CK_APB divider APB=CK_MAIN/1
- CSC_CK_AHB_Divider_Select(AHB_DIV_1); // Modify CK_AHB divider AHB=APB/1
- /* CK_HS selection */
- CSC_IHRCO_Select(IHRCO_12MHz); // IHRCO Sel 12MHz
- CSC_IHRCO_Cmd(ENABLE);
- while(CSC_GetSingleFlagStatus(CSC_IHRCOF) == DRV_Normal);
- CSC_ClearFlag(CSC_IHRCOF);
- CSC_CK_HS_Select(HS_CK_IHRCO); // CK_HS select IHRCO
- /* PLL */
- /**********************************************************/
- CSC_PLL_CFG.InputDivider=PLLI_DIV_2; // 12M/2=6M
- CSC_PLL_CFG.Multiplication=PLLIx16; // 6M*16=96M
- CSC_PLL_CFG.OutputDivider=PLLO_DIV_2; // PLLO=96M/2=48M
- CSC_PLL_Config(&CSC_PLL_CFG);
- CSC_PLL_Cmd(ENABLE);
- while(CSC_GetSingleFlagStatus(CSC_PLLF) == DRV_Normal);
- CSC_ClearFlag(CSC_PLLF);
- /**********************************************************/
- /* CK_MAIN */
- CSC_CK_MAIN_Select(MAIN_CK_HS);
- /* Configure ICKO function */
- /* Configure peripheral clock */
- CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB);
- CSC_PeriphOnModeClock_Config(CSC_ON_SPI0,ENABLE);
- CSC_PeriphOnModeClock_Config(CSC_ON_PortB,ENABLE);
- CSC_PeriphOnModeClock_Config(CSC_ON_PortE,ENABLE);
- ProtectModuleReg(CSCprotect);
- }
- void InitSPI0(void)
- {
- PIN_InitTypeDef PINX_InitStruct;
- //===Set CSC init====
- //MG32x02z_CSC_Init.h(Configuration Wizard)
- //Select CK_HS source = CK_IHRCO
- //Select IHRCO = 12Mz
- //Select CK_MAIN Source = CK_HS
- //Configure PLL->Select APB Prescaler = CK_MAIN/1
- /*=== 1. Enable CSC to SPI clock ===*/
- //[A] When Use Wizard
- //Configure Peripheral On Mode Clock->SPI0 = Enable and Select SPI0_PR Source = CK_APB
- //Configure Peripheral On Mode Clock->Port B = Enable
- //[B] When Use Driver
- // UnProtectModuleReg(CSCprotect); // Unprotect CSC module
- // CSC_PeriphOnModeClock_Config(CSC_ON_SPI0, ENABLE); // Enable SPI0 module clock
- // CSC_PeriphOnModeClock_Config(CSC_ON_PortB, ENABLE); // Enable PortB clock
- // CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB); // CK_SPIx_PR = CK_APB = 12MHz
- // ProtectModuleReg(CSCprotect); // protect CSC module
- /*=== 2. Default Initial SPI ===*/
- SPI_DeInit(SPI0);
- /*=== 3. Configure clock divider ===*/ // SPI clock = 1MHz
- SPI_Clock_Select(SPI0, SPI_CK_SPIx_PR); // CK_SPIx = CK_SPIx_PR
- SPI_PreDivider_Select(SPI0, SPI_PDIV_2); // PDIV outpu = CK_SPIx /2
- SPI_Prescaler_Select(SPI0, SPI_PSC_3); // Prescaler outpu = PDIV outpu /3
- SPI_Divider_Select(SPI0, SPI_DIV_2); // DIV outpu = PDIV outpu /2
- /*=== 4. Configure SPI data line, mode and data size... ===*/
- SPI_DataLine_Select(SPI0, SPI_Standard); // SPI Standard Mode
- SPI_ModeAndNss_Select(SPI0, SPI_Master); // Master
- SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge); // CPHA = 0
- SPI_ClockPolarity_Select(SPI0, SPI_Low); // CPOL = 0
- SPI_FirstBit_Select(SPI0, SPI_MSB); // MSB first
- SPI_DataSize_Select(SPI0, SPI_8bits); // Data size 8bits
- /*=== 5. Config SPI0 IO ===*/
- PINX_InitStruct.PINX_Mode = PINX_Mode_PushPull_O; // Pin select pusu pull mode
- PINX_InitStruct.PINX_PUResistant = PINX_PUResistant_Enable; // Enable pull up resistor
- PINX_InitStruct.PINX_Speed = PINX_Speed_Low;
- PINX_InitStruct.PINX_OUTDrive = PINX_OUTDrive_Level1; // Pin output driver full strength.
- PINX_InitStruct.PINX_FilterDivider = PINX_FilterDivider_Bypass;// Pin input deglitch filter clock divider bypass
- PINX_InitStruct.PINX_Inverse = PINX_Inverse_Disable; // Pin input data not inverse
- PINX_InitStruct.PINX_Alternate_Function = 2; // Pin AFS = 2
- GPIO_PinMode_Config(PINB(2),&PINX_InitStruct); // CLK setup at PB2
- PINX_InitStruct.PINX_OUTDrive = PINX_OUTDrive_Level1; // Pin output drive strength 1/4
- GPIO_PinMode_Config(PINB(3),&PINX_InitStruct); // MOSI setup at PB3
- PINX_InitStruct.PINX_Mode = PINX_Mode_OpenDrain_O; // Setting open drain mode
- PINX_InitStruct.PINX_Alternate_Function = 2; // Pin AFS = 2
- GPIO_PinMode_Config(PINB(1),&PINX_InitStruct); // MISO setup at PB1
- PINX_InitStruct.PINX_Alternate_Function = 0; // Pin AFS = 0
- GPIO_PinMode_Config(PINB(0),&PINX_InitStruct); // NSS setup at PB0
- PINX_InitStruct.PINX_Mode = PINX_Mode_OpenDrain_O; // Pin select Push Pull mode
- PINX_InitStruct.PINX_Alternate_Function = 0; // Pin AFS = 0
- GPIO_PinMode_Config(PINE(13),&PINX_InitStruct); // PE13
- GPIO_PinMode_Config(PINE(14),&PINX_InitStruct); // PE14
- /*=== 6. Enable SPI ===*/
- SPI_Cmd(SPI0, ENABLE);
- }
- int main()
- {
- u32 i,y;
- u8 x;
- uint32_t RDAT;
- CSC_Init();
- InitSPI0();
- x=y=0;
- i=0;
- while(1)
- {
- i++;
- if(i>=500000)
- {
- i=0;
- SPI_NSS = 0;
- PE13=0;
- SPI_SetTxData(SPI0, SPI_1Byte, 0x05); // Send 1 byte and received 1 byte the same time
- while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened); // Wait TCF flag
- SPI_ClearFlag(SPI0, SPI_TCF); // Clear flag
- SPI_NSS = 1;
- PE13=1;
- }
- }
- }
在发送的时候比较简单,直接主机拉低NSS线之后使用SPI_SetTxData函数直接发送你要发送的数据即可,后面的while保证了数据发送的完整性,发送完成之后需要手动清除flag并拉高NSS线,就这样,数据就发送到从机上去了。
从机接收程序:
- #include "MG32x02z_DRV.H"
- #include
- typedef uint8_t u8;
- typedef uint16_t u16;
- typedef uint32_t u32;
- typedef uint64_t u64;
- #define Dummy_Data 0xFFFFFFFF
- #define SPI_NSS PB0 // SPI_NSS
- #define URTX URT0
- void CSC_Init (void)
- {
- CSC_PLL_TyprDef CSC_PLL_CFG;
- UnProtectModuleReg(MEMprotect); // Setting flash wait state
- MEM_SetFlashWaitState(MEM_FWAIT_ONE); // 50MHz> Sysclk >=25MHz
- ProtectModuleReg(MEMprotect);
- UnProtectModuleReg(CSCprotect);
- CSC_CK_APB_Divider_Select(APB_DIV_1); // Modify CK_APB divider APB=CK_MAIN/1
- CSC_CK_AHB_Divider_Select(AHB_DIV_1); // Modify CK_AHB divider AHB=APB/1
- /* CK_HS selection */
- CSC_IHRCO_Select(IHRCO_12MHz); // IHRCO Sel 12MHz
- CSC_IHRCO_Cmd(ENABLE);
- while(CSC_GetSingleFlagStatus(CSC_IHRCOF) == DRV_Normal);
- CSC_ClearFlag(CSC_IHRCOF);
- CSC_CK_HS_Select(HS_CK_IHRCO); // CK_HS select IHRCO
- /* PLL */
- /**********************************************************/
- CSC_PLL_CFG.InputDivider=PLLI_DIV_2; // 12M/2=6M
- CSC_PLL_CFG.Multiplication=PLLIx16; // 6M*16=96M
- CSC_PLL_CFG.OutputDivider=PLLO_DIV_2; // PLLO=96M/2=48M
- CSC_PLL_Config(&CSC_PLL_CFG);
- CSC_PLL_Cmd(ENABLE);
- while(CSC_GetSingleFlagStatus(CSC_PLLF) == DRV_Normal);
- CSC_ClearFlag(CSC_PLLF);
- /**********************************************************/
- /* CK_MAIN */
- CSC_CK_MAIN_Select(MAIN_CK_HS);
- /* Configure ICKO function */
- /* Configure peripheral clock */
- CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB);
- CSC_PeriphProcessClockSource_Config(CSC_UART0_CKS, CK_APB);
- CSC_PeriphOnModeClock_Config(CSC_ON_SPI0,ENABLE);
- CSC_PeriphOnModeClock_Config(CSC_ON_UART0,ENABLE);
- CSC_PeriphOnModeClock_Config(CSC_ON_PortB,ENABLE);
- CSC_PeriphOnModeClock_Config(CSC_ON_PortE,ENABLE);
- ProtectModuleReg(CSCprotect);
- }
- int fputc(int ch,FILE *f)
- {
- URT_SetTXData(URTX,1,ch);
- while(URT_GetITSingleFlagStatus(URTX,URT_IT_TC)==DRV_UnHappened);
- URT_ClearITFlag(URTX,URT_IT_TC);
- return ch;
- }
- void UartSendByte(int ch)
- {
- URT_SetTXData(URTX,1,ch);
- while(URT_GetITSingleFlagStatus(URTX,URT_IT_TC)==DRV_UnHappened);
- URT_ClearITFlag(URTX,URT_IT_TC);
- }
- void URT0_Init(void)
- {
- URT_BRG_TypeDef URT_BRG;
- URT_Data_TypeDef DataDef;
- PIN_InitTypeDef PINX_InitStruct;
- //==Set GPIO init
- //PB8 PPO TX ,PB9 ODO RX
- PINX_InitStruct.PINX_Mode = PINX_Mode_PushPull_O; // Pin select Push Pull mode
- PINX_InitStruct.PINX_PUResistant = PINX_PUResistant_Enable; // Enable pull up resistor
- PINX_InitStruct.PINX_Speed = PINX_Speed_Low;
- PINX_InitStruct.PINX_OUTDrive = PINX_OUTDrive_Level0; // Pin output driver full strength.
- PINX_InitStruct.PINX_FilterDivider = PINX_FilterDivider_Bypass; // Pin input deglitch filter clock divider bypass
- PINX_InitStruct.PINX_Inverse = PINX_Inverse_Disable; // Pin input data not inverse
- PINX_InitStruct.PINX_Alternate_Function = PB8_AF_URT0_TX; // Pin AFS = URT0_TX
- GPIO_PinMode_Config(PINB(8),&PINX_InitStruct); // TXD at PB8
- PINX_InitStruct.PINX_Mode = PINX_Mode_OpenDrain_O; // Pin select Open Drain mode
- PINX_InitStruct.PINX_Alternate_Function = PB9_AF_URT0_RX; // Pin AFS = URT0_RX
- GPIO_PinMode_Config(PINB(9),&PINX_InitStruct); // RXD at PB9
- //=====Set Clock=====//
- //---Set BaudRate---//
- URT_BRG.URT_InteranlClockSource = URT_BDClock_PROC;
- URT_BRG.URT_BaudRateMode = URT_BDMode_Separated;
- URT_BRG.URT_PrescalerCounterReload = 0; //Set PSR
- URT_BRG.URT_BaudRateCounterReload = 3; //Set RLR
- URT_BaudRateGenerator_Config(URTX, &URT_BRG); //BR115200 = f(CK_URTx)/(PSR+1)/(RLR+1)/(OS_NUM+1)
- URT_BaudRateGenerator_Cmd(URTX, ENABLE); //Enable BaudRateGenerator
- //---TX/RX Clock---//
- URT_TXClockSource_Select(URTX, URT_TXClock_Internal); //URT_TX use BaudRateGenerator
- URT_RXClockSource_Select(URTX, URT_RXClock_Internal); //URT_RX use BaudRateGenerator
- URT_TXOverSamplingSampleNumber_Select(URTX, 25); //Set TX OS_NUM
- URT_RXOverSamplingSampleNumber_Select(URTX, 25); //Set RX OS_NUM
- URT_RXOverSamplingMode_Select(URTX, URT_RXSMP_3TIME);
- URT_TX_Cmd(URTX, ENABLE); //Enable TX
- URT_RX_Cmd(URTX, ENABLE); //Enable RX
- //=====Set Mode=====//
- //---Set Data character config---//
- DataDef.URT_TX_DataLength = URT_DataLength_8;
- DataDef.URT_RX_DataLength = URT_DataLength_8;
- DataDef.URT_TX_DataOrder = URT_DataTyped_LSB;
- DataDef.URT_RX_DataOrder = URT_DataTyped_LSB;
- DataDef.URT_TX_Parity = URT_Parity_No;
- DataDef.URT_RX_Parity = URT_Parity_No;
- DataDef.URT_TX_StopBits = URT_StopBits_1_0;
- DataDef.URT_RX_StopBits = URT_StopBits_1_0;
- DataDef.URT_TX_DataInverse = DISABLE;
- DataDef.URT_RX_DataInverse = DISABLE;
- URT_DataCharacter_Config(URTX, &DataDef);
- //---Set Mode Select---//
- URT_Mode_Select(URTX, URT_URT_mode);
- //---Set DataLine Select---//
- URT_DataLine_Select(URTX, URT_DataLine_2);
- //=====Set Data Control=====//
- URT_RXShadowBufferThreshold_Select(URTX, URT_RXTH_1BYTE);
- URT_IdlehandleMode_Select(URTX, URT_IDLEMode_No);
- URT_TXGaudTime_Select(URTX, 0);
- //=====Enable URT Interrupt=====//
- //URT_IT_Cmd(URTX, URT_IT_RX, ENABLE);
- //URT_ITEA_Cmd(URTX, ENABLE);
- //NVIC_EnableIRQ(URT0_IRQn);
- //=====Enable URT=====//
- URT_Cmd(URTX, ENABLE);
- //==See MG32x02z_URT0_IRQ.c when interrupt in
- }
- void InitSPI0(void)
- {
- PIN_InitTypeDef PINX_InitStruct;
- //===Set CSC init====
- //MG32x02z_CSC_Init.h(Configuration Wizard)
- //Select CK_HS source = CK_IHRCO
- //Select IHRCO = 12Mz
- //Select CK_MAIN Source = CK_HS
- //Configure PLL->Select APB Prescaler = CK_MAIN/1
- /*=== 1. Enable CSC to SPI clock ===*/
- //[A] When Use Wizard
- //Configure Peripheral On Mode Clock->SPI0 = Enable and Select SPI0_PR Source = CK_APB
- //Configure Peripheral On Mode Clock->Port B = Enable
- //[B] When Use Driver
- // UnProtectModuleReg(CSCprotect); // Unprotect CSC module
- // CSC_PeriphOnModeClock_Config(CSC_ON_SPI0, ENABLE); // Enable SPI0 module clock
- // CSC_PeriphOnModeClock_Config(CSC_ON_PortB, ENABLE); // Enable PortB clock
- // CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB); // CK_SPIx_PR = CK_APB = 12MHz
- // ProtectModuleReg(CSCprotect); // protect CSC module
- /*=== 2. Default Initial SPI ===*/
- SPI_DeInit(SPI0);
- /*=== 3. Configure clock divider ===*/ // SPI clock = 1MHz
- SPI_Clock_Select(SPI0, SPI_CK_SPIx_PR); // CK_SPIx = CK_SPIx_PR
- SPI_PreDivider_Select(SPI0, SPI_PDIV_2); // PDIV outpu = CK_SPIx /2
- SPI_Prescaler_Select(SPI0, SPI_PSC_3); // Prescaler outpu = PDIV outpu /3
- SPI_Divider_Select(SPI0, SPI_DIV_2); // DIV outpu = PDIV outpu /2
- /*=== 4. Configure SPI data line, mode and data size... ===*/
- SPI_DataLine_Select(SPI0, SPI_Standard); // SPI data line 1-line Bidirectional~ SPI0_MOSI
- SPI_ModeAndNss_Select(SPI0, SPI_SlaveWithNss); // Slave
- SPI_NSSInputSignal_Select(SPI0,SPI_NssPin); // Nss
- SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge); // CPHA = 0
- SPI_ClockPolarity_Select(SPI0, SPI_Low); // CPOL = 0
- SPI_FirstBit_Select(SPI0, SPI_MSB); // MSB first
- SPI_DataSize_Select(SPI0, SPI_8bits); // Data size 8bits
- SPI_SlaveModeReceivedThreshold_Select(SPI0, SPI_1Byte); // Set SPI0 received data buffer high threshold
- /*=== 5. Config SPI0 IO ===*/
- PINX_InitStruct.PINX_Mode = PINX_Mode_Digital_I; // Pin select digital input mode
- PINX_InitStruct.PINX_PUResistant = PINX_PUResistant_Enable; // Enable pull up resistor
- PINX_InitStruct.PINX_Speed = PINX_Speed_Low;
- PINX_InitStruct.PINX_OUTDrive = PINX_OUTDrive_Level0; // Pin output driver full strength.
- PINX_InitStruct.PINX_FilterDivider = PINX_FilterDivider_Bypass;// Pin input deglitch filter clock divider bypass
- PINX_InitStruct.PINX_Inverse = PINX_Inverse_Disable; // Pin input data not inverse
- PINX_InitStruct.PINX_Alternate_Function = 2; // Pin AFS = 2
- GPIO_PinMode_Config(PINB(0),&PINX_InitStruct); // NSS setup at PB0
- GPIO_PinMode_Config(PINB(2),&PINX_InitStruct); // CLK setup at PB2
- GPIO_PinMode_Config(PINB(3),&PINX_InitStruct); // MOSI setup at PB3
- PINX_InitStruct.PINX_Mode = PINX_Mode_PushPull_O; // Setting pusu pull mode
- GPIO_PinMode_Config(PINB(1),&PINX_InitStruct); // MISO setup at PB1
- PINX_InitStruct.PINX_Mode = PINX_Mode_OpenDrain_O; // Setting pusu pull mode
- PINX_InitStruct.PINX_Alternate_Function = 0; // Pin AFS = 0
- GPIO_PinMode_Config(PINE(13),&PINX_InitStruct); // D4 setup at PE13
- GPIO_PinMode_Config(PINE(14),&PINX_InitStruct); // D4 setup at PE13
- GPIO_PinMode_Config(PINE(15),&PINX_InitStruct); // D6 setup at PE15
- /*=== 6. Enable SPI ===*/
- SPI_Cmd(SPI0, ENABLE); // Enable SPI
- }
- int main()
- {
- uint32_t RDAT,TDAT;
- int i;
- CSC_Init();
- InitSPI0();
- URT0_Init();
- printf("hellon");
- while(1)
- {
- i++;
- if(i>=500000)
- {
- i=0;
- PE13=0;
- SPI_SetTxData(SPI0, SPI_1Byte, Dummy_Data); // Received 1 byte and send 1 byte the same time
- while(SPI_GetSingleFlagStatus(SPI0, SPI_RXF) == DRV_UnHappened); // Wait RXF flag
- SPI_ClearFlag(SPI0, (SPI_TXF | SPI_RXF)); // Clear TXF and RXF
- RDAT = SPI_GetRxData(SPI0); // Get received data
- printf("0x%02Xn",RDAT);
- PE13=1;
- }
- }
- }
你会发现,从机接收的部分就不一样了,首先,那个0x00是什么意思呢?刚刚我们说过,SPI总线比较特殊,发送的同时你就接收了一次数据,因此,你要接收数据,你就要发送数据,如果你要接收的数据是1字节的数据,就只需要发0x00,如果是3字节的数据,则需要发送0xffffff,因此平时方便起见直接发0xffffff即可,然后发送出去后等带flag的到来即可完成接收过程。
从机要反过来做发送也是和主机一样的道理,仿照主机即可。
另外从机建议模式选择SlaveWithNSS,为什么呢,因为这样的话能保证主机故障重启后从机接收到的数据依然是正常的,不然从机会一直接受到错误的数据直到你复位从机。
|