S32K144 板对板 SPI 通信中的奇怪行为 大家好,我在 S32K144 板中设置 SPI 中断通信时遇到了一些问题。该项目旨在与 PC33771B 设备通信,但目前处于一种由 33664EVB 提供的环回通信中。 在大多数情况下,它似乎是有效的,但数据在我的缓冲区内的实际存储方式却很奇怪。我有一条 5 字节的消息,一般来说它遵循以下顺序: B5 0 0 0 B1 B2 B3 B4 鉴于 LPSPI 是以单词为单位工作的,我想这应该是正确的。但出于某种原因,并非每次都是这样。启动董事会时,有时顺序是: B1 B2 B3 B4 B5 0 0 0 有时只是 B1 B2 B3 B4 0 0 0 0 完全丢失第五个字节。 我做了一个小的测试代码,以便使用 CAN 进行调试。我向 SPI_1 发送我想要的信息,并接收回 SPI_0 缓冲区中结束的信息。我还在使用逻辑分析仪查看发生了什么: 第一条信息 rchust_1-1756882155720.png 首先,spi 消息遵循 S32K144 惯例,因此第五个字节将是 CRC。它还使用 cmd 进入第四个字节,我很方便地把它改成了四字节。即使我等待 SPI_0 再次准备就绪,它也会产量零的结果。这种情况只发生在第一次。 第二条信息 rchust_2-1756882331448.png 最后一个字节根本不显示。也许它不知何故丢失了,但即便如此,如果其他四个字节是由 MSB 排序的,也不应该出现在第一个单词中。 第三条信息 rchust_3-1756882533429.png 这似乎与预期的一样,能获取所有数据,而且我猜是按照预期的顺序。我说,我猜这是预期的顺序,因为在结算后,我收到的所有信息都是如此。 问题在于,它并不总是第三条消息,一条是好消息,有时是第五或第六条消息,有时第五个字节根本不出现,有时它出现在第二个单词上。一旦开始正确操作,它就会持续工作。有什么办法可以解决这个问题?下面是代码和配置: 无效 响应420(数据包* 数据包){ zc_spi_transfer(&spi_rx,&spi_to_can_packet); transfer_E2E_spi_packet(&E2E_spi、&包,&packet->temp_data[0]); memcpy(&can_response.temp_data, spi_too_can_packet.rx_buffer, 8); zc_can_send(&can,&can_response, MAILBOX_0); } void zc_spi_transfer(zc_spi_hw* hw_config、数据包* 数据包){ hw_config->数据包= 数据包; 如果(hw_config->hw_mode== 主模式){ SPI_MasterTransfer(hw_config->实例数据包>tx_buffer数据包>数据包数据包>信息字节长度*NUMBER_OF_BITS_IN_BYTE)/hw_config->主配置->帧大小); }否则{ SPI_SlaveTransfer(hw_config->实例数据包>tx_buffer数据包>数据包数据包>信息字节长度*NUMBER_OF_BITS_IN_BYTE)/hw_config->从配置->帧大小); } } void transfer_E2E_spi_packet(E2E_spi_handler* E2E_spi_handler E2E_spi_packet* 数据包、 uint8_t* 数据){ E2E_spi->保护器处理程序->保护包(E2E_spi->保护器处理程序,数据,数据包->数据包.data_length_bytes, &(数据包>raw_spi_packet.tx_buffer[0]), packet->数据包.E2E_packet_id,数据包>数据包.计数器); zc_spi_transfer(E2E_spi-)>处理程序&(packet->raw_spi_packet)); 数据包>数据包.计数器++; // 在此 CRC 格式中实际上并未使用此函数,但此函数可用于多种 CRC 格式 如果(packet->数据包.计数器> E2E_spi->保护器处理程序->溢出计数器){数据包->数据包.计数器= 0;} } response420 函数是接收 CAN 数据包的"回调" ,当 CAN 回调本身的标志上升时,主程序内部会调用该函数。CAN 部分其实并不重要,因为这个错误是在没有 CAN 的情况下发生的,我在调试器出现这个错误后尝试了 CAN,以便测试更多的输入。 一般来说,我使用的是 PAL,从函数 SPI_SlaveTransfer 和 SPI_Master 传输中可以看出这一点。这是 PAL 配置: SPI_1 config: { .baudRate = 2000000U、 .frameSize = 40U、 .bitOrder = spi_transfer_msb_first, .clockPolarity = .spi_active_high, .ssPolarity = SPI_ACTIVE_LOW, .clockPhase = 读取偶数边沿, .ssPin = 0、 .transferType = 传输类型, .rxDMAChannel = 0U、 .txDMAChannel = 0U、 .callback = NULL、 .callbackParam = NULL、 .extension = NULL } SPI_0 配置: { .frameSize = 40U、 .bitOrder = spi_transfer_msb_first, .clockPolarity = .spi_active_high, .ssPolarity = SPI_ACTIVE_LOW, .clockPhase = 读取偶数边沿, .transferType = 传输类型, .rxDMAChannel = 0U、 .txDMAChannel = 0U、 .callback = NULL、 .callbackParam = NULL、 .extension = NULL } 有人发现过类似问题吗? Re: Weird behavior in S32K144 board to board SPI communication 好的,很高兴知道。非常感谢@danielmartynek! Re: Weird behavior in S32K144 board to board SPI communication 很好,看来现在可以正常工作了。
硬件支持字节交换,但是 SDK 驱动程序不支持。
danielmartynek_0-1757591362505.png
Re: Weird behavior in S32K144 board to board SPI communication 好的,我最大限度地简化了代码: uint8_tdata_too_send[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; uint8_tdata_received[8]; lpspi_state_tlpspiState; int main(){ zc_clock_init(); zc_start_scheduler(); const clock_names_tclocknames[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES; clock_names_tclockname = clocknames[1]; lpspi_master_config_tspiConfig = { .bitcount = 8U、 .bitsPerSec = 20000000、 .callback = NULL、 .callbackParam = NULL、 .clkPhase = 1、 .clkPolarity = 0、 .isPcsContinuous = true, .lpspiSrcClk = 时钟名、 .lsbFirst = false、 .pcsPolarity = 0、 .rxDMAChannel = 0、 .transferType = LPSPI_USING_INTERRUPTS、 .txDMAChannel = 0、 .whichPcs = 0、 }; LPSPI_DRV_MasterInit(1,&lpspiState,&spiConfig); config_spi_pinout(spi_pinoutconfigs[1].引脚输出); 而(1){ LPSPI_DRV_MasterTransfer(1,&data_too_send[0],&data_received[0], 8); zc_delay_milliseconds(1000); } 返回0; } 如果我这样做,并将比特数设为 8,结果就是这样: rchust_0-1757584304367.png 间距是这里的问题所在,但至少与预期的效果差不多 位数 32 也是如此: rchust_1-1757584408075.png 每个单词中的字节都会反转... 最后,同样使用 64 位,看看会发生什么: rchust_2-1757584507750.png 一样的。 如果我把它放在字数组而不是 uint8_t 数组中,会发生什么情况? uint32_tdata_too_send[2] = {x001020304, 0x05060708}; uint8_tdata_received[8]; lpspi_state_tlpspiState; int main(){ zc_clock_init(); zc_start_scheduler(); const clock_names_tclocknames[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES; clock_names_tclockname = clocknames[1]; lpspi_master_config_tspiConfig = { .bitcount = 64U、 .bitsPerSec = 20000000、 .callback = NULL、 .callbackParam = NULL、 .clkPhase = 1、 .clkPolarity = 0、 .isPcsContinuous = true、 .lpspiSrcClk = 时钟名、 .lsbFirst = false、 .pcsPolarity = 0、 .rxDMAChannel = 0、 .transferType = LPSPI_USING_INTERRUPTS、 .txDMAChannel = 0、 .whichPcs = 0、 }; LPSPI_DRV_MasterInit(1,&lpspiState,&spiConfig); config_spi_pinout(spi_pinoutconfigs[1].引脚输出); 而(1){ LPSPI_DRV_MasterTransfer(1, (uint8_t*)&data_to_send[0],&data_received[0], 8); zc_delay_milliseconds(1000); } 返回0; } rchust_3-1757584645130.png 它确实有效... 这样看来,如果不使用帧大小 8,就会按字发送,而字是 Little endian 的。有办法更改字节序吗? Re: Weird behavior in S32K144 board to board SPI communication 你好@danielmartynek 我已经使用了 uint8_t 数组 Re: Weird behavior in S32K144 board to board SPI communication 嗨,@rchust、
如何定义 tx_buffer?
驱动程序希望得到一个指向 8 位数组的 8 位指针(在 LPSPI_DRV_MasterTransfer()中)。
那么,能否使用 uint8_t[5] tx_buffer 代替在此处传递字?
谢谢
Re: Weird behavior in S32K144 board to board SPI communication 你好@danielmartynek、 我使用8位帧进行了测试,它可以正常工作,按顺序发送字节。但有两个问题。 首先,在 8 位帧中,硬件按字节拆分数据,这应该是帧的定义,但将来这可能会给我带来问题,我还没有测试 PC33771 是否接受具有这些间距的消息。它应该这样做,但并不完全符合预期。 第二个问题(也是我尚未使用 PC33771 进行测试的原因)是,pal 库不允许我将连续模式设置为 true,pal 库中的 Master_init 方法只是在将其传递给LPSPI_DRV_MasterInit之前将其硬设置为 false: status_t SPI_MasterInit(态 spi_instance_t* const实例、 (const)、(const) 配置*config) { status_tstatus = STATUS_ERROR; uint8_tindex = 0; /* 通过 LPSPI 定义 SPI PAL */ #if(定义了 (SPI_OVER_LPSPI) /*!用于 LPSPI 的简短时钟名称 */ const 时钟名称g_lpspiClock[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES 如果(instance->instType== spi_inst_type_lpspi) { lpspi_master_config_tlpspiConfig; lpspiConfig.比特每秒= 配置->波特率; lpspiConfig.whichPcs= (lpspi_which_pcs_t) config->ssPin; lpspiConfig.pcsPolarity= (lpspi_signal_polarity_t)(!(bool)(config->ssPolarity)); lpspiConfig.比特数= config->帧大小; (void)CLOCK_SYS_GetFreq(g_lpspiClock[(uint32_t)实例->instIdx]&lpspiConfig.lpspiSrcClk); lpspiConfig.clkPhase= (lpspi_clock_phase_t) config->时钟相位; lpspiConfig.clkPolarity= (lpspi_sck_polarity_t) config->时钟极性; lpspiConfig.lsbFirst= config->位顺序; lpspiConfig.传输类型= (传输类型) config->传输类型; lpspiConfig.rxDMAChannel= config->rxDMAChannel; lpspiConfig.txDMAChannel= config->txDMAChannel; lpspiConfig.回调= config->回调; lpspiConfig.回调参数= config->回调参数; lpspiConfig.isPcsContinuous= false; /* 为该实例分配一个 LPSPI 状态结构 */ 索引 = SpiAllocateState(LpspiStateIsAllocated,LpspiStateInstanceMapping,instance->instIdx,no_of_lpspi_insts_for_spi); status = LPSPI_DRV_MasterInit(instance-)>instIdx, (lpspi_state_t*)(&LpspiState[index]),&lpspiConfig); } else #endif 我需要更改所有库,停止使用 pal,开始使用 DRV 方法,然后才能在连续模式下进行测试。我将这样做并更新结果,但在 8 位帧时,它似乎确实是按正确的顺序发送的。不过,没有 40 位帧仍然令人沮丧。 Re: Weird behavior in S32K144 board to board SPI communication 嗨,@rchust、
感谢您的更新。
能否使用 8 位数组作为 tx_buffer?
Re: Weird behavior in S32K144 board to board SPI communication 好了,经过一些测试,我找到了问题的根源。 看来,即使我不使用 CAN,我也在配置它的引脚,其中一个引脚确实与主站的 CS 相撞。我不知道为什么会出现这样那样的问题,但在移除 CAN 配置后,大部分问题都消失了,只有一个问题除外。 出于某种原因,当我以高于 8 位的帧发送数据时,每个字中的字节会互换。如果我将一个 64 位帧的数据 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 -> 0x04 0x03 0x02 0x01 0x8 0x07 0x06 0x05。这似乎是因为 spi 在内部使用单词而我正在逐字节放置数据。也可能是 Pal 图书馆。 Re: Weird behavior in S32K144 board to board SPI communication 你好@danielmartynek、 首先你是对的,我说了我的集成开发环境版本,SDK 是 4.0.2;对不起。 我展示的代码是 CAN 回调,我将 CAN 数据复制到 SPI 缓冲区。代码是这样的,因为我们试图将其嵌入到一个自定义库中,但实际上它只是将从 CAN 读取的内容发送到 SPI(SPI1),然后再将从属设备(SPI0)读取的内容发送到 CAN。 CAN 发送 4 个字节,然后 protect 添加最后一个字节,即 CRC,因此 SPI 发送 5 个字节,然后读取 5 个字节,然后 CAN 只发送缓冲区前 8 个字节内的任何内容。缓冲区本身实际上更大,但是 SPI_MasterTransfer 只发送其中的前 5 个字节。 我检查了调试模式,发送时SPI的字节在 SPI_MasterTransfer中总是按预期顺序排列,没有间隔。它似乎总是能正确发送(或者至少保持一致性),所以问题似乎在于从属的接收。 在主拦截系统中,似乎也会出现同样的问题。我不能用从站阻塞来检查,因为这样会阻止主站发送。我还发现,把主站和从站的时钟极性都设置为低电平会使它错过很多高比特,但还是先解决接收第一条信息失灵的问题吧。 Re: Weird behavior in S32K144 board to board SPI communication 嗨,@rchust、
看来您指定的是集成开发环境(3.6.2),而不是 SDK/RTD。
如果我有版本的编号,我可以检查是否有报告的错误。
我看到您使用了非阻塞方法,能否用阻塞传递函数进行测试?
代码的可读性不强。
您在传递函数中将哪些值作为参数?
如何填充缓冲区?
在 SPI 通信中观察到的间隙是由驱动程序开销造成的--驱动程序无法足够快地填充发送 FIFO。 在 8 位模式下,驱动程序一次向 FIFO 写入一个字节的数据,这会导致连续写入之间的延迟。SPI 时钟速度越高,这种延迟越明显。 为减少这一问题,建议使用 DMA。
此致,
丹尼尔
Re: Weird behavior in S32K144 board to board SPI communication 你好,丹尼尔、 我的 SDK 是 3.6.2 版、我通过 33664EVB 板及其 TPL 使用 SPI,我没有使用芯片选择,通道分别是 SPI1_clock、SPI1_tx、TPL1_Data 和 TPL1_clock。为了避免混淆,我将在今后的图片中为它们命名。我要指出的是,我测试过将后两者直接接入 SPI0_rx 和 SPI0_clock,结果显示相同。 我在 8 位模式下进行了测试,结果如下: 第一条信息 rchust_0-1756888805291.png 第四条信息 rchust_1-1756888893698.png 首先值得注意的是,第一个词与第二个词之间的巨大差距。我还用更大的信息进行了测试,当使用 8 位时,每个字之间会出现间隙。如果我试着降低频率,间隙就会减小,直到 500 千赫左右才消失。尽管如此,33664EVB和3771应用笔记仍建议使用2MHz,通常不希望降低速度。 那么,问题虽然不完全相同,但仍然类似。起初最后一个字节根本不出现,然后它首先出现,然后是按正确顺序出现的其他字节。还需要指出的是,在 8 位模式下,数据是按照我输入的顺序发送的,而在 40 位模式下,数据在信号中交换,然后由从属设备再次交换。 如果不是因为字与字之间的巨大差距,8 位会更受欢迎,但问题依然存在。8 位 500kHz: 第一条信息: rchust_2-1756889381283.png 第二条信息 rchust_3-1756889458503.png 第三条信息,以此类推: rchust_4-1756889521919.png 这显示了两个问题,第一个是我所说的从机读取的数据不一致,然后看到TPL的时钟我们可以看到第二个问题;TPL保持脉冲宽度就好像是2MHz一样。这也是我需要这种速度的原因之一。 Re: Weird behavior in S32K144 board to board SPI communication 嗨,@rchust、
能否说明驱动程序的版本?
您使用的是什么协议?您使用芯片选择信号吗?
你能在逻辑分析器捕获中标记通道吗?
LPSPI 硬件支持连续发送 8 位帧,我们的软件驱动程序与之兼容。
您可以通过将 8 位数据放入 FIFO,在连续模式下传输 40 位帧。
此外,请尝试以较低的波特率测试 SPI 通信,以消除与定时或信号完整性有关的任何潜在问题。
此致,
丹尼尔
View full article