Porting Guidelines¶
This section describes the steps required to run a simple application on custom hardware and highlights important things to consider when porting to that hardware. SPARK transceivers can accommodate a wide range of applications, from low-duty cycle wireless sensor nodes to full quality audio streaming. Hence, the microcontroller requirements will vary.
Here is a list of hardware features that impact the speed of execution of a given SPARK enabled application:
CPU core: some CPU cores (e.g. Arm Cortex-M4) may be more or less efficient than others for a given task.
CPU clock speed: running a given CPU core at a higher clock speed will result in faster processing time which is sometimes required for higher performance applications.
MCU architecture: some MCUs have hardware accelerators, multiple cores, direct memory access (DMA) buses for efficient non-blocking data transfers and faster memory zones for code execution. For example, the STM32G473 MCU on the SPARK EVK board has CCM (Core-Coupled Memory) where critical code can be copied and executed from without any wait states leading to faster response and lower execution times.
Amount of memory: more memory means more room for code optimization (e.g. inline functions or unrolled loops are usually executed faster but take more space).
Effective SPI data throughput: SPARK transceivers use SPI for all communications with the MCU, whether it is for frame transfers or configuration. SPI clock speed, byte interspacing and initial setup time (i.e. time between the falling edge of the chip select and the rising edge of the first SPI clock pulse) are all dependent on the MCU used. For a given SPI clock speed, the effective data throughput can vary.
The MCU must support the following hardware peripherals:
1x GPIO pin to drive the transceiver’s reset pin
1x GPIO pin to serve as the SPI chip select
1x SPI bus controller configured as master
1x External interrupt pin for servicing the transceiver’s IRQs
1x Timer with millisecond accuracy
1x GPIO pin to drive the transceiver’s shutdown pin (if feature is used)
2x DMA channels for the SPI data transfers between the MCU and the transceiver (if WPS is used)
1x Timer with 250 microseconds accuracy (if WPS is used)
1x Software interrupt (if WPS is used)
The simplest way to start porting the SPARK SDK to a new board is to substitute the EVK board BSP with the user’s own hardware BSP and update the BSP interface.
A second way would be for the user to add their own BSP alongside the EVK BSP, then add the required files in the interface and update the STM32CubeIDE project paths. The BSP interface was made to accommodate multiple BSPs without the need to modify the application examples. The examples are not coupled directly with the EVK BSP, the interface is an abstraction layer for the hardware BSP. Therefore each application makes calls to some functions with iface_ as a prefix.
Figure 28: Application, BSP interface and hardware BSP relationship.¶
The BSP interface is split in multiple source files, one for the Wireless Core, one for Audio Core, one for Pairing module and one for each application example.
The most basic application to port is Blinky, which makes use of the transceiver-level API (SR1000 API) to execute uncoordinated data exchanges. Once Blinky works, Hello World would be the next one to port. Hello World makes use of the Wireless Protocol Stack API to establish a full coordinated TDMA link and requires more BSP functions to implement. With those two applications ported, the BSP should be ready to cover most use cases. To get the most out of the custom BSP, care should be taken to optimize the SPI drivers as much as possible.
Adding a BSP alongside the EVK BSP¶
If the user chooses not to substitute the EVK BSP and wants to add their own hardware BSP alongside the existing one, they can do it by following the steps shown later in this section.
Below is a file structure that shows what needs to be added in order to run the example application audio_4-channel on a custom user_bsp.
sdk_spark_vx.y.z/
└───bsp/
├───hardware/
│ ├───evk/
| └─── **user_bsp/**
└───interface/
├───wireless_core/
| ├───iface_wireless.h
| ├───iface_wireless_evk.c
| └─── **iface_wireless_user_bsp.c**
├───audio_core/
| ├───iface_audio.h
| ├───iface_audio_evk.c
| └─── **iface_audio_user_bsp.c**
└───app/
└───audio_4-channel/
├───iface_audio_4-channel.h
├───iface_audio_4-channel_evk.c
└─── **iface_audio_4-channel_user_bsp.c**
The user simply needs to follow these steps:
Copy the interface source files
*_evk.c.Rename the copied files with the user own hardware suffix.
Update the function implementations with the user’s own hardware BSP functions.
void iface_audio_dma_complete_callbacks(void(*tx_callback)(void), void(*rx_callback)(void))
{
evk_audio_set_sai_tx_dma_cplt_callback((irq_callback)tx_callback);
evk_audio_set_sai_rx_dma_cplt_callback((irq_callback)rx_callback);
}
void iface_audio_dma_complete_callbacks(void(*tx_callback)(void), void(*rx_callback)(void))
{
user_bsp_set_sai_tx_dma_cplt_callback((irq_callback)tx_callback);
user_bsp_set_sai_rx_dma_cplt_callback((irq_callback)rx_callback);
}