资讯动态

ESP-IDF Parallel IO TX 驱动完全指南:从 QPI 时序模拟到无限循环传输与 BitScrambler

发布时间:2026/9/16 14:28:57 来源:尧图企业网站定制
ESP-IDF Parallel IO TX 驱动完全指南从 QPI 时序模拟到无限循环传输与 BitScrambler【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf导读Parallel IO TX 单元下文简称 TX 单元是 ESP-IDF 并行接口Parallel IO / PARLIO的发送侧通过 GDMA 在并行总线上完成片外设备与内部存储器的数据通信。本文以 parlio_tx.rst 为主线结合 esp_driver_parlio 组件源码与 parlio_tx 示例系统讲解 TX 单元的创建使能、事务发起、事件回调、外部时钟、无限循环传输、BitScrambler 装饰、电源管理与 Cache 安全等完整使用链路。读完本文你将能够使用 TX 单元驱动 HUB75 RGB LED 矩阵、模拟 QPI/SPI/I80 等并行时序并掌握其底层 DMA 调度与时钟分频原理。引言TX 单元能做什么TX 单元属于通用并行接口Parallel IO的发送部分它借助 GDMA 在并行数据总线上实现片外设备与片内存储器之间的数据发送。得益于数据位宽与时钟的灵活性TX 单元可以当作通用接口连接各种外设典型应用场景包括驱动 LCD、LED 显示屏如 HUB75 接口 RGB LED 矩阵与其他设备进行高速并行通信在外设数量不足时模拟其他外设的时序。从源码角度看TX 单元句柄 parlio_tx_unit_handle_t 本质是指向 TX 单元内存对象的指针驱动内部通过原子变量维护有限状态机FSMINIT → WAIT → ENABLE/RUN并用 FreeRTOS 队列管理事务描述符相关实现见 parlio_tx.c。快速开始用 TX 单元模拟 QPI 时序本节通过一个模拟 QPIQuad Peripheral Interface四线外设接口传输时序的简单示例演示如何创建并使能 TX 单元、发起传输事务、注册事件回调。整体使用流程为通过parlio_tx_unit_config_t配置参数并调用parlio_new_tx_unit创建实例调用parlio_tx_unit_enable使能单元调用parlio_tx_unit_transmit发起传输注册事件回调获取完成通知不再使用时先parlio_tx_unit_disable再parlio_del_tx_unit释放资源。创建并使能 TX 单元以下代码展示了如何创建一个用于模拟 QPI 的 TX 单元实例parlio_tx_unit_handle_t tx_unit NULL; parlio_tx_unit_config_t config { .clk_src PARLIO_CLK_SRC_DEFAULT, // 选择默认时钟源 .data_width 4, // 数据宽度为 4 位 .clk_in_gpio_num -1, // 不使用外部时钟源 .valid_gpio_num EXAMPLE_PIN_CS, // 使用 valid 信号作为片选 .clk_out_gpio_num EXAMPLE_PIN_CLK, .data_gpio_nums { EXAMPLE_PIN_DATA0, EXAMPLE_PIN_DATA1, EXAMPLE_PIN_DATA2, EXAMPLE_PIN_DATA3, }, .output_clk_freq_hz 10 * 1000 * 1000, // 输出时钟频率为 10 MHz .trans_queue_depth 32, // 事务队列深度为 32 .max_transfer_size 256, // 最大传输大小为 256 字节 .shift_edge PARLIO_SHIFT_EDGE_NEG, // 在时钟下降沿移位数据 .flags { .invert_valid_out true, // valid 信号默认高有效取反后模拟 QPI 时序中的片选信号 CS } }; // 创建 TX 单元实例 ESP_ERROR_CHECK(parlio_new_tx_unit(config, tx_unit)); // 使能 TX 单元 ESP_ERROR_CHECK(parlio_tx_unit_enable(tx_unit));创建实例时需要通过parlio_tx_unit_config_t配置时钟源、数据宽度、输出时钟频率等参数结构体定义见 parlio_tx.h然后调用parlio_new_tx_unit返回指向新实例的句柄。parlio_tx_unit_config_t 配置参数详解参数说明clk_src设置 TX 单元的时钟源。可用时钟源见parlio_clock_source_t只能选择一个。不同时钟源在分辨率、精度与功耗上有所差异。clk_in_gpio_num使用外部时钟作为时钟源时设置对应的时钟输入 GPIO 号否则设为-1驱动使用内部clk_src作为时钟源。该选项优先级高于clk_src。input_clk_src_freq_hz外部输入时钟源的频率仅在clk_in_gpio_num不为-1时有效。output_clk_freq_hz设置输出时钟频率由内部或外部时钟源分频得到。注意并非所有频率都能精确实现无法达到设定频率时驱动会自动调整到最近频率。clk_out_gpio_num输出时钟信号的 GPIO 号。data_widthTX 单元的数据总线宽度必须是 2 的幂且不大于SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH。data_gpio_numsTX 数据的 GPIO 号数组未使用的 GPIO 应设为-1。valid_gpio_numvalid 信号的 GPIO 号不使用则设为-1。TX 单元传输数据期间 valid 信号保持高电平。注意在某些特定芯片上使能 valid 信号会占用 MSB 数据位使 TX 单元最大数据宽度减少 1 位此时最大可配置总线宽度为SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH / 2请检查parlio_new_tx_unit的返回值。valid_start_delayvalid 信号在 TX 单元开始传输数据前保持高电平的时钟周期数。该选项依赖具体硬件特性在不支持的芯片上使能或配置无效值时会出现类似invalid valid delay的错误信息。valid_stop_delayvalid 信号在 TX 单元传输完数据后仍保持高电平的时钟周期数。该选项依赖具体硬件特性配置无效时同样会出现invalid valid delay错误。trans_queue_depth内部事务队列深度。队列越深可排队的待处理事务越多。max_transfer_size单次事务的最大传输大小字节。该值决定每个事务使用的 DMA 节点数量。dma_burst_sizeDMA 突发传输大小字节必须是 2 的幂。shift_edgeTX 单元的数据移位边沿PARLIO_SHIFT_EDGE_POS/PARLIO_SHIFT_EDGE_NEG。bit_pack_order设置一个字节内数据位的打包顺序仅在data_width 8时有效。flags用于微调驱动行为的标志位包括flags::invert_valid_out决定是否在将 valid 信号送到 GPIO 引脚前将其取反。在支持对应特性的芯片上flags还包含以下选项由编译期宏门控flags::clk_gate_enSOC_PARLIO_TX_CLK_SUPPORT_GATING使能 TX 单元时钟门控输出时钟由数据总线的 MSB 位控制即向data_gpio_nums[SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH - 1]写高电平使能时钟输出、写低电平关闭。此时数据总线宽度需配置为SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH。注意若同时使能 valid 信号输出与时钟门控时钟门控可来自 valid 信号此时对数据总线宽度没有限制但在某些芯片上 valid 信号占用 MSB 数据位最大可配置总线宽度为SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH / 2。flags::allow_pdSOC_PARLIO_SUPPORT_SLEEP_RETENTION配置驱动是否允许系统在睡眠模式下关闭外设电源。进入睡眠前系统会备份 TX 单元寄存器上下文退出睡眠时恢复。关闭外设电源可节省功耗但代价是消耗更多内存保存寄存器上下文需要权衡功耗与内存。该选项依赖具体硬件特性在不支持的芯片上使能会看到类似register back up is not supported的错误信息。源码佐证在 parlio_new_tx_unit 中驱动会校验data_width必须是 2 的幂且不超过SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH第 264 行在不支持时钟门控或睡眠保留的芯片上分别返回ESP_ERR_NOT_SUPPORTED第 279、283 行valid_start_delay/valid_stop_delay通过parlio_ll_tx_set_valid_delay配置失败时报invalid valid delay第 329 行。注意如果当前芯片的所有 TX 单元都已被占用parlio_new_tx_unit会返回ESP_ERR_NOT_FOUND错误。TX 单元使用前必须先使能。parlio_tx_unit_enable会将驱动内部状态机切换到激活态同时完成一些系统服务请求/注册例如请求电源管理锁对应的parlio_tx_unit_disable会释放全部系统服务。注意parlio_tx_unit_enable与parlio_tx_unit_disable必须成对使用不能连续调用两次相同的函数。这种成对调用原则保证了资源的正确管理与释放。注意TX 单元使能后会检查当前工作队列如果队列中有待处理的传输事务驱动会立即启动传输。发起 TX 传输事务使能 TX 单元后可以配置传输参数并调用parlio_tx_unit_transmit发起 TX 事务#define PAYLOAD_SIZE 128 // 配置 TX 单元传输参数 parlio_transmit_config_t transmit_config { .idle_value 0x00, // 空闲状态下所有数据线为低电平 }; // 准备要发送的数据 uint8_t payload[PAYLOAD_SIZE] {0}; for (int i 0; i PAYLOAD_SIZE; i) { payload[i] i; } // 第一次调用 parlio_tx_unit_transmit 会立即启动传输此时没有正在进行的传输 ESP_ERROR_CHECK(parlio_tx_unit_transmit(tx_unit, payload, PAYLOAD_SIZE * sizeof(uint8_t) * 8, transmit_config)); // 第二次调用可能在上一笔传输未完成时排队该事务并在上一笔完成后于 ISR 上下文中调度 ESP_ERROR_CHECK(parlio_tx_unit_transmit(tx_unit, payload, PAYLOAD_SIZE * sizeof(uint8_t) * 8, transmit_config)); // 可选等待 TX 单元完成所有事务 ESP_ERROR_CHECK(parlio_tx_unit_wait_all_done(tx_unit, -1));TX 单元以“位”为单位传输数据传输位长必须是总线宽度的整数倍。parlio_tx_unit_transmit需要单元句柄、payload 缓冲区、payload 大小单位为位等参数同时通过parlio_transmit_config_t提供本次传输的具体配置。parlio_transmit_config_t配置参数说明参数说明idle_value设置 TX 单元传输完成进入空闲状态后数据线上的值。该值在调用parlio_tx_unit_disable禁用 TX 单元后仍会保持。bitscrambler_programSOC_BITSCRAMBLER_SUPPORTED指向 BitScrambler 程序二进制文件的指针本次传输不使用 BitScrambler 时设为NULL。flags::queue_nonblocking设置传输队列满时函数是否需要等待。若为true队列满时函数立即返回错误码ESP_ERR_INVALID_STATE否则函数会阻塞当前线程直到传输队列有空位。flags::loop_transmissionSOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION设为true时使能无限循环传输。此时传输不会停止除非手动调用parlio_tx_unit_disable且不会产生trans_done事件。由于循环由 DMA 控制TX 单元可以用极少的 CPU 干预产生周期性序列。parlio_tx_unit_transmit内部会构造一个事务描述符并送入工作队列通常在 ISR 上下文中调度。因此当parlio_tx_unit_transmit返回时事务可能尚未开始——在事务结束前不能回收或修改 payload 内容。可以通过parlio_tx_unit_register_event_callbacks注册事件回调来获知事务完成为确保所有待处理事务完成也可以调用阻塞式的parlio_tx_unit_wait_all_done。从源码看parlio_tx_unit_transmit 会做一系列校验payload 位长必须对齐总线宽度第 678 行、不能超过max_transfer_size * 8第 679 行、payload 地址与长度需满足 DMA 对齐约束第 704-707 行当 payload 位于可缓存内存时还会先执行esp_cache_msync写回缓存保证 DMA 读到的数据与 CPU 一致第 716-720 行。事务描述符从 READY/COMPLETE 队列中获取然后送入 PROGRESS 队列等待调度。QPI 数据发送的波形示意见仓库中的 sim_qpi_waveform.jsonwavedrom 波形定义展示 4 位数据线、输出时钟与取反后的 valid/CS 信号时序。注册事件回调由于parlio_tx_unit_transmit是异步接口我们往往需要知道传输事务何时完成。以下代码演示如何注册传输完成事件回调static bool test_parlio_tx_done_callback(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx) { // 事件回调的一般处理流程 // 1. 从 user_ctx 中取出用户上下文数据由注册时传入 // 2. 执行用户自定义操作 // 3. 返回上述操作过程中是否唤醒了高优先级任务通知调度器切换任务 BaseType_t high_task_wakeup pdFalse; // 使用 FreeRTOS 任务句柄作为用户上下文 TaskHandle_t task (TaskHandle_t)user_ctx; // 传输完成后向指定任务发送任务通知 vTaskNotifyGiveFromISR(task, high_task_wakeup); // 返回该函数是否唤醒了一个高优先级任务 return (high_task_wakeup pdTRUE); } parlio_tx_event_callbacks_t cbs { // 将 test_parlio_tx_done_callback 设为传输完成的事件回调 .on_trans_done test_parlio_tx_done_callback, }; ESP_ERROR_CHECK(parlio_tx_unit_register_event_callbacks(tx_unit, cbs, xTaskGetCurrentTaskHandle()));当 TX 单元产生传输完成等事件时会通过中断通知 CPU。如果需要事件发生时调用某个函数可以调用parlio_tx_unit_register_event_callbacks将事件回调注册到 TX 单元驱动的中断服务程序ISR中。由于回调函数在 ISR 中执行回调内应避免复杂操作包括任何可能阻塞的操作以免影响系统实时性。该函数还允许传入上下文指针以便在回调中访问用户自定义数据。TX 单元支持的事件回调见parlio_tx_event_callbacks_t定义于 parlio_tx.hon_trans_done设置“传输完成”事件的回调函数函数原型为parlio_tx_done_callback_t见 parlio_types.h。on_buffer_switched设置“缓冲区切换”事件的回调函数函数原型为parlio_tx_buffer_switched_callback_t见 parlio_types.h。该事件用于无限循环传输中切换 payload 缓冲区。从源码看parlio_tx_default_isr 在处理 DMA EOF 中断时会先调用on_trans_done回调再把完成的事务描述符移入 COMPLETE 队列并尝试从 PROGRESS 队列调度下一笔事务回调返回true时通过portYIELD_FROM_ISR触发任务切换。资源回收当不再需要 TX 单元时应调用parlio_del_tx_unit释放软件与硬件资源。删除前必须确保 TX 单元已禁用ESP_ERROR_CHECK(parlio_tx_unit_disable(tx_unit)); ESP_ERROR_CHECK(parlio_del_tx_unit(tx_unit));从源码看parlio_del_tx_unit 要求单元必须处于 INIT 状态否则返回ESP_ERR_INVALID_STATE并会关闭所有已配置的数据、valid、时钟输出 GPIO若单元仍挂着 BitScrambler 装饰删除会失败并提示先调用parlio_tx_unit_undecorate_bitscrambler()见 parlio_destroy_tx_unit。高级特性掌握基本用法后可以进一步探索 TX 单元驱动的高级特性。使用外部时钟作为 TX 单元时钟源TX 单元可以选择多种时钟源其中外部时钟源比较特殊。通过配置clk_src、clk_in_gpio_num与input_clk_src_freq_hz来使能外部时钟源输入parlio_tx_unit_handle_t tx_unit NULL; parlio_tx_unit_config_t config { .clk_src PARLIO_CLK_SRC_EXTERNAL, // 选择外部时钟源 .data_width 4, // 数据宽度为 4 位 .clk_in_gpio_num EXAMPLE_PIN_CLK_IN, // 设置外部时钟源输入引脚 .input_clk_src_freq_hz 10 * 1000 * 1000, // 外部时钟源频率为 10 MHz .valid_gpio_num -1, // 不使用 valid 信号 .clk_out_gpio_num EXAMPLE_PIN_CLK_OUT, .data_gpio_nums { EXAMPLE_PIN_DATA0, EXAMPLE_PIN_DATA1, EXAMPLE_PIN_DATA2, EXAMPLE_PIN_DATA3, }, .output_clk_freq_hz 5 * 1000 * 1000, // 输出时钟频率为 5 MHz注意不能超过输入时钟频率 .trans_queue_depth 32, .max_transfer_size 256, .shift_edge PARLIO_SHIFT_EDGE_NEG, // 在时钟下降沿移位数据 }; // 创建 TX 单元实例 ESP_ERROR_CHECK(parlio_new_tx_unit(config, tx_unit)); // 使能 TX 单元 ESP_ERROR_CHECK(parlio_tx_unit_enable(tx_unit)); #define PAYLOAD_SIZE 64 // 配置 TX 单元传输参数 parlio_transmit_config_t transmit_config { .idle_value 0x00, // 空闲状态下所有数据线为低电平 }; // 准备要发送的数据 uint8_t payload[PAYLOAD_SIZE] {0}; for (int i 0; i PAYLOAD_SIZE; i) { payload[i] i; } // 启动传输事务 ESP_ERROR_CHECK(parlio_tx_unit_transmit(tx_unit, payload, PAYLOAD_SIZE * sizeof(uint8_t) * 8, transmit_config));外部时钟输入的波形示意见 external_clock_input_waveform.json。注意input_clk_src_freq_hz与output_clk_freq_hz的比值决定了 TX 单元的内部时钟分频系数。当外部时钟实际频率与input_clk_src_freq_hz不一致时TX 单元实际产生的输出时钟频率也会相应变化。从源码看parlio_select_periph_clock 中若配置了clk_in_gpio_num且clk_src不是PARLIO_CLK_SRC_EXTERNAL驱动会警告并强制切换为外部时钟源第 202-205 行外部时钟模式下源频率直接取input_clk_src_freq_hz第 208-210 行随后通过hal_utils_calc_clk_div_frac_accurate或整数分频计算分频系数第 229-242 行若分频存在精度损失会打印precision loss警告第 251-253 行。另外parlio_tx_do_transaction 中对外部非自由运行时钟做了特殊处理启动事务前先切换到内部 XTAL 自由运行时钟完成复位再切回外部时钟第 518-537 行。无限循环传输部分目标芯片支持无限循环传输SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSIONTX 单元可以在无 CPU 干预的情况下产生周期性序列。通过配置parlio_transmit_config_t::flags::loop_transmission来使能无限循环传输parlio_tx_unit_handle_t tx_unit NULL; parlio_tx_unit_config_t config { .clk_src PARLIO_CLK_SRC_DEFAULT, // 选择默认时钟源 .data_width 4, // 数据宽度为 4 位 .clk_in_gpio_num -1, // 不使用外部时钟源 .valid_gpio_num -1, // 不使用 valid 信号 .clk_out_gpio_num EXAMPLE_PIN_CLK, .data_gpio_nums { EXAMPLE_PIN_DATA0, EXAMPLE_PIN_DATA1, EXAMPLE_PIN_DATA2, EXAMPLE_PIN_DATA3, }, .output_clk_freq_hz 10 * 1000 * 1000, // 输出时钟频率为 10 MHz .trans_queue_depth 32, .max_transfer_size 256, .shift_edge PARLIO_SHIFT_EDGE_NEG, // 在时钟下降沿移位数据 .flags { .invert_valid_out true, // valid 信号默认高有效取反后模拟 QPI 时序中的片选信号 CS } }; // 创建 TX 单元实例 ESP_ERROR_CHECK(parlio_new_tx_unit(config, tx_unit)); // 使能 TX 单元 ESP_ERROR_CHECK(parlio_tx_unit_enable(tx_unit)); #define PAYLOAD_SIZE 64 // 配置 TX 单元传输参数 parlio_transmit_config_t transmit_config { .idle_value 0x00, // 空闲状态下所有数据线为低电平 .loop_transmission true, // 使能无限循环传输 }; // 准备要发送的数据 uint8_t payload[PAYLOAD_SIZE] {0}; for (int i 0; i PAYLOAD_SIZE; i) { payload[i] i; } // 启动循环传输事务 ESP_ERROR_CHECK(parlio_tx_unit_transmit(tx_unit, payload, PAYLOAD_SIZE * sizeof(uint8_t) * 8, transmit_config));循环传输的波形示意见 loop_transmission_waveform.json。这种模式下传输不会停止除非手动调用parlio_tx_unit_disable且不会产生trans_done事件。注意使能无限循环传输后如果需要修改传输 payload可以保持loop_transmission配置并携带新的 payload 缓冲区再次调用parlio_tx_unit_transmit驱动会在旧缓冲区完整传输完成后切换到新缓冲区。此时可注册on_buffer_switched回调来感知“缓冲区切换”事件并且需要维护两个缓冲区避免过早修改或回收旧缓冲区导致数据不一致。源码佐证循环传输通过 DMA 链表的环形拼接实现——parlio_mount_buffer 在循环模式下用两条 DMA 链表PARLIO_DMA_LINK_NUM交替挂载缓冲区并通过gdma_link_concat把下一帧的链表接到当前帧末尾实现复用第 480、506-510 行当 payload 较小时还会拆成两个 DMA 描述符以触发缓冲区切换事件第 482-500 行。切换事件回调 parlio_tx_gdma_buffer_switched_callback 会向应用上报old_buffer_addr与new_buffer_addr事件数据结构见 parlio_types.h。使用 BitScrambler 生成自定义比特流在支持 BitScrambler 的芯片上SOC_BITSCRAMBLER_SUPPORTED可以利用 BitScrambler 汇编代码控制 DMA 路径上的数据实现一些简单的编码工作。相比 CPU 编码BitScrambler 性能更高且不消耗 CPU 资源但受限于 BitScrambler 有限的指令内存无法实现复杂编码。关于 BitScrambler 的详细介绍参见 BitScrambler 文档。编写 BitScrambler 程序后通过调用parlio_tx_unit_decorate_bitscrambler使其生效并将parlio_transmit_config_t::bitscrambler_program配置为指向 BitScrambler 程序的二进制文件。不同的传输事务可以使用不同的 BitScrambler 程序。二进制文件必须符合 BitScrambler 汇编语言规范运行时会被加载到 BitScrambler 的指令内存中。BitScrambler 程序的编写与编译方法参见 BitScrambler 编程指南。注意esp32p4由于硬件限制在 rev3.0 之前的芯片版本上bitscrambler 生成的比特流长度必须与原比特流相同否则可能出现传输阻塞或数据丢失。parlio_tx_unit_decorate_bitscrambler与parlio_tx_unit_undecorate_bitscrambler需要成对使用。删除 TX 单元时需要先调用parlio_tx_unit_undecorate_bitscrambler移除 BitScrambler否则 parlio_destroy_tx_unit 会报错并拒绝删除。BitScrambler 的具体实现见 parlio_bitscrambler.cparlio_tx_unit_transmit也会校验“TX 单元未装饰 BitScrambler 却传入程序指针”的非法组合见 parlio_tx.c。电源管理当使能电源管理CONFIG_PM_ENABLE时系统在进入睡眠前可能调整或关闭时钟源导致 TX 单元的内部时基无法正常工作。为防止这种情况TX 单元驱动内部会创建一个电源管理锁。锁的类型根据不同的时钟源设置。驱动在parlio_tx_unit_enable中获取锁、在parlio_tx_unit_disable中释放锁见 parlio_tx.c。这意味着无论电源管理策略如何在这两个函数之间系统都不会进入睡眠模式时钟源也不会被关闭或调整从而保证任何 TX 事务都能正常工作。从源码看锁的类型默认是ESP_PM_NO_LIGHT_SLEEPXTAL 与 PLL 时钟源在浅睡眠中会被关闭因此该锁已足够而在 ESP32-P4 上使用ESP_PM_CPU_FREQ_MAX以保证 DFS动态调频期间的 PSRAM 带宽与可用性见 parlio_tx.c外部时钟模式下不创建 PM 锁。在支持睡眠保留的芯片上SOC_PARLIO_SUPPORT_SLEEP_RETENTION除了关闭时钟源系统还可以在进入睡眠时关闭 TX 单元的电源以进一步降低功耗。为此需将parlio_tx_unit_config_t::flags::allow_pd设为true系统进入睡眠前会把 TX 单元的寄存器上下文备份到内存唤醒时恢复。注意使能该选项会降低功耗但增加内存占用使用时需要权衡功耗与内存。线程安全驱动使用临界区critical section保证对寄存器的原子操作。驱动句柄中的关键成员也受临界区保护。驱动内部状态机使用原子指令保证线程安全并使用线程安全的 FreeRTOS 队列管理传输事务。因此TX 单元驱动 API 可以在多线程环境中使用无需额外加锁。从源码看parlio_new_tx_unit 中初始化了spinlock与 FSM、缓冲区切换标志两个原子变量parlio_tx_unit_enable/disable 通过atomic_compare_exchange_strong实现状态机迁移事务队列则用带内存分配属性的 FreeRTOS 队列实现见 parlio_tx_create_trans_queue。Cache 安全当文件系统执行 Flash 读写操作时系统会临时禁用 Cache 功能以避免从 Flash 加载指令与数据时出错。这会导致在此期间 TX 单元的中断处理程序无响应用户回调函数无法及时执行。如果希望中断处理程序在 Cache 禁用期间正常运行可以启用CONFIG_PARLIO_TX_ISR_CACHE_SAFE选项。注意启用该选项后所有中断回调函数及其上下文数据必须驻留在内部内存中。因为在 Cache 禁用时系统无法从外部内存加载数据和指令。从源码看Kconfig 中PARLIO_TX_ISR_CACHE_SAFE会连带选中PARLIO_TX_ISR_HANDLER_IN_IRAM与GDMA_ISR_HANDLER_IN_IRAM驱动在注册回调时若使能了该选项会强制校验回调函数位于 IRAM、用户数据位于内部 RAM见 parlio_tx_unit_register_event_callbacksDMA 通道分配时也会带上isr_cache_safe标志见 parlio_tx_unit_init_dma。在支持以下选项的芯片上Flash 读写期间 Cache 不会被自动禁用因此不必使能CONFIG_PARLIO_TX_ISR_CACHE_SAFECONFIG_SPI_FLASH_AUTO_SUSPENDSOC_SPI_MEM_SUPPORT_AUTO_SUSPENDCONFIG_SPIRAM_XIP_FROM_PSRAMSOC_SPIRAM_XIP_SUPPORTED性能为提高中断处理的实时响应能力TX 单元驱动提供了CONFIG_PARLIO_TX_ISR_HANDLER_IN_IRAM选项默认使能。启用后会将中断处理程序放入内部 RAM减少从 Flash 加载指令时因 Cache 未命中产生的延迟。注意中断处理程序调用的用户回调函数与上下文数据仍可能位于 FlashCache 未命中问题依然存在。用户需要将回调函数与数据放入内部 RAM例如使用IRAM_ATTR与DRAM_ATTR宏。其他 Kconfig 选项CONFIG_PARLIO_ENABLE_DEBUG_LOG强制使能 TX 单元驱动的全部调试日志不受全局日志级别设置影响。使能该选项有助于开发者在调试时获得更详细的日志信息便于定位和解决问题。该选项与 RX 单元驱动共享。此外Kconfig 中还保留了已废弃的PARLIO_ISR_IRAM_SAFE选项同时选中 TX/RX 的 Cache Safe 选项以及内部使用的PARLIO_OBJ_CACHE_SAFE选项保证驱动对象不会从可能被禁用 Cache 的内存区域分配详见 Kconfig。资源消耗使用 idf-size 工具 可以查看 TX 单元驱动的代码与数据消耗。以下为测试条件以 ESP32-H2 为例编译器优化级别设为-Os以保证最小的代码体积默认日志级别设为ESP_LOG_INFO平衡调试信息与性能禁用以下驱动优化选项CONFIG_PARLIO_TX_ISR_HANDLER_IN_IRAM—— 中断处理程序不放入 IRAMCONFIG_PARLIO_TX_ISR_CACHE_SAFE—— 不使能 Cache 安全选项。注意以下数据并非精确值仅供参考。数据可能因芯片型号与 IDF 版本不同而变化。组件层总大小DIRAM.bss.data.textFlash 代码.rodata.textsoc92000092092hal18000018018driver647812120064665865880此外每个 TX 单元句柄会从堆上动态分配约800字节内存事务队列深度为 4 时。如果使能parlio_tx_unit_config_t::flags::allow_pd选项每个 TX 单元在睡眠期间还会额外消耗32字节内存用于保存寄存器上下文。应用示例仓库提供了以下 TX 单元相关的完整示例simple_rgb_led_matrix演示如何使用目标芯片的 TX 单元驱动支持 HUB75 接口的 RGB LED 矩阵屏并使用 LVGL 库显示简单的 UI 元素。示例包含 pytest 测试脚本、多芯片 sdkconfigesp32c6/esp32h2/esp32p4/esp32s31以及主程序源码。advanced_rgb_led_matrixSOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION演示如何使用 TX 单元的无限循环传输特性支持 HUB75 接口 RGB LED 矩阵屏。相比 simple_rgb_led_matrix 示例它无需手动循环扫描更加灵活。parlio_simulateSOC_PARLIO_LCD_SUPPORTED演示如何使用并行 IO 外设的 TX 单元驱动驱动 SPI 或 I80 接口的屏幕。API 参考TX 单元驱动的完整 API 定义位于以下头文件driver/parlio_tx.hTX 单元配置结构体、传输配置结构体、事件回调结构体及全部 TX APIparlio_new_tx_unit、parlio_del_tx_unit、parlio_tx_unit_enable、parlio_tx_unit_disable、parlio_tx_unit_transmit、parlio_tx_unit_wait_all_done、parlio_tx_unit_register_event_callbacks等driver/parlio_types.hTX/RX 单元句柄类型、事件数据结构parlio_tx_done_event_data_t、parlio_tx_buffer_switched_event_data_t以及回调函数原型。对应英文原文文档位于 docs/en/api-reference/peripherals/parlio/parlio_tx.rst中文翻译版位于 docs/zh_CN/api-reference/peripherals/parlio/parlio_tx.rst。驱动实现与 HAL 层代码可分别参考 src/parlio_tx.c 与 esp_hal_parlio 目录。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价