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:
  1. SPI

  2. DMA

  3. GPIOs

  4. Timers

  5. MCU Exception Callbacks

  6. Enter/Exit Critical Section

Step 1. Populate the swc_hal_t Structure

The code block below represents one of the functions of the BSP Interface which aims to populate the structure swc_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.

Listing 1 This SDK function is located in the bsp interface: sdk/bsp/interface/wireless_core/iface_wireless_evk.c.
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.

Listing 2 This SDK function is located in the bsp interface: sdk/bsp/interface/wireless_core/iface_wireless_pulsar.c.
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_irq_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_irq_it;
    hal->radio_hal[1].enable_radio_dma_irq              = pulsar_radio_2_enable_dma_irq_it;

    hal->timer_start = pulsar_timer_multi_radio_timer_start;
    hal->timer_stop = pulsar_timer_multi_radio_timer_stop;
    hal->timer_set_period = pulsar_timer_multi_radio_timer_set_period;
    hal->disable_timer_irq = pulsar_timer_multi_radio_timer_disable_irq;
    hal->enable_timer_irq = pulsar_timer_multi_radio_timer_enable_irq;
#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 swc_hal_t structure and its elements that need to be populated by the user.

Listing 3 This SDK function is located in the wireless core: sdk/core/wireless/api/swc_api.h.
typedef struct swc_hal {
    swc_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)
    void (*timer_start)(void);                 /*!< Radio timer start interface. */
    void (*timer_stop)(void);                  /*!< Radio timer stop interface. */
    void (*timer_set_period)(uint16_t period); /*!< Radio timer set period interface. */
    void (*disable_timer_irq)(void);           /*!< Disable Multi radio interrupt source */
    void (*enable_timer_irq)(void);            /*!< Enable Multi radio interrupt source */
#endif
} swc_hal_t;

See child elements in details

Step 2. Provide Callback Function Setters

Additionally to the swc_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.