Definition of "driver".

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,609
Is there a formal definition for the term "driver" in the MCU world? I see the term used a lot as I read blogs and peruse library code but it seems somewhat vague. In traditional computing terms "driver" usually means something that acts as a bridge between a hardware specific interface and a hardware independent abstract interface.

Such code also generally executes (or parts of it anyway) in "kernel" mode, that is it is afforded execution privileges that are generally unavailable to "application" code, like temporarily masking interrupts, or accessing "kernel" stacks and heaps, some of these ideas though are likely the province of operating systems and if we don't have one then these terms are again rather vague.

Thoughts?
 

nsaspook

Joined Aug 27, 2009
13,262
There are usually two types of "drivers' in a real OS like Linux with privilege and protection so there is a technical necessity of division of processing work. Hardware drivers (usually kernel but can be user-land) that implement a abstract programming device API for a real hardware device using registers, memory mapped I/O, etc....
Protocol drivers (kernel or user-land) that use that hardware API abstraction to create a standard user application interface like a ioctl interface.

SPI controller -> specific hardware driver for a chip or device level SPI interface (it could just be a plain-jane actual shift register) to a standard system defined by a SPI device SPI CORE specification.
SPI protocol -> standard system defined SPI device to a standard I/O interface like /dev/spi0 using the SPIDEV protocol driver or a specific device like a GLCD display.
https://www.kernel.org/doc/html/v4.9/driver-api/spi.html

In the MCU 8-bit world the driver functions are sometimes combined into a unified controller and protocol driver because of chip resource, performance and application I/O limitations. For 16+ bit devices, we usually see some abstraction of hardware controller register details into a standard API for higher-level functionality but it's not usually a technical necessity until privilege and protection are added to flat-world bare-metal operations.

The MCU world is very big so there are formal driver definitions for MCU's that run real OS systems that require specific hardware capabilities and not so formal 'driver' definitions for just about everything else because there are no hardware technical reasons for a formal definition, only wants for programmers.
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,262
For a simple MCU bare-metal GLCD display we could have 'driver' separation of logical programming functions to provide structured programming.

The GLCD display needs a Raster display memory buffer we can manipulate with computer memory operations to form images or text.
https://github.com/nsaspook/wfi32/blob/wfi/firmware/lcd_drv/OledDriver.c

Raster
C:
/* This array is the offscreen frame buffer used for rendering.
** It isn't possible to read back frome the OLED display device,
** so display data is rendered into this offscreen buffer and then
** copied to the display.
*  must be in uncached memory for pic32 DMA so use __attribute__((coherent))
* DMA0 SPI TX transfers DATA, CMD
* DMA1 GLCD buffer transfers
* DMA2 SPI TX transfers CMD, NOT USED
*/
#ifdef __32MK0512MCJ048__    // NO bank 2 for this CPU so memory in in bank 1
uint8_t __attribute__((address(BANK1), coherent)) rgbOledBmp0[cbOledDispMax]; // two display buffers for page flipping
uint8_t __attribute__((address(BANK1 + cbOledDispMax), coherent)) rgbOledBmp1[cbOledDispMax];
#ifdef USE_DMA
static uint8_t __attribute__((address(BANK1 - 8), coherent)) rgbOledBmp_blank[4] = {0x00, 0x00, 0x00, 0x00}; // 32-bit frame-buffer clearing variable
#endif
volatile uint8_t __attribute__((address(BANK1 - 16), coherent)) rgbOledBmp_page[5];
#endif

#ifdef __32MZ1025W104132__    // bank 2 for this CPU
uint8_t __attribute__((address(BANK2), coherent)) rgbOledBmp0[cbOledDispMax]; // two display buffers for page flipping
uint8_t __attribute__((address(BANK2 + cbOledDispMax), coherent)) rgbOledBmp1[cbOledDispMax];
#ifdef USE_DMA
static uint8_t __attribute__((address(BANK2 - 8), coherent)) rgbOledBmp_blank[4] = {0x00, 0x00, 0x00, 0x00}; // 32-bit frame-buffer clearing variable
#endif
volatile uint8_t __attribute__((address(BANK2 - 16), coherent)) rgbOledBmp_page[5];
#endif
We have hardware 'driver' functions to clear the raster buffer using DMA function calls.

C:
void OledClearBuffer(void)
{
    uint8_t * pb;

    if (disp_frame) {
        pb = rgbOledBmp0;
    } else {
        pb = rgbOledBmp1;
    }

#ifdef USE_DMA
    /*
     * DMAC_ChannelCallbackRegister in OledInit
     */
    while (dstate != D_idle) {
    };
    wait_lcd_done();
    /* setup the source and destination parms */
    DMAC_ChannelTransfer(DMAC_CHANNEL_1, (const void *) rgbOledBmp_blank, (size_t) 4, (const void*) pb, (size_t) cbOledDispMax, (size_t) cbOledDispMax);
    DCH1ECONSET = _DCH1ECON_CFORCE_MASK; // set CFORCE to 1 to start the transfer
#else
#endif
}
and hardware/protocol 'driver' functions to send that buffer to the display device using DMA hardware function calls to implement the SPI protocols for that display chip.

C:
/***    OledUpdate
**
**    Parameters:
**        none
**
**    Return Value:
**        none
**
**    Errors:
**        none
**
**    Description:
**        Update the OLED display with the contents of the memory buffer
*/

void OledUpdate(void)
{
#ifdef DMA_STATE_M
    wait_lcd_done();
    SPI1DmaChannelHandler_State(0, DMA_MAGIC); // set DMA state machine init mode to start transfers
    return;
#else
#endif
}

/*
* start a GLCD update: Called in user code with contextHandle set to DMA_MAGIC for a background screen update,
* during background transfers this function is used as the callback for DMA transfer complete events to
* sequence commands and data to the GLCD via the SPI port using the dstate ENUM variable
* dstate is set to 'D_idle' when the complete set of transfers is done.
*/
void SPI1DmaChannelHandler_State(DMAC_TRANSFER_EVENT event, uintptr_t contextHandle)
{
    static int32_t ipag = 0; // buffer page number
    static uint8_t* pb; // buffer page address

    // back to mainline code, GLCD updates in background using DMA and interrupts
    LCD_UNSELECT();
    if (contextHandle == DMA_MAGIC) { // re-init state machine for next GLCD update
        dstate = D_init;
    }

    switch (dstate) {
    case D_init:
        ipag = 0;
        if (disp_frame) { // select flipper buffer
            pb = rgbOledBmp0;
        } else {
            pb = rgbOledBmp1;
        }
        /* FALLTHRU */
    case D_page: // send the page address commands via DMA
        LCD_SELECT(); // enable the GLCD chip for SPI transfers
        dstate = D_buffer;
        lcd_moveto_xy(ipag, 0); // calculate address data nibbles and store in rgbOledBmp_page array
        /*
         * DMAC_ChannelCallbackRegister and SPI setup in OledInit
         */
        LCD_CMD();
        DMAC_ChannelTransfer(DMAC_CHANNEL_0, (const void *) rgbOledBmp_page, (size_t) 4, (const void*) &SPI1BUF, (size_t) 1, (size_t) 1);
        break;
    case D_buffer: // send the GLCD buffer data via DMA
        ipag++;
        if (ipag <= cpagOledMax) {
            LCD_SELECT(); // enable the GLCD chip for SPI transfers
            dstate = D_page;
            LCD_DRAM();
            DMAC_ChannelTransfer(DMAC_CHANNEL_0, (const void *) pb, (size_t) ccolOledMax, (const void*) &SPI1BUF, (size_t) 1, (size_t) 1);
            pb += ccolOledMax;
        } else {
            dstate = D_idle;
            LCD_UNSELECT(); // all done with the GLCD
        }
        break;
    case D_idle:
    default:
        LCD_UNSELECT();
        break;
    }
}
It's nice and structured to divide the code into 'driver' sections but it's not a technical necessity on this MCU to separate user and hardware functions when it's not using privilege and protection (the MIPS core processor is capable of those duties but they are not used) .
 
Last edited:

BobaMosfet

Joined Jul 1, 2009
2,113
Is there a formal definition for the term "driver" in the MCU world? I see the term used a lot as I read blogs and peruse library code but it seems somewhat vague. In traditional computing terms "driver" usually means something that acts as a bridge between a hardware specific interface and a hardware independent abstract interface.

Such code also generally executes (or parts of it anyway) in "kernel" mode, that is it is afforded execution privileges that are generally unavailable to "application" code, like temporarily masking interrupts, or accessing "kernel" stacks and heaps, some of these ideas though are likely the province of operating systems and if we don't have one then these terms are again rather vague.

Thoughts?
A driver, in any environment is a piece of code that sits between the processor and the device being accessed. It's purpose is to obfuscate and genericize access to the device. For example, any device no matter what it is, can be accessed and controlled with no more than 5 calls (read/write/status, etc).

However, it isn't just a driver- you need the kernel to have a device manager. It provides a toolbox of calls to the kernel and applications, while understanding the 5-call access model to driver. It manages parameter blocks, callbacks, etc, for each driver. This allows the same interface to be used (basically) for any device. Normally, this device manager is given a little bit more knowledge about driver internals, but it does not pass this on to the kernel or applications- they don't need to know.

I've written a kernel, with a device manager (and other things), and a set of drivers for the ATMEGA line which takes only 3-7K of flash depending on how many drivers are loaded. This has allowed me to create adjunct devices (like IV-22 displays, for example) and accompanying drivers to control them. It significantly simplifies application program, and offloads device management to the driver. I've written drivers for RTC clock chips, etc.

Drivers are powerful because they can do so many things, from allowing callbacks into kernel or app, or yielding regular time to the device, and so much more.

Here is one of the IV-22 displays (digit display plus back-ground color in RGB can be controlled via the driver):
1667480302407.png
 
Last edited:
Top