Driver Use-cases, Types, and Variants

Driver use-cases
The application functionality, which a peripheral can be used for, such as PWM and Timer for a Timer-Counter (TC) peripheral.
Driver variants
Different driver implementation architectures, such the Synchronous-, Asynchronous-, DMA-, and RTOS-Drivers.
Driver Types
Relates to whether a driver supports a peripheral, utility function, or middleware.

Driver Use-cases

Instead of having one generic driver per peripheral, the ASF4 drivers provide interfaces to ways of using the peripheral. These ways are named "use-cases". A use-case typically implements a subset of the total functionality provided by the peripheral. This is useful as many of the peripherals on SAM devices, such as the SERCOM, provide a very broad functionality. This would cause a generic driver providing access to all the functionality of the module to be very large. Because the use-case limits the scope of functionality provided to the user, the driver is easier to implement and test and is more optimal than a generic driver would be. The figure below shows that a SERCOM hardware module can be used to implement various communication protocols, each protocol (or use-case) being implemented by a specific ASF4 driver. There is no generic "SERCOM" driver in the ASF4 HAL layer, but instead a specific "USART" driver, "I2C" driver, "LIN" driver, and so on.

The use-case approach together with the HAL and HPL layers allow the driver to be implemented in different ways, depending on the available hardware. As an example, a driver that issues a periodic interrupt can be implemented using for example:

  • TC Timer
  • TCC Timer
  • RTC
  • Systick in CPU

Atmel START is used to select the hardware instance to be used to implement the driver. This is done during ASF4 configuration.

Figure 1. Example of Use-cases for a SERCOM Module

ASF4 has different types of drivers; Peripheral-, Utility-, and Middleware-drivers.

Driver Variants

A use-case such as "ADC" can be implemented using drivers with different architectures, such as:
  • ADC with blocking receive/transmit functions
  • ADC with non-blocking receive/transmit functions
  • ADC implemented using DMA transfer of data between peripheral registers to memory
  • ADC intended for use with a Real-Time operating system

ADC Synchronous Driver

The driver will block (i.e. not return) until the requested data has been read. Functionality is therefore synchronous to the calling thread, i.e. the thread waits for the result to be ready. The adc_sync_read_channel( ) function will perform a conversion of the voltage on the specified channel and return the result when it is ready.

ADC Asynchronous Driver

The driver adc_async_read_channel function will attempt to read the required number of conversion results from a ring buffer. It will return immediately (i.e. not block), even if the requested number of data is not available immediately. If data was not available, or fewer data than requested was available, this will be indicated in the function's return value. The asynchronous driver uses interrupts to communicate that ADC data is available, and the driver's IRQ handler reads data from hardware and into ringbuffers in memory. These ringbuffers decouple the generation of data in the ADC with the timing of the application request for this data. In a way, the producer and consumer events are asynchronous to each other. The user can register a callback function to piggyback on the IRQ handler routine for communicating with the main application.

ADC DMA Driver

Uses DMA system to transfer data from ADC to a memory buffer in RAM. The user must configure the DMAC system driver accordingly. To set the memory buffer and its size the adc_dma_read function is used. This function programs DMA to transfer the results of input signal conversion to the given buffer. A callback is called when all data is transferred if it is registered via the adc_dma_register_callback function.

ADC RTOS Driver

The driver is intended for using ADC functions in a real-time operating system, i.e. a thread-safe system.

For drivers providing multiple variants, the variant to be used is selected during the ASF4 configuration in START.

Driver Types

Driver Types relate to whether a driver supports a peripheral, utility function, or middleware.

Peripheral Driver

A peripheral driver is a driver that is directly related to some functionality in some hardware peripherals. This is usually not the full functionality set available in the hardware peripheral, but a subset to make it portable between hardware platforms with different hardware peripheral implementations. A peripheral driver in the ASF4 consists of the HRI, HPL, and HAL layers. The user will normally interface only with the topmost HAL layer.

Utility Driver

Utility drivers are hardware agnostic drivers that implement commonly used software concepts. The utility drivers are available for both the ASF4 drivers and the user application. Examples of utility drivers are a generic linked list or a ring buffer. Utility drivers can also be in form of C macro definitions.

Moving commonly used code into utility drivers makes it easier to maintain code and help the compiler to optimize the code because the same code is used by different drivers, but only one copy is needed. The utility drivers are fully abstracted and not bound to any particular hardware platform or type.

Middleware Driver

Middleware drivers are built on top of peripheral drivers and do not have any direct link to the underlying hardware. A middleware driver can depend on multiple peripheral drivers at the same time or support a range of different peripheral drivers. These drivers usually implement highly abstracted code that implements some kind of software concepts like graphics libraries, USB classes, or file systems.