It is up to the implemention to provide the interfaces:
- SPI Master Interupt based or using DMA
- External GPIO IRQ interupt
A good Baudrate for SPI is around 1.125MBits/s, but not much lower. SPI Mode is zero (CPOL = 0, CPHA = 0).
You can find the Source Code for the library in the Vision External Example or download it from here:
Include
Just add all the files to your project. Include “libIqMeshSpiInterface.h“ and call the necessary functions.
#include "libIqMeshSpiInterface.h"
Provide necessary hardware functions
Make sure to provide this external hardware functions:
/* Start SPI Transmit and Receive interupt or DMA based */
void HardwareIqMeshSpiSetTxRx(uint8_t* buf, uint16_t length);
/* Set SPI CS Pin regarding set value */
void HardwareIqMeshSpiSetCsPin(bool set);
/* Read state of IRQ Gpio Pin */
bool HardwareIqMeshGpioReadIrqPin(void);
Initialization
For initialization you have to call “iqMesh_init“ function. Therefore you have to provide the RDM UID, the necessary callbacks, DMX receive length and if you support device firmware updates.
uint8_t rdmId[6];
uint16_t visionSpecialDmxFootprint= 100; // The Footprint of the Special DMX Mode 255. (APP Mode)
bool supportDfu = false;
// Register necessary callbacks
iqmesh_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 iQMesh
iqMesh_init(rdmId, visionSpecialDmxFootprint,supportDfu, callbacks);
Change RDM UID
If the serial number is changing and therefore the RDM UID, it is possible to overwrite the RDM UID using:
iqMesh_setRdmId(rdm_id);
Provide Task event
In order to process the data its necesary to call “iqMesh_task” whenever there is time. For example in the while loop: (Use a lower priority than the interput routine from SPI and IRQ EXTI)
while (1)
{
uint32_t timems = HAL_GetTick();
iqMesh_task(timems);
}
Provide SPI completion event
After completion or if an error occured you have to call “iqMesh_extSpiEvent“.
For example using STM32 HAL callbacks:
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
iqMesh_extSpiEvent(SPI_EVENT_COMPLETION, dmaBufRx, dmaBufLength);
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
iqMesh_extSpiEvent(SPI_EVENT_ERROR, dmaBufRx, dmaBufLength);
}
void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,GPIO_PIN_SET);
iqMesh_extSpiEvent(SPI_EVENT_ERROR, dmaBufRx, dmaBufLength);
}
Provide GPIO edge detection event
In order to detect edges for the “IRQ” pin, HAL EXTI Callback is used. Because of many controller do not have support for complete edge detection we have to check them in the interrupt. Make sure you detect the falling and 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))
{
iqMesh_extIrqInterupt(SPIEXT_IRQ_EDGE_RISING);
}
else
{
iqMesh_extIrqInterupt(SPIEXT_IRQ_EDGE_FALLING);
}
}
}
Use of RdmReceived callback
The RdmReceived callback has the priority from the Task event. Here you have to decode the RDM message.
static void RdmReceived(const uint8_t* buf, uint16_t length)
{
// Handle RDM Data
RdmDecodeMessage(buf, length);
}
If you have to answer this message write a response directly using:
uint8_t msg[length];
iqMesh_WriteRdm(msg,length);
Use of DmxReceived Callback
The DmxReceived callback has the priority from the Task event. The buffer is released after return from this event. So make sure to copy the data.
You have to use the provided personality if it is bigger than 0. But make sure not to change the dmx personality of the fixture. If it is zero use the personality which is selected from the system.
static void DmxReceived(uint8_t personality, const uint8_t* buf, uint16_t length)
{
// Handle DMX Data
if(personality > 0)
{
// Use this personality to interpret the dmx input
}
else if(personality == 255)
{
// Use special personality with default settings optimized for app control.
}
else
{
// Use selected personality from the fixture
}
}
Use of Dfu Callbacks
The Dfu callback has the priority from the Task event.
static void DfuFlagReceived(iqmesh_dfu_flag_t flag)
{
// Handle DFU data
if(flag == IQMESH_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
iqMesh_WriteDfu(DFU_SUCCESS);
}
if(flag == IQMESH_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
iqMesh_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
// iqMesh_WriteDfu(DFU_ERROR_WRONG_PACKETNR);
}
Debug Library – Find Issues
In order to find issues regarding hardware or firmware implementation there is a step by step guide how to debug the library:
Analyse logs of Vision Wireless Controller
To obtain a special firmware version of the Vision Wireless Controller for log collection, please navigate to CUSTOM IMPLEMENTATION Project Artery IC and refer to the chapter Analyse logs of Vision Wireless Controller at the end of the page. The logs can be very helpful during the implementation process.