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/TM4C1294NCPDT:具有 SPI 接收数据问题的 TM4C1294NCPDT DMA

Guru**** 2482225 points
Other Parts Discussed in Thread: TM4C1294NCPDT, ADS127L01

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/719695/ccs-tm4c1294ncpdt-tm4c1294ncpdt-dma-with-spi-receive-data-problem

器件型号:TM4C1294NCPDT
主题中讨论的其他器件: ADS127L01

工具/软件:Code Composer Studio

您好!

我使用 TM4C1294NCPDT 接收  来自 ADS127L01 ADC 的测量值。 我最近正在努力将 DMA 功能添加到我的旧项目中。 我的代码所做的是提供 SPI 总线以与 ADC 通信、然后数据通过 TCP 套接字发送到客户端设备。 由于我需要定期将数据从固定地址移动到以太网缓冲器、因此我决定在采用乒乓配置的 RX FIFO 上使用 DMA。 我以前在其他一些应用中使用过它。 客户端的最终结果 几乎与没有 DMA 功能的情况相同、唯一的区别是缓冲区的最后2个样本总是被破坏。  

我填充大小为700的 rdata2缓冲器(短型数组、2字节变量)。  SPI 外设上的 RX DMA 由 RX FIFO 中的4个或更多字触发 、这就是我使指向 rdata2缓冲器的指针递增的方式。 下面的代码显示了 RX DMA 中断、传输变量是单个 DMA 传输的大小、并且被设置为4 (索引大小的条件基于708而不是700、因为以太网数据包中有一些固定的起始帧(大小为8)) 变量索引被重置为8。

基本上、在这个中断中、我跟踪目的地址、递增 RES_DEST2指针(指向 rdata2缓冲区)、并且在填充后将其复位为&rdata2[8]。

//
//
//这是 SSI1的处理程序,在 DMA RX 传输后进行处理
//
*********
void IntSSI1 (void)
{
// test_variable=test_variable+1;

int ui32mode1;
int ui32mode2;
ui32mode1 = uDMAChannelModeGet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT);
ui32mode2 = uDMAChannelModeGet (UDMA_CHANGE_SSI1RX | UDMA_ALT_SELECT);

index=index+transfer;


if (index<708)//缓冲区中有空间,因此目的地址通过传输递增(4)
{
//
//主要配置,配置并在传输停止后重新启用
//
RES_DEST2 = RES_DEST2 +传输;
if (ui32mode1 = udma_mode_stop)
{
test_variable=test_variable+1;

uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_MODE_PINGONG、(void *)(SSI1_BASE + 0x008)、 //0x008是 SSIDR 寄存器
RES_DEST2、//递增地址
传输);//要传输的数据项数,如果 SSI FIFO 使用突发 DMA (使用大小为8的一半 FIFO)
,则传输大小为4}
//
//次要配置,配置并在传输停止后重新启用
//
if (ui32mode2 = udma_mode_stop)
{
test_variable2=test_variable2+1;

uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_ALT_SELECT、
UDMA_MODE_PINGONG、(void *)(SSI1_BASE + 0x008)、 //0x008是 SSIDR 寄存器
RES_DEST2、//递增地址
传输);//要传输的数据项数,如果 SSI FIFO 使用突发 DMA (使用大小为8的一半 FIFO)
,则传输大小为4}
}

否则、if (index>=708)//目标地址需要复位
{
RES_DEST2=&rdata2[8];
//
//主要配置,配置并在传输停止后重新启用
//
if (ui32mode1 = udma_mode_stop)
{

uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_MODE_PINGONG、(void *)(SSI1_BASE + 0x008)、 //0x008是 SSIDR 寄存器
RES_DEST2、//递增地址
传输);//要传输的数据项数,如果 SSI FIFO 使用突发 DMA (使用大小为8的一半 FIFO)
,则传输大小为4}
//
//次要配置,配置并在传输停止后重新启用
//
if (ui32mode2 = udma_mode_stop)
{

uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_ALT_SELECT、
UDMA_MODE_PINGONG、(void *)(SSI1_BASE + 0x008)、 //0x008是 SSIDR 寄存器
RES_DEST2、//递增地址
传输);//要传输的数据项数,如果 SSI FIFO 使用突发 DMA (使用大小为8的一半 FIFO)
,则传输大小为4}

send_sign=1;//Flag 通过 TCP 套接
字发送数据}

我的缓冲区类型为 short、它始终指向 SPI 模块的数据寄存器((void *)(SSI1_base + 0x008)。 DMA 的初始化代码如下:

dma_conf (RES_dest2、pui8ControlTable、transfer);,其中:

RES_DEST2=&rdata2[8]和

void dma_conf (unsigned short * buf、unsigned char * ControlTable、unsigned int Transfer_size)
{
//
//在系统级别启用 uDMA 控制器。
//
SysCtlPeripheralEnable (SYSCTL_Periph_UDMA);

//
//启用 UDMA 控制器。
//
uDMAEnable();

//
//指向控制表以用于通道控制结构体。 作为输入参数传递
//
uDMAControlBaseSet (ControlTable);

//
//禁用所有属性
//
uDMAChannelAttributeDisable (UDMA_CHANGE_SSI1RX、UDMA_ATTR_ALL);

//
//启用特定 DMA 通道,SSI1 RX 为24
//
uDMAChannelAttributeEnable (uDMA_CHANGE_SSI1RX、UDMA_ATTR_USEBURST);//uDMAChannelAttributeEnable ()函数可用于为通道分配不同的外围设备(第680页为 DS)

//
//配置主设置,使用32位 uint 变量大小。 使用突发传输 UDMA_NEW_USEBURST、SSI FIFO 缓冲区将结果加载到同一地址、因此无 SRC 增量
//
uDMAChannelControlSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_SIZE_16 | UDMA_DST_INC_16 | //地址增量值必须等于或大于 dest/src size (DSTSIZE)的值。
UDMA_SRC_INC_NONE |
// UDMA_ARB_8); //仲裁大小必须至少为外设可容纳的项目数(如果 SSI FIFO 为半个、因此为4帧)
UDMA_ARB_4); //仲裁大小必须至少为外设可容纳的项目数(如果 SSI FIFO 为半个、因此为4帧)

//
//分配缓冲区,将有8个传输(buf 大小)
//
uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_MODE_PINGONG、
(void *)(SSI1_base + 0x008)、 //0x008是 SSIDR 寄存器
BUF、
// sizeof (buf));
transfer_size);


uDMAChannelControlSet (UDMA_CHANGE_SSI1RX | UDMA_ALT_SELECT、
UDMA_SIZE_16 | UDMA_DST_INC_16 | //地址增量值必须等于或大于 dest/src size (DSTSIZE)的值。
UDMA_SRC_INC_NONE |
// UDMA_ARB_8); //仲裁大小必须至少为外设可容纳的项目数(如果 SSI FIFO 为半个、因此为4帧)
UDMA_ARB_4); //仲裁大小必须至少为外设可容纳的项目数(如果 SSI FIFO 为半个、因此为4帧)

//
//分配缓冲区,将有8个传输(buf 大小)
//
uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_ALT_SELECT、
UDMA_MODE_PINGONG、
(void *)(SSI1_base + 0x008)、 //0x008是 SSIDR 寄存器
BUF、
// sizeof (buf));
transfer_size);

//
//一旦启用了通道,外设就会启动
//发出传输请求,数据传输将开始。
//
uDMAChannelEnable (UDMA_CHANGE_SSI1RX);


} 

此数据由客户端接收、这是在测试期间将基准正弦信号馈送到 ADC 时输出的结果:

缩放:

由于 rdata2包含原始测量值、实际上2个 ADC 帧代表一个测量指数349、350对应于 rdata2数组中的最后4个值(rdata2[704]-[707])。 可以看到、最后2次测量总是损坏的、但实际上、使用索引1049、1050的测量具有正确的索引699和700的值。 如果通孔测量持续10秒或分钟、则其一致性不受影响。 看起来每个帧的最后一个 DMA 传输被延迟、并为下一个帧更新了 rdata2的最后4个元素。

在调试之后、我发现这不是以太网通信或数据转换问题、因为在 MCU 存储器中检查 rdata2时发现这是在 MCU 端发生的。 我对如何实现这一目标的想法已一转不下。 我多次检查索引、没有发现任何原因。 另外一点是、其他点也很好、所以最后一次 DMA 传输出现了问题(大小为4的最后一次 DMA 传输与2个测量值完全一致)。

SPI 时钟为15MHz、16位帧 SSI_FRF_MOTO_MODE_1 (受控 ADC 需要)作为主器件工作。

我将赞赏任何想法和意见。  

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

    如果您关于 DMA 滞后的理论是正确的、那么在更改帧时、是否不能放置一个子句、您最后一次传输来更新缓冲区中的元素? 这似乎很容易做到、然后对我进行测试。

    或者、如果不需要最后4个值、则在启动几个帧缓冲区时、可以将它们设置为0xFF 或0xAA 等特定值、然后查看它们是否更新。 如果它们这样做、结果是错误的、那么我们知道 DMA 正在更新、但数据错误、但如果它们不这样做、将证明更新缓冲区时存在滞后的理论。

    仔细阅读细节、我目前还没有更好的理论。 我认为尝试执行我上面提到的操作将有助于我们以一种或另一种方式清楚地了解问题是 DMA 滞后还是其他问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我不打算这篇文章是"挑衅性的" 、而是试图理解您的"动机"、然后提出可能的"解决办法"。

    [引用 user="Lukasz Huchel"> 客户端的最终结果 是'几乎与没有 DMA 功能的情况相同'、 唯一的区别是缓冲区的最后2个样本始终损坏。  [/报价]

    因此-根据您的"报价"(上面)、您知道:

    •   µDMA 的 μ µDMA 功能产生的结果(几乎相同)与过去的结果相同-非 μ 结果。
    • 现在-缓冲区中的最后2个样本(始终损坏!)

    而且您(显然)在 这个过程中已经做出了良好的承诺:"时间/精力/焦点"。   因此-询问是否公平/恰当-因为"最终结果"是"相同的"-但(现在)负担得起错误-这项工作(似乎)是否没有真正的优点?   (我已询问过几位(其他)技术 Biz 所有者-我们(所有人)同意这一点。)

    您(可能)有一些"改进目标"(证明您的时间/努力是合理的)、但这些目标在这里不可见。   我无法检测到您(直接)要求(任何)µDMA '加速'(而只是那些最终的'2次错误测量')显示您的目标。

    由于这些错误测量(现在)已知且可预测/可重复、因此您无法:

    • 拒绝(仅限最终2次测量)... 或
    • 增加测量总次数 -使您获得 "所需、无错误的样本"的(精确)数量。

    并非所有"希望的目标都能实现"-您已经做出了显著的努力-未明确识别"失去的绩效收益"(再次称为"希望实现")-为 (更多)时间/努力的理由-证明难以理解...

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

    尊敬的 Ralph 和 CB1_MOBILE:

    感谢您的回答和帮助。

    至于 Ralph 的建议、我进行了班次测试、正如我在原始问题中提到的那样。 最后一个 DMA 传输(4个 SPI 帧)将移开孔缓冲器。 红色是未修改的数据、绿色是移位的样本(699至349、750至350等)。下图:

    已缩放:

    我也做了其他实验。 我在缓冲器中最多计算704、而不是708。 这意味着数据[704-707]将始终为零。 这是真正的问题、而转移到样片的问题[700-703]。 这意味着问题总是在最后一次 DMA 传输时发生。 我已经尝试在最后一个 DMA 传输和发送整个帧(rdata2)之间插入一个轻微的延迟、但没有任何改进(这是一个预期的开始、因为 DMA ISR 在 DMA 完成后处理、因此延迟不会起作用)。

    我今天一直在研究其他软件 DMA 方法(软件配置)。 当 FIFO 中有4次测量时、我让 SSI RX FIFO 中断通知我、然后我触发 SW DMA。 通过这种方法、我得到了很好的响应:

    正如 CB1_MOBILE 提到的、理论上我可以忍受2个样本被破坏、尤其是现在我可以通过某种方式对此进行补偿。 我只是想全面了解这个问题、甚至是为了将来参考。

    我可以在本例中使用 SW DMA、没关系。 不过、理论上建议对来自外设的周期性流进行乒乓配置。

    如果您有任何想法、我将很高兴地讨论、

    谢谢你。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、 感谢您的回答。 该器件在没有 DMA 功能的情况下工作。 我正在进行测试、以减轻 MCU 在未来开发中的负担。 我想节省存储器访问时间。 我在下面发布了详细更新。 谢谢你
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您-尤其是(现在)提到"您希望减轻 MCU 的负担"。   请注意、(获得)"此类减少量的增加量"应为"高目标"-否则、您可能会受到"一厢情愿的思考者"的标签!   如果此类测量"未知"、您如何(进一步优化)或帮助提高稳健性?

    值得尊敬的是、您努力获得这样(准确)的理解、但您的发展的"所有其他"重要方面都已完全完成、然后是详尽的"测试/验证"?   抓住项目的"一个"方面(即使是一个具有挑战性且令人愉快的方面)证明(几乎)"具有破坏性"-特别是如果它导致"妥协"... 其他地方。   (在我的经验中、这种情况经常会"证明情况"。   公司/I 定期与"VC"(资本筹集公司)合作、这种"趋势"(众所周知)引起了人们的关注!)

    现在返回到您的(重点)问题: "这意味着问题总是在最后一次 DMA 传输时发生。"   您是否详尽地检查过(所有)成功的先前转让与 (可怕的)总是失败的转让之间的任何和所有区别 ?"最后的 µDMA 转让?"   它(必须)为 true -存在(某些)差异-并且可能在您的中:排序、μ µDMA ISR、或者(某处) w/在 μ µDMA 传输中-本身。   再次-您 (认真且深入) 是否搜索了"最后一次传输 µDMA 传输?"中显示的任何/所有差异   您应该"深入思考"-如何才能最好地"识别"-任何此类差异!

    我的团队现在和现在都是“亲吻”的忠实粉丝。   您无法简化此问题-也许:

    • 创建全新的-大大"简化代码"-足以完成(更小的此类转移)-同时消除所有其他计划功能和/或方面!   (理论是-"某些(但未知)"外部影响"会影响"上次转移!"   (即使不太可能、尤其是不太可能、也应考虑这样!   不止一次-这种方法已为我的团队节省了成本!)
    • 更改"转移代码"的顺序。  也许有一些"敏感"。
    • 再次-非常仔细地检查-以确保-µDMA 内容保持"纯"-并且"唯一且始终"-"最后一次传输"-证明了村民!  

    通过"尽力"展示您问题的大幅缩减代码版本-然后此处展示(减少)版本-您(可能)鼓励他人(可能甚至鼓励其他供应商) (进一步)检查并武装他们(肯定)的"内幕知识"—也许只是一个解决方案—将会出现。   (仅将负担放在"一个" (您)身上、证明"不出名"是 有效的"问题解决机制!)  (笑声) (笑声)  不要问-只是如何-我(当然)知道...