Virtual Connectivity Manager Library
Overview

Virtual-Connectivity-Manager (VCM) is a library that enables connectivity libraries to add multi-core support through virtualization. Virtualization allows the connectivity stack running on one core to be accessed from another core using Inter-Processor Communication (IPC). With VCM, the connectivity stack can be run on two cores, where one core contains the full connectivity stack (primary core) and the other core contains a subset of virtual-only APIs (secondary core).

Internally, VCM uses IPC to send API requests from the secondary core to the primary core where the API is executed, and then the result is sent back to the secondary core. This makes it seem like the API was executed on the secondary core itself. VCM simplifies the process of adding multi-core support by hiding the details of IPC from both the connectivity libraries and the end application.

Features and functionality

The current implementation has the following features and functionality:

  • Supports the following WCM virtual APIs:
    • cy_wcm_is_connected_to_ap
    • cy_wcm_register_event_callback
    • cy_wcm_deregister_event_callback
  • Supports the following MQTT virtual APIs:
    • cy_mqtt_get_handle
    • cy_mqtt_register_event_callback
    • cy_mqtt_deregister_event_callback
    • cy_mqtt_subscribe
    • cy_mqtt_unsubscribe
    • cy_mqtt_publish

Supported platforms

This library and its features are supported on the following Infineon platforms:

Dependent libraries

This library is not bundled as part of any other library by default.

Quick start

  • Define the following compile-time macro in the project Makefile of primary core side:
    DEFINES+=ENABLE_MULTICORE_CONN_MW
  • Define the following compile-time macros in the project Makefile of secondary core side:
    DEFINES+=ENABLE_MULTICORE_CONN_MW USE_VIRTUAL_API
  • To use MQTT virtual APIs, define the following compile-time macro in the project Makefile of both cores:
    DEFINES+=VCM_ENABLE_MQTT
  • Call the cy_vcm_init() function provided by the VCM library in both the projects.
    Note
    - To ensure that the VCM initialization is synchronized, the project which boots first (i.e., CM0+ project in case of psoc62) must call cy_vcm_init before it brings up the second project (i.e., CM4 project in case of psoc62).
    - The first project must initialize VCM by passing config.hal_resource_opt as CY_VCM_CREATE_HAL_RESOURCE in cy_vcm_init. The second project must pass config.hal_resource_opt as CY_VCM_USE_HAL_RESOURCE.
    - VCM initialization can also be done in any order from any core provided that the first project initializing VCM sets config.hal_resource_opt as CY_VCM_CREATE_HAL_RESOURCE in cy_vcm_init and the second project sets config.hal_resource_opt as CY_VCM_USE_HAL_RESOURCE. In this case synchronizing VCM initialization between the two cores will be the responsibility of the application. If not synchronised correctly, this can lead to unexpected behaviour.
  • VCM utilizes HAL IPC queue resource to perform inter-core communication. Each HAL IPC queue is associated with a channel number and queue number. For a given channel number (provided by the application during VCM initialization), VCM uses queue numbers in the range of 1-7 which should not be used by the application while using VCM.
    Channel Number Queue Number
    Any IPC Channel configured by the application for VCM 1-7(Reserved by VCM)
    Note
    The application cannot use queue numbers 1-7 for the configured channel number, as they are reserved for VCM.
  • VCM utilizes one of the IPC queues to send asynchronous event callback data from the primary core to the secondary core. By default, the size of this queue is set to 20. However, if the application expects to receive event callbacks in the secondary core in large bursts, this queue size can be modified to avoid queue overflow. To customize the event queue size, define and set the CY_VCM_EVENT_QUEUE_SIZE macro in the Makefile of the project which initializes VCM with config.hal_resource_opt as CY_VCM_CREATE_HAL_RESOURCE. For e.g., the Makefile entry for updating the queue size to 25 would be as follows:
    DEFINES+=CY_VCM_EVENT_QUEUE_SIZE=25

Enable debug logs in VCM library

Enable VCM log messages

The VCM library disables all the debug log messages by default. To enable log messages, the application must perform the following:

  • To enable VCM logs in a dual-core application, add the ENABLE_VCM_LOGS macro to the DEFINES in the project Makefile. Depending on where the VCM logs need to be enabled, you can add this macro to either side of the project Makefile.
    DEFINES+=ENABLE_VCM_LOGS
  • Call the cy_log_init() function provided by the cy-log module. cy-log is part of the connectivity-utilities library. See connectivity-utilities library API documentation.

Enable logs in dual core application

To enable debug log messages on both cores, the application needs to reserve two distinct UART ports. If you are using one of Infineon's BSPs for the connectivity application, you can use the on-board KitProg3 USB-UART COM port to print debug logs for one core. However, you still need another USB-UART bridge to print debug logs for the other core.

  • One core can use the default CYBSP_DEBUG_UART_TX and CYBSP_DEBUG_UART_RX pins to enable the SCB block for KitProg3 using the retarget-io library.
    cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);
  • The other core can use any of the remaining SCB blocks to select the appropriate TX and RX pins. These TX and RX pins can be configured using the retarget-io library.
    • For example, in the CY8CEVAL-062S2-MUR-43439M2 board, the following pins can be configured for an additional UART port.
      • P13.4 and P13.5 (CYBSP_MIKROBUS_UART_RX, CYBSP_MIKROBUS_UART_TX)
      • P5.4 and P5.5 (CYBSP_D4, CYBSP_D5)
        cy_retarget_io_init(CYBSP_D5, CYBSP_D4, CY_RETARGET_IO_BAUDRATE);
    • For the second core, the selected TX and RX pins can be connected to an external USB-UART bridge (FTDI) using jumper wires, which will be emulated as a UART COM port.

Code snippets

Snippet 1: Initialize VCM

The following snippet demonstrates how to initialize the VCM library on two cores.

/***************************** Secondary core ***************************/
/* Flag to be set when VCM initialization is completed on the other core */
static volatile bool is_vcm_init_complete = false;
/* VCM callback registered in the secondary core to handle events from VCM. */
void vcm_callback_sec_core(cy_vcm_event_t event)
{
switch(event)
{
{
/* VCM init complete */
is_vcm_init_complete = true;
break;
}
default:
break;
}
}
void snippet_vcm_init_sec_core()
{
cy_rslt_t result;
/* Initialize the VCM library on the core that is brought up first. */
config.channel_num = CYHAL_IPC_CHAN_0;
config.event_cb = vcm_callback_sec_core;
/* Initialize VCM */
result = cy_vcm_init(&config);
if(result != CY_RSLT_SUCCESS)
{
printf("\n cy_vcm_init failed on core 1....!\n");
}
/* Enable the other core.
* For example, for enabling CM4, the following code is applicable.
* When this is called, the application on the primary core will begin executing. Ensure cy_vcm_init()
* is called on the second core when the execution begins.
*/
Cy_SysEnableCM4(CY_CORTEX_M4_APPL_ADDR);
/* Wait for CY_VCM_EVENT_INIT_COMPLETE event in the callback. */
while ( !is_vcm_init_complete )
{
cy_rtos_delay_milliseconds(1000);
}
/* Proceed to use virtual APIs from the secondary core. */
}
/***************************** Primary core ***************************/
/* VCM callback registered by core 2 application to handle events from VCM. */
void vcm_callback_prim_core(cy_vcm_event_t event)
{
switch(event)
{
{
/* Handle remote deinit */
break;
}
default:
break;
}
}
void snippet_vcm_init_prim_core()
{
cy_rslt_t result;
/* When the primary core is enabled, initalize VCM library with the below configurations. */
config.channel_num = CYHAL_IPC_CHAN_0;
config.event_cb = vcm_callback_prim_core;
/* Initialize VCM. This will cause CY_VCM_EVENT_INIT_COMPLETE event to be received on the secondary core. */
result = cy_vcm_init(&config);
if(result != CY_RSLT_SUCCESS)
{
printf("\ncy_vcm_init failed on the primary core....!\n");
}
/* Proceed with the rest of the application logic. */
}
cy_vcm_event_t
Virtual-Connectivity-Manager event type.
Definition: cy_vcm.h:75
@ CY_VCM_EVENT_INIT_COMPLETE
Event generated on the core which initializes VCM first when VCM initialization is complete on both c...
Definition: cy_vcm.h:76
@ CY_VCM_EVENT_DEINIT
Event generated on a core when the other core initiates VCM de-initialization.
Definition: cy_vcm.h:77
@ CY_VCM_CREATE_HAL_RESOURCE
Option to be set during cy_vcm_init in the core which initializes VCM first.
Definition: cy_vcm.h:86
@ CY_VCM_USE_HAL_RESOURCE
Option to be set during cy_vcm_init in the core which initializes VCM second.
Definition: cy_vcm.h:87
cy_rslt_t cy_vcm_init(cy_vcm_config_t *config)
Initializes the virtual connectivity manager.
Virtual-Connectivity-Manager config structure.
Definition: cy_vcm.h:124
cy_vcm_event_callback_t event_cb
Callback function which receives the VCM events.
Definition: cy_vcm.h:127
cy_vcm_hal_resource_opt_t hal_resource_opt
This is used to identify the core that should create the HAL resources.
Definition: cy_vcm.h:125
uint32_t channel_num
IPC channel number passed by user during initialization (e.g.
Definition: cy_vcm.h:126

Snippet 2: Deinitialize VCM

The following snippet demonstrates how to deinitialize the VCM library from two cores.

/***************************** Secondary core ***************************/
/* Flag that is set when VCM deinit is started by the other core.
* When this event is received, call cy_vcm_deinit() to deinitialize VCM
* on the current core.
*/
static bool is_vcm_deinit_requested_1 = false;
/* VCM callback registered in secondary core to handle events from VCM. */
void vcm_callback_prim_core_2(cy_vcm_event_t event)
{
cy_rslt_t result;
switch(event)
{
{
/* The other core has initiated VCM deinit. Deinitialize VCM locally. */
is_vcm_deinit_requested_1 = true;
break;
}
default:
break;
}
}
/* Secondary core initiates VCM deinitialization. */
void snippet_vcm_deinit_sec_core()
{
cy_rslt_t result;
/* VCM initialized on both cores */
/* ... */
/* VCM is no longer needed. Call deinit on secondary core. */
result = cy_vcm_deinit();
if( result != CY_RSLT_SUCCESS )
{
printf("\ncy_vcm_deinit failed on core 1!...\n");
}
}
/***************************** Primary core ***************************/
/* Flag that is set when VCM deinit is started by the other core.
* When this event is received, call cy_vcm_deinit() to deinitialize VCM
* on the current core.
*/
static bool is_vcm_deinit_requested = false;
/* VCM callback registered in primary core to handle events from VCM. */
void vcm_callback_prim_core_2(cy_vcm_event_t event)
{
cy_rslt_t result;
switch(event)
{
{
/* The other core has initiated VCM deinit. Deinitialize VCM locally. */
is_vcm_deinit_requested = true;
break;
}
default:
break;
}
}
/* Primary core waits for deinit to be started by the secondary core. When CY_VCM_EVENT_DEINIT
* event is received in the application callback, VCM is deinitialized locally.
*/
void snippet_vcm_deinit_prim_core()
{
cy_rslt_t result;
/* VCM initialized on both cores */
/* ... */
/* Wait for deinit to be initiated from the other core. */
while( !is_vcm_deinit_requested )
{
cy_rtos_delay_milliseconds(1000);
}
/* VCM deinit event received. Call deinit. */
result = cy_vcm_deinit();
if( result != CY_RSLT_SUCCESS )
{
printf("\n cy_vcm_deinit failed on primary core! \n");
return;
}
}
cy_rslt_t cy_vcm_deinit()
De-initializes the virtual connectivity manager.