1# Theory of Operation {#theoryOperation} 2 3[TOC] 4 5This section gives an overview of the general operation of CMSIS-Drivers. It explains the \ref DriverFunctions that are common in all CMSIS-Drivers along with the \ref CallSequence. The topic \ref Data_Xfer_Functions describes how data read/write operations to the peripheral are implemented. 6 7Each CMSIS-Driver defines an \ref AccessStruct for calling the various driver functions and each peripheral (that is accessed via a CMSIS-Driver) has one \ref DriverInstances "Driver Instance". 8 9 10## Common Driver Functions {#DriverFunctions} 11 12Each CMSIS-Driver contains these functions: 13 14 - `GetVersion`: can be called at any time to obtain version information of the driver interface. 15 16 - `GetCapabilities`: can be called at any time to obtain capabilities of the driver interface. 17 18 - `Initialize`: must be called before powering the peripheral using `PowerControl`. This function performs the following: 19 - allocate I/O resources. 20 - register an optional `SignalEvent` callback function. 21 22 - `SignalEvent`: is an optional callback function that is registered with the `Initialize` function. This callback function is initiated from interrupt service routines and indicates hardware events or the completion of a data block transfer operation. 23 24 - `PowerControl`: Controls the power profile of the peripheral and needs to be called after `Initialize`. Typically, three power options are available (see \ref ARM_POWER_STATE): 25 - `ARM_POWER_FULL`: Peripheral is turned on and fully operational. The driver initializes the peripheral registers, interrupts, and (optionally) DMA. 26 - `ARM_POWER_LOW` : (optional) Peripheral is in low power mode and partially operational; usually, it can detect external events and wake-up. 27 - `ARM_POWER_OFF`: Peripheral is turned off and not operational (pending operations are terminated). This is the state after device reset. 28 29 - `Uninitialize`: Complementary function to Initialize. Releases the I/O pin resources used by the interface. 30 31 - `Control`: Several drivers provide a control function to configure communication parameters or execute miscellaneous control functions. 32 33The section \ref CallSequence contains more information on the operation of each function. Additional functions are specific to each driver interface and are described in the individual sections of each driver. 34 35## Cortex-M Processor Mode {#ProcessorMode} 36 37The CMSIS-Driver functions access peripherals and interrupts and are designed to execute in **Privileged** mode. When calling CMSIS-Driver functions from RTOS threads, it should be ensure that these threads execute in **Privileged** mode. 38 39 40## Function Call Sequence {#CallSequence} 41 42For normal operation of the driver, the API functions `GetVersion`, `GetCapabilities`, `Initialize`, `PowerControl`, `Uninitialize` are called in the following order: 43 44\msc 45 a [label="", textcolor="indigo", linecolor="indigo", arclinecolor="indigo"], 46 b [label="", textcolor="blue", linecolor="blue", arclinecolor="blue"]; 47 48 a rbox a [label="Middleware", linecolor="indigo"], 49 b rbox b [label="Driver", linecolor="blue"]; 50 --- [label="Verify API version"]; 51 a=>b [label="GetVersion ()", textcolor="gray", linecolor="gray"]; 52 --- [label="Obtain driver features"]; 53 a=>b [label="GetCapabilities (...)", textcolor="gray", linecolor="gray"]; 54 --- [label="Setup software resources"]; 55 a=>b [label="Initialize (...)", textcolor="red", linecolor="red"]; 56 --- [label="Setup the peripheral"]; 57 a=>b [label="PowerControl (ARM_POWER_FULL)", textcolor="red", linecolor="red"]; 58 --- [label="Operate with the peripheral"]; 59 a=>b [label="Data Transfer Functions"]; 60 a<=b [label="SignalEvent (...)"]; 61 --- [label="Wait for external hardware events"]; 62 a=>b [label="PowerControl (ARM_POWER_LOW)"]; 63 a<=b [label="SignalEvent (...)"]; 64 --- [label="Stop working with peripheral"]; 65 a=>b [label="PowerControl (ARM_POWER_OFF)", textcolor="red", linecolor="red"]; 66 a=>b [label="Uninitialize (...)", textcolor="red", linecolor="red"]; 67\endmsc 68 69The functions `GetVersion` and `GetCapabilities` can be called any time to obtain the required information from the driver. These functions return always the same information. 70 71 72### Start Sequence {#CS_start} 73 74To start working with a peripheral the functions `Initialize` and `PowerControl` need to be called in this order: 75 76```c 77 drv->Initialize (...); // Allocate I/O pins 78 drv->PowerControl (ARM_POWER_FULL); // Power up peripheral, setup IRQ/DMA 79``` 80 81 - `Initialize` typically allocates the I/O resources (pins) for the peripheral. The function can be called multiple times; if the I/O resources are already initialized it performs no operation and just returns with \ref ARM_DRIVER_OK. 82 - `PowerControl` (`ARM_POWER_FULL`) sets the peripheral registers including interrupt (NVIC) and optionally DMA. The function can be called multiple times; if the registers are already set it performs no operation and just returns with \ref ARM_DRIVER_OK. 83 84### Stop Sequence {#CS_stop} 85 86To stop working with a peripheral the functions `PowerControl` and `Uninitialize` need to be called in this order: 87 88```c 89 drv->PowerControl (ARM_POWER_OFF); // Terminate any pending transfers, reset IRQ/DMA, power off peripheral 90 drv->Uninitialize (...); // Release I/O pins 91``` 92 93The functions `PowerControl` and `Uninitialize` always execute and can be used to put the peripheral into a **Safe State**, for example after any data transmission errors. To restart the peripheral in a error condition, you should first execute the \ref CS_stop and then the \ref CS_start. 94 95 - `PowerControl` (`ARM_POWER_OFF`) terminates any pending data transfers with the peripheral, disables the peripheral and leaves it in a defined mode (typically the reset state). 96 - when DMA is used it is disabled (including the interrupts) 97 - peripheral interrupts are disabled on NVIC level 98 - the peripheral is reset using a dedicated reset mechanism (if available) or by clearing the peripheral registers 99 - pending peripheral interrupts are cleared on NVIC level 100 - driver variables are cleared 101 - `Uninitialize` always releases I/O pin resources. 102 103## Shared I/O Pins {#Share_IO} 104 105All CMSIS-Driver provide a \ref CS_start and \ref CS_stop. Therefore two different drivers can share the same I/O pins, for example UART1 and SPI1 can have overlapping I/O pins. In this case the communication channels can be used as shown below: 106 107```c 108 SPI1drv->Initialize (...); // Start SPI1 109 SPI1drv->PowerControl (ARM_POWER_FULL); 110 ... // Do operations with SPI1 111 SPI1drv->PowerControl (ARM_POWER_OFF); // Stop SPI1 112 SPI1drv->Uninitialize (); 113 ... 114 USART1drv->Initialize (...); // Start USART1 115 USART1drv->PowerControl (ARM_POWER_FULL); 116 ... // Do operations with USART1 117 USART1drv->PowerControl (ARM_POWER_OFF); // Stop USART1 118 USART1drv->Uninitialize (); 119``` 120 121## Data Transfer Functions {#Data_Xfer_Functions} 122 123A CMSIS-Driver implements non-blocking functions to transfer data to a peripheral. This means that the driver configures the read or write access to the peripheral and instantly returns to the calling application. The function names for data transfer end with: 124 125 - `Send` to write data to a peripheral. 126 - `Receive` to read data from a peripheral. 127 - `Transfer` to indicate combined read/write operations to a peripheral. 128 129During a data transfer, the application can query the number of transferred data items using functions named <b>Get<i>xxx</i>Count</b>. On completion of a data transfer, the driver calls a callback function with a specific event code. 130 131During the data exchange with the peripheral, the application can decide to: 132 133 - Wait (using an RTOS scheduler) for the callback completion event. The RTOS is controlled by the application code which makes the driver itself RTOS independent. 134 - Use polling functions that return the number of transferred data items to show progress information or partly read or fill data transfer buffers. 135 - Prepare another data transfer buffer for the next data transfer. 136 137The following diagram shows the basic communication flow when using the `_Send` function in an application. 138 139 140 141## Access Struct {#AccessStruct} 142 143A CMSIS-Driver publishes an \ref AccessStruct with the data type name `ARM_DRIVER_xxxx` that gives to access the driver functions. 144 145**Code Example:** Function Access of the SPI driver 146 147```c 148typedef struct _ARM_DRIVER_SPI { 149 ARM_DRIVER_VERSION (*GetVersion) (void); 150 ARM_SPI_CAPABILITIES (*GetCapabilities) (void); 151 int32_t (*Initialize) (ARM_SPI_SignalEvent_t cb_event); 152 int32_t (*Uninitialize) (void); 153 int32_t (*PowerControl) (ARM_POWER_STATE state); 154 int32_t (*Send) (const void *data, uint32_t num); 155 int32_t (*Receive) ( void *data, uint32_t num); 156 int32_t (*Transfer) (const void *data_out, void *data_in, uint32_t num); 157 uint32_t (*GetDataCount) (void); 158 int32_t (*Control) (uint32_t control, uint32_t arg); 159 ARM_SPI_STATUS (*GetStatus) (void); 160} const ARM_DRIVER_SPI; 161``` 162 163### Driver Instances {#DriverInstances} 164 165A device may offer several peripherals of the same type. For such devices, the CMSIS-Driver publishes multiple instances of the \ref AccessStruct. The name of each driver instance reflects the names of the peripheral available in the device. 166 167**Code Example:** \ref AccessStruct for three SPIs in a microcontroller device. 168 169```c 170ARM_DRIVER_SPI Driver_SPI1; // access functions for SPI1 interface 171ARM_DRIVER_SPI Driver_SPI2; // access functions for SPI2 interface 172ARM_DRIVER_SPI Driver_SPI3; // access functions for SPI3 interface 173``` 174 175The access functions can be passed to middleware to specify the driver instance that the middleware should use for communication. 176 177**Naming Convention** 178 179The access structs need to follow this naming convention: the keyword `Driver` followed by an underscore `_`, the interface name `IFNAME` (usually in upper case letters), and the instance number `n`. Here's the full list of access struct names for all drivers (n to be replaced with the actual instance number): 180 181```c 182Driver_CANn 183Driver_ETH_MACn 184Driver_ETH_PHYn 185Driver_Flashn 186Driver_GPIOn 187Driver_I2Cn 188Driver_MCIn 189Driver_NANDn 190Driver_SAIn 191Driver_SPIn 192Driver_Storagen 193Driver_USARTn 194Driver_USBDn 195Driver_USBHn 196Driver_WiFin 197``` 198 199 200**Example:** 201 202```c 203void init_middleware (ARM_DRIVER_SPI *Drv_spi) ... 204\\ inside the middleware the SPI driver functions are called with: 205\\ Drv_spi->function (...); 206``` 207 208```c 209\\ setup middleware 210init_middleware (&Driver_SPI1); // connect middleware to SPI1 interface 211 : 212init_middleware (&Driver_SPI2); // connect middleware to SPI2 interface 213``` 214 215## CMSIS-Driver Files {#cmsis_driver_files} 216 217The API of each CMSIS-Driver peripheral is published in a corresponding header file in the directory `.\CMSIS\Driver\Include\` It is recommended to include such header file in the implementation file of the CMSIS-Driver. 218 219Template files are available to simplify the development of a CMSIS-Driver. These are code skeletons that provide the structure of a CMSIS-Driver. They are available in the directory`.\CMSIS\Driver\DriverTemplates\`. You can also refer to working \ref listOfImplementations "CMSIS-Driver Implementations" to see how CMSIS-Drivers get implemented on real devices. 220 221The table below summarizes the API header and template files for CMSIS-Driver interfaces, with links to GitHub and API references. 222 223 224| Header File | Template File | API Reference 225:----------------------|:-------------------------|:----------------------- 226[Driver_Common.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_Common.h)| Not applicable | \ref common_drv_gr 227[Driver_CAN.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_CAN.h) | [Driver_CAN.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_CAN.c) |\ref can_interface_gr 228[Driver_ETH.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_ETH.h) | - |\ref eth_interface_gr 229[Driver_ETH_MAC.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_ETH_MAC.h) | [Driver_ETH_MAC.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_ETH_MAC.c) | \ref eth_mac_interface_gr 230[Driver_ETH_PHY.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_ETH_MAC.h) | [Driver_ETH_PHY.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_ETH_PHY.c) | \ref eth_phy_interface_gr 231[Driver_Flash.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_Flash.h) | [Driver_Flash.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_Flash.c) | \ref flash_interface_gr 232[Driver_GPIO.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_GPIO.h) | [Driver_GPIO.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_GPIO.c) | \ref gpio_interface_gr 233[Driver_I2C.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_I2C.h) | [Driver_I2C.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_I2C.c) | \ref i2c_interface_gr 234[Driver_MCI.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_MCI.h) | [Driver_MCI.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_MCI.c) | \ref mci_interface_gr 235[Driver_NAND.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_NAND.h) | [Driver_NAND.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_NAND.c) | \ref nand_interface_gr 236[Driver_SAI.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_SAI.h) | [Driver_SAI.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_SAI.c) | \ref sai_interface_gr 237[Driver_SPI.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_SPI.h) | [Driver_SPI.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_SPI.c) | \ref spi_interface_gr 238[Driver_Storage.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_Storage.h) | [Driver_Storage.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_Storage.c) | \ref storage_interface_gr 239[Driver_USART.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_USART.h) | [Driver_USART.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_USART.c) | \ref usart_interface_gr 240[Driver_USB.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_USB.h) | - | \ref usb_interface_gr 241[Driver_USBD.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_USBD.h) | [Driver_USBD.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_USBD.c) | \ref usbd_interface_gr 242[Driver_USBH.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_USBH.h) | [Driver_USBH.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_USBH.c) | \ref usbh_interface_gr 243[Driver_WiFi.h](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/Include/Driver_WiFi.h) | [Driver_WiFi.c](https://github.com/ARM-software/CMSIS_6/blob/main/CMSIS/Driver/DriverTemplates/Driver_WiFi.c) | \ref wifi_interface_gr 244 245## Driver Configuration {#DriverConfiguration} 246 247For a device family, the drivers may be configurable, but the configuration of the drivers itself is not part of the CMSIS-Driver specification. 248 249## Code Example {#CodeExample} 250 251The following example code shows the usage of the SPI interface. 252 253\include SPI_Demo.c 254