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.

[参考译文] MSP430FR5739:使用 DMA 进行 SPI 通信+新问题

Guru**** 2529560 points
Other Parts Discussed in Thread: MSP430FR2355

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/722900/msp430fr5739-spi-communiation-using-dma-new-question

器件型号:MSP430FR5739
主题中讨论的其他器件:MSP430FR2355

我尝试一次使用具有 STE 的 SPI 从器件发送4元件缓冲器的内容  

低电平有效和 DMA。

假设缓冲区内容为:buff ={30、31、32、33}。 这只是为了进行详细说明、否则缓冲器在一个定时器 ISR 中每250ms 更新一次。

行为:

当连续运行时、示波器在所有4个事务上显示30。

运行到 curser 时:

点击1:30 30 30 30

点击2:31 31 31 31

点击3:32 32 32 32

点击4:33 33 33 33 33

点击5:30 30 30 30

(笑声) 等等

而我希望每个周期的情况都是这样:30 31 32 33

以下是应实现此目的的代码部分:

void main (void)
{
SPI_Init();
dma_init ();
while (1)
{
缓冲区={30、31、32、33};
DMA0CTL |= DMAEN + DMAREQ;
}


void SPI_Init (void)
{
//为 UCA1设置 SPI 模式
UCA1CTLW0 = UCMSB + UCSYNC + UCMODE1 + UCSWRST;
//打开 SPI
UCA1CTLW0 &=~UCSWRST;


void

= DMAC0TMA17;}DMAC0 (void) //通道0上的触发器17对应于 UCA1TX

/*DMA 通道0源地址*/
DMA0SA =(无符号短整型) TempBuff1; // src = RAM 存储器

/*DMA 通道0目的地址*/
DMA0DA =(无符号短整型)&UCA1TXBUF; //最小单个地址

/*DMA 通道0传输块大小*/
DMA0SZ = 0x04; //块大小

/*DMA 通道0源地址增量1 */*/
*传输采用重复单字节*/
*/*传输按字节*/
*DMA 通道0 INT 禁用 */
*DMA 通道0被禁用 //
DMA0CTL = DMADD_4 + DMASRCINCR_3 + DMASBDB + DMALEVEL;// inc src、enable、byte access
} 

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

    你好,Ahmad

    这可能是由 DMA 传输速度引起的、远高于 UART、因此您可以在 UART TX ISR 中进行 DMA 数据传输。

    此致
    Gary

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您是指 UART 提供的 SPI? 或 UART。 此外、SPI 中断与 DMA? 据我了解、如果启用了 SPI 中断、DMA 将不会触发。
    此外、由于 DMA 等待其触发、即 UCA0IFG 的 UCTXIFG 位、我认为这不应该是速度问题。 我更怀疑 DMA0CTL 上的正确位组合。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好,Ahmad

    抱歉、这是错误、我是指 SPI。 您可以遵循以下建议
    1.测试 DMA 配置:将其他数组定义为 DMA 目标并启用 DMA 中断以查看结果。
    由于用 SPI 启动时间更新 UCA1TXBUF 的 DMA 是异步事件、并且两个事件的速度不同。 因此,您必须采取某种措施来同步这两项内容。(MCLK 和 SPI CLK 的频率是多少?)

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

    我将做第一部分、并将告知您。

    对于2:MCLK 的频率为8MHz、而作为 Raspberry PI 单元的 SPI 主设备的频率也为8MHz。

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

    您好、Gary、

    我做了以下工作:

    定义了以下全局变量:

    unsigned char dummyBuff[20];
    unsigned char dummyVar;
    int dummyPtr = 0; 

    在 dma_init 函数中将 DMA0DA 修改为以下内容:

    DMA0DA =(无符号短整型)&dummyVar; 

    现在、我尝试通过以下方法测试功能:

    DMA0CTL |= DMAEN + DMAREQ;
    dummyBuff[dummyPtR]= dummyVar;
    IF (+dummyPtr >= 20)
    DummyPtr = 0; 

    然后、我在"dummyPtr = 0"行放置一个断点;

    第一次跑步时、哑铃看起来是这样的:

    0 0 0 0 31 32 33 33 33 33 33 33 30 30 30 30 ...

    我不确定我是否正在制定正确的测试方案

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    也许我无法提供正确的测试案例。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    在重新启动 DMA 之前、您实际上应该等待 DMA 完成。 我不确定在 DMA 运行时设置 DMAREQ 会产生什么影响。

    尝试将类似"__delay_cycles (100);"(32个时钟实际上应该足够了)的内容插入主循环、看看它的运行方式是否不同。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、实际上我插入了以下内容:

    while (!(DMA0CTL&DMAIFG)); //等待发送完所有字节
    DMA0CTL &&~DMAIFG; //清除 DMAIFG 

    我认为这应该照顾到等待的部分。

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

    您好、Ahmad、

    关于 DMA0CTL、我不确定 DMALEVEL 是您想要的。 如果我没有弄错、它必须对边缘敏感。 这可能是您的问题。

    我想正在发生的情况是、您使用 DMAREQ 强制执行第一个操作、但在该操作之后、DMA 不会在 TXREG 中放置任何其他内容。 因此、SPI 外设会反复发送相同的字节。

    现在来看一个坏消息... 您正在使用的芯片已被卷曲。 查看 器件勘误表中的 DMA9。 基本上、已知 DMA 会随机停止工作。 这可能不是您现在遇到的问题。 不过、您可能会遇到这种情况。 尽管存在此缺陷、但可以使 DMA 可靠地工作、但只能用于一个通道。 如果这就是您所需要的一切、那就没问题。 否则、切换到另一个没有此缺陷的芯片将会很好。

    这一 DMA9缺陷是我存在的祸根。 TI 刚刚推出了一款全新的芯片 MSP430FR2355、它 具有更多外设、DMA、RAM、FRAM、模拟、 等等 但目前还没有广泛提供。 它与 FR5739不具有引脚兼容性。 :(

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

    嗯、当我查看"slau272c"第7.2.3.2节时、它显示如下:

    "。。 为了正常运行、电平触发器只能 在外部触发 DMAE0被选为触发器时使用。 "

    因此、我认为"电平敏感型"是可以的。 此外、我测试了"边缘敏感"、但它仅发送0、其他什么也不发送。

    我确实按照 Bruce 的建议应用了100周期延迟、因为 DMAIFG 从未获得1、所以我始终处于无限等待循环中。

    因此、很少有第一个交易 可以正常工作、然后在其余时间内它仍然保持在一个特定的数字。

    我还测试了单次传输和块传输、但它们根本无关紧要。

    我不知道这是否有帮助、但我的接收端是运行非实时操作系统的 Raspberry PI 单元、但我不明白为什么它很重要。

    关于坏消息、我不会担心太多、因为我只使用一个 DMA 通道、我不想进行硬件修改以适应新的芯片引脚变化。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    即使您仅使用一个 DMA 通道、TI 也会推荐一种特定的权变措施来确保 DMA 正常工作。 勘误文档在 DMA9下对其进行了详细说明。 同样、它可能与您目前遇到的问题有关、也可能与之无关、但值得考虑。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    此外、我不相信您使用的是 DMAE0。 这将是一个外部触发器。 因此、电平敏感型不应该起作用。 我缺少什么吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我认为 SPI 模块等任何外设硬件都是外部触发源。 此外还有:

    DMACTL0 = DMA0TSEL_17; //通道0上的触发器17对应于 UCA1TX 

    我想用触发器17指定 DMA0?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    否 DMAE0专门触发31、它是 P1.0上的次级模块功能
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    那么、在这种情况下、边沿触发器为我发送零。 有什么建议吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我为 SPI 从器件配置它的方法是在软件中将第一个字节写入 TXBUF (不会立即开始发送)、然后启用 DMA 将所有剩余字节排队、并且不设置 DMAREQ。 我不确定它是否理想、但值得一试。

    我认为我的方案对 SPI 主器件不是很适用、因为它将在写入 TXBUF 时立即开始传输、并且在您启用 DMA 时、它已经错过了下一个 TXIFG 标志。 因此、我可能不是最好的方法。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    哦、这是另一个想法。 在尝试我在最后一条消息中建议的操作之前:先尝试设置 DMAEN、然后立即设置 DMAREQ。 也许同时设置这两个值会导致它错过 DMAREQ 的边沿。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Greg、

    感谢您建议将数据放在 TXBUF 的第一位、然后等待通信开始。 这是保持触发的东西。 看起来我不需要 DMAREQ。 我还了解到、我应该选择不重复单字节来保持数据的干净。 我仍然会看到一些数据丢失的干扰、但我觉得某些干扰是由计时器中断引起的。 尽管数据表中说 DMA 传输保持了正常的 CPU 操作、但我不知道为什么计时 器中断会偶尔触发一次并对数字进行扰频。

    谢谢、

    Ahmad

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Greg、
    因此、正如我说过的、DMA 最终开始工作。 但是、我偶尔会松开一些样本、例如10分钟内一次或两次采样。 您认为这可能是任何 SPI+DMA 配置的典型情况、还是应该对此进行修复?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    当您说您丢失了样本时、您是否完全没有得到任何数据、或者您是否只得到部分传输?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    本例中的一个示例是一个34字节的流。 该错误通过两种方式发生:

    1:部分流来自一个样本、另一部分来自另一个样本

    2.整个数据流丢失(我从丢失的计数器知道这一点)

    让我为我完成的更新再次添加代码。

    接收端设置为边沿敏感型、每当数据就绪标志(P3.0)上升时、它都会启动一个事务并保持该状态、直到 P3.0下降。 P3.0变为低电平后、它会离开并循环、并再次检查 P3.0以获得下一个事务就绪通知。

    void main (void)
    {
    WDTCTL = WDTPW + WDTHOLD; //停止 WDT
    DMA_init ();
    while (1)
    {
    _bis_SR_register (GIE); //在不进入 LPM 模式的情况下启用中断
    __no_operation();//用于调试器
    while (!(P3IN & BIT2)); //如果圆周率尚未就绪,请在此处等待
    INPTr = 0、OUTPTr = 0、p = 0;
    q = 0、r = 0;newDataCnt = 0;
    TempEmpty = true;
    //启用计时器中断
    TA0CCTL0 |= CCIE;
    while (P3IN 和 BIT2) //并在圆周率上升时一直读取 ADC
    {
    MANAG_Data_and_Flags();
    }
    //禁用计时器中断
    TA0CCTL0 &=~CCIE;
    }
    
    
    /******** //**
    *@针对 Mode2的简短计时器 A0 ISR、缓慢 FRAM 写入、40ms 计时
    器*
    @param none
    *
    @返回 none
    /
    
    #pragma vector = TIMER0_A0_vector
    __interrupt void Timer_A (void)
    {
    //
    关闭 P3.0 (Pi 单元的数据就绪标志)以避免在 uC 时进行 SPI 事务
    该 ISR 中处于繁忙状态。如果需要再次提出它、这将是
    发生在"copy1Row2TempBuff"函数中。
    ///P3OUT
    &=~BIT0; //但实际上这在两种情况下都无关紧要(中止或退出)
    TA0R = 0;
    //读取 ADC */
    GetADCnt (CS1、DRDY1、LCchan、NumberOfSensors);// GetADCValue 函
    数不执行任何操作它使用 UCB0与 ADC 进行通信的 UCA1模块 GetADCnt+
    、NumberOfValue+;
    /*跟踪样本计数*/
    IF (+Sercnt >=250)
    Sercnt = 1;
    }
    
    void Manage_Data_and_Flags (void)
    {
    unsigned int tempCntr = outptr;
    P3OUT &=~BIT0; //通常假设数据未就绪
    ,前提是(((inptr != tempCnt)&& newDataCnt >0)
    {
    copy1Row2TempBuff();
    outptr += 11;
    if (outptr > BuffSize - NumberOfSensors - NumberOfFilms)
    outptr = 0;
    newDataCnt-;
    }
    
    
    }void copy1Row2TempBuff (void)
    {
    int i、j;
    UCA1TXBUF = buff[outptr ][colNum - 1];
    j = 0;
    while (j < 3*(NumberOfSensors + NumberOfFilms)))
    }{
    for (i = 0;i < colNum - 1;i++)
    TempBuff1[j + i]=缓冲区[outptr + j/(colNum - 1)][i];
    J +=(colNum - 1);
    }
    TempBuff1[3*(NumberOfSensors + NumberOfFilms)]= newDataCnt;
    //启用 DMA 通道0 (用于传输)*/
    DMA0CTL |= DMAEN;
    __DELAY_CYCLLES (500);
    TempEmpty = false;
    //向发送设备发出信号
    |=数据准备就绪;* ITPi = 0
    /*理想情况下,以下行应等待 DMAEN 下降,这是一个标志
    交易结束、通过该结束可以得知 Pi 已经确认了
    "数据就绪标志(P3.0为一个)。
    但是、由于某种原因、DMAEN 或 DMAIFG 始终保持低电平(每一次)
    一段时间内)导致一切阻止被发送。 因此、另一个
    检查是否已到位以释放暂停、该暂停将检查是否已累积更多数据
    循环缓冲器中。
    //
    while (((DMA0CTL & DMAEN)&&(P3IN & BIT2)&&(newDataCnt < 2));
    //在数据未就绪时阻止进一步的事务*/
    P3OUT &=~BIT0;
    DMA0CTL &=~DMAIFG; //清除 DMAIFG
    TempBuffEmpty = true;
    //
    等待 CS_NOT (P2.3)为低电平。 这会阻止程序执行
    事务正在进行时循环
    */
    while (!(P2IN & BIT3)&&(P3IN & BIT2);
    }
    
    void dma_init (void)
    {
    DMACTL0 = DMA0TSEL_17; //通道0上的触发器17对应于 UCA1TX
    
    /*DMA 通道0源地址*/
    DMA0SA =(无符号短整型) TempBuff1; // src = RAM 存储器
    
    /*DMA 通道0目的地址*/
    DMA0DA =(无符号短整型)&UCA1TXBUF;//&dummyVar; //最小单个地址
    
    /*DMA 通道0传输块大小*/
    DMA0SZ = sizeof (TempBuff1)/sizeof (TempBuff1[0]); //块大小
    
    /*DMA 通道0源地址增量1 */*/
    *传输为单字节*/
    */*传输为按字节*/
    *DMA 通道0 INT 禁用 */
    *DMA 通道0被禁用 */
    DMA0CTL = DMADD_0 + DMASBDB + DMASRCINCR_3;
    } 

    下面是 SPI 的配置方式:

    void SPI_Init (void)
    {
    UCA1CTLW0 = UCMSB + UCSYNC + UCSWRST;
    UCA1BRW = 2; //更改 SPI 时钟频率(但在从模式下无关紧要)
    UCA1CTLW0 &=~UCSWRST;
    } 

    SPI 主时钟频率设置为8MHz、您认为这可能会导致 问题吗?

    谢谢、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    /*理想情况下,以下行应等待 DMAEN 下降,这是一个标志
    交易结束、通过该结束可以得知 Pi 已经确认了
    "数据就绪标志(P3.0为一个)。
    但是、由于某种原因、DMAEN 或 DMAIFG 始终保持低电平(每一次)
    一段时间内)导致一切阻止被发送。 因此、另一个
    检查是否已到位以释放暂停、该暂停将检查是否已累积更多数据
    循环缓冲器中。
    * 

    这似乎与偶尔丢失的数据有关。 (DMAEN 也将保持高电平、而不是低电平。) 您还记得我一直提到 DMA9勘误表吗? 您可能需要再看一下。