S32K144-33664-BCC33772B spi 从站回调问题 你好,论坛、 我在使用 S32K144 与 BCC33772 通信时遇到了问题。 我正确地唤醒了 TPL 收发器,为 BCC33772 分配了一个 ID,并询问了电压;我甚至得到了 BCC33772 对我的从属设备的响应。 问题就在最后,因为这种响应不会触发信号 spi 从站的回调,就好像它没有收到大小合适的传输,但总线上有总线。 令我不解的是,它确实正确接收了我为确保建立正确通信而分配的 ID 检索传输,但问题似乎出在要求多个响应上。 我使用该功能既与主站通信,又与从站接收: void spi_hw_transfer(zc_spi_hw* hw_config、数据包* 数据包){ hw_config->数据包= 数据包; uint16_ttotal_bytes = (((packet->消息字节长度<<3) - 1 + hw_config->帧数据字节数) / hw_config->帧数据大小比特)* hw_config->帧总字节数; 如果(hw_config->hw_mode== 主模式){ hw_config->zc_hw_load_spi_buffer(hw_config, packet->tx_buffer数据包>消息字节长度); LPSPI_DRV_MasterTransfer(hw_config->spi_id, hw_config->传输缓冲区, hw_config->接收缓冲区, total_bytes); }否则{ hw_config->zc_hw_load_spi_buffer(hw_config, packet->tx_buffer数据包>消息字节长度); LPSPI_DRV_SlaveTransfer(hw_config->spi_id, hw_config->传输缓冲区, hw_config->接收缓冲区, total_bytes); } } 数据包只是一个结构体,其中包含几个变量,用于指定我想要做的事情,但这里基本上有三个相关的数据包: send_order,其信息字节长度为 6 receive_single_response,其信息字节长度为 12 receive_voltage_response,其信息字节长度为 42 我使用这个函数将我想要发送的顺序填入 send_order: void BCC33772_load_binary_payload(数据包* 数据包、 uint8_tmemdata_high、 uint8_tmemdata_low、 uint8_tregister_addr、 uint8_tdevice_id、 uint8_tdevice_cr、 uint8_tcmd){ uint8_t* 缓冲区 = 数据包->tx_buffer; 缓冲区[0] = memdata_high; 缓冲区[1] = memdata_low; buffer[2] = register_addr; //我们假定响应位为零,因为这个 有效载荷是一个请求 缓冲区[3] = 设备 ID; buffer[4] = device_cr<< 4 | cmd; } 这些都是在配置后检查 ID 集和要求电压的调用: BCC33772_load_binary_payload(&send_order, 0x0, 0x1, BCC33772B_INIT_REGISTER, 0x1, 0, BCC33772B_READ_CMD); spi_hw_transfer(&spi_rx,&send_order); spi_hw_transfer(&spi_tx,&receive_single_response); ,这确实有效。然后调用六种电压: BCC33772_load_binary_payload(&send_order, 0x0, 0x6, BCC33772B_INIT_REGISTER, 0x1, 0, BCC33772B_READ_CMD); spi_hw_transfer(&spi_rx,&send_order); spi_hw_transfer(&spi_tx,&receive_voltage_response); ,而不是。(如果 BCC33772 关闭并且只是一遍又一遍地填充 send_order 数据,它确实会触发信号)。 这是 spi_rx 和 spi_tx 通道上的信息(延迟是因为 TPL 的缘故) rchust_0-1764241709697.png 这是我的配置: RX = { .bitcount = 48u、 .callback = NULL、 .callbackParam = NULL、 .clkPhase = LPSPI_CLOCK_PHASE_2ND_EDGE、 .clkPolarity = 0、 .lsbFirst = false、 .pcsPolarity = LPSPI_ACTIVE_LOW、 .rxDMAChannel = 0、 .transferType = LPSPI_USING_INTERRUPTS、 .txDMAChannel = 0、 .whichPcs = 0、 }; TX = { .bitcount = 48u、 .bitsPerSec = 2000000、 .callback = NULL、 .callbackParam = NULL、 .clkPhase = LPSPI_CLOCK_PHASE_2ND_EDGE、 .clkPolarity = 0、 .isPcsContinuous = true、 .lpspiSrcClk = 48000000、 .lsbFirst = false、 .pcsPolarity = LPSPI_ACTIVE_LOW、 .rxDMAChannel = 0xFF、 .transferType = LPSPI_USING_INTERRUPTS、 .txDMAChannel = 0xFF、 .whichPcs = 0、 }; (它们都配置为从 FIR 时钟馈电) Re: S32K144-33664-BCC33772B spi slave callback problem 您好,
您没有详细说明硬件(原理图、连接等),因此假定硬件已正确连接。 如果您使用的是 MC33772B,那么该 BCC 使用 40 位命令,而 C 版本使用 48 位命令。 因此,对于 MC33772B,您的代码是不正确的。无论如何你可以参考 MC33771B/MC33772B 的 BCC 软件驱动程序代码包,可在 https://www.nxp.com/design/design-center/software/analog-expert-software-and-tools/sdk-analog-expert-drivers/embedded-sw-battery-cell-controller-software-driver-for-mc33771b-mc33772b:EMBEDDED-SW-BCC#downloads 上获得
BR, Petr Re: S32K144-33664-BCC33772B spi slave callback problem 在此之前,我提供了一份我的代码简历,但现在我删掉了一些东西,只保留了主代码所需的最低限度,而这正是我的代码: #definevoltage_count 6 #defineID_33772 1 uint32_tsingle_response_counter; uint32_t电压响应计数器; zc_spi_packet发送顺序; zc_spi_packetreceive_single_response; zc_spi_packet 接收电压响应; zc_spi_hwspi_tx; zc_spi_hwspi_rx; zc_digital_out引脚 1; zc_digital_out引脚 2; zc_digital_out引脚 3; 无效 唤醒(zc_spi_hw* spi){ spi_hw_set_cs_polarity(spi, 0, true); //这将关闭它,因为我们没有发送信息,所以选中时为高电平 + 未选中时 = 低电平 zc_delay_microseconds(21U); spi_hw_set_cs_polarity(spi, 0, false); zc_delay_microseconds(600U); spi_hw_set_cs_polarity(spi, 0, true); zc_delay_microseconds(21U); spi_hw_set_cs_polarity(spi, 0, false); zc_delay_microseconds(1000U); } void load_binary_payload(数据包* 数据包、 uint8_tmemdata_high、 uint8_tmemdata_low、 uint8_tregister_addr、 uint8_tdevice_id、 uint8_tdevice_cr、 uint8_tcmd、 uint8_tcrc){ uint8_t* buffer = packet->tx_buffer; 缓冲区[0] = memdata_high; 缓冲区[1] = memdata_low; buffer[2] = register_addr; //我们假定响应位为零,因为这个 有效载荷是一个请求 缓冲区[3] = 设备 ID; buffer[4] = device_cr<< 4 | cmd; buffer[5] = crc; } void single_callback(数据包* 数据包){ single_response_counter++; } void 电压回调(数据包* 数据包){ 电压响应计数器++; } int main(){ zc_clock_init(); zc_start_scheduler(); zc_create_spi_packet(&send_order, 6, NULL, NULL); zc_create_spi_packet(&receive_single_response, 12, single_callback, NULL); zc_create_spi_packet(&接收电压响应, 42, voltage_callback, NULL); initialize_hw_spi(&spi_tx,SPI_1、 主); initialize_hw_spi(&spi_rx,SPI_2、 驱动); //在 33664 中启用 TPL2 zc_init_digital_out(&pin1,&PD4); zc_init_digital_out(&pin2,&PA16); zc_init_digital_out(&pin3,&PC13); zc_turn_on_do(&pin1); zc_turn_on_do(&pin2); zc_turn_on_do(&pin3); //启动 33664 wakeup(&spi_tx); wakeup(&spi_tx); //RESET 33772 uint8_tsoft_reset_data[2] = {0 、 bcc33772b_soft_reset}; load_binary_payload(&send_order, soft_reset_data[0], soft_reset_data[1]、 BCC33772B_SYS_CFG1_CONFIG_REGISTER, 0, 0, BCC33772B_WRITE_GLOBAL_CMD, 0x5A); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(2000U); /设置 ID uint8_tset_id_data[2] = {0 , ID_33772}; load_binary_payload(&send_order, set_id_data[0], set_id_data[1]、 BCC33772B_INIT_REGISTER, 0, 0, bcc33772b_write_cmd, 0x85); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(2000U); //读取设置 ID load_binary_payload(&send_order, 0, 1、 BCC33772B_INIT_REGISTER, ID_33772, 0、 bcc33772b_read_cmd, 0x1D); spi_hw_transfer(&spi_rx,&receive_single_response); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(2000U); /设置 ID uint8_tset_id_data_2[2] = {0 , ID_33772+1}; load_binary_payload(&send_order, set_id_data_2[0], set_id_data_2[1]、 BCC33772B_INIT_REGISTER, 0, 0, bcc33772b_write_cmd, 0x75); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(2000U); //读取设置 ID load_binary_payload(&send_order, 0, 1、 BCC33772B_INIT_REGISTER, id_33772+1, 0、 bcc33772b_read_cmd, 0x09); spi_hw_transfer(&spi_rx,&receive_single_response); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(2000U); 而(1){ 如果(every_100_ms){ every_100_ms = false; //阅读电压 uint8_tadc_cfg_data[2] = { 0x4 | 0x8, 0x3F}; load_binary_payload(&send_order, adc_cfg_data[0], adc_cfg_data[1]、 bcc33772b_adc_cfg_config_register, ID_33772, 0、 bcc33772b_write_cmd, 0x39); spi_hw_transfer(&spi_tx,&send_order); zc_delay_microseconds(200); load_binary_payload(&send_order, 0, 6、 BCC33772B_MEASURE_CELL6_VOLTAGE, ID_33772, 0、 bcc33772b_read_cmd, 0x04); spi_hw_transfer(&spi_rx、&接收电压响应); spi_hw_transfer(&spi_tx,&send_order); } } 返回0; } zc_spi_hw.c 文件很长,但大部分内容都是配置和兼容性。这些都是在本案中可能很重要的: void spi_hw_transfer(zc_spi_hw* hw_config、数据包* 数据包){ hw_config->数据包= 数据包; uint16_ttotal_bytes = (((packet->消息字节长度<<3) - 1 + hw_config->帧数据字节数) / hw_config->帧数据大小比特)* hw_config->帧总字节数; 如果(hw_config->hw_mode== 主模式){ hw_config->zc_hw_load_spi_buffer(hw_config, packet->tx_buffer数据包>消息字节长度); LPSPI_DRV_MasterTransfer(hw_config->spi_id, hw_config->传输缓冲区, hw_config->接收缓冲区, total_bytes); }否则{ hw_config->zc_hw_load_spi_buffer(hw_config, packet->tx_buffer数据包>消息字节长度); LPSPI_DRV_SlaveTransfer(hw_config->spi_id, hw_config->传输缓冲区, hw_config->接收缓冲区, total_bytes); } } void spi_hw_set_cs_polarity(zc_spi_hw* hw_config、 uint8_tcs_id, bool high_on_select){ lpspi_signal_polarity_tpolarity = high_on_select ? 高电平: lpspi_active_low; LPSPI_DRV_SetPcs(hw_config->spi_id,cs_id,极性); } void __zc_hw_load_spi_buffer_full_byte(zc_spi_hw* hw_config、 uint8_t* 数据、 uint16_tdata_length){ uint16_tframe_data_size_bytes = (data_length - 1 + hw_config-)>frame_data_size_bytes)/ hw_config->帧数据字节数; 为(uint16_ti = 0; i< frames_to_send; i++){ memcpy(hw_config->传输缓冲区+ hw_config->frame_total_size_bytes*数据 + hw_config->帧数据大小字节*数据 + hw_config- frame_data_size_bytes>帧数据大小字节); uint32_t* last_word_of_frame = (uint32_t*) (hw_config->传输缓冲区+ hw_config->frame_total_size_bytes*(i+1) - 4); *last_word_of_frame = *last_word_of_frame<< hw_config->帧_比特_padding; } } void __zc_hw_unload_spi_buffer_full_byte(zc_spi_hw* hw_config、 uint8_t* 数据、 uint16_tdata_length){ uint16_t帧接收 = (data_length - 1 + hw_config-)>frame_data_size_bytes)/ hw_config->帧数据字节数; 为(uint16_ti = 0; i< frames_to_receive; i++){ uint32_t* last_word_of_frame = (uint32_t*) (hw_config->接收缓冲区+ hw_config->frame_total_size_bytes*(i+1) - 4); *last_word_of_frame = *last_word_of_frame>> hw_config->帧_比特_padding; memcpy(数据 + hw_config->frame_data_size_bytes数据 *i, hw_config->接收缓冲区+ hw_config->帧总数据字节数*帧>frame_data_size_bytes); } } void __zc_hw_spi_callback_master(void*驱动状态、 事件事件、 void*用户数据){ (void) 驱动状态; (void) 事件; zc_spi_hw* spi_handler = (用户数据*) userData; zc_spi_packet* packet = (spi_handler)->传输的数据包; 如果(packet != NULL&& packet->回调!= NULL){ 数据包>回调(数据包); } } void __zc_hw_spi_callback_slave(驱动状态*驱动状态、 事件事件、 void*用户数据){ (void) 驱动状态; (void) 事件; zc_spi_hw* hw_config = (zc_spi_hw*用户数据; zc_spi_packet* 数据包 = hw_config->传输的数据包; hw_config->zc_hw_unload_spi_buffer(hw_config, packet->rx_buffer数据包>消息字节长度); 如果(packet != NULL&& packet->回调!= NULL){ 数据包>回调(数据包); } } 问题是,当试图读取电压时,spi_rx 输出LPSPI_TRANSMIT_FAIL,我不知道为什么。在 spi_hw_transfer 中调用 LPSPI_DRV_SlaveTransfer 的结果是: LPSPI_DRV_SlaveTransfer(2, spi_rx->transfer_buffer, spi_rx->receive_buffer, 56) 56 来自 uint16_ttotal_bytes = (((packet->消息字节长度<<3) - 1 + hw_config->帧数据字节数) / hw_config->帧数据大小比特)* hw_config->帧总字节数; 因为我们发送的是 48 位大小的帧,而 SPI 外围设备是以全字工作的。因此,实际帧大小为 64 位,而且只发送其中的前 48 位。至少这是我在 PAL 库中读到的信息,而且似乎有效(除了最后一条信息)。 Re: S32K144-33664-BCC33772B spi slave callback problem 您好, 很抱歉我弄错了,是 33772C;我弄混了,因为我之前用的是 33771B,它确实有 40 位。 所有硬件、crc 计算、信息大小和 ID 分配都应该是正确的,因为我可以在逻辑分析仪上看到数据交换,而且 33772C 在我要求时也确实以我给它的 ID 回应我。事实上,如图所示,它也对电压数据做出了响应,只是我的从属设备没有捕捉到而已。 这是一个接收时的代码问题,我想我已经缩小了范围。错误似乎出在 TX 上,因为如果我在 tx 缓冲区中输入 NULL,它就能正常工作。从技术上讲,这种使用情况是可以解决的,因为这是 TPL 从站,33664 从站接收不到任何信息(甚至没有路由)。 不过,我还是想知道为什么发送时不工作。如果我将 zc_create_spi_packet(&receive_voltage_response,X,voltage_callback,NULL); 其中 X 为 32 或更低值,就能捕捉到它。所以看来它最多可以发送 32 字节但如果发送更多字节就会失败? Re: S32K144-33664-BCC33772B spi slave callback problem 您好,
对于 MC33772C,只需参考可用的驱动程序;https://www.nxp.com/webapp/Download?colCode=EMBEDDED-SW-BCC-MC33771C&appType=license 它还使用 NULL 作为从站/主站 TX/RX 缓冲区的参数。
PetrS_2-1764594742261.png
PetrS_0-1764594498684.png
还要确定缓冲区的对齐方式和 SDK 传输函数中使用的 transferByteCount 值
PetrS_1-1764594690958.png
BR, Petr Re: S32K144-33664-BCC33772B spi slave callback problem 我发现了发生了什么,至少我是这么认为的。 只有当我尝试使用 DRV 库从属接收长度超过 8 个字的报文时,问题才会出现。 我还发现,如果将传输缓冲区设置为空值,告诉 DRV 只接收,错误就不会再发生了。错误发生在传输过程中,我看到传输缓冲区中没有传输我给它的 0,而是出现了一些满是 1 的帧。 最后,我试着用另一个 s32k144 进行测试,发现只有在频率达到或超过 2MHz 时才会出现这种情况,而且我还为 MCU 配置了 48MHz 时钟,而不是 80MHz 时钟。 因此,似乎是软件运行不足,DRV 回调无法以足够快的速度向从属设备上的中断传输缓冲区提供数据,从而导致错误。至于 33772C,由于要通过 TPL,所以不需要在从属设备上转接,我就不转接了。今后,使用 DMA 代替中断很可能会解决这个问题。
記事全体を表示