Cypress Logo Wi-Fi Host Driver (WHD) Public API Reference Guide
 
Wi-Fi Host Driver (WHD) Documentation

WHD Overview

The WHD is an independent, embedded Wi-Fi Host Driver that provides a set of APIs to interact with Cypress WLAN chips. The WHD is an independent firmware product that is easily portable to any embedded software environment, including popular IOT frameworks like Mbed OS, Amazon FreeRTOS, etc. Hence, the WHD includes hooks for RTOS and TCP/IP network abstraction layers.
The WHD requires the following services:

  • HAL: High-level abstraction layer that provides access to hardware like SDIO/SPI host controllers within the platform.
  • RTOS: The WHD uses the abstraction layer to access RTOS functionality like threads, semaphores etc. This is the same interface that the Cypress Middleware uses.

WHD Features

  • Supports Wi-Fi Station (STA) and AP mode of operation.
  • Supports concurrent operation of STA and AP interface.
  • Includes multiple security support like WPA2, WPA3, and open.
  • Provides function to perform Advanced Power Management.
  • Supports low power offloads, including ARP and packet filters.
  • Includes WFA Pre-certification support for 802.11n and WPA3.

WHD Folder Structure

  • whd\src - Core WHD files
  • whd\inc - WHD API files
  • whd\resources - WLAN Firmware
  • whd.mk - A simple make file to build a libwhd.a library.

WHD Architecture

The WHD consists of 3 different components as shown in the following architectural diagram. Blocks highlighted in red are external dependencies for the WHD, blue ones are Porting layer and black ones are WHD core.

whd_arch.png

Porting WHD

To port the WHD, implement the following APIs or Function Pointers (shown in the the WHD Architecture section diagram), so that the WHD is functional:


CY RTOS API

The CY RTOS API provides prototypes for functions that allow the WHD to use RTOS functionality, such as threads, semaphores, and timing functions.
You must implement the appropriate functions in your code. See here for an example implementation.

Function

Description

cy_rtos_create_thread

Create RTOS thread.

The WHD calls this function to create the main WHD thread.

cy_rtos_terminate_thread

Terminate the RTOS thread.

The WHD calls this function to terminate WHD main thread created using cy_rtos_create_thread. It is called after calling cy_rtos_join_thread().

cy_rtos_join_thread

Join the RTOS thread.

The WHD calls this function so that any resources that were allocated for it are cleaned up. It is called by WHD before cy_rtos_terminate_thread()

cy_rtos_get_time

To provide time in milliseconds since RTOS start

The WHD uses this to get the time in milliseconds.

cy_rtos_delay_milliseconds

Delay for a specified number of milliseconds.

The WHD calls this function to obtain the time delay.

cy_rtos_init_semaphore

Create a semaphore.

The WHD uses only binary semaphore, this function is used to init a semaphore

cy_rtos_get_semaphore

Get/Acquire a semaphore

cy_rtos_set_semaphore

Set/Release a semaphore

cy_rtos_deinit_semaphore

Deletes a semaphore

This function frees the resources associated with a semaphore.


CY HAL Resource API

The Wi-Fi firmware, NVRAM, and CLM BLOB information are treated as resources to be downloaded onto the Wi-Fi chip. Refer to the file inc\whd_resource_api.h for a detailed description.
You must implement the appropriate function pointers in your code. See here for an example implementation.

Function

Description

whd_resource_size

Gets the size of the resource for respective resource type

whd_get_resource_block

Gets the resource block for specified resource type

whd_get_resource_no_of_blocks

Gets block count for the specified resource_type

whd_get_resource_block_size

Gets block size for the specified resource_type


Buffer Interface API

The WHD requires packet buffers to exchange information between the host and Wi-Fi firmware. Refer to the file inc\whd_network_types.h for a detailed description.
You must implement the appropriate function pointers in your code. See here for an example implementation.

Function

Description

whd_host_buffer_get

Allocates a packet buffer

You can implement this function by allocating a pre-existing packet from a pool, using a static buffer, or by dynamically allocating memory. The method chosen must match the way the network stack expects packet buffers to be allocated. Usually, the WHD requires a packet of size of WHD_LINK_MTU which includes the MTU and various other headers. Refer to whd_types.h to find the size of WHD_LINK_MTU. The following include expected return error codes other than WHD_SUCCESS:
  • WHD_BUFFER_UNAVAILABLE_PERMANENT : Attempt to allocate more than MTU size
  • WHD_BUFFER_UNAVAILABLE_TEMPORARY : No Packet available in any pool
  • WHD_BUFFER_ALLOC_FAIL : Packet allocation fails

whd_buffer_release

Releases a packet buffer

The WHD uses this function to indicate that it no longer requires a packet buffer. The buffer can then be released back into a pool for reuse, or the dynamically allocated memory can be freed, according to how the packet was allocated.

whd_buffer_get_current_piece_data_pointer

Retrieves the current pointer of a packet buffer

Since packet buffers usually need to be created with space at the front for additional headers, this function allows the WHD to get the current 'front' location pointer.

whd_buffer_get_current_piece_size

Retrieves the size of a packet buffer

Since packet buffers usually need to be created with space at the front for additional headers, the memory block used to contain a packet buffer will often be larger than the current size of the packet buffer data. This function allows the WHD to retrieve the current size of a packet buffer's data.

whd_buffer_set_size

Sets the current length of a WHD packet buffer.

whd_buffer_add_remove_at_front

Moves the current pointer of a packet buffer

Since packet buffers usually need to be created with space at the front for additional headers, this function allows the WHD to move the current 'front' location pointer. This ensures that the WHD has space to add headers to transmit packets, and that the network stack does not see the internal WHD headers on received packets.


Network Interface API

The WHD calls this function pointer to pass the received TCP/IP data packet from WLAN. Refer to the file inc\whd_network_types.h for a detailed description.
You must implement the appropriate function pointers in your code. See here for an example implementation.

FUNCTION

Description

whd_network_process_ethernet_data

The WHD calls this function pointer to pass received data to the network stack. You must provide the definition of the function.

This function pointer is called asynchronously in the context of the WHD thread whenever new data has arrived.

Packet buffers are allocated within the WHD, and ownership is transferred to the network stack. The network stack or application is thus responsible for releasing the packet buffers. Most packet buffering systems have a pointer to the 'current point' within the packet buffer. When this function is called, the pointer points to the start of the Ethernet header. There are other inconsequential data before the Ethernet header.

It is preferable that you implement this function simply by putting the received packet on a queue for processing by another thread. This avoids the WHD thread being unnecessarily tied up which would delay other packets being transmitted or received.


CY HAL SPI/SDIO Bus API

The WHD uses the following functions to access the host bus controller for SDIO or SPI buses.
You must implement these functions in your code. See here for an example implementation.
Based on the target environment implementation, replace and use these functions appropriately to ensure bus operations.

Function

Description

cyhal_spi_register_irq The SPI interrupt handler registration.

cyhal_spi_transfer

Writes a block out and receives a value. The total number of bytes sent and received will be the maximum of tx_length and rx_length. The bytes written will be padded with the value 0xff.

cyhal_spi_irq_enable

Configure SPI interrupt. This function is used for word-approach.

cyhal_sdio_register_irq

 

The SDIO interrupt handler registration.

cyhal_sdio_irq_enable

 

Configures the SDIO interrupt

cyhal_sdio_send_cmd

Sends a command to the SDIO block.

cyhal_sdio_bulk_transfer

Performs a bulk data transfer (CMD=53) to the SDIO block.


WHD Power up sequence

Before starting the WHD, perform the following steps:

  • Connect the WLAN chip to a 32 kHz reference clock and to the sleep clock input pin.
  • Toggle the WL_REG_ON pin shown in the WHD Power up sequence chart.

    • WL_REG_ON pin has same polarity for all the WLAN chips
    • For SDIO Case, SHDC complete the SD Enumeration as per the “SDIO Simplified Specification.” Refer to https://www.sdcard.org/downloads/pls/ “Part E1 Simplified”, “SDIO Simplified Specification,” section 3.1.2, flowchart in Figure 3-2.


    whd_power_up.png


WHD Modes of Operation

There are basically three modes of operation in WHD:


WHD STA or AP mode

The following example code shows the program flow for execution in STA/AP mode:

#############################
File whd.h
##############################
//Abstract struct
typedef struct whd_driver *whd_driver_t;
typedef struct whd_interface *whd_interface_t;
##############################
File app.c
###############################
#include "whd.h"
app_start_whd()
{
whd_driver_t whd_driver;
// Each wifi chip, will have it's own instance of whd_driver.
// Each whd_driver may use multiple instance of whd_interface_t structs to define behavior and functionality.
// Most of the WHD function calls take this structure as input.
// The default primary interface is created automatically at the time of power up of wifi chip, whd_wifi_on(..).
// Primary interface is STA/AP role neutral.
// 4. Call whd_init per wifi chip (in other words per bus slot, two SDIO Wifi chip requires two calls.)
// 6. Attach a bus SDIO or SPI
whd_bus_sdio_attach(whd_driver, &whd_sdio_cfg, &sdhc_obj);
//or whd_bus_spi_attach(whd_driver, &whd_spi_cfg, &spi_obj);
...
//9. Switch on Wifi, download firmware and create a primary interface, returns whd_interface_t
whd_wifi_on(whd_driver, &ifp);
//11a. Join to AP - Note that it doesn't take whd_driver, instead whd_interface_t
whd_wifi_join(ifp , "AP SSID", WHD_SECURITY_OPEN, security_key, strlen(security_key), NULL);
//whd_ifp will be in STA role from now on
// or 11b. It can an start AP also here, then interface will be in AP role
//whd_wifi_init_ap(ifp ..)
//whd_wifi_start_ap(ifp);
//12 Leave the AP
// or Stop the AP
//whd_wifi_stop_ap(ifp , ...);
//13. Switch off Wifi
whd_wifi_off(ifp );
//Deletes all the interface and De-init the whd, free whd_driver memory
whd_deinit(ifp);
}


WHD STA+AP concurrent mode

The WHD supports STA+AP concurrent mode of operation. There is no support for STA+STA or AP+AP. For concurrent mode of operation, you need to create a secondary interface along with the primary interface. The primary interface must have an STA interface, and the secondary interface must have an AP interface. Running AP in the primary interface and running STA in the secondary interface is invalid.

The following example code shows the flow for execution in STA+AP concurrent mode:

app_start_whd()
{
whd_driver_t whd_driver;
whd_interface_t prim_ifp;
whd_interface_t sec_ifp;
// Each wifi chip, will have it's own instance of whd_driver
// Each whd_driver may use multiple instance of whd_interface_t structs to define behavior and functionality.
// Most of the WHD function calls take this structure as input.
// The default primary interface is created automatically at the time of power up of wifi chip, whd_wifi_on(..).
// Primary interface is STA/AP role neutral, but in case of concurrent mode of STA+AP mode, primary interface must have STA role only.
// 4. Call whd_init per wifi chip (in other words per bus slot, two SDIO Wifi chip requires two calls.)
whd_init(&whd_driver, &whd_init_cfg, &whd_resource_source, &whd_buffer_funcs, &whd_netif_funcs) ;
// 6. Attach a bus SDIO or SPI
whd_bus_sdio_attach(whd_driver, &whd_sdio_cfg, &sdhc_obj);
//or whd_bus_spi_attach(whd_driver, &whd_spi_cfg, &spi_obj);
...
// 9. Switch on Wifi, download firmware and create a primary interface, returns whd_interface_t
whd_wifi_on(whd_driver, &prim_ifp );
// 10. Add the secondary interface. Secondary interface can only be used as AP
whd_add_secondary_interface(whd_driver, mac_addr, &sec_ifp );
// 11. Join to AP - Note that it doesn't take whd_driver, instead whd_interface_t
whd_wifi_join(prim_ifp , "AP SSID", WHD_SECURITY_OPEN, security_key, strlen(security_key), NULL);
// whd_ifp will be in STA role from now on
// 12. Now start AP in secondary interface, then it will be in AP role
whd_wifi_init_ap(sec_ifp ..)
// 12 Leave the AP
whd_wifi_leave(prim_ifp );
// 13. Stop the AP
whd_wifi_stop_ap(sec_ifp , ...);
// 14. Switch off Wifi
whd_wifi_off(prim_ifp );
// 15. Deletes all the interface and De-init the whd, free whd_driver memory
whd_deinit(prim_ifp);
}


WHD WPA3/WPA2 transition mode

The WHD supports WPA3/WPA2 transition mode. In this mode, if the WPA3 AP goes down and a WPA2 AP is started with the same SSID, the STA automatically transitions to join the WPA2 AP. This mode requires two security keys for the join to be completed.
The security keys can be the same or different,one key is for setting the psk passphrase, and second key is for setting WPA3 password but it is highly recommended to use different passwords.

The following example code shows the flow for execution in WPA3/WPA2 transition mode:

app_start_whd()
{
whd_driver_t whd_driver;
// Each wifi chip, will have it's own instance of whd_driver
// Each whd_driver may use multiple instance of whd_interface_t structs to define behavior and functionality.
// Most of the WHD function calls take this structure as input.
// The default primary interface is created automatically at the time of power up of wifi chip, whd_wifi_on(..).
// Primary interface is STA/AP role neutral.
// 4. Call whd_init per wifi chip (in other words per bus slot, two SDIO Wifi chip requires two calls.)
whd_init(&whd_driver, &whd_init_cfg, &whd_resource_source, &whd_buffer_funcs, &whd_netif_funcs);
// 6. Attach a bus SDIO or SPI
whd_bus_sdio_attach(whd_driver, &whd_sdio_cfg, &sdhc_obj);
//or whd_bus_spi_attach(whd_driver, &whd_spi_cfg, &spi_obj);
...
//9. Switch on Wifi, download firmware and create a primary interface, returns whd_interface_t
whd_wifi_on(whd_driver, &ifp);
//Enable WHD internal supplicant and set WPA2 passphrase in case of WPA3/WPA2 transition mode
//Here, security_key_psk is WPA2 passphrase for WHD_SECURITY_WPA3_WPA2_PSK authentication type
whd_wifi_enable_sup_set_passphrase( ifp, security_key_psk, strlen(security_key_psk), WHD_SECURITY_WPA3_WPA2_PSK );
//11a. Join to AP
//Here, security key is WPA3 password
whd_wifi_join(ifp , "AP SSID", WHD_SECURITY_WPA3_WPA2_PSK, security_key, strlen(security_key), NULL);
//12 Leave the AP
//13. Switch off Wifi
whd_wifi_off(ifp );
//Deletes all the interface and De-init the whd, free whd_driver memory
whd_deinit(ifp);
}


Internals of WHD

The WHD consists of various internal modules as shown in the following diagram and explained in the following sections. Once the WHD is powered up, the WLAN Bus specific init sequence is completed, and the WLAN chip is ready for operation.

whd_design.png

FW Download Module

This module downloads the WLAN Firmware, NVRAM, and CLM file using HAL Resource API. This module does not use the services of control or data path module. It directly accesses the "WHD Bus Interface" to write the resources. After download is completed, this module allows the WLAN firmware to run.

WLAN Chip Logging Module

This module is responsible for obtaining the WLAN Chip logs using the WHD Debug APIs.

Control Module

IOCTLs provide control access to the WLAN Chip, and this module routes all these control messages to/from the WLAN chip.

Data Module

This module handles User Data received in the TCP/IP interface. It also to sends the User Data received from the WLAN Chip.

Event Module

Event module handles the events generated from the WLAN chip. It also exposes a function for the application to register for limited set of events and process them.

Protocol Module

Any packet sent to the WLAN chip needs to have a Protocol Header. Protocol Headers are of two types:
  • CDC (for control packet like IOCTL and IOVAR)
  • BDC (for User Data or ethernet packets from TCP/IP layer)
The protocol layer is bus independent and is required for either SDIO/SPI/USB.
  • CDC Layer
  • The Control Module sends messages to this CDC layer, which adds a 16-byte header known as CDC header. The following shows the header details:
    cdc_msg.png



    typedef struct
    {
    uint32_t cmd; // ioctl command value
    uint32_t len; // lower 16: output buflen; upper 16: input buflen (excludes header)
    uint32_t flags; // flag defns given in bcmcdc.h
    uint32_t status; // status code returned from the device
    }cdc_header_t;


  • BDC Layer
  • The User Data Module sends messages to the BDC Layer. It adds a 4-byte header known as the BDC header. The following shows the header details:
    bdc_msg.png



    typedef struct
    {
    uint8_t flags; // Flags
    uint8_t priority; // 802.1d Priority (low 3 bits)
    uint8_t flags2;
    uint8_t data_offset; // Offset from end of BDC header to packet data, in 4-uint8_t words.
    // Leaves room for optional headers.
    } bdc_header_t;


Bus Layer

The Bus layer provides bus level protocol handling. For SDIO, a bus protocol known as SDPCM is used.
  • SDPCM - SDIO/SPI Bus Layer
  • SDPCM Layer takes care of:
    • Adding a Sequence number to packet sent to WLAN Chip
    • Flow control between WHD and WLAN Chip
    SDPCM layer adds a fixed 10-byte header and packet format as below:
    sdpcm_msg.png




  • SDPCM Header
  • typedef struct
    {
    uint16_t frametag[2]; // SDPCM packet size
    uint8_t sequence; // Sequence number of pkt
    uint8_t channel_and_flags; // IOCTL/IOVAR or User Data or Event
    uint8_t next_length;
    uint8_t header_length; // Offset to BDC or CDC header
    uint8_t wireless_flow_control;
    uint8_t bus_data_credit; // Credit from WLAN Chip
    uint8_t _reserved[2];
    } sdpcm_header_t;


  • SDIO - SDPCM Flow control
  • Before sending any data to the WLAN, the SDPCM Layer must wait for credit from WLAN chip. Credit is sent by the WLAN either in a SDPCM header packet or as piggy-banked information in a RX User Data packet. The SDPCM Layer should not send any packet if no credit is available.

    sdpcm_flow.png


Packet Engine

All the control or User Data is queued in a link list in this layer. Once the credit is available, this layer sends the data to WLAN chip. Also, this layer checks for any RX data from WLAN Chip and sends the data to host TCP/IP stack via its TCP/IP interface.

data_flow.png










WHD Bus Interface

This module provides bus independent access functions to the packet engine/sdpcm layer. It is primarily used to keep the access functions common between SDIO/SPI.

SDIO HAL Interface

Use the CY HAL interface to access the SDIO Host Controller Hardware. It is external to the WHD driver.

SPI HAL Interface

Use the CY HAL interface to access the SPI Host Controller Hardware. It is external to the WHD driver


WHD API

The WHD provides services in the form of the WLAN API which can be used by layers above the WHD. Broadly, the WLAN API can be classified into the following:

  • Basic API (like scan, join)
  • Intermediate API (like SoftAP)
  • Advanced API (to send direct IOCTL to WLAN Chip)
Based on the functionality, APIs can be classified as follows: