Integrator can take 3 approaches to integrate A2B stack:
1. Using Wrapper Services Layer 1
Code Snippet: Wrapper Services Layer 1 Usage
2. Using Wrapper Services Layer 2
Each Stack state is explained in the following sub-section
3. A2B Network Stack Public APIs
The environmental control block (or ECB) is the container for all platform and environment data passed throughout the Stack. Most PAL functions receive a pointer to the ECB making this a central data structure for the PAL.
The core Stack ECB is defined by the a2b_Ecb structure which is comprised of two other sub-structure definitions as shown in Table (ECB Components).
|a2b_BaseEcb||This contains the basic platform-independent environment parameters. This structure must be defined first in the ECB structure.|
|a2b_PalEcb||These are the platform-specific environment properties defined by the PAL. This structure must be defined second in the ECB structure.|
Application-specific extensions can be added to the standard Stack ECB by adding custom application fields in the appropriate structures of a2b_Ecb.
One of the most powerful elements of the Stack is the plug-in architecture for initializing and managing slave nodes throughout an A2B network lifecycle. Plugins can initialize peripheral hardware on slave nodes, manipulate GPIO, communicate directly with I2C/SPI devices, create timers for periodic events, service interrupts, and monitor A2B diagnostic registers. Plugins can also send/receive notifications to/from the application to enable rich interactive system features. Custom plugins can be developed to support new A2B hardware.
Unordered List ItemThe Stack in all example Target projects comes with a Master and a generic Slave plugin designed using the plugin architecture.
In some cases, it may be necessary for the plugins to handle interrupts generated by A2B nodes. The function a2b_pluginInterrupt() in the plugin shall be implemented to handle such interrupts. The Stack takes care of passing the interrupt to the appropriate plugin depending on the interrupt type and location.
The Master plugin in the Stack comes with a default implementation to handle master interrupts and to invoke appropriate application callback functions if registered.
The generic Slave plugin in the Stack doesn’t come with a default implementation for interrupts generated by a slave node (GPIO pin). If a specific functionality is required on a slave node upon an interrupt, it can be implemented in the a2b_pluginInterrupt() function of the slave plugin after checking the Interrupt Type and Source node as shown in Code Snippet.
A custom plugin can be developed to support a new A2B hardware based on an example plugin. A Stack plugin must export a set of functions as indicated in the below table (Plugin Functions).
|a2b_pluginInit()||Called by the Stack once to initialize the a2b_PluginApi structure allowing the plugin to register the remaining entry-point functions. This is the only function that should be exported by a plugin.|
|a2b_pluginOpen()||Called during network discovery to see if the plugin handles a specific node. Any plugin related resources should be allocated here.|
|a2b_pluginExecute()||Called when a job needs to be processed by this plugin.|
|a2b_pluginInterrupt()||Called to process an interrupt for the slave associated with this plugin. Slave plugins only receive GPIO related interrupts.|
|a2b_pluginClose()||Called to close the plugin. Any plugin related resources should be freed here.|
A typical a2b_pluginInit() function for a plugin looks like this:
Implementation details for other plugin functions can be referred in file .\a2bplugin-slave\src\a2bslave_plugin.c.
An example implementation of the custom slave plugin is provided in file .\Target\examples\advancedapp\remoteTuner\a2b-bf\a2bplugin-rtm\src\a2brtm_plugin.c.
The custom plugin name and initialization function prototype are defined in file .\Target\examples\advancedapp\remoteTuner\a2b-bf\a2bplugin-rtm\inc \rtm_plugin.h as follows.
The PAL layer registers a custom plugin load function as below in file .\Target\examples\advancedapp\remoteTuner\a2b-bf\a2bstack-pal\adi_a2b_pal.c in function a2b_palInit.
The plugins load function will load the RTM plugin as shown below. In this demo, RTM is connected to slave node 1 and slave node 0 has generic slave plugin. Refer to function a2brtm_pluginsLoad in file .\Target\examples\advancedapp\remoteTuner\a2b-bf\a2bplugin-rtm\src\a2b-rtm_plugin.c
The RTM plugin implementation has the following functions:
|A2B_RTM_PLUGIN_INIT||Called by the plugin's load function. This is the only function that should be exported by a plugin.|
|a2b_pluginOpen()||Called during network discovery to see if the plugin handles a specific node. Any plugin-related resources should be allocated here.|
|a2b_pluginExecute()||The RTM booting, tuning, and mute functionalities are implemented in this custom function.|
|a2b_pluginInterrupt()||Called to process an interrupt for the slave associated with this plugin. Slave plugins only receive GPIO-related interrupts.|
|a2b_pluginClose()||Called to close the plugin. Any plugin-related resources should be freed here.|
The custom Plugin execute function supports RTM specific messages which can be called externally.
|A2B_MSGREQ_RTM_BOOT||RTM boot message|
|A2B_MSGREQ_RTM_TUNE||RTM tune to a particular frequency|
|A2B_MSGREQ_RTM_MUTE||Mute/Unmute the RTM|
Post discovery, RTM custom messages are triggered by the application to perform specific functions. In the example application, UART-based commands are used to trigger these custom messages on a specific UART command as shown below. Refer .\Target\examples\demo\a2b-uart-utility\cmd_parse.c.
Plugins are loaded into the Stack through the a2b_PluginsLoadFunc PAL function. This function returns a structured list of pointers pointing to the a2b_pluginInit() function of each plugin.
During the discovery process, each registered plugin is queried, in order, when a new slave node is discovered to determine whether or not that plugin can service the node. The first plugin to respond affirmatively by returning a non-NULL value will be assigned by the Stack to that node.
Since each discovered slave node carries its own context, a single plugin can service more than one slave node concurrently. It’s important to note, however, that each slave plugin instance is responsible for maintaining its context.
In cases where the Host processor is controlling multiple A2B Masters, it is necessary to maintain multiple stack instances. At the application level, one stack context is mapped per network master. Each individual instance maintains the complete Stack state for an A2B network. Multiple instances allow the Stack to manage multiple A2B networks simultaneously.
Each application context can either register separate callback functions (for Discovery completion, Power Fault or Interrupt events) or have a single function with a unique callback parameter for each network chain.
An example project to demonstrate multi-master bus setup is provided in ‘ADI_A2B-SSPlus_Software-RelX.Y.Z\Target\examples\advancedapp\multimaster’ of the A2B Software package. This example uses an ADSP-SC584 processor to discover and route the audio between two A2B networks. In the example project, the structure a2b_App_t represents the application-level instance. Separate objects of this structure are created for each network instance. Each instance is identified with an index – ‘nChainIndex’, starting with 0. This parameter is used inside notification callback and PAL functions to differentiate the handling between two A2B networks.
Note that when requiring to support multiple A2B Masters on a different platform, it is not just sufficient to change the macro ‘A2B_CONF_MAX_NUM_MASTER_NODE’ in Target/examples/demo/<a2b-xx»/a2bstack-pal/platform/a2b/conf.h but also would require modifications to the functions in adi_a2b_pal.c.
The Stack running on the master node target processor can communicate with an intelligent slave node having a connected processor. This can be achieved by using the Mailbox Communication Channel module. The module enables the exchange of control and command messages between the two processors.
An example project for demonstrating the inter-processor communication using mailbox communication channel is provided in ‘ADI_A2B-SSPlus_Software-RelX.Y.Z\ Target\examples\ advancedapp\mboxcommch of the A2B Software package. Refer a2bsspluscommchinterationguide for more details on running the demo. The document also provides details of the module APIs and the integration approach
One example use case of this module is when Custom node authentication using Mailbox option is set in SigmaStudioPlus. In this case, the Stack running on the Target/Host processor queries a slave node processor for Node Identifier using A2B_COMMCH_MSG_REQ_SLV_NODE_SIGNATURE and the slave node responds with A2B_COMMCH_MSG_RSP_SLV_NODE_SIGNATURE using the module API as shown in Figure. The figure also shows an example sequence of exchange when the slave initiates a request message transmission with message ID say A2B_COMMCH_MSG_REQ_MSTR_VERSION and the master responds back with the response message ID A2B_COMMCH_MSG_RES_MSTR_VERSION.
Every message communicated has a unique ID assigned that is common across master and slave nodes. Message ID is 6 bits in length. Message IDs up to 0xA are reserved to be used for communication with the Master Plugin and should not be used by the application. All these message IDs are defined in ‘ADI_A2B-SSPlus_Software-RelX.Y.Z/Target/a2bcommchannel/ inc/adi_a2b_commch_interface.h’ file.
The Target example projects in ‘ADI_A2B-SSPlus_Software-RelX.Y.Z\Target\examples\demo’ does not come with the mailbox communication channel module integrated. To use the module for inter-processor communication the following pre-requisites shall be met.
For details on integration of A2B mailbox into application, please refer a2bsspluscommchinterationguide.
A2B network’s biggest advantage is “setup once and forget”. After network discovery and setup of all the nodes, minimal host intervention is required. Audio streams get transmitted across nodes seamlessly. So host intervention is only limited to fault monitoring. Host action is required only when bus faults are detected.
With AD243x supporting SPI tunnelling, there is a need to have post discovery action as well. So the A2B stack has been adapted to provide post discovery APIs to application software in order to transfer asynchronous data across A2B nodes through SPI tunnels.
To ease applications in performing some basic post discovery operations, the following APIs are provided to the application. Post discovery APIs are provided in .\Target\examples\demo\app-plugin\src\a2bapp.c.
|a2b_reset()||This function does A2B network soft reset.|
|a2b_AppWriteReg()||This function writes a register value to a particular A2B node.|
|a2b_AppReadReg()||This function reads a register value from a particular A2B node.|
|a2b_app_handle_becovf()||This routine periodically resets BECNT and BECOVF registers and checks for bus drop.|
|a2b_AppDetectBusDrop()||This function reads the Vendor Id register of all A2B nodes discovered and declares a bus drop at a particular node where the read value is not the expected.|
|a2b_AppPWMSetup()||This function configures the PWM registers for the PWM functionality in AD243x. It is called one time to setup the PWM channel (AD243x only)|
while PWM channel is running (AD243x only)|
|a2bapp_VMTRMonitor()||API for VMTR monitor to check if the monitored voltages are beyond the min and max thresholds. This API can be periodically called to determine voltage-related errors. This API assumes that all the VMTR threshold registers are already statically configured (AD243x only)|
Post-discovery SPI APIs are available in .\Target\a2bstack\a2bstack\src\perieng.c. These APIs can be used to read/write from a remote SPI peripheral device like EEPROM via an A2B bus. Please refer to the .\Docs\ AE_09_A2B_Stack_API_Reference.chm(19.10.0) for detailed API reference.
|A2B_SPI_ATOMIC||Use Atomic SPI transactions to allow a write or read initiated on any node in an A2B system to occur at a peripheral on a different node|
|A2B_SPI_BULK||Use Bulk SPI transactions|
|A2B_SPI_FD_CMD_BASED||Use Full duplex SPI transaction - slave select 0 (ADR1) selects the SPI slave from the host|
|A2B_SPI_FD_REG_BASED||Use Full duplex register-based SPI transaction – the A2B node is selected by either the ADR2 or SIO2 pin|
|A2B_SPI_BULK_EXTENDED||Use Bulk extended transactions (more than 256 bytes in a single transaction at remote node)|
|A2B_SPI_FD_CMD_BASED_EXTENDED||Use Full duplex extended SPI transaction (more than 256 bytes in a single transaction at remote node)|
|A2B_API_BLOCKING||API returns only after entire payload is Transmitted/Received|
|A2B_API_NON_BLOCKING||API returns immediately and does not wait for entire payload to be Transmitted/Received|
|a2b_SpiConfig||Structure holding the various configurable parameters of SPI|
|a2b_SpiWrRdParams||Structure holding the various write/read parameters of SPI|
Please refer the .\Docs\ AE_09_A2B_Stack_API_Reference.chm(19.10.0 Rel) for details on structure members.
|adi_a2b_spiPeriCreate()||This function is used to allocate the SPI to SPI peripheral configuration time-out timer. This function shall be called only once.|
|adi_a2b_spiPeriSetMode()||This function is used to register the call back function, SPI mode of operation etc, for SPI peripheral post-discovery event handling.|
|adi_a2b_spiPeriGetMode()||This function is used get the current SPI & API mode of operation.|
|adi_a2b_spiPeriWrRd()||This function is used to write/write-read payload to/from peripherals connected to A2B nodes using the SPI interface. The write and read buffers have to be configured in “a2b_SpiWrRdParams” structure before accessing this API. The application can submit the buffer to this API. The API will handle the segmentation and convert it into one or many A2B SPI bus transactions internally.|
Please refer the .\Docs\ AE_09_A2B_Stack_API_Reference.chm(19.10.0 Rel) for details on API reference and its call and return parameters.
These APIs provide access to A2B registers (master or slave nodes) via I2C or SPI depending on the stack’s access interface and node.
|a2b_regWrite()||Writes bytes to the SPI/I2C device. This is a synchronous call and will block until the operation is complete.|
|a2b_regWriteRead()||Writes and then reads bytes from the SPI/I2C device. This is a synchronous call and will block until the operation is complete.|