10个帖子/ 0个新
最后发表
mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
SPI GTL死锁

你好,

我正在外部处理器配置下操作DA14580。它由一个使用GTL 5线SPI协议的uC (SPI主机)控制。我总是遇到陷入僵局的问题。当在BLE上传输一些数据时(因此在uC和DA之间有很多流量),我遇到了DA和uC都想同时传输的状态。更确切地说,地方检察官被困在spi_hci_write_func ()函数。它驱动DREADY信号高,并等待SPI传输(spi_wait_for_transfer ()):

...
spi_dready_high ();//请求发送
{做
spi_wait_for_transfer ();//等待来自SPI主设备的SPI事务
...

然而,uC试图在同一时间发送消息,并被卡在spi_send_hci_msg ()函数,等待DREADY信号变低:

...
//禁用可怕中断
dready_irq_disable ();
//轮询DREADY以检测是否正在接收数据
而(dready_get_status ());
...

情况如下:
—在DA断言可怕信号之前,uC禁用可怕中断。
—dready信号高,但uC侧没有中断。
—相反,uC等待可怕的信号变低。
-可怕的信号不会低,因为DA正在等待SPI传输。
——>死锁

我想知道协议打算如何避免遇到上面描述的死锁。从目前的情况来看,没有任何机制可以阻止这种情况的发生。

谢谢!
mabraun

编辑:试图使问题描述更全面

关键词:
设备:
MT_dialog
离线
最后看到:6个月1日前
工作人员
加入:2015-06-08 34
嗨mabraun,

嗨mabraun,

在SPI总线上传输数据有一个顺序,设备之间交换的信号和数据不仅是DREADY,为了防止这种情况,在两个设备可以通过SPI总线传输数据之前,还应该交换flow_on和flow_off数据。你可以看一下UM-B-013,以便详细检查协议。在主从通信之前有一个特定的过程,反之亦然,为了避免这种死锁,在主从可以传输之前,应该在调用spi_send_hci_msg()和禁用中断之前检查从是否可用(如果从发送的最后一条消息是字节流)。

由于MT_dialog

mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
嗨MT_dialog,

嗨MT_dialog,

谢谢你的回复。我很清楚flow_on/flow_off原理,我已经仔细阅读了UM-B-013。值得澄清的是,我使用了来自SDK5的接近报告器示例中提供的源代码(用于主机和DA),这就是流控制机制被(或应该)正确实现的原因。我遇到的问题与流量控制机制无关,甚至在UM-B-013的6.2.3节中得到了解决:

防止主从双方同时传输的事件(即主人)
发送0x05开始字节以同时开始消息和从机的传输
发送一个流的字节,随后传输另一个消息)
,大师不得不承认
从服务器的DREADY请求。

突出显示的例子正是我遇到的问题:主想要发送消息(0x05),从想要发送流字节。它仍在继续:

为此,当主机检测到DREADY处于活动状态时,它会发送一个
确认字节(ACK,选择为0x08),以通知从服务器它可以继续发送
流出字节(或任何其他数据)。此功能如图3所示。在任何可怕的上升边缘,
主设备必须承认它检测到它,并允许从设备发送数据。如果
主不承认DREADY上升边,从等待直到芯片选择行
inactive(这将表明主服务器已经完成发送消息),激活DREADY
再次,并等待确认继续传输。

然而,上面描述的行为(粗体)似乎并没有在DA端实现(参见spi_hci.c):

bool spi_hci_flow_off_func(空白)

uint8_t tmp;
//首先检查是否正在进行传输
如果((spi_cs_getf () = = 0))

返回错误;

NVIC_DisableIRQ (SPI_IRQn);//关闭CPU SPI中断
spi_dready_high ();//请求发送
{做
spi_wait_for_transfer ();//等待来自SPI主设备的SPI事务
TMP = spi_rxtxreg_read();//从SPI获取字节
} while (tmp != DREADY_ACK);//如果DREADY未被确认,请重试
[…]


上面的代码首先检查传输是否正在进行,然后它断言DREADY行,然后它无限期地等待一个SPI传输(或DREADY_ACK字节)。这种行为不符合:

如果主服务器没有确认DREADY上升边,从服务器等待直到Chip Select行不活跃(这将表明主服务器已经完成发送消息),再次激活DREADY,并等待确认继续传输。

让我们看看uC(主机)端:第6.2.3节也说明了这一点

在任何DREADY上升沿上,主设备必须承认它检测到了它,并使从设备能够发送数据。

spi_hci_msg.c的代码如下所示:

Void spi_send_hci_msg(uint16_t size, uint8_t *msg_ptr)

uint16_t我;
//禁用可怕中断
NVIC_DisableIRQ (GPIO0_IRQn);
//轮询DREADY以检测是否正在接收数据
而(GPIO_GetPinStatus (SPI_GPIO_PORT SPI_DREADY_PIN));
spi_cs_high ();//关闭CS
spi_cs_low ();// Open CS
spi_access (0 x05);
[…]


的代码第一个禁用DREADY中断,然后它投票给DREADY,然后它将SPI芯片选择线拉低。如果DREADY在中断被禁用后立即变高,uC将无限期地等待DREADY再次变低,并且DREADY irq请求将不会被服务。另外,CS行并不能阻止这种情况的发生,因为它在停用DREADY中断后被拉低。

我是不是遗漏了什么?

抱歉写了这么长一段,但我想确保我的意思被正确理解。

干杯!

MT_dialog
离线
最后看到:6个月1日前
工作人员
加入:2015-06-08 34
嗨mabraun,

嗨mabraun,

请原谅我,如果我弄错了,你已经注意到,当有一个正在进行的事务从主,所以奴隶已经发送了一个流,主已经发送了一个0x08,以确认它,所以主准备发送数据和禁用IRQ,在那之后,奴隶立即发出一个flow_off,以发送数据,所以DREADY引脚在CS被禁用的时候变得很高(很高,所以它逃避了spi_cs_getf()函数中的CS检查),因为DREADY被拉高,主服务器被卡在轮询过程中,从服务器被卡在等待一个永远不会来自主服务器的0x08消息。

您在应用程序中遇到过这种问题吗?如果遇到过,您是否捕获了SPI事务?

由于MT_dialog

mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
嗨MT_dialog,

嗨MT_dialog,

是的,你完全正确。在附上的图片中,你会发现4个信号:
1.SPI CLK(黄色)
2.SPI味噌(蓝色)
3.SPI CS(粉红色)
4.所(绿色)
我的瞄准镜只有4个通道,所以我无法捕捉到MOSI线。

在屏幕截图的开头,您可以看到flow_off通信:2 SPI字节,包含DREADY_ACK和FLOW_ON字节。在此之后,主服务器发起传输(注意当DREADY不活动时CS线路是如何变低的)。在(成功)传输之后,从服务器断言DREADY信号(因为它想发送一个flow_off消息),主服务器也想发送一个消息,并将CS线拉低。(为了更好的可视化,我移动了spi_cs_low ()前代码行而(dready_get_status ());.否则你不会看到CS线被拉低。)注意DREADY和CS几乎同时被断言(CS低,DREADY高),但是没有后续的SPI通信可见。这就是死锁发生的时候。

谢谢你的帮助!
mabraun

附件:
MT_dialog
离线
最后看到:6个月1日前
工作人员
加入:2015-06-08 34
嗨mabraun,

嗨mabraun,

我已经与支持团队进行了检查,据他们所能告诉我的是,这种情况很可能发生,没有超时或任何其他机制可以阻止580在主机刚刚开始发送数据时发送一个流断开命令,死锁似乎可以发生,很少发生,但它是可能的。因为我们从来没有ecountered这种问题,在操作SPI你能确保这个僵局是肯定的原因拖延你的系统,你能提供一个更完整的捕捉你的信号,为了确保0 x05离开宿主(莫西人信号)或如果你能调试,你确认这就是代码困在双方(spi_send_hci_msg()和spi_hci_flow_of_func ()) ?

由于MT_dialog

mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
嗨MT_dialog,

嗨MT_dialog,

谢谢你的回复。在我当前的设置中,我能够调试两边,这就是为什么我知道两边确实都卡在spi_send_hci_msg()和spi_hci_flow_off_func()中。

我附上了4个屏幕截图。我捕获了所有5条信号线(都用紫色显示),顺序如下:CLK, MOSI, MISO, CS, DREADY。此外,我使用了一个协议分析器来解释MOSI和MISO行,在屏幕截图中以蓝色显示。总线1对应于MOSI,总线2对应于MISO。

1. png:对导致死锁的问题序列的总体看法。

2. png:Flow-On序列的放大视图。DREADY是高的,主承认它(0x08)和从发送FlowOn字节(0x06)。

3. png:放大的Master发送的第一个字节视图,标记消息的开始(0x05)。

4. png:放大的Master发送的消息结束的视图(CS被拉高)。之后,发生死锁:Slave想要发送FlowOff(由断言DREADY开始),Master想要发送下一条消息。请注意:与我之前的帖子相反,我做到了移动spi_cs_low ()前代码行而(dready_get_status ()),这就是为什么你看不到CS线被拉低的原因。这是原始的代码行为。然而,问题仍然是一样的:主进程卡在spi_send_hci_msg()中,等待DREADY信号变低。slave卡在spi_hci_flow_off_func()中,等待SPI传输。

如果您还需要其他信息,请告诉我。

谢谢你的帮助,
mabraun

mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
有最新进展吗?你会

有最新进展吗?您是否能够提供5线SPI协议的固定实现?

谢谢,
mabraun

MT_dialog
离线
最后看到:6个月1日前
工作人员
加入:2015-06-08 34
嗨mabraun,

嗨mabraun,

目前,这个问题是作为变更请求提交的,到目前为止,我们有一个可能的解决方案来克服这个僵局,但它需要一些时间来测试和评估任何问题或限制。我将在本周或下周有更多关于这方面的信息,我会让你知道。

很抱歉给您带来不便。

由于MT_dialog

mabraun
离线
最后看到:3年9个月前
加入:2015-11-16 15:57
嗨MT_dialog,

嗨MT_dialog,

谢谢你的更新,这是个好消息。请随时通知我。

问候,
mabraun