工具/软件:Code Composer Studio
大家好
现在、我需要两个 EXP_MSP430F5529LP 开发板来验证 SPI 通信、一个主模式(运行 ti-RTOS)、另一个运行 SPI 从模式(没有 ti-RTOS)、现在我使用【MSP430F55xx_USCI_SPI_standard_slave】SPI 从模式的示例代码。
现在 、我发现 SPI 主模式在第一次读取数据时只是正常的、其余的则发生故障、您必须将从模式开发板复位一次才能读取正常数据。我不知道为什么? 现在只想将从模块板仿真为 SPI 闪存、谁有更好的建议?
谢谢你
XC_MO
MSP430F55xx_USCI_SPI_standard_slave 代码
// // MSP430F552x 演示- USCI_A0、SPI 三线制从器件多字节 RX/TX // 说明:SPI 主器件与 SPI 从器 件通信发送和接收// 3条不同长度的消息。 SPI 从器 件将在等待使用 SPI 中断发送/接收消息时进入 LPM0 //。 // ACLK = nA、MCLK = SMCLK = DCO 16MHz。 // // //////// MSP430F5529 // -------- // /|\| P2.0|<-主器件的 GPIO (芯片选择) // || | // ---|RST RST |<-主器件的 GPIO (用于复位从器件) // | | // | P3.3|<-数据输入(UCA0SIMO) // | | // | P3.4|->数据输出(UCA0SOMI) // | | // | P2.7|-串行时钟输入(UCA0CLK) // Nima Eskandari // Texas Instruments Inc. // 2017年4月 //使用 CCS V7.0构建 /********* #include #include #include // //示例命令(Example Commands Commands // #define 虚拟0xFF #define SLAVE_CS_IN P2IN #define SLAVE_CS_DIR P2DIR #define SLAVE_CS_PIN BIT0 /* CMD_TYPE_X_SLAVE 是主器件发送到从器件的示例命令。 *从属方将发送示例 SlaveTypeX 缓冲区进行响应。 * * CMD_TYPE_X_MASTER 是主器件发送到从器件的示例命令。 *从器件将初始化自身以接收 MasterTypeX 示例缓冲区。 **/ #define CMD_TYPE_0_SLAVE 0 #define CMD_TYPE_1_SLAVE 1 #define CMD_TYPE_2_SLAVE 2 #define CMD_TYPE_0_MASTER 3 #define CMD_TYPE_1_MASTER 4 #define CMD_TYPE_2_MASTER 5 #define TYPE_0_LENGTH 1 #define TYPE_1_LENGTH 2 #define TYPE_2_LENGTH 6 #define MAX_BUFFER_SIZE 20 /* MasterTypeX 是在主设备中初始化的示例缓冲 区,主设备将*将它们发送给从设备。 * SlaveTypeX 是在从器件中初始化的示例缓冲 区,它们将由从器件*发送到主器件。 */ uint8_t MasterType2 [type_2_length]={0}; uint8_t MasterType1 [type_1_length]={0、0}; uint8_t MasterType0 [type_0_length]={0}; uint8_t SlaveType2 [type_2_length]={1、'D'、'D'、'1'、'D' '2'}; uint8_t SlaveType1 [TYP_1_LENGTH]={0x15、0x16}; uint8_t SlaveType0 [TYP_0_LENGTH]={0x11}; //********* //通用 SPI 状态机 // typedef 枚举 SPI_ModeEnum{ IDLE_MODE、 TX_REG_ADDRESS_MODE、 RX_REG_ADDRESS_MODE、 TX_DATA_MODE、 RX_DATA_MODE、 timeout_mode }SPI_Mode; //用于跟踪软件状态机的状态*/ SPI_Mode SlaveMode = RX_REG_ADDRESS_MODE; //要使用的寄存器地址/命令*/ uint8_t ReceiveRegAddr = 0; // ReceiveBuffer:用于接收 ISR 中数据的缓冲 区* RXByteCtr:要接收的字节数 *索引: ReceiveBuffer * TransmitBuffer:用于在 ISR 中传输数据的缓冲区 * TXByteCtr:剩余要传输的字节数 * TransmitIndex:要在 TransmitBuffer 中传输的下一个字节的索引 */ uint8_t ReceiveBuffer[MAX_buffer_size]={0}; uint8_t RXByteCtr = 0; uint8_t ProcesseIndex = 0; uint8_t TransmitBuffer[MAX_buffer_size]={0}; uint8_t TXByteCtr = 0; uint8_t TransmitIndex = 0; //根据接收到的 cmd * 命令初始化软件状态机* cmd:uint8_t transmitCtr = 0;uint8_t received * uint8命令* uintmtrl * void * mcmd_t register /*从设备和主设备之间的传输已完成。 使用 cmd *执行事务后操作。 (将数据从 SendeBuffer *放置到基于上次接收的相应缓冲区 cmd) * cmd:与已完成 的*事务对应的命令/寄存器地址 * / void SPI_Slave_TransactionDone (uint8_t cmd); void CopyArray (uint8_t * source、uint8_t * dest、uint8_t count); void CopyData (uint8_t);uint0ival (uint0uintval) void SendUCA0Data (uint8_t val) { while (!(UCA0IFG & UCTXIFG)); // USCI_A0 TX 缓冲器就绪? UCA0TXBUF = val; } void SPI_Slave_ProcessCMD (uint8_t cmd) { ReceiveIndex = 0; TransmitIndex = 0; RXByteCtr = 0; TXByteCtr = 0; 开关(cmd) { 情况(CMD_TYPE_0_SLAVE): //发送从属设备 ID (此设备的 ID) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_0_LENGTH; //填充 TransmitBuffer CopyArray (SlaveType0、TransmitBuffer、TYPE_0_LENGTH); //发送第一个字节 SendUCA0Data (TransmitBuffer[TransmitIndex++]); TXByteCtr --; 中断; 情况(CMD_TYPE_1_SLAVE): //发送从设备时间(该设备的时间) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_1_LENGTH; //填充 TransmitBuffer CopyArray (SlaveType1、TransmitBuffer、type_1_length); //发送第一个字节 SendUCA0Data (TransmitBuffer[TransmitIndex++]); TXByteCtr --; 中断; 情况(CMD_TYPE_2_SLAVE): //发送从属设备位置(该设备的位置) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_2_LENGTH; //填充 TransmitBuffer CopyArray (SlaveType2、TransmitBuffer、TYPE_2_LENGTH); //发送第一个字节 SendUCA0Data (TransmitBuffer[TransmitIndex++]); TXByteCtr --; 中断; 情况(CMD_TYPE_0_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_0_LENGTH; 中断; 情况(CMD_TYPE_1_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_1_LENGTH; 中断; 情况(CMD_TYPE_2_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_2_LENGTH; 中断; 默认值: //while (1); __no_operation(); 中断; } } void SPI_Slave_TransactionDone (uint8_t cmd) { 开关(cmd) { 情况(CMD_TYPE_0_SLAVE): //从设备 ID 已发送(此设备的 ID) 中断; 情况(CMD_TYPE_1_SLAVE): //从器件时间已发送(此器件的时间) 中断; 情况(CMD_TYPE_2_SLAVE): //发送从属设备位置(该设备的位置) 中断; 情况(CMD_TYPE_0_MASTER): CopyArray (ReceiveBuffer、MasterType0、TYPE_0_LENGTH); 中断; 情况(CMD_TYPE_1_MASTER): CopyArray (ReceiveBuffer、MasterType1、Type_1_length); 中断; 情况(CMD_TYPE_2_MASTER): CopyArray (ReceiveBuffer、MasterType2、TYPE_2_LENGTH); 中断; 默认值: __no_operation(); 中断; } } void CopyArray (uint8_t *源、uint8_t * dest、uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0;copyIndex < count;copyIndex++) { dest[copyIndex]= source[copyIndex]; } } //********* //设备初始化 // void initGPIO() { //LEDs P1OUT = 0x00; //针对 LED 和复位输出 P1DIR 的 P1设置 |= BIT0 + BIT4; P4DIR |= BIT7; P4OUT &=~(BIT4); //SPI 引脚 P3SEL |= BIT3 + BIT4; // P3.3、4选项选择 P2SEL |= BIT7; // P2.7选项选择 } void initSPI() {// 时钟极性:无效状态为高 电平//MSB 优先,8位,主器件,3引脚模式,同步 UCA0CTL1 = UCSWRST; //**将状态机复位** UCA0CTL0 |= UCCKPL + UCMSB + UCSYNC; // 3引脚8位 SPI 从 器件 UCA0CTL1 &=~UCSWRST; //**初始化 USCI 状态机** UCA0IE |= UCRXIE; //启用 USCI0 RX 中断 slave_CS_DIR &=~(slave_CS_PIN); } void initClockTo16MHz () { UCSCTL3 |= SELREF_2; //设置 DCO FLL 基准= REFO UCSCTL4 |= SE拉美 经济体系2; //设置 ACLK = REFO _bis_SR_register (SCG0); //禁用 FLL 控制环路 UCSCTL0 = 0x0000; //设置可能的最低 DCOx、MODx UCSCTL1 = DCORSEL_5; //选择 DCO 范围16MHz 操作 UCSCTL2 = FLLD_0 + 487; //将 DCO 乘法器设置为16MHz //(N + 1)* FLLRef = Fdco //(487 + 1)* 32768 = 16MHz //设置 FLL Div = fDCOCLK _BIC_SR_register (SCG0); //启用 FLL 控制环路 // DCO 范围位已经存在时、DCO 的最坏情况稳定时间 //已更改 n x 32 x 32 x f_MCLK / f_FLL_reference。 请参阅5xx 中的 UCS 一章 // UG 进行优化。 // 32 x 32 x 16 MHz/32、768Hz = 500000 = DCO 稳定的 MCLK 周期 _DELAY_CYCLES (50000);// //循环直到 XT1、XT2和 DCO 故障标志被清除 操作 { UCSCTL7 &=~(XT2OFFG + XT1LFOFFG + DCOFFG);//清除 XT2、XT1、DCO 故障标志 SFRIFG1 &=~OFIFG; //清除故障标志 } while (SFRIFG1&OFIFG); //测试振荡器故障标志 } void SetVcoreUp (无符号整型) { //打开 PMM 寄存器进行写入 PMMCTL0_H = PMMPW_H; //设置 SVS/SVM 高侧新电平 SVSMHCTL = SVSHE + SVSHRVL0 *电平+ SVMHE + SVSMHRRL0 *电平; //将 SVM 低电平设置为新电平 SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 *电平; //等待 SVM 稳定 时间((((PMMIFG & SVSMLDLYIFG)=0); //清除已设置的标志 PMMIFG &=~(SVMLVLRIFG + SVMLMRYIFG) = 0;//将 PMMCL0设置为新电平 //如果 ((PMMIFG & SVMLIFG))、则等待达到新的电平 while (((PMMIFG & SVMLVLRIFG)=0); //将 SVS/SVM 低电平设置为新的电平 SVSMLCTL = SVSLE + SVSLRVL0 *电平+ SVMLE + SVSMLRRL0 *电平; //锁定 PMM 寄存器以进行写访问 PMMCTL0_H = 0x00; } //主要内容 //进入 LPM0并等待 SPI 中断。 从主器件发送的数据是* //然后被解释、器件将相应地做出响应 * //********* void main (void){ WDTCTL = WDTPW + WDTHOLD; //停止看门狗计时器 //while (!(P1IN & BIT4)); //如果来自 MSTR 的时钟信号保持低电平、 //尚未处于 SPI 模式 //??? 对于16MHz 时钟、//设置 VCORE = 2 SetVcoreUp (0x01); SetVcoreUp (0x02); initClockTo16MHz(); initGPIO(); initspi(); _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断 __NO_OPERAT(); }//********* // SPI 中断 // #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_) #pragma vector=USCI_A0_vector __interrupt void USCI_A0_ISR (void) #Elif defined (__GNU__) void __attribute__(interrupt (USCI_A1_vector))#USCI_A0 Compiler #a0_aid! #endif { uint8_t uca0_rx_val = 0; switch (_even_in_range (UCA0IV、4)) { 情况0:中断; //向量0 -无中断 案例2: UCA0_Rx_val = UCA0RXBUF; 如果(!(SLAVE_CS_IN 和 SLAVE_CS_PIN)//!!!!!!!!!!!!!!!!!!!!!!!! { 切换(SlaveMode) { 情况(RX_REG_ADDRESS_MODE): ReceiveRegAddr = uca0_Rx_val; SPI_Slave_ProcessCMD (ReceiveRegAddr); 中断; 情况(RX_DATA_MODE): ReceiveBuffer[ReceiveIndex++]= uca0_Rx_val; RXByteCtr---; IF (RXByteCtr = 0) { //完成接收 MSG SlaveMode = RX_REG_ADDRESS_MODE; SPI_Slave_TransactionDone (ReceiveRegAddr); } 中断; 情况(TX_DATA_MODE): IF (TXByteCtr > 0) { SendUCA0Data (TransmitBuffer[TransmitIndex++]); TXByteCtr --; } IF (TXByteCtr = 0) { //完成发送 MSG SlaveMode = RX_REG_ADDRESS_MODE; SPI_Slave_TransactionDone (ReceiveRegAddr); } 中断; 默认值: __no_operation(); 中断; } } 中断; 案例4:中断; //向量4 - TXIFG 默认值:中断; } }