SPI 库
实现方需要提供 prepared Vision SPI library 所使用的硬件接口:
- SPI master,基于 interrupt 或使用 DMA
- External GPIO IRQ interrupt
SPI 的推荐 Baudrate 约为 1.125MBits/s,不应低很多。SPI Mode 为 zero (CPOL = 0, CPHA = 0)。
您可以在 Vision External Example 中找到该 library 的 source code,也可以从这里下载:
https://kk-t.com/wp-content/uploads/2026/05/VisionSpiLibrary_2026_05_25.zip
Include 文件
只需将所有文件添加到您的项目中。Include libVisionSpiInterface.h,并调用必要函数。当前 library 使用 Vision naming。较旧的 package 和 example 曾使用 iQMesh/iqMesh;如果您对照旧资料,请将这些名称理解为同一个 Vision SPI library 的旧名称。
#include "libVisionSpiInterface.h"
Memory mode
该 library 支持两种 memory modes:dynamic allocation 和 static allocation。
在 dynamic allocation mode 下,内存会在运行时按需分配,从而降低整体内存使用。
在 static allocation mode 下,所有必需内存都会在编译时以全局方式定义。
默认情况下,该 library 使用 dynamic allocation。
如需启用 static allocation,请在项目中定义 compile-time constant VISION_USE_STATIC_ALLOCATION,或在 libVisionSpiInterface.h 底部取消注释。
提供必要的 hardware functions
请确保提供以下 external hardware functions:
/* Start SPI transmit and receive interrupt or DMA based */
void HardwareVisionSpiSetTxRx(uint8_t* buf, uint16_t length);
/* Set SPI CS Pin regarding set value */
void HardwareVisionSpiSetCsPin(bool set);
/* Read state of IRQ Gpio Pin */
bool HardwareVisionGpioReadIrqPin(void);
初始化
初始化时必须调用 "vision_init" function。因此需要提供 RDM UID、必要 callbacks、DMX receive length,以及是否支持 device firmware updates。
uint8_t rdmId[6];
uint16_t visionSpecialDmxFootprint= 100; // The footprint used for Vision Control Behavior 255. (App Control)
bool supportDfu = false;
// Register necessary callbacks
vision_callbacks_t callbacks;
// Dfu callback implementation is not needed if dfu is not supported
callbacks.DfuDataReceived = &DfuDataReceived;
callbacks.DfuFlagReceived = &DfuFlagReceived;
// For receiving Dmx frames
callbacks.DmxReceived = &DmxReceived;
// For receiving Rdm frames
callbacks.RdmReceived = &RdmReceived;
// Init Vision SPI library
vision_init(rdmId, visionSpecialDmxFootprint,supportDfu, callbacks);
修改 RDM UID
如果 serial number 发生变化,因此 RDM UID 也需要变化,可以使用以下函数覆盖 RDM UID:
vision_setRdmId(rdm_id);
提供 Task event
为了处理数据,需要在有时间时调用 "vision_task"。例如在 while loop 中调用:(优先级应低于 SPI 和 IRQ EXTI 的 interrupt routine)
while (1)
{
uint32_t timems = HAL_GetTick();
vision_task(timems);
}
提供 SPI completion event
SPI 完成后,或发生错误时,必须调用 "vision_extSpiEvent"。
例如使用 STM32 HAL callbacks:
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
vision_extSpiEvent(SPI_EVENT_COMPLETION, dmaBufRx, dmaBufLength);
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
vision_extSpiEvent(SPI_EVENT_ERROR, dmaBufRx, dmaBufLength);
}
void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
vision_extSpiEvent(SPI_EVENT_ERROR, dmaBufRx, dmaBufLength);
}
提供 GPIO edge detection event
为了检测 "IRQ" pin 的边沿,这里使用 HAL EXTI Callback。由于许多 controller 不支持完整的 edge detection,因此必须在 interrupt 中检查。请确保检测 falling edge 和 rising edge。
.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == SPI_IRQ_Pin)
{
if (HAL_GPIO_ReadPin(SPI_IRQ_GPIO_Port, SPI_IRQ_Pin))
{
vision_extIrqInterupt(SPIEXT_IRQ_EDGE_RISING);
}
else
{
vision_extIrqInterupt(SPIEXT_IRQ_EDGE_FALLING);
}
}
}
使用 RdmReceived callback
RdmReceived callback 的优先级来自 Task event。在这里需要 decode RDM message。
在大多数项目中,应将接收到的数据传入与有线 RDM 相同的 RDM decoder。Vision 不需要单独的第二套 RDM stack。只需将必需的 Vision custom RDM commands 添加到您现有的 RDM 实现中。
static void RdmReceived(const uint8_t* buf, uint16_t length)
{
// Handle RDM Data
RdmDecodeMessage(buf, length);
}
如果需要应答该 message,可以直接使用以下函数写入 response:
uint8_t msg[length];
vision_WriteRdm(msg,length);
使用 DmxReceived callback
DmxReceived callback 的优先级来自 Task event。从该 event 返回后 buffer 会被释放,因此请确保复制数据。
Vision DMX stream 中的第一个值是 Vision Control Behavior。它只用于解释当前 Vision DMX frame。不要因此改变灯具保存的 DMX personality、display settings、RDM settings 或其他协议设置。
对于 Vision Control Behavior 0,请将 DMX data 传入与有线 DMX 相同的 DMX handling。对于 Vision Control Behavior 255,只对当前 frame 应用定义好的 App Control defaults。
static void DmxReceived(uint8_t personality, const uint8_t* buf, uint16_t length)
{
// Handle DMX Data
if(personality == 255)
{
// Use App Control behavior with App Control default settings.
}
else if(personality > 0)
{
// Use DMX Control with this temporary DMX personality override.
}
else
{
// Use selected personality from the fixture
}
}
使用 DFU callbacks
Dfu callback 的优先级来自 Task event。
static void DfuFlagReceived(vision_dfu_flag_t flag)
{
// Handle DFU data
if(flag == VISION_DFUFLAG_STOP)
{
// Check if dfu has started
// Check received data for example using a CRC
// if anything is good answer with success and initiate the update. There is a timeout about of 10 sec for answering
vision_WriteDfu(DFU_SUCCESS);
}
if(flag == VISION_DFUFLAG_START)
{
// Check if dfu has not already started
// Prepare flash, .. for receiving dfu
// if anything is good answer with success to start the transmission. There is a timeout about of 10 sec for answering
vision_WriteDfu(DFU_SUCCESS);
}
}
static void DfuDataReceived(uint16_t packetNr, const uint8_t* buf, uint16_t length)
{
// Check if packetNr is correct. Store packet.
// if something is wrong answer with a error reason
// vision_WriteDfu(DFU_ERROR_WRONG_PACKETNR);
}
不要遗漏:
请确保调用以下 library functions:
- vision_init
- vision_task
- vision_extSpiEvent
- vision_extIrqInterupt
并实现以下 callbacks:
- void HardwareVisionSpiSetTxRx(uint8_t* buf, uint16_t length);
- void HardwareVisionSpiSetCsPin(bool set);
- bool HardwareVisionGpioReadIrqPin(void);
并实现以下 callbacks 来处理数据:
- DfuDataReceived
- DfuFlagReceived
- DmxReceived
- RdmReceived
Debug library - 查找问题
为了查找硬件或固件实现相关问题,我们提供了一个 step by step guide,用于调试该 library:
分析 Vision Wireless Controller logs
如需获取用于日志收集的特殊 Vision Wireless Controller 固件版本,请进入 CUSTOM IMPLEMENTATION Project Artery IC,并参考页面末尾的 Analyse logs of Vision Wireless Controller 章节。这些 logs 在实现过程中非常有帮助。