{"id":2181,"date":"2018-07-14T19:27:07","date_gmt":"2018-07-14T17:27:07","guid":{"rendered":"https:\/\/playembedded.org\/?p=2181"},"modified":"2023-04-07T15:13:59","modified_gmt":"2023-04-07T13:13:59","slug":"chibioshal-design-an-object-oriented-approach","status":"publish","type":"post","link":"https:\/\/playembedded.org\/blog\/chibioshal-design-an-object-oriented-approach\/","title":{"rendered":"ChibiOS\/HAL design: an object-oriented approach"},"content":{"rendered":"<h3 id=\"1_The_ChibiOS_Hardware_Abstraction_Layer\" class=\"level_1\">The ChibiOS Hardware Abstraction Layer<\/h3>\n<p>The C programming language is clearly an imperative programming language not designed to be object-oriented. Anyway, the&nbsp;object-oriented approach remains something much more related to the design and mindset more than to syntax. The <b>ChibiOS\/HAL&nbsp;<\/b><span style=\"font-size: 1em;\">is an Hardware Abstraction Layer<\/span>&nbsp;which design could be considered very object-oriented.&nbsp;<span style=\"font-size: 1em;\">We encountered it in almost every article related to ChibiOS but we often ignored its design as it comes with a series of demos which allow to use it easily without a deep knowledge of its internal mechanisms.<\/span><\/p>\n<p>This article is dedicated to people who want to go in deep and see how stuff works. Starting from ChibiOS 3.0, <b>ChibiOS\/HAL<\/b> became essentially a standalone product that is not rigidly attached to the OS and can be used on bare metal or in conjunction with any other RTOS.<\/p>\n<p><b>ChibiOS\/HAL<\/b>&nbsp;provides a hardware abstraction allowing nevertheless a custom use of peripherals. <b>HAL<\/b> has undergone a lot of changes based on community&rsquo;s suggestions and after years of upgrades and bug fixes, it has reached a high level of stability, reliability and flexibility.<br>\nTo pursue its goals, <b>HAL<\/b> has:<\/p>\n<ul>\n<li>To encapsulate the driver complexities allowing somehow to properly address the hardware-dependent configuration: such implementation allows to cover many different scenarios.<\/li>\n<li>To provide an hardware-independent and universal high level API: this ensure that application are portable across different microcontrollers.<\/li>\n<li>To ensure an intrinsic optimization and provide and non-polled implementation to make HAL usable in Real Time applications.<\/li>\n<li>To be able to work as stand-alone in OS-less applications;<\/li>\n<li>To support most common peripherals like ADC, CAN, DAC, GPIO, ICU, PWM, SPI, TIM, UART, USB and many others.<\/li>\n<\/ul>\n<h3 id=\"2_Achieving_abstraction_using_a_layered_architecture_design\" class=\"level_1\">Achieving abstraction using a layered architecture design<\/h3>\n<p><b>HAL<\/b> is organized in a multi-layered way and more precisely it has two layers.<\/p>\n<ul>\n<li>The top layer which offers a universal <strong>Application Programming Interface<\/strong> (also abbreviated as <strong>API<\/strong>) we can directly approach.<\/li>\n<li>The <strong>low level driver<\/strong> (or <strong>LLD<\/strong>) layer which resolves differences across different hardware.<\/li>\n<\/ul>\n<p>We could imagine this architecture as a LEGO wall: we can directly approach only from its top layer and this provide us an universal interface to the underlying low level. The interface&nbsp;remains unchanged in time and across different microcontrollers and this makes application built on top portable across different hardware and easy to maintain in time.<\/p>\n<figure id=\"attachment_6064\" aria-describedby=\"caption-attachment-6064\" style=\"width: 2310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2015\/07\/HAL-organization.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-6064 size-full\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2015\/07\/HAL-organization.png\" alt=\"\" width=\"2310\" height=\"626\"><\/a><figcaption id=\"caption-attachment-6064\" class=\"wp-caption-text\">A diagram which explains how HAL layers are organized<\/figcaption><\/figure>\n<p>The trick is done linking proper LLD drivers depending on underlying microcontroller. To understand this let&rsquo;s take a look to the organization of HAL files. HAL is contained inside the folder <em>hal <\/em>contained in our <em>ChibiOS root<\/em> directory.<\/p>\n<figure id=\"attachment_2578\" aria-describedby=\"caption-attachment-2578\" style=\"width: 209px\" class=\"wp-caption alignright\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-2578\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy.jpg\" alt=\"ChibiOS\/HAL hierarchy\" width=\"209\" height=\"181\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy.jpg 209w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy-150x130.jpg 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy-24x21.jpg 24w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy-36x31.jpg 36w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_HAL_hierarchy-48x42.jpg 48w\" sizes=\"auto, (max-width: 209px) 100vw, 209px\"><\/a><figcaption id=\"caption-attachment-2578\" class=\"wp-caption-text\">A screenshot of the ChibiOS\/HAL hierarchy<\/figcaption><\/figure>\n<p>What we have called Top Layer is contained inside the two folders <em>include<\/em> and <em>src<\/em>. Exploring the first folder we will header files like <em>hal_adc.h<\/em>, <em>hal_pal.h<\/em>,&nbsp; <em>hal_pwm.h<\/em>, &hellip; while in the second source files like <em>hal_adc.c<\/em>, <em>hal_pal.c<\/em>,&nbsp; <em>hal_pwm.c, &hellip; <\/em>and so on.<\/p>\n<p>&nbsp;<\/p>\n<p>Such code performs those operations which are common to any hardware. Operations which are hardware dependent are executed calling low level driver API. While there is only one top level layer there are many LLD layers which are related to specific platforms.<\/p>\n<p>These LLD are contained inside the folder ports. As example considering the folder <em>hal\/ports\/stm32\/&nbsp;<\/em>we can find<\/p>\n<ul>\n<li>a folder for each STM32 subfamily&nbsp;which contains the low level drivers specific of that subfamily and the <em>platform.mk<\/em>&nbsp;(a piece of makefile used to list and link drivers used by that platform).<\/li>\n<li>a folder named LLD which contains certain driver which are common across more than a subfamily.<\/li>\n<\/ul>\n<p>What follows is the <em>platform.mk<\/em> of the STM32F4xx subfamily were we can spot all the LLD used by it. As example F4 uses the ADCv2, CANv1, DACv1 and so on.<\/p>\n<pre class=\"lang:c decode:true\"># Required platform files.\nPLATFORMSRC := $(CHIBIOS)\/os\/hal\/ports\/common\/ARMCMx\/nvic.c \\\n               $(CHIBIOS)\/os\/hal\/ports\/STM32\/STM32F4xx\/stm32_isr.c \\\n               $(CHIBIOS)\/os\/hal\/ports\/STM32\/STM32F4xx\/hal_lld.c\n\n# Required include directories.\nPLATFORMINC := $(CHIBIOS)\/os\/hal\/ports\/common\/ARMCMx \\\n               $(CHIBIOS)\/os\/hal\/ports\/STM32\/STM32F4xx\n\n# Optional platform files.\nifeq ($(USE_SMART_BUILD),yes)\n\n# Configuration files directory\nifeq ($(CONFDIR),)\n  CONFDIR = .\nendif\n\nHALCONF := $(strip $(shell cat $(CONFDIR)\/halconf.h | egrep -e \"\\#define\"))\n\nelse\nendif\n\n# Drivers compatible with the platform.\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/ADCv2\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/CANv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/DACv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/DMAv2\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/EXTIv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/GPIOv2\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/I2Cv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/MACv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/OTGv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/QUADSPIv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/RTCv2\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/SPIv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/SDIOv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/TIMv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/USARTv1\/driver.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/LLD\/xWDGv1\/driver.mk\n\n# Shared variables\nALLCSRC += $(PLATFORMSRC)\nALLINC  += $(PLATFORMINC)\n<\/pre>\n<p>To complete the trick the proper platform.mk shall be included in the project makefile. As example the following codebox contains a&nbsp;snippet of makefile from a demo for the STM32 Nucleo-64 F401RE. We can see that it includes&nbsp;<em>hal\/ports\/STM32\/STM32F4xx\/platform.mk&nbsp;<\/em><\/p>\n<pre class=\"lang:c decode:true\"># Project, sources and paths\n#\n\n# Define project name here\nPROJECT = ch\n\n# Imported source files and paths\nCHIBIOS = ..\/..\/..\n\n# Licensing files.\ninclude $(CHIBIOS)\/os\/license\/license.mk\n# Startup files.\ninclude $(CHIBIOS)\/os\/common\/startup\/ARMCMx\/compilers\/GCC\/mk\/startup_stm32f4xx.mk\n# HAL-OSAL files (optional).\ninclude $(CHIBIOS)\/os\/hal\/hal.mk\ninclude $(CHIBIOS)\/os\/hal\/ports\/STM32\/STM32F4xx\/platform.mk\ninclude $(CHIBIOS)\/os\/hal\/boards\/ST_NUCLEO64_F401RE\/board.mk\ninclude $(CHIBIOS)\/os\/hal\/osal\/rt\/osal.mk\n# RTOS files (optional).\ninclude $(CHIBIOS)\/os\/rt\/rt.mk\ninclude $(CHIBIOS)\/os\/common\/ports\/ARMCMx\/compilers\/GCC\/mk\/port_v7m.mk\n# Other files (optional).\ninclude $(CHIBIOS)\/test\/lib\/test.mk\ninclude $(CHIBIOS)\/test\/rt\/rt_test.mk\ninclude $(CHIBIOS)\/test\/oslib\/oslib_test.mk\n\n# Define linker script file here\nLDSCRIPT= $(STARTUPLD)\/STM32F401xE.ld<\/pre>\n<p>To next table reports the LLD associated to each STM32 subfamily<\/p>\n<table style=\"width: 100%; display: block; overflow-x: auto;\">\r\n<thead>\r\n<tr>\r\n<td style=\"text-align: center;\">Sub-Family<\/td>\r\n<td style=\"text-align: center;\">ADC<\/td>\r\n<td style=\"text-align: center;\">BDMA<\/td>\r\n<td style=\"text-align: center;\">CAN<\/td>\r\n<td style=\"text-align: center;\">CRYP<\/td>\r\n<td style=\"text-align: center;\">DAC<\/td>\r\n<td style=\"text-align: center;\">DMA<\/td>\r\n<td style=\"text-align: center;\">EXTI<\/td>\r\n<td style=\"text-align: center;\">GPIO<\/td>\r\n<td style=\"text-align: center;\">I2C<\/td>\r\n<td style=\"text-align: center;\">MAC<\/td>\r\n<td style=\"text-align: center;\">OTG<\/td>\r\n<td style=\"text-align: center;\">QUADSPI<\/td>\r\n<td style=\"text-align: center;\">RTC<\/td>\r\n<td style=\"text-align: center;\">SDIO<\/td>\r\n<td style=\"text-align: center;\">SDMMC<\/td>\r\n<td style=\"text-align: center;\">SPI<\/td>\r\n<td style=\"text-align: center;\">TIM<\/td>\r\n<td style=\"text-align: center;\">USART<\/td>\r\n<td style=\"text-align: center;\">USB<\/td>\r\n<td style=\"text-align: center;\">xWDG<\/td>\r\n<\/tr>\r\n<\/thead>\r\n<tbody>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F0<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F1<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">Specific<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">MACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">OTGv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SDIOv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F2<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">MACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">OTGv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">QUADSPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SDIOv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F3<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">\r\n<p>ADCv3<\/p>\r\n<p>Specific<\/p>\r\n<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F4<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">MACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">OTGv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">QUADSPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SDIOv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32F7<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CRYPv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">MACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">OTGv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">QUADSPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SDMMCv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32H7<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv4<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">BDMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CRYPv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv3<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv3<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv3<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32L0<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32L1<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">Specific<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<tr>\r\n<th style=\"text-align: center; vertical-align: middle;\">STM32L4<\/th>\r\n<td style=\"text-align: center; vertical-align: middle;\">ADCv3<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">CANv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DACv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">DMAv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">EXTIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">GPIOv3<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">I2Cv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">OTGv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">QUADSPIv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">RTCv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">ND<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SDMMCv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">SPIv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">TIMv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USARTv2<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">USBv1<\/td>\r\n<td style=\"text-align: center; vertical-align: middle;\">xWDGv1<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\n<h3 id=\"3_Driver_enabling_and_peripheral_allocation\" class=\"level_1\">Driver enabling and peripheral allocation<\/h3>\n<p>HAL allows to completely exclude code from the compiled binary through the <strong>driver&nbsp;switch<\/strong>. W<span style=\"font-size: 1em;\">orking with embedded systems, it is extremely usual to deal with textual configuration headers which contains a lot of preprocessor directives. A driverswitch is just a boolean constant definition which include\/exclude piece of code from the compilation process. In ChibiOS the driver switches related are <\/span>contained<span style=\"font-size: 1em;\">&nbsp;in the halconf.h file<\/span><\/p>\n<p><span style=\"font-size: 1em;\">The following code snippet has been taken by a demo for STM32 and we can see it contains two switches: the first one is enabled and includes all the code related to <\/span><strong style=\"font-size: 1em;\">Serial Driver<\/strong><span style=\"font-size: 1em;\">, the second one is disabled and excludes all the code related to <\/span><strong style=\"font-size: 1em;\">PWM Driver<\/strong><span style=\"font-size: 1em;\">.<\/span><\/p>\n<pre class=\"lang:c decode:true\">\/**\n * @brief   Enables the SERIAL subsystem.\n *\/\n#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)\n#define HAL_USE_SERIAL              TRUE\n#endif\n\n\/**\n * @brief   Enables the PWM subsystem.\n *\/\n#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)\n#define HAL_USE_PWM                 FALSE\n#endif<\/pre>\n<p>A driver relies on hardware peripheral. To use it we have then to assign a peripheral to the driver and this can be&nbsp;done acting on <em>mcuconf.h<\/em>.<\/p>\n<p>As example in the following code we are assigning&nbsp;USART2 to the Serial Driver. As side note this code has been copied from the MCU configuration header of the original demo for STM32 Nucleo-64 F401RE.<\/p>\n<pre class=\"lang:c decode:true\">\/*\n * SERIAL driver system settings.\n *\/\n#define STM32_SERIAL_USE_USART1             FALSE\n#define STM32_SERIAL_USE_USART2             TRUE\n#define STM32_SERIAL_USE_USART6             FALSE\n#define STM32_SERIAL_USART1_PRIORITY        12\n#define STM32_SERIAL_USART2_PRIORITY        12\n#define STM32_SERIAL_USART6_PRIORITY        12<\/pre>\n<figure id=\"attachment_5975\" aria-describedby=\"caption-attachment-5975\" style=\"width: 300px\" class=\"wp-caption alignright\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2018\/07\/Error-multiple-assignement.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-5975\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2018\/07\/Error-multiple-assignement-300x84.png\" alt=\"\" width=\"300\" height=\"84\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2018\/07\/Error-multiple-assignement-300x84.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2018\/07\/Error-multiple-assignement-150x42.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2018\/07\/Error-multiple-assignement.png 498w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\"><\/a><figcaption id=\"caption-attachment-5975\" class=\"wp-caption-text\">Compile error while assigning same peripheral to multiple drivers<\/figcaption><\/figure>\n<p>Note that is not possible to assign the same peripheral to different driver because this would generate conflict on IRQ management and the project would not compile.<\/p>\n<p>As instance, it is not possible to assign USART 2 both to the Serial Driver and UART Driver and trying to do will result in a compile error. In figure 4 the problem windows reports the compile error derived by such operation. The error is due to the tentative to assign the same IRQ line (VectorD8) to two different drivers.<\/p>\n<p>&nbsp;<\/p>\n<p>Each ChibiOS driver can be enabled or disabled in the <em>halconf.h<\/em> file and each project has is own HAL configuration header. In the original demos all unused drivers are usually disabled. If you have launched the default demo you should have noticed that we use Serial Driver to print test suite results, and us most likely your project will be a copy of the default one most-likely you will find the SD already enabled.<\/p>\n<pre class=\"lang:c decode:true\">\/**\n * @brief   Enables the SERIAL subsystem.\n *\/\n#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)\n#define HAL_USE_SERIAL                      TRUE\n#endif<\/pre>\n<h3 id=\"4_The_driver_object\" class=\"level_1\">The driver object<\/h3>\n<p>Each driver is represented by a structure and every API associated to a certain driver requires its pointer. As this structure contains almost every information related to driver, API doesn&rsquo;t require a long list of parameters and moreover this implementation allows multiple instances.<\/p>\n<p>As example considering&nbsp; the SPI driver we have an instance for each SPI peripheral<\/p>\n<pre class=\"height:100 lang:c decode:true\">#if STM32_SPI_USE_SPI1 &amp;&amp; !defined(__DOXYGEN__)\nextern SPIDriver SPID1;\n#endif\n\n#if STM32_SPI_USE_SPI2 &amp;&amp; !defined(__DOXYGEN__)\nextern SPIDriver SPID2;\n#endif\n\n#if STM32_SPI_USE_SPI3 &amp;&amp; !defined(__DOXYGEN__)\nextern SPIDriver SPID3;\n#endif<\/pre>\n<p>As example assigning the STM32 SPI1 to serial driver the SPID1 object would become available. Note that, the driver implementation inumbering is aligned to peripheral numbering: SPI peripheral 1 is associated to SPID1, SPI peripheral 2 is associated to SPID2 and so on.<\/p>\n<p>We can also note that there is a certain strictness in coding style. We can indeed notice that<\/p>\n<blockquote><p>Each API of the a driver starts with the prefix. Function names are camel-case, preprocessor constants uppercase and variables lowercase.<\/p><\/blockquote>\n<h4 id=\"5_Driver_finite_state_machine\" class=\"level_2\">Driver finite state machine<\/h4>\n<p>Each driver in ChibiOS\\HAL implements a <strong>Finite State Machine<\/strong>. The current state of the driver is stored inside the object in&nbsp;a field named <strong>state<\/strong> (you can access it using structure syntax as example <em>SPID2.state <\/em>or<em> PWMD1.state<\/em>). The following image has been grabbed from the <a href=\"http:\/\/chibios.sourceforge.net\/docs3\/hal\/group___s_e_r_i_a_l.html\" target=\"_blank\" rel=\"noopener\">ChibiOS\\HAL documentation<\/a>&nbsp;and illustrates the finite state machine of the SPI driver<\/p>\n<figure id=\"attachment_2580\" aria-describedby=\"caption-attachment-2580\" style=\"width: 980px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM.jpg\" rel=\"attachment wp-att-2580\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2580 size-full\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM.jpg\" alt=\"SPI Driver FSM\" width=\"980\" height=\"498\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM.jpg 980w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM-150x76.jpg 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM-300x152.jpg 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM-24x12.jpg 24w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM-36x18.jpg 36w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_009_SPI_FSM-48x24.jpg 48w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\"><\/a><figcaption id=\"caption-attachment-2580\" class=\"wp-caption-text\">The Finite State Machine for the SPI Driver.<\/figcaption><\/figure>\n<h4 id=\"6_Driver_initialization\" class=\"level_2\">Driver initialization<\/h4>\n<p>Looking at SPI finite state machine, we cannot call function <em>spiStart()<\/em> on <em>SPID1<\/em> if this driver is into the state <em>SPI_UNINIT<\/em>.<\/p>\n<p>Every driver must be initialized and its state moved to&nbsp;<em>XXX_STOP<\/em> (in our example <em>SPI_STOP<\/em>): this operation is performed by a function named <em>xxxInit() <\/em>(in our example <em>spiInit<\/em>). There is an &ldquo;init&rdquo; function for every driver and they are called automatically by <em>halInit()<\/em> if the driver switch is enabled<\/p>\n<pre class=\"\">\/**\n * @brief   HAL initialization.\n * @details This function invokes the low level initialization code then\n *          initializes all the drivers enabled in the HAL. Finally the\n *          board-specific initialization is performed by invoking\n *          @p boardInit() (usually defined in @p board.c).\n *\n * @init\n *\/\nvoid halInit(void) {\n  \/* Initializes the OS Abstraction Layer.*\/\n  osalInit();\n  \/* Platform low level initializations.*\/\n  hal_lld_init();\n#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__)\n  palInit(&amp;pal_default_config);\n#endif\n#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__)\n  adcInit();\n#endif\n#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__)\n  canInit();\n#endif\n#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)\n  dacInit();\n#endif\n#if (HAL_USE_EXT == TRUE) || defined(__DOXYGEN__)\n  extInit();\n#endif\n#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__)\n  gptInit();\n#endif\n#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)\n  i2cInit();\n#endif\n#if (HAL_USE_I2S == TRUE) || defined(__DOXYGEN__)\n  i2sInit();\n#endif\n#if (HAL_USE_ICU == TRUE) || defined(__DOXYGEN__)\n  icuInit();\n#endif\n#if (HAL_USE_MAC == TRUE) || defined(__DOXYGEN__)\n  macInit();\n#endif\n#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__)\n  pwmInit();\n#endif\n#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__)\n  sdInit();\n#endif\n#if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__)\n  sdcInit();\n#endif\n#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)\n  spiInit();\n#endif\n#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__)\n  uartInit();\n#endif\n#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__)\n  usbInit();\n#endif\n#if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__)\n  mmcInit();\n#endif\n#if (HAL_USE_SERIAL_USB == TRUE) || defined(__DOXYGEN__)\n  sduInit();\n#endif\n#if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__)\n  rtcInit();\n#endif\n  \/* Community driver overlay initialization.*\/\n#if defined(HAL_USE_COMMUNITY) || defined(__DOXYGEN__)\n#if (HAL_USE_COMMUNITY == TRUE) || defined(__DOXYGEN__)\n  halCommunityInit();\n#endif\n#endif\n  \/* Board specific initialization.*\/\n  boardInit();\n\/*\n *  The ST driver is a special case, it is only initialized if the OSAL is\n *  configured to require it.\n *\/\n#if OSAL_ST_MODE != OSAL_ST_MODE_NONE\n  stInit();\n#endif\n}<\/pre>\n<blockquote><p><span style=\"font-size: 1em;\">If a ChibiOS driver&nbsp;is enabled in the HAL configuration file, it is automatically initialized on HAL initialization. Initialization is related to variable initialization more than on hardware configuration.<\/span><\/p><\/blockquote>\n<h4 id=\"7_Configuring_a_driver\" class=\"level_2\">Configuring a driver<\/h4>\n<p>Before to use it, the a driver shall be properly initialized and configured. This operation is carried out by another function: the start. The following code box reports some start function from different drivers.<\/p>\n<pre class=\"lang:c decode:true\">\/**\n * @brief   Configures and starts the driver.\n *\n * @param[in] sdp       pointer to a @p SerialDriver object\n * @param[in] config    the architecture-dependent serial driver configuration.\n *                      If this parameter is set to @p NULL then a default\n *                      configuration is used.\n *\n * @api\n *\/\nvoid sdStart(SerialDriver *sdp, const SerialConfig *config) {\n  ...\n}\n\n\n\n\/**\n * @brief   Configures and activates the SPI peripheral.\n *\n * @param[in] spip      pointer to the @p SPIDriver object\n * @param[in] config    pointer to the @p SPIConfig object\n *\n * @api\n *\/\nvoid spiStart(SPIDriver *spip, const SPIConfig *config) {\n  ...\n}\n\n\n\n\/**\n * @brief   Configures and activates the ADC peripheral.\n *\n * @param[in] adcp      pointer to the @p ADCDriver object\n * @param[in] config    pointer to the @p ADCConfig object. Depending on\n *                      the implementation the value can be @p NULL.\n *\n * @api\n *\/\nvoid adcStart(ADCDriver *adcp, const ADCConfig *config) {\n  ...\n}<\/pre>\n<p>Such functions shall be called at least once by the user application before the real usage. Their purpose is to configure the peripherals and this involves setup of all that hardware configurability.<\/p>\n<blockquote><p>In ChibiOS\/HAL every driver except PAL shall be started before to be used.<\/p><\/blockquote>\n<p>The <em>xxxStart<\/em> function receives two parameters which are a pointer to the serial driver object we want to start (e.g. &amp;SD1, &amp;SPI3, &amp;PWM7 or whatever is the driver we are going to use) and a pointer to a structure which represent the related configuration. This structure contains all the dependencies which are strictly related to the underlying hardware. This means that moving from a STM32 family to another which has a different underlying hardware we most likely have to apply some changes to these configuration structures.<\/p>\n<blockquote><p>Starting a driver we need a pointer to it&nbsp; and a pointer to its configuration structure. This structure contains all the HW dependencies and has to been reviewed if we port our application on a different microcontroller.<\/p><\/blockquote>\n<p>The start function usually enables peripheral clock. In certain application (especially those addressed to low power) it is undesidered to keep a peripheral clocked when it is not used. Because of that there is another function we could use to stop the driver and stop the peripheral clock: the stop.<\/p>\n<pre class=\"lang:c decode:true\">\/**\n * @brief   Stops the driver.\n * @details Any thread waiting on the driver's queues will be awakened with\n *          the message @p MSG_RESET.\n *\n * @param[in] sdp       pointer to a @p SerialDriver object\n *\n * @api\n *\/\nvoid sdStop(SerialDriver *sdp) {\n  ...\n}\n\n\n\n\/**\n * @brief   Deactivates the SPI peripheral.\n * @note    Deactivating the peripheral also enforces a release of the slave\n *          select line.\n *\n * @param[in] spip      pointer to the @p SPIDriver object\n *\n * @api\n *\/\nvoid spiStop(SPIDriver *spip) {\n  ...\n}\n\n\n\n\/**\n * @brief   Deactivates the ADC peripheral.\n *\n * @param[in] adcp      pointer to the @p ADCDriver object\n *\n * @api\n *\/\nvoid adcStop(ADCDriver *adcp) {\n  ...\n}<\/pre>\n<p>This function can be called by the user application when the peripheral is unnecessary. It is almost intuitive that after a stop we need a new start to be able to use again the driver.<\/p>\n<h5 id=\"8_Start_Do_Stop\" class=\"level_3\">Start Do Stop<\/h5>\n<p>A most common paradigm is the&nbsp;<strong>Start-Do-Stop:<\/strong><\/p>\n<ul>\n<li>we start the driver when needed configuring it.<\/li>\n<li>we do some operations on that driver.<\/li>\n<li>we stop it as soon as it has completed operations.<\/li>\n<\/ul>\n<pre class=\"lang:c decode:true\">\/* Starting Serial Driver 2 with my configuration. *\/\nsdStart(&amp;SD2, &amp;my_sd_configuration);\n\n\/* Doing some operation on Serial Driver 2. *\/\n\n\/* Stopping. *\/ \nsdStop(&amp;SD2);\n\n...\n\n\/* Starting again. *\/ \nsdStart(&amp;SD2, &amp;my_sd_configuration);\n\n\/* Carrying out other operation. *\/\n\n\/* Stopping. *\/ \nsdStop(&amp;SD2);\n<\/pre>\n<p>This offers advantage especially if peripheral is actually used in a small slice of the whole time amount of execution time.<\/p>\n<blockquote><p>It is possible to stop a driver to reduce hardware power consumption when peripheral is used for a small percentage of execution time. After being stopped a the driver shall be re-started to be used again.<\/p><\/blockquote>\n<h5 id=\"9_Changing_configuration_on_the_fly\" class=\"level_3\">Changing configuration on the fly<\/h5>\n<p>An approach similar to Start-Do-Stop can be used is used when we need to change driver configuration on-the-fly. In such scenario we can start peripheral multiple time with different configuration. Note that stop is not required rather is discouraged as in case of subsequent start operation certain operation are skipped.<\/p>\n<pre class=\"lang:c decode:true\">\/* Starting Serial Driver 2 with my configuration. *\/\nsdStart(&amp;SD2, &amp;sd_cfg1);\n\n\/* Doing some operation on Serial Driver 2 with configuration 1. *\/\nsdDoStuff(&amp;SD2, additional_params);\n\n\/* Starting again. *\/ \nsdStart(&amp;SD2, &amp;sd_cfg2);\n\n\/* Doing some operation on Serial Driver 2 with configuration 2. *\/\nsdDoStuff(&amp;SD2, additional_params);\n<\/pre>\n<blockquote><p>It is possible to start driver more than once&nbsp;with different configuration in case we need to change driver configuration on-the-fly.<\/p><\/blockquote>\n<p>The configuration structure is composed by two separated parts: the first part remains unchanged across all kind of hardware, the second is strictly hardware dependent. Dealing with configuration there are some hints that can help you to figure out how to correctly compose them:<\/p>\n<ul>\n<li>Take a look to demos under the <em><strong>testhal <\/strong><\/em>folder and <em><strong>testex <\/strong><\/em>folders: in these demos you can find some precomposed configuration that you can copy and use in your application. As the configuration depends on hardware be sure to pick a demo for the subfamily you are currently using.<\/li>\n<li>You can take a look to the definition of configuration structure following the breadcrumbs: first you need to detect which LLD your platform is using through the <em>platform.mk<\/em> file, then you have to open the related low level driver header where you can find the configuration structure definition.<\/li>\n<li>Those fields which are related to hardware are described in the reference manual, use it to spot the meaning of each bit.<\/li>\n<li>Remember that the start function usually does some internal obvious modification to register values passed through the configuration.<\/li>\n<li>There are some simple techniques to change certain bit of the register leaving others unchanged. Such operation takes the name of <strong>bit-masking<\/strong> and the adopted paradigm to deal with registers <strong>read-modify-write<\/strong>. This is a knowledge you really should do have. If don&rsquo;t I highly suggest to read <a href=\"https:\/\/playembedded.org\/registers-and-bit-masks\/\">this article<\/a>&nbsp;(even at later moment).<\/li>\n<li>You do not have to define register bitmasks as they are already defined and available in <strong>CMSIS<\/strong> header files. You can find these files under the folder <em>chibios182\\os\\common\\ext\\ST.<\/em><\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>The ChibiOS Hardware Abstraction Layer The C programming language is clearly an imperative programming language not designed to be object-oriented. Anyway, the&nbsp;object-oriented approach remains something much more related to the design and mindset more than to syntax. The ChibiOS\/HAL&nbsp;is an Hardware Abstraction Layer&nbsp;which design could be considered very object-oriented.&nbsp;We encountered it in almost every article [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":6068,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1221],"tags":[],"coauthors":[241],"class_list":["post-2181","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-further-readings","pumpkin"],"views":21819,"jetpack_featured_media_url":"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2015\/07\/Object-Oriented.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/2181","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/comments?post=2181"}],"version-history":[{"count":0,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/2181\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media\/6068"}],"wp:attachment":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media?parent=2181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/categories?post=2181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/tags?post=2181"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/coauthors?post=2181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}