Wireless Core Porting Article¶
The Wireless Core needs access to some MCU peripherals for it to function. This article provides a detailed description of all the hooks required for the BSP development of a new hardware platform.
- The Wireless Core needs control over the following MCU peripherals & features:
SPI
DMA
GPIOs
Timers
MCU Exception Callbacks
Enter/Exit Critical Section
Step 1. Populate the wireless_core_hal_t Structure¶
The code block below represents one of the functions of the BSP Interface which aims to
populate the structure wireless_core_hal_t with BSP functions of the EVK1.4 board.
The user needs to create the same functions while using their new BSP
implementation instead.
void iface_swc_hal_init(swc_hal_t *hal)
{
hal->radio_hal[0].set_shutdown_pin = evk_radio_set_shutdown_pin;
hal->radio_hal[0].reset_shutdown_pin = evk_radio_reset_shutdown_pin;
hal->radio_hal[0].set_reset_pin = evk_radio_set_reset_pin;
hal->radio_hal[0].reset_reset_pin = evk_radio_reset_reset_pin;
hal->radio_hal[0].read_irq_pin = evk_radio_read_irq_pin;
hal->radio_hal[0].set_cs = evk_radio_spi_set_cs;
hal->radio_hal[0].reset_cs = evk_radio_spi_reset_cs;
hal->radio_hal[0].delay_ms = evk_timer_delay_ms;
hal->radio_hal[0].transfer_full_duplex_blocking = evk_radio_spi_transfer_full_duplex_blocking;
hal->radio_hal[0].transfer_full_duplex_non_blocking = evk_radio_spi_transfer_full_duplex_non_blocking;
hal->radio_hal[0].is_spi_busy = evk_radio_is_spi_busy;
hal->radio_hal[0].context_switch = evk_radio_context_switch;
hal->radio_hal[0].disable_radio_irq = evk_radio_disable_irq_it;
hal->radio_hal[0].enable_radio_irq = evk_radio_enable_irq_it;
hal->radio_hal[0].disable_radio_dma_irq = evk_radio_disable_dma_irq_it;
hal->radio_hal[0].enable_radio_dma_irq = evk_radio_enable_dma_irq_it;
hal->context_switch = evk_radio_callback_context_switch;
hal->get_tick_quarter_ms = evk_timer_get_free_running_tick_ms;
}
Note
The pulsar name is a placeholder name since the EVK1.4 does not support the dual radio.
void iface_swc_hal_init(swc_hal_t *hal)
{
hal->radio_hal[0].set_shutdown_pin = pulsar_radio_1_set_shutdown_pin;
hal->radio_hal[0].reset_shutdown_pin = pulsar_radio_1_reset_shutdown_pin;
hal->radio_hal[0].set_reset_pin = pulsar_radio_1_set_reset_pin;
hal->radio_hal[0].reset_reset_pin = pulsar_radio_1_reset_reset_pin;
hal->radio_hal[0].read_irq_pin = pulsar_radio_1_read_irq_pin;
hal->radio_hal[0].set_cs = pulsar_radio_1_spi_set_cs;
hal->radio_hal[0].reset_cs = pulsar_radio_1_spi_reset_cs;
hal->radio_hal[0].delay_ms = pulsar_timer_delay_ms;
hal->radio_hal[0].transfer_full_duplex_blocking = pulsar_radio_1_spi_transfer_full_duplex_blocking;
hal->radio_hal[0].transfer_full_duplex_non_blocking = pulsar_radio_1_spi_transfer_full_duplex_non_blocking;
hal->radio_hal[0].is_spi_busy = pulsar_radio_1_is_spi_busy;
hal->radio_hal[0].context_switch = pulsar_radio_1_context_switch;
hal->radio_hal[0].disable_radio_irq = pulsar_radio_1_disable_irq_it;
hal->radio_hal[0].enable_radio_irq = pulsar_radio_1_enable_irq_it;
hal->radio_hal[0].disable_radio_dma_irq = pulsar_radio_1_disable_dma_it;
hal->radio_hal[0].enable_radio_dma_irq = pulsar_radio_1_enable_dma_irq_it;
hal->context_switch = pulsar_radio_1_callback_context_switch;
hal->get_tick_quarter_ms = pulsar_timer_get_free_running_tick_ms;
#if (WPS_RADIO_COUNT == 2)
hal->radio_hal[1].set_shutdown_pin = pulsar_radio_2_set_shutdown_pin;
hal->radio_hal[1].reset_shutdown_pin = pulsar_radio_2_reset_shutdown_pin;
hal->radio_hal[1].set_reset_pin = pulsar_radio_2_set_reset_pin;
hal->radio_hal[1].reset_reset_pin = pulsar_radio_2_reset_reset_pin;
hal->radio_hal[1].read_irq_pin = pulsar_radio_2_read_irq_pin;
hal->radio_hal[1].set_cs = pulsar_radio_2_spi_set_cs;
hal->radio_hal[1].reset_cs = pulsar_radio_2_spi_reset_cs;
hal->radio_hal[1].delay_ms = pulsar_timer_delay_ms;
hal->radio_hal[1].transfer_full_duplex_blocking = pulsar_radio_2_spi_transfer_full_duplex_blocking;
hal->radio_hal[1].transfer_full_duplex_non_blocking = pulsar_radio_2_spi_transfer_full_duplex_non_blocking;
hal->radio_hal[1].is_spi_busy = pulsar_radio_2_is_spi_busy;
hal->radio_hal[1].context_switch = pulsar_radio_2_context_switch;
hal->radio_hal[1].disable_radio_irq = pulsar_radio_2_disable_irq_it;
hal->radio_hal[1].enable_radio_irq = pulsar_radio_2_enable_irq_it;
hal->radio_hal[1].disable_radio_dma_irq = pulsar_radio_2_disable_dma_it;
hal->radio_hal[1].enable_radio_dma_irq = pulsar_radio_2_enable_dma_irq_it;
hal->multi_cfg.timer_start = pulsar_timer_multi_radio_timer_start;
hal->multi_cfg.timer_stop = pulsar_timer_multi_radio_timer_stop;
hal->multi_cfg.timer_set_period = pulsar_timer_multi_radio_timer_set_period;
#endif
}
The HAL is pointing to the EVK1.4 hardware BSP which is a great starting point to look into the dependencies and implementation.
The code block below shows the wireless_core_hal_t structure and its elements
that need to be populated by the user.
typedef struct swc_hal {
radio_hal_t radio_hal[WPS_RADIO_COUNT]; /*!< Radio HAL */
void (*context_switch)(void); /*!< Context switch function pointer */
uint64_t (*get_tick_quarter_ms)(void); /*!< Get tick quarter ms function pointer */
#if (WPS_RADIO_COUNT == 2)
wps_multi_cfg_t multi_cfg; /*!< MCU timer functions for dual radio configuration */
#endif
} swc_hal_t;
See child elements in details
Step 2. Provide Callback Function Setters¶
Additionally to the wireless_core_hal_t structure, the user must provide callback setters to run some part of the Wireless Core code when specific IRQ events are triggered. The user needs to create the same functions and adapt them to the user hardware BSP.
Step 3. Provide Enter/Exit Critical Section Functions¶
The Wireless Core uses the lib/spark/queue library which has some dependencies that need to be satisfied. This queue library needs a mean to enter and exit critical sections.