This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/MSP430FR5969:SPI 读取问题

Guru**** 2558390 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/676525/ccs-msp430fr5969-spi-reading-problem

器件型号:MSP430FR5969

工具/软件:Code Composer Studio

大家好、

我使用 USCI_A1 SPI 模块与从器件通信。 读取例程时出现问题。 我知道、要接收一个字节、主器件必须发送一个虚拟字节以使模块实际激活时钟。 发送例程成功、示波器监测到的信号表明从器件返回了一个字节。 但是从 UCA1RXBUF 中读取的数据总是0x00。 我不知道我的程序有什么问题。 因此、请帮助我查看以下代码、我希望您能告诉我哪里出错了。

//变量声明
静态结构{
bool bPortInUse;
bool bNewDataReceived;
unsigned int indexRx;
unsigned int indexTx;
unsigned int uiBytesToSend;
uint8_t *pcRxBuffer;
uint8_t * pcTxBuffer;
}spiSM;

//此函数用于从从站发送/接收数据
//rxBuf、txBuf:分别接收/发送数据的指针
// size:要接收/传输

的字节数 bool SPI_transaction (uint8_t* rxBuf、uint8_t* txBuf、uint16_uintt)

spiSM.bNewDataReceived = false;
spiSM.indexRx = 0;
spiSM.indexTx = 0;
spiSM.uiBytesToSend =大小;

spiSM.pcRxBuffer = rxBuf; // pcRxBuffer 指向接收缓冲区
spiSM.pcTxBuffer = txBuf; // pcTxBuffer 指向发送缓冲区

SPI_EN; //SPI 被禁用(UCA1CTLW0 &=~UCSWRST)
UCA1IE |= UCTXIE | UCRXIE; //中断被使能,但是中断标志仍然= 0,因为 GIE 没有被置位

执行{
//重置接收标志
spiSM.bNewDataReceived = false;

//开始传输
TXBUF_Temp = spiSM.pcTxBuffer[spiSM.indexTx];

//在发送/接收中断标志发生前保持睡眠状态
_bis_SR_register (LPM3_bits|GIE);

//移至下一个 TX 和 RX 索引
spiSM.indexTx++;
spiSM.indexRx++;
spiSM.uiBytesToSend--;

} while (spiSM.uibtesToSend); //重复,直到接收所有所需的字节

SPI_DIIS; //SPI 被禁用(UCA1CTLW0 |= UCSWRST)

返回 true;
}

#pragma vector=USCI_A1_vector
__interrupt void SPI_ISR (void){

if (UCRXIFG){
spiSM.pcRxBuffer[spiSM.indexRx]= UCA1RXBUF;
spiSM.bNewDataReceived = true;
UCA1IFG &=~UCRXIFG;//不确定是否编写此命令至关重要,但这与写入时一样重要
_BIC_SR_REGISTER_ON_EXIT (LPM4_BITS);
}

if (UCTXIFG){
UCA1TXBUF = TXBUF_Temp;
UCA1IFG &=~UCTXIFG;
_BIC_SR_REGISTER_ON_EXIT (LPM3_BIS|GIE); //最近刚添加
}
} 

这是在示波器上监控的信号。 在本例中、我想读取从器件的 FIFO 状态寄存器。 读取例程如下图所示、绿色为 MOSI、红色为 CLK、蓝色为 MISO。 它表明、在主器件发送命令代码后、从器件返回了一个数据#0 (在第二个8位时钟上)、但 UCA1RXBUF 返回0。   

非常感谢您的支持、期待您的支持。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我还想问一件事。 在《MSP430FR5x 系列用户指南》第784页中、可以看到"UCRXIFG 被置位、表示 RX/TX 操作完成"。 但是在第787页中、会说"每次接收到一个字符并将其加载到 UCxRXBUF 中时、UCRXIFG 中断标志都会被置位"。 那么、我应该了解什么? 任何完整的传输、无论是发送还是接收、都能激活 UCRXIFG 吗? 如果是、我如何知道 Rx (而不是 Tx)何时完成并且数据在缓冲器中可用?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    > if (UCRXIFG){
    此条件始终为真。 尝试:
    > if (UCA1IFG &UCRXIFG){

    > UCA1IFG &=~UCRXIFG;//不确定是否编写此命令至关重要,但这与写入时一样重要
    请勿这么做。 读取 UCA1RXBUF 会将 RXIFG 清零。 明确地将其清除是丢失中断事件的一种方法。

    [这两个点也适用于 UCTXIFG。]

    TXIFG 和 RXIFG 配对、但会逐个关闭、因为 TXIFG 表示加载移位寄存器、RXIFG 表示移位完成。 跟踪这两种情况有点令人头疼。 对于短传输、我建议一次送入一个字节:写入 TXBUF、等待 RXIFG、然后读取 RXBUF (然后重复该过程)。 (对于长事务、我建议使用 DMA。)

    更常见的情况是:对于快速 SPI 时钟、中断只会增加复杂性并降低速度。 考虑使用一个简单的逐字节 PIO 环路来执行此操作。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Bruce:

    非常感谢您的推荐。 我需要中断、因为我的应用需要尽可能节省功耗。 因此、在等待期间睡眠将是更好的选择。 但我会尝试您的建议、并给出结果。

    但是、正如您所建议的、写入 TXBUF 并等待 RXIFG。 发送完成时、RXIFG = 1。 但是、如果 RXBUF 上没有数据、会发生什么情况? 为什么我的代码无法捕获接收到的数据? 请您向我解释一下、我仍然对此感到很不满意。 非常感谢。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    RXIFG 和 TXIFG 意味着不同的东西、不过由于 SPI 的双工特性、每个 RXIFG (通常)都伴随一个 TXIFG 条件。

    当 RXBUF 被载入时、RXIFG 被置位。 如果 SPI 单元移入0x00 (与示波器跟踪中的第一个时钟突发一样)、则将出现这种情况。 不太明显的是、当您实际读取 RXBUF 以查看其内容时。

    多个唤醒可能会使您的环路感到困惑、尤其是在 SPI 时钟非常慢的情况下(如您所建议)。 当我读取它时、可能没有理由在 TXIFG 上唤醒主器件、因此我建议您将其删除。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bruce:

    非常感谢您的友好支持。 我已按照您的建议更改了我的代码、并且 SPI 模块工作正常(以下代码)。 因此我现在不使用中断。 稍后、我将再次尝试 ISR 例程。 再次感谢你。




    UCA1TXBUF = spiSM.pcTxBuffer[spiSM.indexTx]; 当 UCAxTXBUF 准备好加载新数据时、// UCTXIFG = 1 //写入 UCAxTXBUF 会激活时钟发生器 //等待接收发生(在命令代码被发送后) while (!(UCA1IFG & UCRXIFG)); spiSM.pcRxBuffer[spiSM.indexRx]= UCA1RXBUF; //将数据保存到*pcRxBuffer 中