diff --git a/Drivers/BSP/STM32L496G-Discovery/License.md b/Drivers/BSP/STM32L496G-Discovery/License.md
new file mode 100644
index 0000000..39e4194
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/License.md
@@ -0,0 +1,3 @@
+# Copyright (c) 2017 STMicroelectronics
+
+This software component is licensed by STMicroelectronics under the **BSD-3-Clause** license. You may not use this software except in compliance with this license. You may obtain a copy of the license [here](https://opensource.org/licenses/BSD-3-Clause).
\ No newline at end of file
diff --git a/Drivers/BSP/STM32L496G-Discovery/Release_Notes.html b/Drivers/BSP/STM32L496G-Discovery/Release_Notes.html
new file mode 100644
index 0000000..ebaa5ab
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/Release_Notes.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+ Release Notes for 32L496GDISCOVERY Board Drivers
+
+
+
+
+
+
+
+
+
+Release Notes for
+32L496GDISCOVERY Board Drivers
+Copyright © 2017 STMicroelectronics
+
+
+
+
License
+
Licensed by ST under BSD 3-Clause license (the "License"). You may not use this package except in compliance with the License. You may obtain a copy of the License at:
+
https://opensource.org/licenses/BSD-3-Clause
+
Purpose
+
This directory contains the board drivers to demonstrate the capabilities of the 32L496GDISCOVERY Kit.
+
+
+
Update History
+
+
V1.1.6 / 11-February-2021
+
+
Main Changes
+
+Minor update of Release Notes template
+Add License.md file for GitHub publication
+
+
+
+
+
V1.1.5 / 26-June-2020
+
+
Main Changes
+
+Remove useless assignment in BSP_COM_Init() function
+Update common GPIO configuration in BSP_SD_MspInit() to remove internal pull-up
+
+
+
+
+
V1.1.4 / 22-November-2019
+
+
Main Changes
+
+Enable the Sample Shift (SSHIFT) feature in BSP_QSPI_Init() to ensure the read data isn’t corrupted when prescaler is div/1
+
+
+
+
+
V1.1.3 / 18-October-2019
+
+
Main Changes
+
+stm32l496g_discovery.c
+
+Remove superfluous settings of PD.11 and PF.00 from FMC_BANK1_MspInit() and FMC_BANK1_MspDeInit() that were preventing a correct usage of PSRAM
+
+Minor update in release notes format
+
+
+
+
+
V1.1.2 / 03-April-2019
+
+
Main Changes
+
+stm32l496g_discovery.c
+
+Correct logical test in DrawChar()
+Comment minor correction
+
+
+
+
+
+
V1.1.1 / 27-July-2018
+
+
Main Changes
+
+Release notes update to new format
+
+
+
+
+
V1.1.0 / 25-August-2017
+
+
Main Changes
+
+stm32l496g_discovery.h/.c
+
+Add BSP_COM_Init()/BSP_COM_DeInit() APIs for ST-Link USB Virtual Com Port
+
+stm32l496g_discovery_audio.h/.c
+
+Add INPUT_DEVICE_DIGITAL_MIC1 and INPUT_DEVICE_DIGITAL_MIC2 to provide the capability to record over a single digital microphone (respectively left and right microphones)
+
+stm32l496g_discovery_sd.c/.h
+
+Add weak BSP SD functions
+
+BSP_SD_MspInit(), BSP_SD_MspDeInit(), BSP_SD_WriteCpltCallback(), BSP_SD_ReadCpltCallback() and BSP_SD_AbortCallback()
+
+
+
+
+
+
+
V1.0.0 / 17-February-2017
+
+
Main Changes
+
+First official release of STM32L496G-Discovery board drivers for STM32Cube L4 FW package
+
+
+
+
+
+
+
+
diff --git a/Drivers/BSP/STM32L496G-Discovery/STM32L496G-Discovery_BSP_User_Manual.chm b/Drivers/BSP/STM32L496G-Discovery/STM32L496G-Discovery_BSP_User_Manual.chm
new file mode 100644
index 0000000..a483419
Binary files /dev/null and b/Drivers/BSP/STM32L496G-Discovery/STM32L496G-Discovery_BSP_User_Manual.chm differ
diff --git a/Drivers/BSP/STM32L496G-Discovery/_htmresc/favicon.png b/Drivers/BSP/STM32L496G-Discovery/_htmresc/favicon.png
new file mode 100644
index 0000000..06713ee
Binary files /dev/null and b/Drivers/BSP/STM32L496G-Discovery/_htmresc/favicon.png differ
diff --git a/Drivers/BSP/STM32L496G-Discovery/_htmresc/mini-st_2020.css b/Drivers/BSP/STM32L496G-Discovery/_htmresc/mini-st_2020.css
new file mode 100644
index 0000000..986f4d4
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/_htmresc/mini-st_2020.css
@@ -0,0 +1,1711 @@
+@charset "UTF-8";
+/*
+ Flavor name: Custom (mini-custom)
+ Generated online - https://minicss.org/flavors
+ mini.css version: v3.0.1
+*/
+/*
+ Browsers resets and base typography.
+*/
+/* Core module CSS variable definitions */
+:root {
+ --fore-color: #03234b;
+ --secondary-fore-color: #03234b;
+ --back-color: #ffffff;
+ --secondary-back-color: #ffffff;
+ --blockquote-color: #e6007e;
+ --pre-color: #e6007e;
+ --border-color: #3cb4e6;
+ --secondary-border-color: #3cb4e6;
+ --heading-ratio: 1.2;
+ --universal-margin: 0.5rem;
+ --universal-padding: 0.25rem;
+ --universal-border-radius: 0.075rem;
+ --background-margin: 1.5%;
+ --a-link-color: #3cb4e6;
+ --a-visited-color: #8c0078; }
+
+html {
+ font-size: 13.5px; }
+
+a, b, del, em, i, ins, q, span, strong, u {
+ font-size: 1em; }
+
+html, * {
+ font-family: -apple-system, BlinkMacSystemFont, Helvetica, arial, sans-serif;
+ line-height: 1.25;
+ -webkit-text-size-adjust: 100%; }
+
+* {
+ font-size: 1rem; }
+
+body {
+ margin: 0;
+ color: var(--fore-color);
+ @background: var(--back-color);
+ background: var(--back-color) linear-gradient(#ffd200, #ffd200) repeat-y left top;
+ background-size: var(--background-margin);
+ }
+
+details {
+ display: block; }
+
+summary {
+ display: list-item; }
+
+abbr[title] {
+ border-bottom: none;
+ text-decoration: underline dotted; }
+
+input {
+ overflow: visible; }
+
+img {
+ max-width: 100%;
+ height: auto; }
+
+h1, h2, h3, h4, h5, h6 {
+ line-height: 1.25;
+ margin: calc(1.5 * var(--universal-margin)) var(--universal-margin);
+ font-weight: 400; }
+ h1 small, h2 small, h3 small, h4 small, h5 small, h6 small {
+ color: var(--secondary-fore-color);
+ display: block;
+ margin-top: -0.25rem; }
+
+h1 {
+ font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); }
+
+h2 {
+ font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) );
+ border-style: none none solid none ;
+ border-width: thin;
+ border-color: var(--border-color); }
+h3 {
+ font-size: calc(1rem * var(--heading-ratio) ); }
+
+h4 {
+ font-size: calc(1rem * var(--heading-ratio)); }
+
+h5 {
+ font-size: 1rem; }
+
+h6 {
+ font-size: calc(1rem / var(--heading-ratio)); }
+
+p {
+ margin: var(--universal-margin); }
+
+ol, ul {
+ margin: var(--universal-margin);
+ padding-left: calc(3 * var(--universal-margin)); }
+
+b, strong {
+ font-weight: 700; }
+
+hr {
+ box-sizing: content-box;
+ border: 0;
+ line-height: 1.25em;
+ margin: var(--universal-margin);
+ height: 0.0714285714rem;
+ background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); }
+
+blockquote {
+ display: block;
+ position: relative;
+ font-style: italic;
+ color: var(--secondary-fore-color);
+ margin: var(--universal-margin);
+ padding: calc(3 * var(--universal-padding));
+ border: 0.0714285714rem solid var(--secondary-border-color);
+ border-left: 0.3rem solid var(--blockquote-color);
+ border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; }
+ blockquote:before {
+ position: absolute;
+ top: calc(0rem - var(--universal-padding));
+ left: 0;
+ font-family: sans-serif;
+ font-size: 2rem;
+ font-weight: 800;
+ content: "\201c";
+ color: var(--blockquote-color); }
+ blockquote[cite]:after {
+ font-style: normal;
+ font-size: 0.75em;
+ font-weight: 700;
+ content: "\a— " attr(cite);
+ white-space: pre; }
+
+code, kbd, pre, samp {
+ font-family: Menlo, Consolas, monospace;
+ font-size: 0.85em; }
+
+code {
+ background: var(--secondary-back-color);
+ border-radius: var(--universal-border-radius);
+ padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); }
+
+kbd {
+ background: var(--fore-color);
+ color: var(--back-color);
+ border-radius: var(--universal-border-radius);
+ padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); }
+
+pre {
+ overflow: auto;
+ background: var(--secondary-back-color);
+ padding: calc(1.5 * var(--universal-padding));
+ margin: var(--universal-margin);
+ border: 0.0714285714rem solid var(--secondary-border-color);
+ border-left: 0.2857142857rem solid var(--pre-color);
+ border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; }
+
+sup, sub, code, kbd {
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline; }
+
+small, sup, sub, figcaption {
+ font-size: 0.75em; }
+
+sup {
+ top: -0.5em; }
+
+sub {
+ bottom: -0.25em; }
+
+figure {
+ margin: var(--universal-margin); }
+
+figcaption {
+ color: var(--secondary-fore-color); }
+
+a {
+ text-decoration: none; }
+ a:link {
+ color: var(--a-link-color); }
+ a:visited {
+ color: var(--a-visited-color); }
+ a:hover, a:focus {
+ text-decoration: underline; }
+
+/*
+ Definitions for the grid system, cards and containers.
+*/
+.container {
+ margin: 0 auto;
+ padding: 0 calc(1.5 * var(--universal-padding)); }
+
+.row {
+ box-sizing: border-box;
+ display: flex;
+ flex: 0 1 auto;
+ flex-flow: row wrap;
+ margin: 0 0 0 var(--background-margin); }
+
+.col-sm,
+[class^='col-sm-'],
+[class^='col-sm-offset-'],
+.row[class*='cols-sm-'] > * {
+ box-sizing: border-box;
+ flex: 0 0 auto;
+ padding: 0 calc(var(--universal-padding) / 2); }
+
+.col-sm,
+.row.cols-sm > * {
+ max-width: 100%;
+ flex-grow: 1;
+ flex-basis: 0; }
+
+.col-sm-1,
+.row.cols-sm-1 > * {
+ max-width: 8.3333333333%;
+ flex-basis: 8.3333333333%; }
+
+.col-sm-offset-0 {
+ margin-left: 0; }
+
+.col-sm-2,
+.row.cols-sm-2 > * {
+ max-width: 16.6666666667%;
+ flex-basis: 16.6666666667%; }
+
+.col-sm-offset-1 {
+ margin-left: 8.3333333333%; }
+
+.col-sm-3,
+.row.cols-sm-3 > * {
+ max-width: 25%;
+ flex-basis: 25%; }
+
+.col-sm-offset-2 {
+ margin-left: 16.6666666667%; }
+
+.col-sm-4,
+.row.cols-sm-4 > * {
+ max-width: 33.3333333333%;
+ flex-basis: 33.3333333333%; }
+
+.col-sm-offset-3 {
+ margin-left: 25%; }
+
+.col-sm-5,
+.row.cols-sm-5 > * {
+ max-width: 41.6666666667%;
+ flex-basis: 41.6666666667%; }
+
+.col-sm-offset-4 {
+ margin-left: 33.3333333333%; }
+
+.col-sm-6,
+.row.cols-sm-6 > * {
+ max-width: 50%;
+ flex-basis: 50%; }
+
+.col-sm-offset-5 {
+ margin-left: 41.6666666667%; }
+
+.col-sm-7,
+.row.cols-sm-7 > * {
+ max-width: 58.3333333333%;
+ flex-basis: 58.3333333333%; }
+
+.col-sm-offset-6 {
+ margin-left: 50%; }
+
+.col-sm-8,
+.row.cols-sm-8 > * {
+ max-width: 66.6666666667%;
+ flex-basis: 66.6666666667%; }
+
+.col-sm-offset-7 {
+ margin-left: 58.3333333333%; }
+
+.col-sm-9,
+.row.cols-sm-9 > * {
+ max-width: 75%;
+ flex-basis: 75%; }
+
+.col-sm-offset-8 {
+ margin-left: 66.6666666667%; }
+
+.col-sm-10,
+.row.cols-sm-10 > * {
+ max-width: 83.3333333333%;
+ flex-basis: 83.3333333333%; }
+
+.col-sm-offset-9 {
+ margin-left: 75%; }
+
+.col-sm-11,
+.row.cols-sm-11 > * {
+ max-width: 91.6666666667%;
+ flex-basis: 91.6666666667%; }
+
+.col-sm-offset-10 {
+ margin-left: 83.3333333333%; }
+
+.col-sm-12,
+.row.cols-sm-12 > * {
+ max-width: 100%;
+ flex-basis: 100%; }
+
+.col-sm-offset-11 {
+ margin-left: 91.6666666667%; }
+
+.col-sm-normal {
+ order: initial; }
+
+.col-sm-first {
+ order: -999; }
+
+.col-sm-last {
+ order: 999; }
+
+@media screen and (min-width: 500px) {
+ .col-md,
+ [class^='col-md-'],
+ [class^='col-md-offset-'],
+ .row[class*='cols-md-'] > * {
+ box-sizing: border-box;
+ flex: 0 0 auto;
+ padding: 0 calc(var(--universal-padding) / 2); }
+
+ .col-md,
+ .row.cols-md > * {
+ max-width: 100%;
+ flex-grow: 1;
+ flex-basis: 0; }
+
+ .col-md-1,
+ .row.cols-md-1 > * {
+ max-width: 8.3333333333%;
+ flex-basis: 8.3333333333%; }
+
+ .col-md-offset-0 {
+ margin-left: 0; }
+
+ .col-md-2,
+ .row.cols-md-2 > * {
+ max-width: 16.6666666667%;
+ flex-basis: 16.6666666667%; }
+
+ .col-md-offset-1 {
+ margin-left: 8.3333333333%; }
+
+ .col-md-3,
+ .row.cols-md-3 > * {
+ max-width: 25%;
+ flex-basis: 25%; }
+
+ .col-md-offset-2 {
+ margin-left: 16.6666666667%; }
+
+ .col-md-4,
+ .row.cols-md-4 > * {
+ max-width: 33.3333333333%;
+ flex-basis: 33.3333333333%; }
+
+ .col-md-offset-3 {
+ margin-left: 25%; }
+
+ .col-md-5,
+ .row.cols-md-5 > * {
+ max-width: 41.6666666667%;
+ flex-basis: 41.6666666667%; }
+
+ .col-md-offset-4 {
+ margin-left: 33.3333333333%; }
+
+ .col-md-6,
+ .row.cols-md-6 > * {
+ max-width: 50%;
+ flex-basis: 50%; }
+
+ .col-md-offset-5 {
+ margin-left: 41.6666666667%; }
+
+ .col-md-7,
+ .row.cols-md-7 > * {
+ max-width: 58.3333333333%;
+ flex-basis: 58.3333333333%; }
+
+ .col-md-offset-6 {
+ margin-left: 50%; }
+
+ .col-md-8,
+ .row.cols-md-8 > * {
+ max-width: 66.6666666667%;
+ flex-basis: 66.6666666667%; }
+
+ .col-md-offset-7 {
+ margin-left: 58.3333333333%; }
+
+ .col-md-9,
+ .row.cols-md-9 > * {
+ max-width: 75%;
+ flex-basis: 75%; }
+
+ .col-md-offset-8 {
+ margin-left: 66.6666666667%; }
+
+ .col-md-10,
+ .row.cols-md-10 > * {
+ max-width: 83.3333333333%;
+ flex-basis: 83.3333333333%; }
+
+ .col-md-offset-9 {
+ margin-left: 75%; }
+
+ .col-md-11,
+ .row.cols-md-11 > * {
+ max-width: 91.6666666667%;
+ flex-basis: 91.6666666667%; }
+
+ .col-md-offset-10 {
+ margin-left: 83.3333333333%; }
+
+ .col-md-12,
+ .row.cols-md-12 > * {
+ max-width: 100%;
+ flex-basis: 100%; }
+
+ .col-md-offset-11 {
+ margin-left: 91.6666666667%; }
+
+ .col-md-normal {
+ order: initial; }
+
+ .col-md-first {
+ order: -999; }
+
+ .col-md-last {
+ order: 999; } }
+@media screen and (min-width: 1280px) {
+ .col-lg,
+ [class^='col-lg-'],
+ [class^='col-lg-offset-'],
+ .row[class*='cols-lg-'] > * {
+ box-sizing: border-box;
+ flex: 0 0 auto;
+ padding: 0 calc(var(--universal-padding) / 2); }
+
+ .col-lg,
+ .row.cols-lg > * {
+ max-width: 100%;
+ flex-grow: 1;
+ flex-basis: 0; }
+
+ .col-lg-1,
+ .row.cols-lg-1 > * {
+ max-width: 8.3333333333%;
+ flex-basis: 8.3333333333%; }
+
+ .col-lg-offset-0 {
+ margin-left: 0; }
+
+ .col-lg-2,
+ .row.cols-lg-2 > * {
+ max-width: 16.6666666667%;
+ flex-basis: 16.6666666667%; }
+
+ .col-lg-offset-1 {
+ margin-left: 8.3333333333%; }
+
+ .col-lg-3,
+ .row.cols-lg-3 > * {
+ max-width: 25%;
+ flex-basis: 25%; }
+
+ .col-lg-offset-2 {
+ margin-left: 16.6666666667%; }
+
+ .col-lg-4,
+ .row.cols-lg-4 > * {
+ max-width: 33.3333333333%;
+ flex-basis: 33.3333333333%; }
+
+ .col-lg-offset-3 {
+ margin-left: 25%; }
+
+ .col-lg-5,
+ .row.cols-lg-5 > * {
+ max-width: 41.6666666667%;
+ flex-basis: 41.6666666667%; }
+
+ .col-lg-offset-4 {
+ margin-left: 33.3333333333%; }
+
+ .col-lg-6,
+ .row.cols-lg-6 > * {
+ max-width: 50%;
+ flex-basis: 50%; }
+
+ .col-lg-offset-5 {
+ margin-left: 41.6666666667%; }
+
+ .col-lg-7,
+ .row.cols-lg-7 > * {
+ max-width: 58.3333333333%;
+ flex-basis: 58.3333333333%; }
+
+ .col-lg-offset-6 {
+ margin-left: 50%; }
+
+ .col-lg-8,
+ .row.cols-lg-8 > * {
+ max-width: 66.6666666667%;
+ flex-basis: 66.6666666667%; }
+
+ .col-lg-offset-7 {
+ margin-left: 58.3333333333%; }
+
+ .col-lg-9,
+ .row.cols-lg-9 > * {
+ max-width: 75%;
+ flex-basis: 75%; }
+
+ .col-lg-offset-8 {
+ margin-left: 66.6666666667%; }
+
+ .col-lg-10,
+ .row.cols-lg-10 > * {
+ max-width: 83.3333333333%;
+ flex-basis: 83.3333333333%; }
+
+ .col-lg-offset-9 {
+ margin-left: 75%; }
+
+ .col-lg-11,
+ .row.cols-lg-11 > * {
+ max-width: 91.6666666667%;
+ flex-basis: 91.6666666667%; }
+
+ .col-lg-offset-10 {
+ margin-left: 83.3333333333%; }
+
+ .col-lg-12,
+ .row.cols-lg-12 > * {
+ max-width: 100%;
+ flex-basis: 100%; }
+
+ .col-lg-offset-11 {
+ margin-left: 91.6666666667%; }
+
+ .col-lg-normal {
+ order: initial; }
+
+ .col-lg-first {
+ order: -999; }
+
+ .col-lg-last {
+ order: 999; } }
+/* Card component CSS variable definitions */
+:root {
+ --card-back-color: #3cb4e6;
+ --card-fore-color: #03234b;
+ --card-border-color: #03234b; }
+
+.card {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-self: center;
+ position: relative;
+ width: 100%;
+ background: var(--card-back-color);
+ color: var(--card-fore-color);
+ border: 0.0714285714rem solid var(--card-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: var(--universal-margin);
+ overflow: hidden; }
+ @media screen and (min-width: 320px) {
+ .card {
+ max-width: 320px; } }
+ .card > .sectione {
+ background: var(--card-back-color);
+ color: var(--card-fore-color);
+ box-sizing: border-box;
+ margin: 0;
+ border: 0;
+ border-radius: 0;
+ border-bottom: 0.0714285714rem solid var(--card-border-color);
+ padding: var(--universal-padding);
+ width: 100%; }
+ .card > .sectione.media {
+ height: 200px;
+ padding: 0;
+ -o-object-fit: cover;
+ object-fit: cover; }
+ .card > .sectione:last-child {
+ border-bottom: 0; }
+
+/*
+ Custom elements for card elements.
+*/
+@media screen and (min-width: 240px) {
+ .card.small {
+ max-width: 240px; } }
+@media screen and (min-width: 480px) {
+ .card.large {
+ max-width: 480px; } }
+.card.fluid {
+ max-width: 100%;
+ width: auto; }
+
+.card.warning {
+ --card-back-color: #e5b8b7;
+ --card-fore-color: #3b234b;
+ --card-border-color: #8c0078; }
+
+.card.error {
+ --card-back-color: #464650;
+ --card-fore-color: #ffffff;
+ --card-border-color: #8c0078; }
+
+.card > .sectione.dark {
+ --card-back-color: #3b234b;
+ --card-fore-color: #ffffff; }
+
+.card > .sectione.double-padded {
+ padding: calc(1.5 * var(--universal-padding)); }
+
+/*
+ Definitions for forms and input elements.
+*/
+/* Input_control module CSS variable definitions */
+:root {
+ --form-back-color: #ffe97f;
+ --form-fore-color: #03234b;
+ --form-border-color: #3cb4e6;
+ --input-back-color: #ffffff;
+ --input-fore-color: #03234b;
+ --input-border-color: #3cb4e6;
+ --input-focus-color: #0288d1;
+ --input-invalid-color: #d32f2f;
+ --button-back-color: #e2e2e2;
+ --button-hover-back-color: #dcdcdc;
+ --button-fore-color: #212121;
+ --button-border-color: transparent;
+ --button-hover-border-color: transparent;
+ --button-group-border-color: rgba(124, 124, 124, 0.54); }
+
+form {
+ background: var(--form-back-color);
+ color: var(--form-fore-color);
+ border: 0.0714285714rem solid var(--form-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: var(--universal-margin);
+ padding: calc(2 * var(--universal-padding)) var(--universal-padding); }
+
+fieldset {
+ border: 0.0714285714rem solid var(--form-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: calc(var(--universal-margin) / 4);
+ padding: var(--universal-padding); }
+
+legend {
+ box-sizing: border-box;
+ display: table;
+ max-width: 100%;
+ white-space: normal;
+ font-weight: 500;
+ padding: calc(var(--universal-padding) / 2); }
+
+label {
+ padding: calc(var(--universal-padding) / 2) var(--universal-padding); }
+
+.input-group {
+ display: inline-block; }
+ .input-group.fluid {
+ display: flex;
+ align-items: center;
+ justify-content: center; }
+ .input-group.fluid > input {
+ max-width: 100%;
+ flex-grow: 1;
+ flex-basis: 0px; }
+ @media screen and (max-width: 499px) {
+ .input-group.fluid {
+ align-items: stretch;
+ flex-direction: column; } }
+ .input-group.vertical {
+ display: flex;
+ align-items: stretch;
+ flex-direction: column; }
+ .input-group.vertical > input {
+ max-width: 100%;
+ flex-grow: 1;
+ flex-basis: 0px; }
+
+[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button {
+ height: auto; }
+
+[type="search"] {
+ -webkit-appearance: textfield;
+ outline-offset: -2px; }
+
+[type="search"]::-webkit-search-cancel-button,
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none; }
+
+input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"],
+[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select {
+ box-sizing: border-box;
+ background: var(--input-back-color);
+ color: var(--input-fore-color);
+ border: 0.0714285714rem solid var(--input-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: calc(var(--universal-margin) / 2);
+ padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); }
+
+input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus {
+ border-color: var(--input-focus-color);
+ box-shadow: none; }
+input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid {
+ border-color: var(--input-invalid-color);
+ box-shadow: none; }
+input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] {
+ background: var(--secondary-back-color); }
+
+select {
+ max-width: 100%; }
+
+option {
+ overflow: hidden;
+ text-overflow: ellipsis; }
+
+[type="checkbox"], [type="radio"] {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ position: relative;
+ height: calc(1rem + var(--universal-padding) / 2);
+ width: calc(1rem + var(--universal-padding) / 2);
+ vertical-align: text-bottom;
+ padding: 0;
+ flex-basis: calc(1rem + var(--universal-padding) / 2) !important;
+ flex-grow: 0 !important; }
+ [type="checkbox"]:checked:before, [type="radio"]:checked:before {
+ position: absolute; }
+
+[type="checkbox"]:checked:before {
+ content: '\2713';
+ font-family: sans-serif;
+ font-size: calc(1rem + var(--universal-padding) / 2);
+ top: calc(0rem - var(--universal-padding));
+ left: calc(var(--universal-padding) / 4); }
+
+[type="radio"] {
+ border-radius: 100%; }
+ [type="radio"]:checked:before {
+ border-radius: 100%;
+ content: '';
+ top: calc(0.0714285714rem + var(--universal-padding) / 2);
+ left: calc(0.0714285714rem + var(--universal-padding) / 2);
+ background: var(--input-fore-color);
+ width: 0.5rem;
+ height: 0.5rem; }
+
+:placeholder-shown {
+ color: var(--input-fore-color); }
+
+::-ms-placeholder {
+ color: var(--input-fore-color);
+ opacity: 0.54; }
+
+button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0; }
+
+button, html [type="button"], [type="reset"], [type="submit"] {
+ -webkit-appearance: button; }
+
+button {
+ overflow: visible;
+ text-transform: none; }
+
+button, [type="button"], [type="submit"], [type="reset"],
+a.button, label.button, .button,
+a[role="button"], label[role="button"], [role="button"] {
+ display: inline-block;
+ background: var(--button-back-color);
+ color: var(--button-fore-color);
+ border: 0.0714285714rem solid var(--button-border-color);
+ border-radius: var(--universal-border-radius);
+ padding: var(--universal-padding) calc(1.5 * var(--universal-padding));
+ margin: var(--universal-margin);
+ text-decoration: none;
+ cursor: pointer;
+ transition: background 0.3s; }
+ button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus,
+ a.button:hover,
+ a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus,
+ a[role="button"]:hover,
+ a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus {
+ background: var(--button-hover-back-color);
+ border-color: var(--button-hover-border-color); }
+
+input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] {
+ cursor: not-allowed;
+ opacity: 0.75; }
+
+.button-group {
+ display: flex;
+ border: 0.0714285714rem solid var(--button-group-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: var(--universal-margin); }
+ .button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], .button-group > .button, .button-group > [role="button"] {
+ margin: 0;
+ max-width: 100%;
+ flex: 1 1 auto;
+ text-align: center;
+ border: 0;
+ border-radius: 0;
+ box-shadow: none; }
+ .button-group > :not(:first-child) {
+ border-left: 0.0714285714rem solid var(--button-group-border-color); }
+ @media screen and (max-width: 499px) {
+ .button-group {
+ flex-direction: column; }
+ .button-group > :not(:first-child) {
+ border: 0;
+ border-top: 0.0714285714rem solid var(--button-group-border-color); } }
+
+/*
+ Custom elements for forms and input elements.
+*/
+button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary {
+ --button-back-color: #1976d2;
+ --button-fore-color: #f8f8f8; }
+ button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus {
+ --button-hover-back-color: #1565c0; }
+
+button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary {
+ --button-back-color: #d32f2f;
+ --button-fore-color: #f8f8f8; }
+ button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus {
+ --button-hover-back-color: #c62828; }
+
+button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary {
+ --button-back-color: #308732;
+ --button-fore-color: #f8f8f8; }
+ button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus {
+ --button-hover-back-color: #277529; }
+
+button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse {
+ --button-back-color: #212121;
+ --button-fore-color: #f8f8f8; }
+ button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus {
+ --button-hover-back-color: #111; }
+
+button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small {
+ padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding));
+ margin: var(--universal-margin); }
+
+button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large {
+ padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding));
+ margin: var(--universal-margin); }
+
+/*
+ Definitions for navigation elements.
+*/
+/* Navigation module CSS variable definitions */
+:root {
+ --header-back-color: #03234b;
+ --header-hover-back-color: #ffd200;
+ --header-fore-color: #ffffff;
+ --header-border-color: #3cb4e6;
+ --nav-back-color: #ffffff;
+ --nav-hover-back-color: #ffe97f;
+ --nav-fore-color: #e6007e;
+ --nav-border-color: #3cb4e6;
+ --nav-link-color: #3cb4e6;
+ --footer-fore-color: #ffffff;
+ --footer-back-color: #03234b;
+ --footer-border-color: #3cb4e6;
+ --footer-link-color: #3cb4e6;
+ --drawer-back-color: #ffffff;
+ --drawer-hover-back-color: #ffe97f;
+ --drawer-border-color: #3cb4e6;
+ --drawer-close-color: #e6007e; }
+
+header {
+ height: 2.75rem;
+ background: var(--header-back-color);
+ color: var(--header-fore-color);
+ border-bottom: 0.0714285714rem solid var(--header-border-color);
+ padding: calc(var(--universal-padding) / 4) 0;
+ white-space: nowrap;
+ overflow-x: auto;
+ overflow-y: hidden; }
+ header.row {
+ box-sizing: content-box; }
+ header .logo {
+ color: var(--header-fore-color);
+ font-size: 1.75rem;
+ padding: var(--universal-padding) calc(2 * var(--universal-padding));
+ text-decoration: none; }
+ header button, header [type="button"], header .button, header [role="button"] {
+ box-sizing: border-box;
+ position: relative;
+ top: calc(0rem - var(--universal-padding) / 4);
+ height: calc(3.1875rem + var(--universal-padding) / 2);
+ background: var(--header-back-color);
+ line-height: calc(3.1875rem - var(--universal-padding) * 1.5);
+ text-align: center;
+ color: var(--header-fore-color);
+ border: 0;
+ border-radius: 0;
+ margin: 0;
+ text-transform: uppercase; }
+ header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus {
+ background: var(--header-hover-back-color); }
+
+nav {
+ background: var(--nav-back-color);
+ color: var(--nav-fore-color);
+ border: 0.0714285714rem solid var(--nav-border-color);
+ border-radius: var(--universal-border-radius);
+ margin: var(--universal-margin); }
+ nav * {
+ padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); }
+ nav a, nav a:visited {
+ display: block;
+ color: var(--nav-link-color);
+ border-radius: var(--universal-border-radius);
+ transition: background 0.3s; }
+ nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus {
+ text-decoration: none;
+ background: var(--nav-hover-back-color); }
+ nav .sublink-1 {
+ position: relative;
+ margin-left: calc(2 * var(--universal-padding)); }
+ nav .sublink-1:before {
+ position: absolute;
+ left: calc(var(--universal-padding) - 1 * var(--universal-padding));
+ top: -0.0714285714rem;
+ content: '';
+ height: 100%;
+ border: 0.0714285714rem solid var(--nav-border-color);
+ border-left: 0; }
+ nav .sublink-2 {
+ position: relative;
+ margin-left: calc(4 * var(--universal-padding)); }
+ nav .sublink-2:before {
+ position: absolute;
+ left: calc(var(--universal-padding) - 3 * var(--universal-padding));
+ top: -0.0714285714rem;
+ content: '';
+ height: 100%;
+ border: 0.0714285714rem solid var(--nav-border-color);
+ border-left: 0; }
+
+footer {
+ background: var(--footer-back-color);
+ color: var(--footer-fore-color);
+ border-top: 0.0714285714rem solid var(--footer-border-color);
+ padding: calc(2 * var(--universal-padding)) var(--universal-padding);
+ font-size: 0.875rem; }
+ footer a, footer a:visited {
+ color: var(--footer-link-color); }
+
+header.sticky {
+ position: -webkit-sticky;
+ position: sticky;
+ z-index: 1101;
+ top: 0; }
+
+footer.sticky {
+ position: -webkit-sticky;
+ position: sticky;
+ z-index: 1101;
+ bottom: 0; }
+
+.drawer-toggle:before {
+ display: inline-block;
+ position: relative;
+ vertical-align: bottom;
+ content: '\00a0\2261\00a0';
+ font-family: sans-serif;
+ font-size: 1.5em; }
+@media screen and (min-width: 500px) {
+ .drawer-toggle:not(.persistent) {
+ display: none; } }
+
+[type="checkbox"].drawer {
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ position: absolute;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%); }
+ [type="checkbox"].drawer + * {
+ display: block;
+ box-sizing: border-box;
+ position: fixed;
+ top: 0;
+ width: 320px;
+ height: 100vh;
+ overflow-y: auto;
+ background: var(--drawer-back-color);
+ border: 0.0714285714rem solid var(--drawer-border-color);
+ border-radius: 0;
+ margin: 0;
+ z-index: 1110;
+ right: -320px;
+ transition: right 0.3s; }
+ [type="checkbox"].drawer + * .drawer-close {
+ position: absolute;
+ top: var(--universal-margin);
+ right: var(--universal-margin);
+ z-index: 1111;
+ width: 2rem;
+ height: 2rem;
+ border-radius: var(--universal-border-radius);
+ padding: var(--universal-padding);
+ margin: 0;
+ cursor: pointer;
+ transition: background 0.3s; }
+ [type="checkbox"].drawer + * .drawer-close:before {
+ display: block;
+ content: '\00D7';
+ color: var(--drawer-close-color);
+ position: relative;
+ font-family: sans-serif;
+ font-size: 2rem;
+ line-height: 1;
+ text-align: center; }
+ [type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus {
+ background: var(--drawer-hover-back-color); }
+ @media screen and (max-width: 320px) {
+ [type="checkbox"].drawer + * {
+ width: 100%; } }
+ [type="checkbox"].drawer:checked + * {
+ right: 0; }
+ @media screen and (min-width: 500px) {
+ [type="checkbox"].drawer:not(.persistent) + * {
+ position: static;
+ height: 100%;
+ z-index: 1100; }
+ [type="checkbox"].drawer:not(.persistent) + * .drawer-close {
+ display: none; } }
+
+/*
+ Definitions for the responsive table component.
+*/
+/* Table module CSS variable definitions. */
+:root {
+ --table-border-color: #03234b;
+ --table-border-separator-color: #03234b;
+ --table-head-back-color: #03234b;
+ --table-head-fore-color: #ffffff;
+ --table-body-back-color: #ffffff;
+ --table-body-fore-color: #03234b;
+ --table-body-alt-back-color: #f4f4f4; }
+
+table {
+ border-collapse: separate;
+ border-spacing: 0;
+ margin: 0;
+ display: flex;
+ flex: 0 1 auto;
+ flex-flow: row wrap;
+ padding: var(--universal-padding);
+ padding-top: 0; }
+ table caption {
+ font-size: 1rem;
+ margin: calc(2 * var(--universal-margin)) 0;
+ max-width: 100%;
+ flex: 0 0 100%; }
+ table thead, table tbody {
+ display: flex;
+ flex-flow: row wrap;
+ border: 0.0714285714rem solid var(--table-border-color); }
+ table thead {
+ z-index: 999;
+ border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0;
+ border-bottom: 0.0714285714rem solid var(--table-border-separator-color); }
+ table tbody {
+ border-top: 0;
+ margin-top: calc(0 - var(--universal-margin));
+ border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); }
+ table tr {
+ display: flex;
+ padding: 0; }
+ table th, table td {
+ padding: calc(0.5 * var(--universal-padding));
+ font-size: 0.9rem; }
+ table th {
+ text-align: left;
+ background: var(--table-head-back-color);
+ color: var(--table-head-fore-color); }
+ table td {
+ background: var(--table-body-back-color);
+ color: var(--table-body-fore-color);
+ border-top: 0.0714285714rem solid var(--table-border-color); }
+
+table:not(.horizontal) {
+ overflow: auto;
+ max-height: 100%; }
+ table:not(.horizontal) thead, table:not(.horizontal) tbody {
+ max-width: 100%;
+ flex: 0 0 100%; }
+ table:not(.horizontal) tr {
+ flex-flow: row wrap;
+ flex: 0 0 100%; }
+ table:not(.horizontal) th, table:not(.horizontal) td {
+ flex: 1 0 0%;
+ overflow: hidden;
+ text-overflow: ellipsis; }
+ table:not(.horizontal) thead {
+ position: sticky;
+ top: 0; }
+ table:not(.horizontal) tbody tr:first-child td {
+ border-top: 0; }
+
+table.horizontal {
+ border: 0; }
+ table.horizontal thead, table.horizontal tbody {
+ border: 0;
+ flex: .2 0 0;
+ flex-flow: row nowrap; }
+ table.horizontal tbody {
+ overflow: auto;
+ justify-content: space-between;
+ flex: .8 0 0;
+ margin-left: 0;
+ padding-bottom: calc(var(--universal-padding) / 4); }
+ table.horizontal tr {
+ flex-direction: column;
+ flex: 1 0 auto; }
+ table.horizontal th, table.horizontal td {
+ width: auto;
+ border: 0;
+ border-bottom: 0.0714285714rem solid var(--table-border-color); }
+ table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) {
+ border-top: 0; }
+ table.horizontal th {
+ text-align: right;
+ border-left: 0.0714285714rem solid var(--table-border-color);
+ border-right: 0.0714285714rem solid var(--table-border-separator-color); }
+ table.horizontal thead tr:first-child {
+ padding-left: 0; }
+ table.horizontal th:first-child, table.horizontal td:first-child {
+ border-top: 0.0714285714rem solid var(--table-border-color); }
+ table.horizontal tbody tr:last-child td {
+ border-right: 0.0714285714rem solid var(--table-border-color); }
+ table.horizontal tbody tr:last-child td:first-child {
+ border-top-right-radius: 0.25rem; }
+ table.horizontal tbody tr:last-child td:last-child {
+ border-bottom-right-radius: 0.25rem; }
+ table.horizontal thead tr:first-child th:first-child {
+ border-top-left-radius: 0.25rem; }
+ table.horizontal thead tr:first-child th:last-child {
+ border-bottom-left-radius: 0.25rem; }
+
+@media screen and (max-width: 499px) {
+ table, table.horizontal {
+ border-collapse: collapse;
+ border: 0;
+ width: 100%;
+ display: table; }
+ table thead, table th, table.horizontal thead, table.horizontal th {
+ border: 0;
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%); }
+ table tbody, table.horizontal tbody {
+ border: 0;
+ display: table-row-group; }
+ table tr, table.horizontal tr {
+ display: block;
+ border: 0.0714285714rem solid var(--table-border-color);
+ border-radius: var(--universal-border-radius);
+ background: #ffffff;
+ padding: var(--universal-padding);
+ margin: var(--universal-margin);
+ margin-bottom: calc(1 * var(--universal-margin)); }
+ table th, table td, table.horizontal th, table.horizontal td {
+ width: auto; }
+ table td, table.horizontal td {
+ display: block;
+ border: 0;
+ text-align: right; }
+ table td:before, table.horizontal td:before {
+ content: attr(data-label);
+ float: left;
+ font-weight: 600; }
+ table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child {
+ border-top: 0; }
+ table tbody tr:last-child td, table.horizontal tbody tr:last-child td {
+ border-right: 0; } }
+table tr:nth-of-type(2n) > td {
+ background: var(--table-body-alt-back-color); }
+
+@media screen and (max-width: 500px) {
+ table tr:nth-of-type(2n) {
+ background: var(--table-body-alt-back-color); } }
+:root {
+ --table-body-hover-back-color: #90caf9; }
+
+table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td {
+ background: var(--table-body-hover-back-color); }
+
+@media screen and (max-width: 500px) {
+ table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td {
+ background: var(--table-body-hover-back-color); } }
+/*
+ Definitions for contextual background elements, toasts and tooltips.
+*/
+/* Contextual module CSS variable definitions */
+:root {
+ --mark-back-color: #3cb4e6;
+ --mark-fore-color: #ffffff; }
+
+mark {
+ background: var(--mark-back-color);
+ color: var(--mark-fore-color);
+ font-size: 0.95em;
+ line-height: 1em;
+ border-radius: var(--universal-border-radius);
+ padding: calc(var(--universal-padding) / 4) var(--universal-padding); }
+ mark.inline-block {
+ display: inline-block;
+ font-size: 1em;
+ line-height: 1.4;
+ padding: calc(var(--universal-padding) / 2) var(--universal-padding); }
+
+:root {
+ --toast-back-color: #424242;
+ --toast-fore-color: #fafafa; }
+
+.toast {
+ position: fixed;
+ bottom: calc(var(--universal-margin) * 3);
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 1111;
+ color: var(--toast-fore-color);
+ background: var(--toast-back-color);
+ border-radius: calc(var(--universal-border-radius) * 16);
+ padding: var(--universal-padding) calc(var(--universal-padding) * 3); }
+
+:root {
+ --tooltip-back-color: #212121;
+ --tooltip-fore-color: #fafafa; }
+
+.tooltip {
+ position: relative;
+ display: inline-block; }
+ .tooltip:before, .tooltip:after {
+ position: absolute;
+ opacity: 0;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%);
+ transition: all 0.3s;
+ z-index: 1010;
+ left: 50%; }
+ .tooltip:not(.bottom):before, .tooltip:not(.bottom):after {
+ bottom: 75%; }
+ .tooltip.bottom:before, .tooltip.bottom:after {
+ top: 75%; }
+ .tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after {
+ opacity: 1;
+ clip: auto;
+ -webkit-clip-path: inset(0%);
+ clip-path: inset(0%); }
+ .tooltip:before {
+ content: '';
+ background: transparent;
+ border: var(--universal-margin) solid transparent;
+ left: calc(50% - var(--universal-margin)); }
+ .tooltip:not(.bottom):before {
+ border-top-color: #212121; }
+ .tooltip.bottom:before {
+ border-bottom-color: #212121; }
+ .tooltip:after {
+ content: attr(aria-label);
+ color: var(--tooltip-fore-color);
+ background: var(--tooltip-back-color);
+ border-radius: var(--universal-border-radius);
+ padding: var(--universal-padding);
+ white-space: nowrap;
+ transform: translateX(-50%); }
+ .tooltip:not(.bottom):after {
+ margin-bottom: calc(2 * var(--universal-margin)); }
+ .tooltip.bottom:after {
+ margin-top: calc(2 * var(--universal-margin)); }
+
+:root {
+ --modal-overlay-color: rgba(0, 0, 0, 0.45);
+ --modal-close-color: #e6007e;
+ --modal-close-hover-color: #ffe97f; }
+
+[type="checkbox"].modal {
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ position: absolute;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%); }
+ [type="checkbox"].modal + div {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: none;
+ width: 100vw;
+ height: 100vh;
+ background: var(--modal-overlay-color); }
+ [type="checkbox"].modal + div .card {
+ margin: 0 auto;
+ max-height: 50vh;
+ overflow: auto; }
+ [type="checkbox"].modal + div .card .modal-close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 1.75rem;
+ height: 1.75rem;
+ border-radius: var(--universal-border-radius);
+ padding: var(--universal-padding);
+ margin: 0;
+ cursor: pointer;
+ transition: background 0.3s; }
+ [type="checkbox"].modal + div .card .modal-close:before {
+ display: block;
+ content: '\00D7';
+ color: var(--modal-close-color);
+ position: relative;
+ font-family: sans-serif;
+ font-size: 1.75rem;
+ line-height: 1;
+ text-align: center; }
+ [type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus {
+ background: var(--modal-close-hover-color); }
+ [type="checkbox"].modal:checked + div {
+ display: flex;
+ flex: 0 1 auto;
+ z-index: 1200; }
+ [type="checkbox"].modal:checked + div .card .modal-close {
+ z-index: 1211; }
+
+:root {
+ --collapse-label-back-color: #03234b;
+ --collapse-label-fore-color: #ffffff;
+ --collapse-label-hover-back-color: #3cb4e6;
+ --collapse-selected-label-back-color: #3cb4e6;
+ --collapse-border-color: var(--collapse-label-back-color);
+ --collapse-selected-border-color: #ceecf8;
+ --collapse-content-back-color: #ffffff;
+ --collapse-selected-label-border-color: #3cb4e6; }
+
+.collapse {
+ width: calc(100% - 2 * var(--universal-margin));
+ opacity: 1;
+ display: flex;
+ flex-direction: column;
+ margin: var(--universal-margin);
+ border-radius: var(--universal-border-radius); }
+ .collapse > [type="radio"], .collapse > [type="checkbox"] {
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ position: absolute;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%); }
+ .collapse > label {
+ flex-grow: 1;
+ display: inline-block;
+ height: 1.25rem;
+ cursor: pointer;
+ transition: background 0.2s;
+ color: var(--collapse-label-fore-color);
+ background: var(--collapse-label-back-color);
+ border: 0.0714285714rem solid var(--collapse-selected-border-color);
+ padding: calc(1.25 * var(--universal-padding)); }
+ .collapse > label:hover, .collapse > label:focus {
+ background: var(--collapse-label-hover-back-color); }
+ .collapse > label + div {
+ flex-basis: auto;
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ position: absolute;
+ clip: rect(0 0 0 0);
+ -webkit-clip-path: inset(100%);
+ clip-path: inset(100%);
+ transition: max-height 0.3s;
+ max-height: 1px; }
+ .collapse > :checked + label {
+ background: var(--collapse-selected-label-back-color);
+ border-color: var(--collapse-selected-label-border-color); }
+ .collapse > :checked + label + div {
+ box-sizing: border-box;
+ position: relative;
+ width: 100%;
+ height: auto;
+ overflow: auto;
+ margin: 0;
+ background: var(--collapse-content-back-color);
+ border: 0.0714285714rem solid var(--collapse-selected-border-color);
+ border-top: 0;
+ padding: var(--universal-padding);
+ clip: auto;
+ -webkit-clip-path: inset(0%);
+ clip-path: inset(0%);
+ max-height: 100%; }
+ .collapse > label:not(:first-of-type) {
+ border-top: 0; }
+ .collapse > label:first-of-type {
+ border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; }
+ .collapse > label:last-of-type:not(:first-of-type) {
+ border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); }
+ .collapse > label:last-of-type:first-of-type {
+ border-radius: var(--universal-border-radius); }
+ .collapse > :checked:last-of-type:not(:first-of-type) + label {
+ border-radius: 0; }
+ .collapse > :checked:last-of-type + label + div {
+ border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); }
+
+/*
+ Custom elements for contextual background elements, toasts and tooltips.
+*/
+mark.tertiary {
+ --mark-back-color: #3cb4e6; }
+
+mark.tag {
+ padding: calc(var(--universal-padding)/2) var(--universal-padding);
+ border-radius: 1em; }
+
+/*
+ Definitions for progress elements and spinners.
+*/
+/* Progress module CSS variable definitions */
+:root {
+ --progress-back-color: #3cb4e6;
+ --progress-fore-color: #555; }
+
+progress {
+ display: block;
+ vertical-align: baseline;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ height: 0.75rem;
+ width: calc(100% - 2 * var(--universal-margin));
+ margin: var(--universal-margin);
+ border: 0;
+ border-radius: calc(2 * var(--universal-border-radius));
+ background: var(--progress-back-color);
+ color: var(--progress-fore-color); }
+ progress::-webkit-progress-value {
+ background: var(--progress-fore-color);
+ border-top-left-radius: calc(2 * var(--universal-border-radius));
+ border-bottom-left-radius: calc(2 * var(--universal-border-radius)); }
+ progress::-webkit-progress-bar {
+ background: var(--progress-back-color); }
+ progress::-moz-progress-bar {
+ background: var(--progress-fore-color);
+ border-top-left-radius: calc(2 * var(--universal-border-radius));
+ border-bottom-left-radius: calc(2 * var(--universal-border-radius)); }
+ progress[value="1000"]::-webkit-progress-value {
+ border-radius: calc(2 * var(--universal-border-radius)); }
+ progress[value="1000"]::-moz-progress-bar {
+ border-radius: calc(2 * var(--universal-border-radius)); }
+ progress.inline {
+ display: inline-block;
+ vertical-align: middle;
+ width: 60%; }
+
+:root {
+ --spinner-back-color: #ddd;
+ --spinner-fore-color: #555; }
+
+@keyframes spinner-donut-anim {
+ 0% {
+ transform: rotate(0deg); }
+ 100% {
+ transform: rotate(360deg); } }
+.spinner {
+ display: inline-block;
+ margin: var(--universal-margin);
+ border: 0.25rem solid var(--spinner-back-color);
+ border-left: 0.25rem solid var(--spinner-fore-color);
+ border-radius: 50%;
+ width: 1.25rem;
+ height: 1.25rem;
+ animation: spinner-donut-anim 1.2s linear infinite; }
+
+/*
+ Custom elements for progress bars and spinners.
+*/
+progress.primary {
+ --progress-fore-color: #1976d2; }
+
+progress.secondary {
+ --progress-fore-color: #d32f2f; }
+
+progress.tertiary {
+ --progress-fore-color: #308732; }
+
+.spinner.primary {
+ --spinner-fore-color: #1976d2; }
+
+.spinner.secondary {
+ --spinner-fore-color: #d32f2f; }
+
+.spinner.tertiary {
+ --spinner-fore-color: #308732; }
+
+/*
+ Definitions for icons - powered by Feather (https://feathericons.com/).
+*/
+span[class^='icon-'] {
+ display: inline-block;
+ height: 1em;
+ width: 1em;
+ vertical-align: -0.125em;
+ background-size: contain;
+ margin: 0 calc(var(--universal-margin) / 4); }
+ span[class^='icon-'].secondary {
+ -webkit-filter: invert(25%);
+ filter: invert(25%); }
+ span[class^='icon-'].inverse {
+ -webkit-filter: invert(100%);
+ filter: invert(100%); }
+
+span.icon-alert {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-bookmark {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); }
+span.icon-calendar {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-credit {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-edit {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); }
+span.icon-link {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-help {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-home {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); }
+span.icon-info {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-lock {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); }
+span.icon-mail {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); }
+span.icon-location {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); }
+span.icon-phone {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); }
+span.icon-rss {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); }
+span.icon-search {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-settings {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); }
+span.icon-share {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-cart {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); }
+span.icon-upload {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); }
+span.icon-user {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2303234b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); }
+
+/*
+ Definitions for STMicroelectronics icons (https://brandportal.st.com/document/26).
+*/
+span.icon-st-update {
+ background-image: url("Update.svg"); }
+span.icon-st-add {
+ background-image: url("Add button.svg"); }
+
+/*
+ Definitions for utilities and helper classes.
+*/
+/* Utility module CSS variable definitions */
+:root {
+ --generic-border-color: rgba(0, 0, 0, 0.3);
+ --generic-box-shadow: 0 0.2857142857rem 0.2857142857rem 0 rgba(0, 0, 0, 0.125), 0 0.1428571429rem 0.1428571429rem -0.1428571429rem rgba(0, 0, 0, 0.125); }
+
+.hidden {
+ display: none !important; }
+
+.visually-hidden {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ margin: -1px !important;
+ border: 0 !important;
+ padding: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(100%) !important;
+ clip-path: inset(100%) !important;
+ overflow: hidden !important; }
+
+.bordered {
+ border: 0.0714285714rem solid var(--generic-border-color) !important; }
+
+.rounded {
+ border-radius: var(--universal-border-radius) !important; }
+
+.circular {
+ border-radius: 50% !important; }
+
+.shadowed {
+ box-shadow: var(--generic-box-shadow) !important; }
+
+.responsive-margin {
+ margin: calc(var(--universal-margin) / 4) !important; }
+ @media screen and (min-width: 500px) {
+ .responsive-margin {
+ margin: calc(var(--universal-margin) / 2) !important; } }
+ @media screen and (min-width: 1280px) {
+ .responsive-margin {
+ margin: var(--universal-margin) !important; } }
+
+.responsive-padding {
+ padding: calc(var(--universal-padding) / 4) !important; }
+ @media screen and (min-width: 500px) {
+ .responsive-padding {
+ padding: calc(var(--universal-padding) / 2) !important; } }
+ @media screen and (min-width: 1280px) {
+ .responsive-padding {
+ padding: var(--universal-padding) !important; } }
+
+@media screen and (max-width: 499px) {
+ .hidden-sm {
+ display: none !important; } }
+@media screen and (min-width: 500px) and (max-width: 1279px) {
+ .hidden-md {
+ display: none !important; } }
+@media screen and (min-width: 1280px) {
+ .hidden-lg {
+ display: none !important; } }
+@media screen and (max-width: 499px) {
+ .visually-hidden-sm {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ margin: -1px !important;
+ border: 0 !important;
+ padding: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(100%) !important;
+ clip-path: inset(100%) !important;
+ overflow: hidden !important; } }
+@media screen and (min-width: 500px) and (max-width: 1279px) {
+ .visually-hidden-md {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ margin: -1px !important;
+ border: 0 !important;
+ padding: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(100%) !important;
+ clip-path: inset(100%) !important;
+ overflow: hidden !important; } }
+@media screen and (min-width: 1280px) {
+ .visually-hidden-lg {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ margin: -1px !important;
+ border: 0 !important;
+ padding: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(100%) !important;
+ clip-path: inset(100%) !important;
+ overflow: hidden !important; } }
+
+/*# sourceMappingURL=mini-custom.css.map */
+
+img[alt="ST logo"] { display: block; margin: auto; width: 75%; max-width: 250px; min-width: 71px; }
+img[alt="Cube logo"] { float: right; width: 30%; max-width: 10rem; min-width: 8rem; padding-right: 1rem;}
+
+.figure {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/Drivers/BSP/STM32L496G-Discovery/_htmresc/st_logo_2020.png b/Drivers/BSP/STM32L496G-Discovery/_htmresc/st_logo_2020.png
new file mode 100644
index 0000000..d6cebb5
Binary files /dev/null and b/Drivers/BSP/STM32L496G-Discovery/_htmresc/st_logo_2020.png differ
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.c
new file mode 100644
index 0000000..6accf84
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.c
@@ -0,0 +1,1645 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery.c
+ * @author MCD Application Team
+ * @brief This file provides a set of firmware functions to manage Leds,
+ * push-button and joystick of STM32L496G-Discovery board (MB1261)
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+#include "stm32l496g_discovery_io.h"
+#include "stm32l496g_discovery_lcd.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY STM32L496G-DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_Common STM32L496G-DISCOVERY Common
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_Private_TypesDefinitions Private Types Definitions
+ * @brief This file provides firmware functions to manage Leds, push-buttons,
+ * COM ports, SD card on SPI and temperature sensor (TS751) available on
+ * STM32L496G-DISCOVERY discoveryuation board from STMicroelectronics.
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_Private_Defines Private Defines
+ * @{
+ */
+
+/**
+ * @brief STM32L496G DISCOVERY BSP Driver version number
+ */
+#define __STM32L496G_DISCOVERY_BSP_VERSION_MAIN (0x01) /*!< [31:24] main version */
+#define __STM32L496G_DISCOVERY_BSP_VERSION_SUB1 (0x01) /*!< [23:16] sub1 version */
+#define __STM32L496G_DISCOVERY_BSP_VERSION_SUB2 (0x06) /*!< [15:8] sub2 version */
+#define __STM32L496G_DISCOVERY_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */
+#define __STM32L496G_DISCOVERY_BSP_VERSION ((__STM32L496G_DISCOVERY_BSP_VERSION_MAIN << 24)\
+ |(__STM32L496G_DISCOVERY_BSP_VERSION_SUB1 << 16)\
+ |(__STM32L496G_DISCOVERY_BSP_VERSION_SUB2 << 8 )\
+ |(__STM32L496G_DISCOVERY_BSP_VERSION_RC))
+/**
+ * @}
+ */
+
+
+/** @defgroup STM32L496G_DISCOVERY_Private_Macros Private Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup STM32L496G_DISCOVERY_Exported_Variables Exported Variables
+ * @{
+ */
+
+/**
+ * @brief LED variables
+ */
+const uint16_t LED_PIN[LEDn] = {LED1_PIN,
+ LED2_PIN
+ };
+
+/**
+ * @brief JOYSTICK variables
+ */
+GPIO_TypeDef *JOY_PORT[JOYn] = {SEL_JOY_GPIO_PORT,
+ LEFT_JOY_GPIO_PORT,
+ RIGHT_JOY_GPIO_PORT,
+ DOWN_JOY_GPIO_PORT,
+ UP_JOY_GPIO_PORT
+ };
+
+const uint16_t JOY_PIN[JOYn] = {SEL_JOY_PIN,
+ LEFT_JOY_PIN,
+ RIGHT_JOY_PIN,
+ DOWN_JOY_PIN,
+ UP_JOY_PIN
+ };
+
+const uint8_t JOY_IRQn[JOYn] = {SEL_JOY_EXTI_IRQn,
+ LEFT_JOY_EXTI_IRQn,
+ RIGHT_JOY_EXTI_IRQn,
+ DOWN_JOY_EXTI_IRQn,
+ UP_JOY_EXTI_IRQn
+ };
+
+
+/**
+ * @brief COM port variables
+ */
+#if defined(HAL_UART_MODULE_ENABLED)
+USART_TypeDef* COM_USART[COMn] = {DISCOVERY_COM1};
+GPIO_TypeDef* COM_TX_PORT[COMn] = {DISCOVERY_COM1_TX_GPIO_PORT};
+GPIO_TypeDef* COM_RX_PORT[COMn] = {DISCOVERY_COM1_RX_GPIO_PORT};
+const uint16_t COM_TX_PIN[COMn] = {DISCOVERY_COM1_TX_PIN};
+const uint16_t COM_RX_PIN[COMn] = {DISCOVERY_COM1_RX_PIN};
+const uint16_t COM_TX_AF[COMn] = {DISCOVERY_COM1_TX_AF};
+const uint16_t COM_RX_AF[COMn] = {DISCOVERY_COM1_RX_AF};
+#endif /* HAL_UART_MODULE_ENABLED */
+
+
+/**
+ * @brief BUS variables
+ */
+#if defined(HAL_I2C_MODULE_ENABLED)
+uint32_t I2c1Timeout = DISCOVERY_I2C2_TIMEOUT_MAX; /*Instance = COM_USART[COM];
+ HAL_UART_Init(huart);
+}
+
+/**
+ * @brief DeInit COM port.
+ * @param COM: COM port to be configured.
+ * This parameter can be one of the following values:
+ * @arg COM1
+ * @param huart: Pointer to a UART_HandleTypeDef structure that contains the
+ * configuration information for the specified USART peripheral.
+ */
+void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart)
+{
+ /* USART deinitialization */
+ huart->Instance = COM_USART[COM];
+ HAL_UART_DeInit(huart);
+
+ /* Disable USART clock */
+ DISCOVERY_COMx_CLK_DISABLE(COM);
+
+ /* USART TX/RX pins deinitializations */
+ HAL_GPIO_DeInit(COM_TX_PORT[COM], COM_TX_PIN[COM]);
+ HAL_GPIO_DeInit(COM_RX_PORT[COM], COM_RX_PIN[COM]);
+
+ /* Disable GPIOs clock is left for application */
+}
+#endif /* HAL_UART_MODULE_ENABLED */
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_BusOperations_Functions Bus Operations Functions
+ * @{
+ */
+
+/*******************************************************************************
+ BUS OPERATIONS
+*******************************************************************************/
+
+#if defined(HAL_I2C_MODULE_ENABLED)
+/******************************* I2C Routines**********************************/
+/**
+ * @brief Discovery I2C2 Bus initialization
+ * @retval None
+ */
+void I2C2_Init(void)
+{
+ if (HAL_I2C_GetState(&I2c2Handle) == HAL_I2C_STATE_RESET)
+ {
+ I2c2Handle.Instance = DISCOVERY_I2C2;
+ I2c2Handle.Init.Timing = DISCOVERY_I2C2_TIMING;
+ I2c2Handle.Init.OwnAddress1 = 0x70;
+ I2c2Handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ I2c2Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
+ I2c2Handle.Init.OwnAddress2 = 0xFF;
+ I2c2Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
+ I2c2Handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
+
+ /* Init the I2C */
+ I2C2_MspInit(&I2c2Handle);
+ HAL_I2C_Init(&I2c2Handle);
+ }
+}
+
+/**
+ * @brief Discovery I2C2 MSP Initialization
+ * @param hi2c: I2C2 handle
+ * @retval None
+ */
+static void I2C2_MspInit(I2C_HandleTypeDef *hi2c)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
+
+ if (hi2c->Instance == DISCOVERY_I2C2)
+ {
+ /*##-1- Configure the Discovery I2C2 clock source. The clock is derived from the SYSCLK #*/
+ RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2;
+ RCC_PeriphCLKInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_SYSCLK;
+ HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
+
+ /*##-2- Configure the GPIOs ################################################*/
+ /* Enable GPIO clock */
+ DISCOVERY_I2C2_SDA_GPIO_CLK_ENABLE();
+ DISCOVERY_I2C2_SCL_GPIO_CLK_ENABLE();
+
+ /* Configure I2C Rx/Tx as alternate function */
+ GPIO_InitStructure.Pin = DISCOVERY_I2C2_SCL_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
+ GPIO_InitStructure.Pull = /*GPIO_NOPULL*/ GPIO_PULLUP;
+ GPIO_InitStructure.Speed = /*GPIO_SPEED_MEDIUM*/ GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = DISCOVERY_I2C2_SCL_SDA_AF;
+ HAL_GPIO_Init(DISCOVERY_I2C2_SCL_GPIO_PORT, &GPIO_InitStructure);
+ GPIO_InitStructure.Pin = DISCOVERY_I2C2_SDA_PIN;
+ HAL_GPIO_Init(DISCOVERY_I2C2_SDA_GPIO_PORT, &GPIO_InitStructure);
+
+ /*##-3- Configure the Discovery I2C2 peripheral #############################*/
+ /* Enable Discovery_I2C2 clock */
+ DISCOVERY_I2C2_CLK_ENABLE();
+
+ /* Force and release the I2C Peripheral Clock Reset */
+ DISCOVERY_I2C2_FORCE_RESET();
+ DISCOVERY_I2C2_RELEASE_RESET();
+
+ /* Enable and set Discovery I2C2 Interrupt to the highest priority */
+ HAL_NVIC_SetPriority(DISCOVERY_I2C2_EV_IRQn, 0x00, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_I2C2_EV_IRQn);
+
+ /* Enable and set Discovery I2C2 Interrupt to the highest priority */
+ HAL_NVIC_SetPriority(DISCOVERY_I2C2_ER_IRQn, 0x00, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_I2C2_ER_IRQn);
+ }
+}
+
+/**
+ * @brief Discovery I2C2 Bus Deinitialization
+ * @retval None
+ */
+void I2C2_DeInit(void)
+{
+ if (HAL_I2C_GetState(&I2c2Handle) != HAL_I2C_STATE_RESET)
+ {
+ /* DeInit the I2C */
+ HAL_I2C_DeInit(&I2c2Handle);
+ I2C2_MspDeInit(&I2c2Handle);
+ }
+}
+
+/**
+ * @brief Discovery I2C2 MSP DeInitialization
+ * @param hi2c: I2C2 handle
+ * @retval None
+ */
+static void I2C2_MspDeInit(I2C_HandleTypeDef *hi2c)
+{
+ if (hi2c->Instance == DISCOVERY_I2C2)
+ {
+ /*##-1- Unconfigure the GPIOs ################################################*/
+ /* Enable GPIO clock */
+ DISCOVERY_I2C2_SDA_GPIO_CLK_ENABLE();
+ DISCOVERY_I2C2_SCL_GPIO_CLK_ENABLE();
+
+ /* Configure I2C Rx/Tx as alternate function */
+ HAL_GPIO_DeInit(DISCOVERY_I2C2_SCL_GPIO_PORT, DISCOVERY_I2C2_SCL_PIN);
+ HAL_GPIO_DeInit(DISCOVERY_I2C2_SDA_GPIO_PORT, DISCOVERY_I2C2_SDA_PIN);
+
+ /*##-2- Unconfigure the Discovery I2C2 peripheral ############################*/
+ /* Force and release I2C Peripheral */
+ DISCOVERY_I2C2_FORCE_RESET();
+ DISCOVERY_I2C2_RELEASE_RESET();
+
+ /* Disable Discovery I2C2 clock */
+ DISCOVERY_I2C2_CLK_DISABLE();
+
+ /* Disable Discovery I2C2 interrupts */
+ HAL_NVIC_DisableIRQ(DISCOVERY_I2C2_EV_IRQn);
+ HAL_NVIC_DisableIRQ(DISCOVERY_I2C2_ER_IRQn);
+ }
+}
+
+/**
+ * @brief Write a value in a register of the device through BUS.
+ * @param Addr: Device address on BUS Bus.
+ * @param Reg: The target register address to write
+ * @param RegSize: The target register size (can be 8BIT or 16BIT)
+ * @param Value: The target register value to be written
+ * @retval None
+ */
+static void I2C2_WriteData(uint16_t Addr, uint16_t Reg, uint16_t RegSize, uint8_t Value)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ __disable_irq();
+
+ status = HAL_I2C_Mem_Write(&I2c2Handle, Addr, (uint16_t)Reg, RegSize, &Value, 1, I2c2Timeout);
+
+ __enable_irq();
+
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initiaize the BUS */
+ I2C2_Error();
+ }
+}
+
+/**
+ * @brief Write a value in a register of the device through BUS.
+ * @param Addr: Device address on BUS Bus.
+ * @param Reg: The target register address to write
+ * @param RegSize: The target register size (can be 8BIT or 16BIT)
+ * @param pBuffer: The target register value to be written
+ * @param Length: buffer size to be written
+ * @retval None
+ */
+static HAL_StatusTypeDef I2C2_WriteBuffer(uint16_t Addr, uint16_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ __disable_irq();
+
+ status = HAL_I2C_Mem_Write(&I2c2Handle, Addr, (uint16_t)Reg, RegSize, pBuffer, Length, I2c2Timeout);
+
+ __enable_irq();
+
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initiaize the BUS */
+ I2C2_Error();
+ }
+
+ return status;
+}
+
+/**
+ * @brief Read a register of the device through BUS
+ * @param Addr: Device address on BUS
+ * @param Reg: The target register address to read
+ * @param RegSize: The target register size (can be 8BIT or 16BIT)
+ * @retval read register value
+ */
+static uint8_t I2C2_ReadData(uint16_t Addr, uint16_t Reg, uint16_t RegSize)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+ uint8_t value = 0x0;
+
+ __disable_irq();
+
+ status = HAL_I2C_Mem_Read(&I2c2Handle, Addr, Reg, RegSize, &value, 1, I2c2Timeout);
+
+ __enable_irq();
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initiaize the BUS */
+ I2C2_Error();
+ HAL_Delay(200);
+ }
+
+ return value;
+}
+
+static uint8_t I2C2_isDeviceReady(uint16_t Addr, uint32_t trial)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+ uint8_t value = 0x0;
+
+ __disable_irq();
+
+ status = HAL_I2C_IsDeviceReady(&I2c2Handle, Addr, trial, 50);
+
+ __enable_irq();
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initiaize the BUS */
+ I2C2_Error();
+ HAL_Delay(200);
+ }
+
+ return value;
+}
+
+/**
+ * @brief Reads multiple data on the BUS.
+ * @param Addr: I2C Address
+ * @param Reg: Reg Address
+ * @param RegSize : The target register size (can be 8BIT or 16BIT)
+ * @param pBuffer: pointer to read data buffer
+ * @param Length: length of the data
+ * @retval 0 if no problems to read multiple data
+ */
+static HAL_StatusTypeDef I2C2_ReadBuffer(uint16_t Addr, uint16_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ __disable_irq();
+
+ status = HAL_I2C_Mem_Read(&I2c2Handle, Addr, (uint16_t)Reg, RegSize, pBuffer, Length, I2c2Timeout);
+
+ __enable_irq();
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initiaize the BUS */
+ I2C2_Error();
+ }
+
+ return status;
+}
+
+/**
+ * @brief Discovery I2C2 error treatment function
+ * @retval None
+ */
+static void I2C2_Error(void)
+{
+ BSP_ErrorHandler();
+
+ /* De-initialize the I2C communication BUS */
+ HAL_I2C_DeInit(&I2c2Handle);
+
+ /* Re- Initiaize the I2C communication BUS */
+ I2C2_Init();
+}
+
+
+
+/******************************* I2C Routines *********************************/
+/**
+ * @brief Initializes I2C HAL.
+ * @param i2c_handler : I2C handler
+ * @retval None
+ */
+static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler)
+{
+
+ if (HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET)
+ {
+ if (i2c_handler == (I2C_HandleTypeDef *)(&hI2cTSHandler))
+ {
+ /* TS (Capacitive Touch Panel) and LCD I2C configuration */
+ i2c_handler->Instance = DISCOVERY_TS_I2Cx;
+
+ /* Need to enable MFX, and in doing so, initialize I2C at the same time */
+ /* MFX_IO_Init();*/
+
+ }
+ else if (i2c_handler == (I2C_HandleTypeDef *)(&hI2cAudioHandler))
+ {
+ /* Audio and LCD I2C configuration */
+ i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx;
+ }
+ else if (i2c_handler == (I2C_HandleTypeDef *)(&hI2cCameraHandler))
+ {
+ i2c_handler->Instance = DISCOVERY_CAMERA_I2Cx;
+ }
+ else
+ {
+ /* External, EEPROM and Arduino connector I2C configuration */
+ i2c_handler->Instance = DISCOVERY_EXT_I2Cx;
+ }
+
+ i2c_handler->Init.Timing = DISCOVERY_I2C_TIMING;
+ i2c_handler->Init.OwnAddress1 = 0x70;
+ i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
+ i2c_handler->Init.OwnAddress2 = 0xFF;
+ i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
+ i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
+
+
+ /* Init the I2C */
+ HAL_I2C_Init(i2c_handler);
+
+ }
+
+}
+
+/**
+ * @brief Reads multiple data.
+ * @param i2c_handler : I2C handler
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param MemAddress: Memory address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval Number of read data
+ */
+static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler,
+ uint8_t Addr,
+ uint16_t Reg,
+ uint16_t MemAddress,
+ uint8_t *Buffer,
+ uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* I2C error occurred */
+ I2Cx_Error(i2c_handler, Addr);
+ }
+ return status;
+}
+
+/**
+ * @brief Writes a value in a register of the device through BUS in using DMA mode.
+ * @param i2c_handler : I2C handler
+ * @param Addr: Device address on BUS Bus.
+ * @param Reg: The target register address to write
+ * @param MemAddress: Memory address
+ * @param Buffer: The target register value to be written
+ * @param Length: buffer size to be written
+ * @retval HAL status
+ */
+static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler,
+ uint8_t Addr,
+ uint16_t Reg,
+ uint16_t MemAddress,
+ uint8_t *Buffer,
+ uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
+
+ /* Check the communication status */
+ if (status != HAL_OK)
+ {
+ /* Re-Initialize the I2C Bus */
+ I2Cx_Error(i2c_handler, Addr);
+ }
+ return status;
+}
+
+/**
+ * @brief Manages error callback by re-initializing I2C.
+ * @param i2c_handler : I2C handler
+ * @param Addr: I2C Address
+ * @retval None
+ */
+static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr)
+{
+ BSP_ErrorHandler();
+
+ /* De-initialize the I2C communication bus */
+ if (i2c_handler == (I2C_HandleTypeDef *)(&hI2cTSHandler))
+ {
+ I2C2_DeInit();
+ }
+ else
+ {
+ HAL_I2C_DeInit(i2c_handler);
+ }
+
+ /* Re-Initialize the I2C communication bus */
+ I2Cx_Init(i2c_handler);
+}
+#endif /*HAL_I2C_MODULE_ENABLED*/
+
+
+/*******************************************************************************
+ LINK OPERATIONS
+*******************************************************************************/
+
+#if defined(HAL_I2C_MODULE_ENABLED)
+/********************************* LINK MFX ***********************************/
+/**
+ * @brief Initializes MFX low level.
+ * @retval None
+ */
+void MFX_IO_Init(void)
+{
+ /* I2C2 init */
+ I2C2_Init();
+
+ /* Wait for device ready */
+ if (I2C2_isDeviceReady(IO1_I2C_ADDRESS, 4) != HAL_OK)
+ {
+ BSP_ErrorHandler();
+ }
+}
+/**
+ * @brief Deinitializes MFX low level.
+ * @retval None
+ */
+void MFX_IO_DeInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable wakeup gpio clock */
+ MFX_WAKEUP_GPIO_CLK_ENABLE();
+
+ /* MFX wakeup pin configuration */
+ GPIO_InitStruct.Pin = MFX_WAKEUP_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ HAL_GPIO_Init(MFX_WAKEUP_GPIO_PORT, &GPIO_InitStruct);
+
+ /* DeInit interrupt pin : disable IRQ before to avoid spurious interrupt */
+ HAL_NVIC_DisableIRQ((IRQn_Type)(MFX_INT_EXTI_IRQn));
+ MFX_INT_GPIO_CLK_ENABLE();
+ HAL_GPIO_DeInit(MFX_INT_GPIO_PORT, MFX_INT_PIN);
+
+ /* I2C2 Deinit */
+ I2C2_DeInit();
+}
+
+/**
+ * @brief Configures MFX low level interrupt.
+ * @retval None
+ */
+void MFX_IO_ITConfig(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable the GPIO clock */
+ MFX_INT_GPIO_CLK_ENABLE();
+
+ /* MFX_OUT_IRQ (normally used for EXTI_WKUP) */
+ GPIO_InitStruct.Pin = MFX_INT_PIN;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
+ HAL_GPIO_Init(MFX_INT_GPIO_PORT, &GPIO_InitStruct);
+
+ /* Enable and set GPIO EXTI Interrupt to the lowest priority */
+ HAL_NVIC_SetPriority((IRQn_Type)(MFX_INT_EXTI_IRQn), 0x0F, 0x0F);
+ HAL_NVIC_EnableIRQ((IRQn_Type)(MFX_INT_EXTI_IRQn));
+}
+
+/**
+ * @brief Configures MFX wke up pin.
+ * @retval None
+ */
+void MFX_IO_EnableWakeupPin(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable wakeup gpio clock */
+ MFX_WAKEUP_GPIO_CLK_ENABLE();
+
+ /* MFX wakeup pin configuration */
+ GPIO_InitStruct.Pin = MFX_WAKEUP_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(MFX_WAKEUP_GPIO_PORT, &GPIO_InitStruct);
+}
+
+/**
+ * @brief Wakeup MFX.
+ * @retval None
+ */
+void MFX_IO_Wakeup(void)
+{
+ /* Set Wakeup pin to high to wakeup Idd measurement component from standby mode */
+ HAL_GPIO_WritePin(MFX_WAKEUP_GPIO_PORT, MFX_WAKEUP_PIN, GPIO_PIN_SET);
+
+ /* Wait */
+ HAL_Delay(1);
+
+ /* Set gpio pin basck to low */
+ HAL_GPIO_WritePin(MFX_WAKEUP_GPIO_PORT, MFX_WAKEUP_PIN, GPIO_PIN_RESET);
+}
+
+/**
+ * @brief MFX writes single data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void MFX_IO_Write(uint16_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2C2_WriteData(Addr, Reg, I2C_MEMADD_SIZE_8BIT, Value);
+}
+
+/**
+ * @brief MFX reads single data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @retval Read data
+ */
+uint8_t MFX_IO_Read(uint16_t Addr, uint8_t Reg)
+{
+ return I2C2_ReadData(Addr, Reg, I2C_MEMADD_SIZE_8BIT);
+}
+
+/**
+ * @brief MFX reads multiple data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval Number of read data
+ */
+uint16_t MFX_IO_ReadMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ return I2C2_ReadBuffer(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief MFX writes multiple data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval None
+ */
+void MFX_IO_WriteMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ I2C2_WriteBuffer(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief MFX delay
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void MFX_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+
+/********************************* LINK AUDIO *********************************/
+/**
+ * @brief Initializes Audio low level.
+ * @retval None
+ */
+void AUDIO_IO_Init(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+ uint8_t Value;
+
+ /* Enable Reset GPIO Clock */
+ AUDIO_RESET_GPIO_CLK_ENABLE();
+
+ /* Audio reset pin configuration */
+ GPIO_InitStruct.Pin = AUDIO_RESET_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(AUDIO_RESET_GPIO, &GPIO_InitStruct);
+
+ /* I2C bus init */
+ I2C2_Init();
+
+ /* Power off the codec */
+ CODEC_AUDIO_POWER_OFF();
+
+ /* wait until power supplies are stable */
+ HAL_Delay(10);
+
+ /* Power on the codec */
+ CODEC_AUDIO_POWER_ON();
+
+ /* Set the device in standby mode */
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x02);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x02, (Value | 0x01));
+
+ /* Set all power down bits to 1 */
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x02, 0x7F);
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x03);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x03, (Value | 0x0E));
+}
+
+/**
+ * @brief Deinitializes Audio low level.
+ * @retval None
+ */
+void AUDIO_IO_DeInit(void)
+{
+ uint8_t Value;
+
+ /* Mute DAC and ADC */
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x08);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x08, (Value | 0x03));
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x07);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x07, (Value | 0x03));
+
+ /* Disable soft ramp and zero cross */
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x06);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x06, (Value & 0xF0));
+
+ /* Set PDN to 1 */
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x02);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x02, (Value | 0x01));
+
+ /* Set all power down bits to 1 */
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x02, 0x7F);
+ Value = AUDIO_IO_Read(AUDIO_I2C_ADDRESS, 0x03);
+ AUDIO_IO_Write(AUDIO_I2C_ADDRESS, 0x03, (Value | 0x0E));
+
+ /* Power off the codec */
+ CODEC_AUDIO_POWER_OFF();
+
+}
+
+/**
+ * @brief Writes a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void AUDIO_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2C2_WriteBuffer(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1);
+}
+
+/**
+ * @brief Reads a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @retval Data to be read
+ */
+uint8_t AUDIO_IO_Read(uint8_t Addr, uint8_t Reg)
+{
+ uint8_t Read_Value = 0;
+
+ I2C2_ReadBuffer((uint16_t) Addr, (uint16_t) Reg, I2C_MEMADD_SIZE_8BIT, &Read_Value, 1);
+
+ return Read_Value;
+}
+
+/**
+ * @brief AUDIO Codec delay
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void AUDIO_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+
+
+
+/*************************** FMC Routines ************************************/
+/**
+ * @brief Initializes FMC_BANK1_LCD_IO MSP.
+ * @param None
+ * @retval None
+ */
+void FMC_BANK1_MspInit(void)
+{
+
+ GPIO_InitTypeDef GPIO_Init_Structure;
+
+ /* Enable FMC clock */
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ HAL_PWREx_EnableVddIO2();
+
+ GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP;
+ GPIO_Init_Structure.Pull = GPIO_PULLUP;
+ GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_Init_Structure.Alternate = GPIO_AF12_FMC;
+ /* GPIOD configuration */ /* GPIO_PIN_7 is FMC_NE1 */
+ GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | \
+ GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_7;
+
+ HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
+
+
+
+
+ /* GPIOE configuration */
+ GPIO_Init_Structure.Pin = GPIO_PIN_7 | \
+ GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | \
+ GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
+ HAL_GPIO_Init(GPIOE, &GPIO_Init_Structure);
+
+ /* GPIOD configuration */
+ GPIO_Init_Structure.Pin = GPIO_PIN_13 ;
+ HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
+
+}
+
+
+/**
+ * @brief Initializes LCD IO.
+ * @param None
+ * @retval None
+ */
+void FMC_BANK1_Init(void)
+{
+ SRAM_HandleTypeDef hsram;
+ FMC_NORSRAM_TimingTypeDef sram_timing;
+ FMC_NORSRAM_TimingTypeDef sram_timing_write;
+
+ /*** Configure the SRAM Bank 1 ***/
+ /* Configure IPs */
+ hsram.Instance = FMC_NORSRAM_DEVICE;
+ hsram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
+
+
+ /* Timing for READING */
+
+ sram_timing.AddressSetupTime = 1;
+ sram_timing.AddressHoldTime = 1;
+ sram_timing.DataSetupTime = 1;
+ sram_timing.BusTurnAroundDuration = 0;
+ sram_timing.CLKDivision = 2;
+ sram_timing.DataLatency = 2;
+ sram_timing.AccessMode = FMC_ACCESS_MODE_A;
+ /* Timing for WRITING */
+ sram_timing_write.AddressSetupTime = 5;
+ sram_timing_write.AddressHoldTime = 1;
+ sram_timing_write.DataSetupTime = 3;
+ sram_timing_write.BusTurnAroundDuration = 2;
+ sram_timing_write.CLKDivision = 2;
+ sram_timing_write.DataLatency = 2;
+ sram_timing_write.AccessMode = FMC_ACCESS_MODE_A;
+
+
+ hsram.Init.NSBank = FMC_NORSRAM_BANK1;
+ hsram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
+ hsram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
+ hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
+ hsram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
+ hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
+ hsram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
+ hsram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
+ hsram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
+ hsram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+ hsram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
+ hsram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
+ hsram.Init.PageSize = FMC_PAGE_SIZE_NONE;
+ hsram.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
+ hsram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
+ /* Initialize the SRAM controller */
+ FMC_BANK1_MspInit();
+ HAL_SRAM_Init(&hsram, &sram_timing, &sram_timing_write);
+
+}
+
+
+/**
+ * @brief DeInitializes FMC_BANK1_LCD_IO MSP.
+ * @param None
+ * @retval None
+ */
+void FMC_BANK1_MspDeInit(void)
+{
+
+ /* Enable FMC clock */
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+
+ HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | \
+ GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_7 | GPIO_PIN_13);
+
+
+
+ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_7 | \
+ GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | \
+ GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
+
+}
+
+
+/**
+ * @brief Writes register value.
+ * @param Data: Data to be written
+ * @retval None
+ */
+static void FMC_BANK1_WriteData(uint16_t Data)
+{
+ /* Write 16-bit Reg */
+ LCD_ADDR->REG = Data;
+}
+
+/**
+ * @brief Writes register address.
+ * @param Reg: Register to be written
+ * @retval None
+ */
+static void FMC_BANK1_WriteReg(uint8_t Reg)
+{
+ /* Write 16-bit Index, then write register */
+ FMC_BANK1_ADDR->REG = Reg;
+}
+
+/**
+ * @brief Reads register value.
+ * @param None
+ * @retval Read value
+ */
+static uint16_t FMC_BANK1_ReadData(void)
+{
+ return LCD_ADDR->REG;
+}
+
+/*******************************************************************************
+ LINK OPERATIONS
+*******************************************************************************/
+
+/********************************* LINK LCD ***********************************/
+
+/**
+ * @brief Initializes LCD low level.
+ * @param None
+ * @retval None
+ */
+void LCD_IO_Init(void)
+{
+ FMC_BANK1_Init();
+}
+
+/**
+ * @brief Writes data on LCD data register.
+ * @param Data: Data to be written
+ * @retval None
+ */
+void LCD_IO_WriteData(uint16_t RegValue)
+{
+ /* Write 16-bit Reg */
+ FMC_BANK1_WriteData(RegValue);
+}
+
+/**
+ * @brief Writes several data on LCD data register.
+ * @param Data: pointer on data to be written
+ * @param Size: data amount in 16bits short unit
+ * @retval None
+ */
+void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size)
+{
+ uint32_t i;
+
+ for (i = 0; i < Size; i++)
+ {
+ FMC_BANK1_WriteData(pData[i]);
+ }
+}
+
+/**
+ * @brief Writes register on LCD register.
+ * @param Reg: Register to be written
+ * @retval None
+ */
+void LCD_IO_WriteReg(uint8_t Reg)
+{
+ /* Write 16-bit Index, then Write Reg */
+ FMC_BANK1_WriteReg(Reg);
+}
+
+/**
+ * @brief Reads data from LCD data register.
+ * @param None
+ * @retval Read data.
+ */
+uint16_t LCD_IO_ReadData(void)
+{
+ return FMC_BANK1_ReadData();
+}
+
+/**
+ * @brief LCD delay
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void LCD_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+
+/************************** LINK TS (TouchScreen) *****************************/
+/**
+ * @brief Initializes Touchscreen low level.
+ * @retval None
+ */
+void TS_IO_Init(void)
+{
+ I2Cx_Init(&hI2cTSHandler);
+
+ if (ts_io_init == 0)
+ {
+ if (BSP_LCD_Init() == LCD_ERROR)
+ {
+ BSP_ErrorHandler();
+ }
+
+ BSP_IO_ConfigPin(TS_RST_PIN, IO_MODE_OUTPUT);
+
+ BSP_IO_WritePin(TS_RST_PIN, GPIO_PIN_RESET);
+ HAL_Delay(10);
+ BSP_IO_WritePin(TS_RST_PIN, GPIO_PIN_SET);
+ HAL_Delay(200);
+
+ ts_io_init = 1;
+ }
+}
+
+/**
+ * @brief Writes a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2Cx_WriteMultiple(&hI2cTSHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&Value, 1);
+}
+
+/**
+ * @brief Reads a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @retval Data to be read
+ */
+uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg)
+{
+ return I2C2_ReadData(Addr, Reg, I2C_MEMADD_SIZE_8BIT);
+}
+
+/**
+ * @brief Reads multiple data with I2C communication
+ * channel from TouchScreen.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval Number of read data
+ */
+uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ return I2Cx_ReadMultiple(&hI2cTSHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief Writes multiple data with I2C communication
+ * channel from MCU to TouchScreen.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval None
+ */
+void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ I2Cx_WriteMultiple(&hI2cTSHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief Delay function used in TouchScreen low level driver.
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void TS_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+
+/************************** Camera *****************************/
+/**
+ * @brief Initializes Camera low level.
+ * @retval None
+ */
+void CAMERA_IO_Init(void)
+{
+ I2Cx_Init(&hI2cCameraHandler);
+}
+
+/**
+ * @brief Camera writes single data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void CAMERA_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2Cx_WriteMultiple(&hI2cCameraHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&Value, 1);
+}
+
+/**
+ * @brief Camera reads single data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @retval Read data
+ */
+uint8_t CAMERA_IO_Read(uint8_t Addr, uint8_t Reg)
+{
+ uint8_t read_value = 0;
+
+ I2Cx_ReadMultiple(&hI2cCameraHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&read_value, 1);
+
+ return read_value;
+}
+
+/**
+ * @brief Camera delay
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void CAMERA_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+
+__weak uint8_t BSP_LCD_Init(void)
+{
+ uint8_t ret = 0;
+ return ret;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.h
new file mode 100644
index 0000000..4211be5
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery.h
@@ -0,0 +1,590 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery.h
+ * @author MCD Application Team
+ * @brief This file contains definitions for STM32L496G_DISCOVERY's LEDs,
+ * push-buttons hardware resources (MB1261).
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_H
+#define __STM32L496G_DISCOVERY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Define for STM32L496G_DISCOVERY board
+ */
+
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l4xx_hal.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_Common
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_Exported_Types Exported Types
+ * @{
+ */
+
+/**
+ * @brief LED Types Definition
+ */
+typedef enum
+{
+ LED1 = 0,
+ LED2 = 1,
+ LED_ORANGE = LED1,
+ LED_GREEN = LED2
+}
+Led_TypeDef;
+
+
+/**
+ * @brief JOYSTICK Types Definition
+ */
+typedef enum
+{
+ JOY_SEL = 0,
+ JOY_LEFT = 1,
+ JOY_RIGHT = 2,
+ JOY_DOWN = 3,
+ JOY_UP = 4,
+ JOY_NONE = 5
+} JOYState_TypeDef;
+
+typedef enum
+{
+ JOY_MODE_GPIO = 0,
+ JOY_MODE_EXTI = 1
+} JOYMode_TypeDef;
+
+typedef enum
+{
+ COM1 = 0
+} COM_TypeDef;
+
+/**
+ * @brief LCD constroller Types Definition
+ */
+typedef struct
+{
+ __IO uint16_t REG;
+ __IO uint16_t RAM;
+} LCD_CONTROLLER_TypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_Exported_Constants Exported Constants
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_FMC FMC LCD Constants
+ * @{
+ */
+/* We use BANK1 as we use FMC_NE1 signal */
+#define FMC_BANK1_BASE ((uint32_t)(0x60000000 | 0x00000000))
+#define FMC_LCD_BASE ((uint32_t)(0x60000000 | 0x00080000)) /*using A18*/
+#define FMC_BANK1_ADDR ((LCD_CONTROLLER_TypeDef *) FMC_BANK1_BASE)
+#define LCD_ADDR ((LCD_CONTROLLER_TypeDef *) FMC_LCD_BASE)
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LED LED Constants
+ * @{
+ */
+/* To do: invert LED1 and LED2 */
+#define LEDn 2
+
+/* LED1 is accessed thru the MFX */
+#define LED1_PIN IO1_PIN_4
+
+#define LED2_PIN GPIO_PIN_13
+#define LED2_GPIO_PORT GPIOB
+#define LED2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+#define LED2_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE()
+
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_BUTTON BUTTON Constants
+ * @{
+ */
+#define JOYn 5
+
+/**
+* @brief Joystick Right push-button
+*/
+#define RIGHT_JOY_PIN GPIO_PIN_11 /* PF.11 */
+#define RIGHT_JOY_GPIO_PORT GPIOF
+#define RIGHT_JOY_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
+#define RIGHT_JOY_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE()
+#define RIGHT_JOY_EXTI_IRQn EXTI15_10_IRQn
+
+/**
+* @brief Joystick Left push-button
+*/
+#define LEFT_JOY_PIN GPIO_PIN_9 /* PI.09 */
+#define LEFT_JOY_GPIO_PORT GPIOI
+#define LEFT_JOY_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define LEFT_JOY_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#define LEFT_JOY_EXTI_IRQn EXTI9_5_IRQn
+
+/**
+* @brief Joystick Up push-button
+*/
+#define UP_JOY_PIN GPIO_PIN_8 /* PI.08 */
+#define UP_JOY_GPIO_PORT GPIOI
+#define UP_JOY_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define UP_JOY_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#define UP_JOY_EXTI_IRQn EXTI9_5_IRQn
+
+/**
+ * @brief Joystick Down push-button
+ */
+#define DOWN_JOY_PIN GPIO_PIN_10 /* PI.10 */
+#define DOWN_JOY_GPIO_PORT GPIOI
+#define DOWN_JOY_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define DOWN_JOY_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#define DOWN_JOY_EXTI_IRQn EXTI15_10_IRQn
+
+/**
+ * @brief Joystick Sel push-button
+ */
+#define SEL_JOY_PIN GPIO_PIN_13 /* PC.13 */
+#define SEL_JOY_GPIO_PORT GPIOC
+#define SEL_JOY_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
+#define SEL_JOY_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
+#define SEL_JOY_EXTI_IRQn EXTI15_10_IRQn
+
+#define JOYx_GPIO_CLK_ENABLE(__JOY__) do { if((__JOY__) == JOY_SEL) { SEL_JOY_GPIO_CLK_ENABLE(); } else \
+ if((__JOY__) == JOY_DOWN) { DOWN_JOY_GPIO_CLK_ENABLE(); } else \
+ if((__JOY__) == JOY_LEFT) { LEFT_JOY_GPIO_CLK_ENABLE(); } else \
+ if((__JOY__) == JOY_RIGHT) { RIGHT_JOY_GPIO_CLK_ENABLE(); } else \
+ if((__JOY__) == JOY_UP) { UP_JOY_GPIO_CLK_ENABLE(); } } while(0)
+
+#define JOYx_GPIO_CLK_DISABLE(__JOY__) do { if((__JOY__) == JOY_SEL) { SEL_JOY_GPIO_CLK_DISABLE(); } else \
+ if((__JOY__) == JOY_DOWN) { DOWN_JOY_GPIO_CLK_DISABLE(); } else \
+ if((__JOY__) == JOY_LEFT) { LEFT_JOY_GPIO_CLK_DISABLE(); } else \
+ if((__JOY__) == JOY_RIGHT) { RIGHT_JOY_GPIO_CLK_DISABLE(); } else \
+ if((__JOY__) == JOY_UP) { UP_JOY_GPIO_CLK_DISABLE(); } } while(0)
+
+#define JOY_ALL_PINS (RIGHT_JOY_PIN | LEFT_JOY_PIN | UP_JOY_PIN | DOWN_JOY_PIN | SEL_JOY_PIN)
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L4R9I_DISCOVERY_COM COM Constants
+ * @{
+ */
+#define COMn 1
+
+/**
+ * @brief Definition for COM port1, connected to USART2 (ST-Link USB Virtual Com Port)
+ */
+#define DISCOVERY_COM1 USART2
+#define DISCOVERY_COM1_CLK_ENABLE() __HAL_RCC_USART2_CLK_ENABLE()
+#define DISCOVERY_COM1_CLK_DISABLE() __HAL_RCC_USART2_CLK_DISABLE()
+
+#define DISCOVERY_COM1_TX_PIN GPIO_PIN_2
+#define DISCOVERY_COM1_TX_GPIO_PORT GPIOA
+#define DISCOVERY_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
+#define DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE()
+#define DISCOVERY_COM1_TX_AF GPIO_AF7_USART2
+
+#define DISCOVERY_COM1_RX_PIN GPIO_PIN_6
+#define DISCOVERY_COM1_RX_GPIO_PORT GPIOD
+#define DISCOVERY_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+#define DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
+#define DISCOVERY_COM1_RX_AF GPIO_AF7_USART2
+
+#define DISCOVERY_COM1_IRQn USART2_IRQn
+
+
+#define DISCOVERY_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_CLK_ENABLE();}} while(0)
+#define DISCOVERY_COMx_CLK_DISABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_CLK_DISABLE();}} while(0)
+
+#define DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_TX_GPIO_CLK_ENABLE();}} while(0)
+#define DISCOVERY_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_TX_GPIO_CLK_DISABLE();}} while(0)
+
+#define DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_RX_GPIO_CLK_ENABLE();}} while(0)
+#define DISCOVERY_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_RX_GPIO_CLK_DISABLE();}} while(0)
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_BUS BUS Constants
+ * @{
+ */
+
+#if defined(HAL_I2C_MODULE_ENABLED)
+/*##################### I2C1 ###################################*/
+/* User can use this section to tailor I2C1 instance used and associated
+ resources */
+/* Definition for I2C1 Pins */
+#define DISCOVERY_I2C1_SCL_GPIO_PORT GPIOG
+#define DISCOVERY_I2C1_SDA_GPIO_PORT GPIOG
+#define DISCOVERY_I2C1_SCL_PIN GPIO_PIN_14
+#define DISCOVERY_I2C1_SDA_PIN GPIO_PIN_13
+
+#define DISCOVERY_I2C1_SCL_SDA_AF GPIO_AF4_I2C1
+
+/* Definition for I2C1 clock resources */
+#define DISCOVERY_I2C1 I2C1
+#define DISCOVERY_I2C1_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
+#define DISCOVERY_I2C1_CLK_DISABLE() __HAL_RCC_I2C1_CLK_DISABLE()
+#define DISCOVERY_I2C1_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
+#define DISCOVERY_I2C1_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
+#define DISCOVERY_I2C1_SDA_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()
+#define DISCOVERY_I2C1_SCL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()
+#define DISCOVERY_I2C1_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
+#define DISCOVERY_I2C1_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
+
+/* Definition for I2C1's NVIC */
+#define DISCOVERY_I2C1_EV_IRQn I2C1_EV_IRQn
+#define DISCOVERY_I2C1_EV_IRQHandler I2C1_EV_IRQHandler
+#define DISCOVERY_I2C1_ER_IRQn I2C1_ER_IRQn
+#define DISCOVERY_I2C1_ER_IRQHandler I2C1_ER_IRQHandler
+
+/* I2C TIMING Register define when I2C clock source is SYSCLK */
+/* I2C TIMING is calculated in case of the I2C Clock source is the SYSCLK = 80 MHz */
+/* Set 0x90112626 value to reach 100 KHz speed (Rise time = 640ns, Fall time = 20ns) */
+#ifndef DISCOVERY_I2C1_TIMING
+#define DISCOVERY_I2C1_TIMING 0x90D00e28/* 0x90112626*/
+#endif /* DISCOVERY_I2C1_TIMING */
+
+/* I2C clock speed configuration (in Hz)
+ WARNING:
+ Make sure that this define is not already declared in other files (ie.
+ stm324xg_discovery.h file). It can be used in parallel by other modules. */
+#ifndef BSP_I2C_SPEED
+#define BSP_I2C_SPEED 100000
+#endif /* BSP_I2C_SPEED */
+
+/* Maximum Timeout values for flags waiting loops. These timeouts are not based
+ on accurate values, they just guarantee that the application will not remain
+ stuck if the I2C communication is corrupted.
+ You may modify these timeout values depending on CPU frequency and application
+ conditions (interrupts routines ...). */
+#define DISCOVERY_I2C1_TIMEOUT_MAX 3000
+
+
+/*##################### I2C2 ###################################*/
+/* User can use this section to tailor I2C2 instance used and associated
+ resources */
+/* Definition for I2C2 Pins */
+#define DISCOVERY_I2C2_SCL_PIN GPIO_PIN_4
+#define DISCOVERY_I2C2_SCL_GPIO_PORT GPIOH
+#define DISCOVERY_I2C2_SDA_PIN GPIO_PIN_14
+#define DISCOVERY_I2C2_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_I2C2_SCL_SDA_AF GPIO_AF4_I2C2
+/* Definition for I2C2 clock resources */
+#define DISCOVERY_I2C2 I2C2
+#define DISCOVERY_I2C2_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE()
+#define DISCOVERY_I2C2_CLK_DISABLE() __HAL_RCC_I2C2_CLK_DISABLE()
+#define DISCOVERY_I2C2_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+#define DISCOVERY_I2C2_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define DISCOVERY_I2C2_SDA_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE()
+#define DISCOVERY_I2C2_SCL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+#define DISCOVERY_I2C2_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET()
+#define DISCOVERY_I2C2_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET()
+
+/* Definition for I2C2's NVIC */
+#define DISCOVERY_I2C2_EV_IRQn I2C2_EV_IRQn
+#define DISCOVERY_I2C2_ER_IRQn I2C2_ER_IRQn
+
+/* I2C TIMING Register define when I2C clock source is SYSCLK */
+/* I2C TIMING is calculated in case of the I2C Clock source is the SYSCLK = 80 MHz */
+/* Set 0x90112626 value to reach 100 KHz speed (Rise time = 25ns, Fall time = 10ns) */
+#ifndef DISCOVERY_I2C2_TIMING
+#define DISCOVERY_I2C2_TIMING 0x40403E5D
+#endif /* DISCOVERY_I2C2_TIMING */
+
+#define IDD_I2C_ADDRESS ((uint16_t) 0x84)
+#define IO1_I2C_ADDRESS ((uint16_t) 0x84)
+#define AUDIO_I2C_ADDRESS ((uint16_t) 0x94)
+#define TS_I2C_ADDRESS ((uint16_t) 0x70)
+#define CAMERA_I2C_ADDRESS ((uint16_t) 0x60)
+
+/* Maximum Timeout values for flags waiting loops. These timeouts are not based
+ on accurate values, they just guarantee that the application will not remain
+ stuck if the I2C communication is corrupted.
+ You may modify these timeout values depending on CPU frequency and application
+ conditions (interrupts routines ...). */
+#define DISCOVERY_I2C2_TIMEOUT_MAX 3000
+
+
+#ifndef DISCOVERY_I2C_TIMING
+#define DISCOVERY_I2C_TIMING /*0x90D00e28*/ 0x90112626
+#endif /* DISCOVERY_I2C2_TIMING */
+
+/* Written here after to enable compilation only, to be thoroughly reviewed */
+
+/* Definition for AUDIO I2Cx resources */
+#define DISCOVERY_AUDIO_I2Cx I2C1
+#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
+#define DISCOVERY_AUDIO_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+
+#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
+#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
+
+/* Definition for I2Cx Pins */
+#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_6
+#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1
+#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_7
+
+/* I2C interrupt requests */
+#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C1_EV_IRQn
+#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C1_ER_IRQn
+
+
+/* Definition for TS (Capacitive Touch Panel) I2Cx resources */
+#define DISCOVERY_TS_I2Cx I2C2
+#define DISCOVERY_TS_I2Cx_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE()
+#define DISCOVERY_TS_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define DISCOVERY_TS_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+#define DISCOVERY_TS_I2Cx_SDA_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE()
+#define DISCOVERY_TS_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define DISCOVERY_TS_I2Cx_SCL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+
+#define DISCOVERY_TS_I2Cx_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET()
+#define DISCOVERY_TS_I2Cx_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET()
+
+/* Definition for I2Cx Pins */
+#define DISCOVERY_TS_I2Cx_SCL_PIN GPIO_PIN_4
+#define DISCOVERY_TS_I2Cx_SCL_GPIO_PORT GPIOH
+#define DISCOVERY_TS_I2Cx_SDA_PIN GPIO_PIN_14
+#define DISCOVERY_TS_I2Cx_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_TS_I2Cx_SCL_SDA_AF GPIO_AF4_I2C2
+
+/* I2C interrupt requests */
+#define DISCOVERY_TS_I2Cx_EV_IRQn I2C2_EV_IRQn
+#define DISCOVERY_TS_I2Cx_ER_IRQn I2C2_ER_IRQn
+
+/* I2C clock setting */
+#define DISCOVERY_TS_RCC_PERIPHCLK_I2C RCC_PERIPHCLK_I2C2
+#define DISCOVERY_TS_RCC_CLKSOURCE_I2C RCC_I2C2CLKSOURCE_SYSCLK
+
+
+
+/* Definition for Camera I2Cx resources */
+#define DISCOVERY_CAMERA_I2Cx I2C2
+#define DISCOVERY_CAMERA_I2Cx_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE()
+#define DISCOVERY_CAMERA_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define DISCOVERY_CAMERA_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+#define DISCOVERY_CAMERA_I2Cx_SDA_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE()
+#define DISCOVERY_CAMERA_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define DISCOVERY_CAMERA_I2Cx_SCL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+
+#define DISCOVERY_CAMERA_I2Cx_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET()
+#define DISCOVERY_CAMERA_I2Cx_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET()
+
+/* Definition for I2Cx Pins */
+#define DISCOVERY_CAMERA_I2Cx_SCL_PIN GPIO_PIN_4
+#define DISCOVERY_CAMERA_I2Cx_SCL_GPIO_PORT GPIOH
+#define DISCOVERY_CAMERA_I2Cx_SDA_PIN GPIO_PIN_14
+#define DISCOVERY_CAMERA_I2Cx_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_CAMERA_I2Cx_SCL_SDA_AF GPIO_AF4_I2C2
+
+/* I2C interrupt requests */
+#define DISCOVERY_CAMERA_I2Cx_EV_IRQn I2C2_EV_IRQn
+#define DISCOVERY_CAMERA_I2Cx_ER_IRQn I2C2_ER_IRQn
+
+/* I2C clock setting */
+#define DISCOVERY_CAMERA_RCC_PERIPHCLK_I2C RCC_PERIPHCLK_I2C2
+#define DISCOVERY_CAMERA_RCC_CLKSOURCE_I2C RCC_I2C2CLKSOURCE_SYSCLK
+
+
+
+
+
+/* Definition for external, camera and Arduino connector I2Cx resources */ /* to be reviewed */
+#define DISCOVERY_EXT_I2Cx I2C2
+#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE()
+#define DISCOVERY_EXT_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+
+#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET()
+#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET()
+
+/* Definition for I2Cx Pins */
+#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_10
+#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_EXT_I2Cx_SCL_AF GPIO_AF4_I2C2
+#define DISCOVERY_EXT_I2Cx_SDA_AF GPIO_AF4_I2C2
+#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_9
+
+/* I2C interrupt requests */
+#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C2_EV_IRQn
+#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C2_ER_IRQn
+
+#ifndef DISCOVERY_I2C_SPEED
+#define DISCOVERY_I2C_SPEED 100000
+#endif /* DISCOVERY_I2C_SPEED */
+
+
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+
+
+/*##################### Audio Codec ##########################*/
+/**
+ * @brief Audio codec chip reset definition
+ */
+/* Audio codec power on/off macro definition */
+#define CODEC_AUDIO_POWER_OFF() HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_RESET)
+#define CODEC_AUDIO_POWER_ON() HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_SET)
+
+/* Audio Reset Pin definition */
+#define AUDIO_RESET_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
+#define AUDIO_RESET_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
+#define AUDIO_RESET_PIN GPIO_PIN_6
+#define AUDIO_RESET_GPIO GPIOC
+
+
+
+
+/*##################### MFX ##########################*/
+/**
+ * @brief MFX interface pins
+ */
+
+#define MFX_INT_GPIO_PORT GPIOC /* GPIOC */
+#define MFX_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
+#define MFX_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
+#define MFX_INT_PIN GPIO_PIN_5 /* PC.05 */
+#define MFX_INT_EXTI_IRQn EXTI9_5_IRQn
+
+#define MFX_WAKEUP_GPIO_PORT GPIOH /* GPIOH */
+#define MFX_WAKEUP_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define MFX_WAKEUP_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+#define MFX_WAKEUP_PIN GPIO_PIN_6 /* PH.06 */
+
+
+
+/* Legacy */
+#define IDD_INT_GPIO_PORT MFX_INT_GPIO_PORT
+#define IDD_INT_GPIO_CLK_ENABLE() MFX_INT_GPIO_CLK_ENABLE()
+#define IDD_INT_GPIO_CLK_DISABLE() MFX_INT_GPIO_CLK_DISABLE()
+#define IDD_INT_PIN MFX_INT_PIN
+#define IDD_INT_EXTI_IRQn MFX_INT_EXTI_IRQn
+#define IDD_WAKEUP_GPIO_PORT MFX_WAKEUP_GPIO_PORT
+#define IDD_WAKEUP_GPIO_CLK_ENABLE() MFX_WAKEUP_GPIO_CLK_ENABLE()
+#define IDD_WAKEUP_GPIO_CLK_DISABLE() MFX_WAKEUP_GPIO_CLK_DISABLE()
+#define IDD_WAKEUP_PIN MFX_WAKEUP_PIN
+
+
+/**
+ * @brief Idd current measurement interface pins on MFX
+ */
+#define IDD_AMP_CONTROL_PIN AGPIO_PIN_1
+
+/**
+ * @brief TS INT pin
+ */
+#define TS_INT_PIN GPIO_PIN_14
+#define TS_INT_GPIO_PORT GPIOG
+#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
+#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()
+#define TS_INT_EXTI_IRQn EXTI15_10_IRQn
+
+/**
+ * @brief TS RST pin
+ */
+/* TS RST is accessed thru the MFX */
+#define TS_RST_PIN IO1_PIN_1
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup STM32L496G_DISCOVERY_Exported_Functions Exported Functions
+ * @{
+ */
+uint32_t BSP_GetVersion(void);
+void BSP_LED_Init(Led_TypeDef Led);
+void BSP_LED_DeInit(Led_TypeDef Led);
+void BSP_LED_On(Led_TypeDef Led);
+void BSP_LED_Off(Led_TypeDef Led);
+void BSP_LED_Toggle(Led_TypeDef Led);
+uint8_t BSP_JOY_Init(JOYMode_TypeDef Joy_Mode);
+void BSP_JOY_DeInit(void);
+JOYState_TypeDef BSP_JOY_GetState(void);
+#if defined(HAL_UART_MODULE_ENABLED)
+void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *husart);
+void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart);
+#endif /* HAL_UART_MODULE_ENABLED */
+
+/* These __weak functions can be surcharged by application code for specific application needs */
+void BSP_ErrorHandler(void);
+
+
+void FMC_BANK1_MspInit(void);
+void FMC_BANK1_MspDeInit(void);
+#if defined(HAL_I2C_MODULE_ENABLED)
+void I2C2_Init(void);
+void I2C2_DeInit(void);
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.c
new file mode 100644
index 0000000..380ea5b
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.c
@@ -0,0 +1,2097 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_audio.c
+ * @author MCD Application Team
+ * @brief This file provides a set of functions needed to manage the
+ * Audio driver for the STM32L496G-Discovery board.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/*==============================================================================
+ User NOTES
+
+1. How To use this driver:
+--------------------------
+ + This driver supports STM32L4xx devices on STM32L496G-Discovery (MB1261) Discovery boards.
+ a) to play an audio file through headset. All functions names start by BSP_AUDIO_OUT_xxx.
+ b) to record an audio file through digital microphones (MP34DT01TR ST mems)
+ or analog microphone (headset microphone). All functions names start by BSP_AUDIO_IN_xxx.
+
+a) PLAY A FILE:
+==============
+ + Call the function BSP_AUDIO_OUT_Init(
+ OutputDevice: physical output mode (only OUTPUT_DEVICE_HEADPHONE).
+ Volume : Initial volume to be set (0 is min (mute), 100 is max (100%)
+ AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...)
+ this parameter is relative to the audio file/stream type.
+ )
+ This function configures all the hardware required for the audio application (codec, I2C, SAI,
+ GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK.
+ If the returned value is different from AUDIO_OK or the function is stuck then the communication with
+ the audio codec has failed.
+ - OUTPUT_DEVICE_HEADPHONE: only Headphone output is available on this board.
+
+ + Call the function BSP_AUDIO_OUT_RegisterCallbacks to register user callbacks
+ required to manage audio data streaming towards the audio codec (ErrorCallback(),
+ HalfTransfer_CallBack() and TransferComplete_CallBack()).
+
+ + Call the function BSP_AUDIO_OUT_Play() to start audio playback (for the first time).
+ + Call the function BSP_AUDIO_OUT_Pause() to pause audio playback.
+ + Call the function BSP_AUDIO_OUT_Resume() to resume audio playback.
+ Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
+ for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
+ Note. This function should be called only when the audio file is played or paused (not stopped).
+ + Call the function BSP_AUDIO_OUT_Stop() to stop audio playback.
+ + To modify the volume level, the sampling frequency, the device output mode,
+ the mute status or the audio configuration or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(),
+ AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetOutputMode(), BSP_AUDIO_OUT_SetMute()and
+ BSP_AUDIO_OUT_ChangeAudioConfig().
+
+Driver architecture:
+--------------------
+ + This driver provides the audio layer high level API: it consists in functions
+ exported in the stm32l496g_discovery_audio.h file (e.g. BSP_AUDIO_OUT_Init(),
+ BSP_AUDIO_OUT_Play(), ...).
+ + This driver also includes the Media Access Layer (MAL): it consists in
+ functions allowing to access setup the audio devices. These functions
+ are included as local functions into the stm32l496g_discovery_audio.c file
+ (e.g. AUDIO_SAIx_Init()).
+
+Known Limitations:
+------------------
+ 1- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some
+ user interrupt routines (in this case, interrupts could be disabled just before the start of
+ communication then re-enabled when it is over). Note that this communication is only done at
+ the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is
+ performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()).
+ When the audio data is played, no communication is required with the audio codec.
+ 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size,
+ File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
+ 3- Supports only 16-bits audio data size.
+
+b) RECORD A FILE:
+================
+ + Call the function BSP_AUDIO_IN_InitEx(
+ InputDevice: physical input mode (INPUT_DEVICE_DIGITAL_MIC
+ INPUT_DEVICE_DIGITAL_MIC1, INPUT_DEVICE_DIGITAL_MIC2
+ or INPUT_DEVICE_ANALOG_MIC)
+ AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...)
+ )
+ This function configures all the hardware required for the audio application (DFSDM or SAI,
+ GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if the
+ configuration completes successfully.
+ - INPUT_DEVICE_DIGITAL_MIC: Record from digital microphones mounted on board.
+ - INPUT_DEVICE_DIGITAL_MIC1: Record from digital microphone 1 mounted on board (left microphone).
+ - INPUT_DEVICE_DIGITAL_MIC2: Record from digital microphone 2 mounted on board (right microphone).
+ - INPUT_DEVICE_ANALOG_MIC: Record from headset microphone.
+
+ + Call the function BSP_AUDIO_IN_RegisterCallbacks to register user callbacks
+ used to stream audio data toward the record buffer (ErrorCallback(),
+ HalfTransfer_CallBack() and TransferComplete_CallBack()).
+
+ + Call the function BSP_AUDIO_IN_Record(
+ pbuf Main buffer pointer for the recorded data storing
+ size Current size of the recorded buffer
+ )
+ to start recording from the microphone.
+
+ + Call the function BSP_AUDIO_IN_STOP() to stop recording.
+==============================================================================*/
+
+/* Includes ------------------------------------------------------------------*/
+#include
+#include "stm32l496g_discovery_audio.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_AUDIO STM32L496G-DISCOVERY AUDIO
+ * @brief This file includes the low layer driver for cs42l51 Audio Codec
+ * available on STM32L496G-Discovery board (MB1261).
+ * @{
+ */
+
+/* Private typedef -----------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Types Private Types
+ * @{
+ */
+typedef struct
+{
+ AUDIO_DrvTypeDef *AudioDrv; /* Audio codec driver */
+ uint32_t OutputDevice; /* Output device */
+ uint32_t Frequency; /* Playback frequency */
+ uint32_t Volume; /* Playback volume */
+ Audio_CallbackTypeDef CbError; /* pointer to the callback function invoked when error occurs */
+ Audio_CallbackTypeDef CbHalfTransfer; /* pointer to the callback function invoked when half transfer occurs */
+ Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when transfer complete occurs */
+} AUDIO_OUT_TypeDef;
+
+typedef struct
+{
+ AUDIO_DrvTypeDef *AudioDrv; /* Audio codec driver */
+ DFSDM_Channel_HandleTypeDef hDfsdmLeftChannel; /* DFSDM channel handle used for left channel */
+ DFSDM_Channel_HandleTypeDef hDfsdmRightChannel; /* DFSDM channel handle used for right channel */
+ DMA_HandleTypeDef hDmaDfsdmLeft; /* DMA handle used for DFSDM regular conversions on left channel */
+ DMA_HandleTypeDef hDmaDfsdmRight; /* DMA handle used for DFSDM regular conversions on right channel */
+ int32_t *LeftRecBuff; /* Buffers for left samples */
+ int32_t *RightRecBuff; /* Buffers for right samples */
+ uint32_t InputDevice; /* Input device */
+ uint32_t Frequency; /* Record Frequency */
+ uint32_t BitResolution; /* Record bit resolution */
+ uint32_t ChannelNbr; /* Record Channel Number */
+ uint16_t *pRecBuf; /* Pointer to record user buffer */
+ uint32_t RecSize; /* Size to record in mono, double size to record in stereo */
+ Audio_CallbackTypeDef CbError; /* pointer to the callback function invoked when a DMA transfer fails */
+ Audio_CallbackTypeDef CbHalfTransfer; /* pointer to the callback function invoked when half of the DMA transfer is completed */
+ Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when the DMA transfer is completed */
+} AUDIO_IN_TypeDef;
+
+/**
+ * @}
+ */
+
+/* Private defines ------------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Constants Private Constants
+ * @{
+ */
+/**
+ * @}
+ */
+
+/* Private macros ------------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Macros Private Macros
+ * @{
+ */
+/*### PLAY ###*/
+/* SCK(kHz) = SAI_CK_x/(SAIClockDivider*2*256) */
+#define SAIClockDivider(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 12 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 2 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 1 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 2 : 1 \
+
+/*### RECORD ###*/
+#define DFSDMOverSampling(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 256 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 16 \
+
+#define DFSDMClockDivider(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 32 \
+
+#define DFSDMFilterOrder(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC4_ORDER : DFSDM_FILTER_SINC5_ORDER \
+
+#define DFSDMRightBitShift(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 8 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 8 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 6 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 8 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 2 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 4 : 4 \
+
+/* Saturate the record PCM sample */
+#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
+
+/**
+ * @}
+ */
+
+/* Private variables ---------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Variables Private Variables
+ * @{
+ */
+/* Audio output context information */
+static AUDIO_OUT_TypeDef hAudioOut = {0};
+
+/* Audio input context information */
+static AUDIO_IN_TypeDef hAudioIn = {0};
+
+/* SAI DMA handle */
+static DMA_HandleTypeDef hDmaSaiTx;
+static DMA_HandleTypeDef hDmaSaiRx;
+
+static uint32_t DmaLeftRecHalfBuffCplt;
+static uint32_t DmaLeftRecBuffCplt;
+static uint32_t DmaRightRecHalfBuffCplt;
+static uint32_t DmaRightRecBuffCplt;
+
+
+/**
+ * @}
+ */
+
+/* Exported variables ---------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Variables Exported Variables
+ * @{
+ */
+/* SAIx handle */
+SAI_HandleTypeDef BSP_AUDIO_hSai_Tx;
+SAI_HandleTypeDef BSP_AUDIO_hSai_Rx;
+
+/* DFSDM filter handle */
+DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmLeftFilter;
+DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmRightFilter;
+/**
+ * @}
+ */
+
+/* Private function prototypes -----------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Functions Private Functions
+ * @{
+ */
+static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq);
+static uint8_t AUDIO_SAIx_DeInit(void);
+static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq);
+static uint8_t AUDIO_DFSDMx_DeInit(void);
+static uint8_t AUDIO_SAIPLLConfig(uint32_t AudioFreq);
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Exported_Functions
+ * @{
+ */
+
+/**
+ * @brief Configures the audio codec related peripherals.
+ * @param OutputDevice: OUTPUT_DEVICE_HEADPHONE.
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval BSP AUDIO status
+ * @note The SAI PLL input clock must be configure in the user application.
+ * The SAI PLL configuration done within this function assumes that
+ * the SAI PLL input clock runs at 8 MHz.
+ */
+uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice,
+ uint8_t Volume,
+ uint32_t AudioFreq)
+{
+ /* Initialize the audio output context */
+ hAudioOut.AudioDrv = &cs42l51_drv;
+ hAudioOut.OutputDevice = OutputDevice;
+ hAudioOut.Frequency = AudioFreq;
+ hAudioOut.Volume = Volume;
+ hAudioOut.CbError = (Audio_CallbackTypeDef)NULL;
+ hAudioOut.CbHalfTransfer = (Audio_CallbackTypeDef)NULL;
+ hAudioOut.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
+
+ /* Check if input device is currently used */
+ if (hAudioIn.InputDevice != 0)
+ {
+ /* If input device is currently used, SAI PLL is already initialized */
+ /* Check that AudioFreq for record and playback is the same */
+ if (hAudioIn.Frequency != hAudioOut.Frequency)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* Configure the SAI PLL according to the requested audio frequency */
+ if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* If input device is analogic mic, SAI is already initialized */
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* SAI data transfer preparation: prepare the Media to be used for the audio
+ transfer from memory to SAI peripheral. */
+ if (AUDIO_SAIx_Init(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Initialize the audio codec internal registers */
+ if (hAudioOut.AudioDrv->Init(AUDIO_I2C_ADDRESS,
+ (hAudioOut.OutputDevice | hAudioIn.InputDevice),
+ Volume,
+ AudioFreq) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief De-Initializes audio codec related peripherals
+ * @retval BSP AUDIO status
+
+ */
+uint8_t BSP_AUDIO_OUT_DeInit(void)
+{
+ if (hAudioIn.InputDevice == INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* Reset playback path on audio codec */
+ if (hAudioIn.AudioDrv->Init(AUDIO_I2C_ADDRESS,
+ hAudioIn.InputDevice,
+ (uint8_t) hAudioOut.Volume,
+ hAudioIn.Frequency) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* De-initializes SAI interface */
+ if (AUDIO_SAIx_DeInit() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* DeInit audio codec */
+ hAudioOut.AudioDrv->DeInit();
+ }
+
+ /* Disable SAI PLL if no more device is used */
+ if (hAudioIn.InputDevice == 0)
+ {
+ if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Reset the audio output context */
+ memset(&hAudioOut, 0, sizeof(hAudioOut));
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Starts playing audio stream from a data buffer for a determined size.
+ * @param pData: pointer on PCM samples buffer
+ * @param Size: Number of audio data HALF WORD.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_Play(uint16_t *pData, uint32_t Size)
+{
+ /* Initiate a DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai_Tx, (uint8_t *)pData, DMA_MAX(Size)) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the audio Codec Play function */
+ if (hAudioOut.AudioDrv->Play(AUDIO_I2C_ADDRESS, pData, Size) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Sends n-Bytes on the SAI interface.
+ * @param pData: pointer on PCM samples buffer
+ * @param Size: number of data to be written
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
+{
+ /* Initiate a DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai_Tx, (uint8_t *)pData, Size) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief This function Pauses the audio file stream. In case
+ * of using DMA, the DMA Pause feature is used.
+ * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
+ * BSP_AUDIO_OUT_Resume() function should be called for resume
+ * (use of BSP_AUDIO_OUT_Play() function for resume could lead
+ * to unexpected behavior).
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_Pause(void)
+{
+ /* Call the Audio Codec Pause function */
+ if (hAudioOut.AudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Pause DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAPause(&BSP_AUDIO_hSai_Tx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief This function Resumes the audio file stream.
+ * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
+ * BSP_AUDIO_OUT_Resume() function should be called for resume
+ * (use of BSP_AUDIO_OUT_Play() function for resume could lead to
+ * unexpected behavior).
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_Resume(void)
+{
+ /* Call the Audio Codec Resume function */
+ if (hAudioOut.AudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Resume DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAResume(&BSP_AUDIO_hSai_Tx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Stops audio playing and Power down the Audio Codec.
+ * @param Option: could be one of the following parameters
+ * - CODEC_PDWN_SW: for software power off (by writing registers).
+ * Then no need to reconfigure the Codec after power on.
+ * - CODEC_PDWN_HW: completely shut down the codec (physically).
+ * Then need to reconfigure the Codec after power on.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(Option);
+
+ /* Call Audio Codec Stop function */
+ if (hAudioOut.AudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Wait at least 100ms */
+ HAL_Delay(100);
+
+ /* Stop DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAStop(&BSP_AUDIO_hSai_Tx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Controls the current audio volume level.
+ * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for
+ * Mute and 100 for Max volume level).
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
+{
+ /* Call the codec volume control function with converted volume value */
+ if (hAudioOut.AudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ hAudioOut.Volume = Volume;
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Enables or disables the MUTE mode by software
+ * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
+ * unmute the codec and restore previous volume level.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
+{
+ /* Call the Codec Mute function */
+ if (hAudioOut.AudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Switch dynamically (while audio file is being played) the output
+ * target (speaker or headphone).
+ * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER,
+ * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
+{
+ /* Call the Codec output device function */
+ if (hAudioOut.AudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Updates the audio frequency.
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @note The SAI PLL input clock must be configure in the user application.
+ * The SAI PLL configuration done within this function assumes that
+ * the SAI PLL input clock runs at 8 MHz.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
+{
+ uint8_t TxData[2] = {0x00, 0x00};
+
+ /* Configure the SAI PLL according to the requested audio frequency */
+ if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
+
+ /* Update the SAI audio frequency configuration */
+ BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
+ BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Rx);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
+ /* Transmit one byte to start FS generation */
+ if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ hAudioOut.Frequency = AudioFreq;
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Changes the Audio Out Configuration.
+ * @param AudioOutOption: specifies the audio out new configuration
+ * This parameter can be any value of @ref BSP_Audio_Out_Option
+ * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
+ * audio out configuration.
+ * @retval None
+ */
+void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption)
+{
+ uint8_t TxData[2] = {0x00, 0x00};
+
+ /********** Playback Buffer circular/normal mode **********/
+ if (AudioOutOption & BSP_AUDIO_OUT_CIRCULARMODE)
+ {
+ /* Deinitialize the Stream to update DMA mode */
+ HAL_DMA_DeInit(BSP_AUDIO_hSai_Tx.hdmatx);
+
+ /* Update the SAI audio Transfer DMA mode */
+ BSP_AUDIO_hSai_Tx.hdmatx->Init.Mode = DMA_CIRCULAR;
+
+ /* Configure the DMA Stream with new Transfer DMA mode */
+ HAL_DMA_Init(BSP_AUDIO_hSai_Tx.hdmatx);
+ }
+ else /* BSP_AUDIO_OUT_NORMALMODE */
+ {
+ /* Deinitialize the Stream to update DMA mode */
+ HAL_DMA_DeInit(BSP_AUDIO_hSai_Tx.hdmatx);
+
+ /* Update the SAI audio Transfer DMA mode */
+ BSP_AUDIO_hSai_Tx.hdmatx->Init.Mode = DMA_NORMAL;
+
+ /* Configure the DMA Stream with new Transfer DMA mode */
+ HAL_DMA_Init(BSP_AUDIO_hSai_Tx.hdmatx);
+ }
+
+ /********** Playback Buffer stereo/mono mode **********/
+ if (AudioOutOption & BSP_AUDIO_OUT_STEREOMODE)
+ {
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+
+ /* Update the SAI audio frame slot configuration */
+ BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_STEREOMODE;
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
+ /* Transmit one byte to start FS generation */
+ HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000);
+ }
+ else /* BSP_AUDIO_OUT_MONOMODE */
+ {
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+
+ /* Update the SAI audio frame slot configuration */
+ BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_MONOMODE;
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
+ /* Transmit one byte to start FS generation */
+ HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000);
+ }
+}
+
+/**
+ * @brief register user callback functions
+ * @param ErrorCallback: pointer to the error callback function
+ * @param HalfTransferCallback: pointer to the half transfer callback function
+ * @param TransferCompleteCallback: pointer to the transfer complete callback function
+ * @retval None
+ */
+void BSP_AUDIO_OUT_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
+ Audio_CallbackTypeDef HalfTransferCallback,
+ Audio_CallbackTypeDef TransferCompleteCallback)
+{
+ hAudioOut.CbError = ErrorCallback;
+ hAudioOut.CbHalfTransfer = HalfTransferCallback;
+ hAudioOut.CbTransferComplete = TransferCompleteCallback;
+}
+
+/**
+ * @brief Tx Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Invoke the registered 'TransferComplete' function (if any) */
+ if (hAudioOut.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioOut.CbTransferComplete();
+ }
+}
+
+/**
+ * @brief Tx Half Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Invoke the registered 'HalfTransfer' callback function (if any) */
+ if (hAudioOut.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioOut.CbHalfTransfer();
+ }
+}
+
+/**
+ * @brief SAI error callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Invoke the registered 'ErrorCallback' callback function (if any) */
+ if (hAudioOut.CbError != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioOut.CbError();
+ }
+ /* Invoke the registered 'ErrorCallback' callback function (if any) */
+ if (hAudioIn.CbError != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioIn.CbError();
+ }
+}
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32L496G_EVAL_AUDIO_Exported_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes micropone related peripherals.
+ * @note This function assumes that the SAI input clock (through PLL_M)
+ * is already configured and ready to be used.
+ * @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
+ * @param BitRes: Audio frequency to be configured for the SAI peripheral.
+ * @param ChnlNbr: Audio frequency to be configured for the SAI peripheral.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
+{
+ return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AudioFreq, BitRes, ChnlNbr);
+}
+
+/**
+ * @brief Initialize wave recording.
+ * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC, INPUT_DEVICE_DIGITAL_MIC1,
+ * INPUT_DEVICE_DIGITAL_MIC2 or INPUT_DEVICE_ANALOG_MIC.
+ * @param AudioFreq: Audio frequency to be configured.
+ * @param BitRes: Audio bit resolution to be configured..
+ * @param ChnlNbr: Number of channel to be configured.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
+{
+ /* Update the audio input context */
+ hAudioIn.AudioDrv = &cs42l51_drv;
+ hAudioIn.InputDevice = InputDevice;
+ hAudioIn.Frequency = AudioFreq;
+ hAudioIn.BitResolution = BitRes;
+ hAudioIn.ChannelNbr = ChnlNbr;
+ hAudioIn.CbError = (Audio_CallbackTypeDef)NULL;
+ hAudioIn.CbHalfTransfer = (Audio_CallbackTypeDef)NULL;
+ hAudioIn.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
+
+ /* Check channel number according device : only record mono with analog mic and stereo with digital mic are allowed */
+ if (((InputDevice == INPUT_DEVICE_DIGITAL_MIC) && (ChnlNbr == 1)) ||
+ ((InputDevice == INPUT_DEVICE_DIGITAL_MIC1) && (ChnlNbr == 2)) ||
+ ((InputDevice == INPUT_DEVICE_DIGITAL_MIC2) && (ChnlNbr == 2)) ||
+ ((InputDevice == INPUT_DEVICE_ANALOG_MIC) && (ChnlNbr == 2)))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Check if output device is currently used */
+ if (hAudioOut.OutputDevice != 0)
+ {
+ /* If output device is currently used, SAI PLL is already initialized */
+ /* Check that AudioFreq for record and playback is the same */
+ if (hAudioIn.Frequency != hAudioOut.Frequency)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* Configure the SAI PLL according to the requested audio frequency */
+ if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if (InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* Initializes the Digital Filter for Sigma-Delta Modulators interface */
+ if (AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* If output device is currently used, SAI is already initialized */
+ if (hAudioOut.OutputDevice == 0)
+ {
+ /* SAI data transfer preparation: prepare the Media to be used for the audio
+ transfer from SAI peripheral to memory. */
+ if (AUDIO_SAIx_Init(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Initialize the audio codec internal registers */
+ if (hAudioIn.AudioDrv->Init(AUDIO_I2C_ADDRESS,
+ (hAudioOut.OutputDevice | hAudioIn.InputDevice),
+ hAudioOut.Volume,
+ AudioFreq) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Initialise transfer control flag */
+ DmaLeftRecHalfBuffCplt = 0;
+ DmaLeftRecBuffCplt = 0;
+ DmaRightRecHalfBuffCplt = 0;
+ DmaRightRecBuffCplt = 0;
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief De-Initializes microphone related peripherals.
+ * @retval BSP AUDIO status
+
+ */
+uint8_t BSP_AUDIO_IN_DeInit(void)
+{
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
+ if (AUDIO_DFSDMx_DeInit() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Check if output device is currently used */
+ if (hAudioOut.OutputDevice != 0)
+ {
+ /* Reset record path on audio codec */
+ if (hAudioOut.AudioDrv->Init(AUDIO_I2C_ADDRESS,
+ hAudioOut.OutputDevice,
+ (uint8_t) hAudioOut.Volume,
+ hAudioOut.Frequency) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* De-initializes SAI interface */
+ if (AUDIO_SAIx_DeInit() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* DeInit audio codec */
+ hAudioIn.AudioDrv->DeInit();
+ }
+ }
+
+ /* Disable SAI PLL if no more device is used */
+ if (hAudioOut.OutputDevice == 0)
+ {
+ if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Reset the audio input context */
+ memset(&hAudioIn, 0, sizeof(hAudioIn));
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Starts audio recording.
+ * @param pbuf: Main buffer pointer for the recorded data storing
+ * @param size: Current size of the recorded buffer
+ * @note The Right channel is start at first with synchro on start of Left channel
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_Record(uint16_t *pbuf, uint32_t size)
+{
+ hAudioIn.pRecBuf = pbuf;
+ hAudioIn.RecSize = size;
+
+
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /* Allocate hAudioIn.LeftRecBuff buffer */
+#if defined(BSP_AUDIO_USE_RTOS)
+ hAudioIn.LeftRecBuff = (int32_t *)k_malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
+#else
+ hAudioIn.LeftRecBuff = (int32_t *)malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
+#endif
+ if (hAudioIn.LeftRecBuff == NULL)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Allocate hAudioIn.RightRecBuff buffer */
+#if defined(BSP_AUDIO_USE_RTOS)
+ hAudioIn.RightRecBuff = (int32_t *)k_malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
+#else
+ hAudioIn.RightRecBuff = (int32_t *)malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
+#endif
+ if (hAudioIn.RightRecBuff == NULL)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Call the Media layer start function for right channel */
+ if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmRightFilter,
+ (int32_t *)hAudioIn.RightRecBuff,
+ (hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /* Call the Media layer start function for left channel */
+ if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter,
+ (int32_t *)hAudioIn.LeftRecBuff,
+ (hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Call the audio Codec Play function */
+ if (hAudioIn.AudioDrv->Play(AUDIO_I2C_ADDRESS, pbuf, size) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Start the process receive DMA */
+ if (HAL_OK != HAL_SAI_Receive_DMA(&BSP_AUDIO_hSai_Rx, (uint8_t *)pbuf, size))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Updates the audio frequency.
+ * @param AudioFreq: Audio frequency used to record the audio stream.
+ * @note This API should be called after the BSP_AUDIO_IN_Init() to adjust the
+ * audio frequency.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_SetFrequency(uint32_t AudioFreq)
+{
+ uint8_t TxData[2] = {0x00, 0x00};
+
+ /* Configure the SAI PLL according to the requested audio frequency */
+ if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
+ if (AUDIO_DFSDMx_DeInit() != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Initializes the Digital Filter for Sigma-Delta Modulators interface */
+ if (AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
+
+ /* Update the SAI audio frequency configuration */
+ BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
+ BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ HAL_SAI_Init(&BSP_AUDIO_hSai_Rx);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
+ /* Transmit one byte to start FS generation */
+ if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ hAudioIn.Frequency = AudioFreq;
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Regular conversion complete callback.
+ * @note In interrupt mode, user has to read conversion value in this function
+ using HAL_DFSDM_FilterGetRegularValue.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ uint32_t index;
+ uint32_t recbufsize = (hAudioIn.RecSize / hAudioIn.ChannelNbr);
+
+ if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ for (index = (recbufsize / 2); index < recbufsize; index++)
+ {
+ hAudioIn.pRecBuf[2 * index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
+ hAudioIn.pRecBuf[(2 * index) + 1] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+ else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ for (index = (recbufsize / 2); index < recbufsize; index++)
+ {
+ hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+ else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ for (index = (recbufsize / 2); index < recbufsize; index++)
+ {
+ hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+
+ /* Invoke the registered 'TransferCompete' callback function (if any) */
+ if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
+ {
+ if (hdfsdm_filter == &BSP_AUDIO_hDfsdmLeftFilter)
+ {
+ if (DmaLeftRecBuffCplt)
+ {
+ BSP_ErrorHandler();
+ }
+
+ DmaLeftRecBuffCplt = 1;
+ }
+ else
+ {
+ if (DmaRightRecBuffCplt)
+ {
+ BSP_ErrorHandler();
+ }
+
+ DmaRightRecBuffCplt = 1;
+ }
+
+ if (((DmaLeftRecBuffCplt != 0) && (DmaRightRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)) ||
+ ((DmaLeftRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)) ||
+ ((DmaRightRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
+ {
+ hAudioIn.CbTransferComplete();
+ DmaLeftRecBuffCplt = 0;
+ DmaRightRecBuffCplt = 0;
+ }
+ }
+}
+
+/**
+ * @brief Half regular conversion complete callback.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ uint32_t index;
+ uint32_t recbufsize = (hAudioIn.RecSize / hAudioIn.ChannelNbr);
+
+ if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ for (index = 0; index < (recbufsize / 2); index++)
+ {
+ hAudioIn.pRecBuf[2 * index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
+ hAudioIn.pRecBuf[(2 * index) + 1] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+ else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ for (index = 0; index < (recbufsize / 2); index++)
+ {
+ hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+ else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ for (index = 0; index < (recbufsize / 2); index++)
+ {
+ hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
+ }
+ }
+
+ /* Invoke the registered 'HalfTransfer' callback function (if any) */
+ if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
+ {
+ if (hdfsdm_filter == &BSP_AUDIO_hDfsdmLeftFilter)
+ {
+ if (DmaLeftRecHalfBuffCplt)
+ {
+ BSP_ErrorHandler();
+ }
+
+ DmaLeftRecHalfBuffCplt = 1;
+ }
+ else
+ {
+ if (DmaRightRecHalfBuffCplt)
+ {
+ BSP_ErrorHandler();
+ }
+
+ DmaRightRecHalfBuffCplt = 1;
+ }
+
+ if (((DmaLeftRecHalfBuffCplt != 0) && (DmaRightRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)) ||
+ ((DmaLeftRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)) ||
+ ((DmaRightRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
+ {
+ hAudioIn.CbHalfTransfer();
+ DmaLeftRecHalfBuffCplt = 0;
+ DmaRightRecHalfBuffCplt = 0;
+ }
+ }
+}
+
+/**
+ * @brief Error callback.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterErrorCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ /* Invoke the registered 'ErrorCallback' callback function (if any) */
+ if (hAudioIn.CbError != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioIn.CbError();
+ }
+}
+
+/**
+ * @brief SAI Rx Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Invoke the registered 'TransferComplete' function (if any) */
+ if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioIn.CbTransferComplete();
+ }
+}
+
+/**
+ * @brief SAI Rx Half Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Invoke the registered 'HalfTransfer' callback function (if any) */
+ if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
+ {
+ hAudioIn.CbHalfTransfer();
+ }
+}
+
+/**
+ * @brief Stops audio recording.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_Stop(void)
+{
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Call the Media layer stop function for right channel */
+ if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /* Call the Media layer stop function for left channel */
+ if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /* Free hAudioIn.LeftRecBuff buffer */
+#if defined(BSP_AUDIO_USE_RTOS)
+ k_free((void *)hAudioIn.LeftRecBuff);
+#else
+ free((void *)hAudioIn.LeftRecBuff);
+#endif
+ }
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Free hAudioIn.RightRecBuff buffer */
+#if defined(BSP_AUDIO_USE_RTOS)
+ k_free((void *)hAudioIn.RightRecBuff);
+#else
+ free((void *)hAudioIn.RightRecBuff);
+#endif
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Call Audio Codec Stop function */
+ if (hAudioIn.AudioDrv->Stop(AUDIO_I2C_ADDRESS, CODEC_PDWN_HW) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Wait at least 100ms */
+ HAL_Delay(100);
+
+ /* Stop DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAStop(&BSP_AUDIO_hSai_Rx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Pauses the audio file stream.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_Pause(void)
+{
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ /* Call the Media layer stop function */
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Pause DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAPause(&BSP_AUDIO_hSai_Rx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Resumes the audio file stream.
+ * @retval BSP AUDIO status
+ */
+uint8_t BSP_AUDIO_IN_Resume(void)
+{
+ if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
+ {
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Call the Media layer start function for right channel */
+ if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmRightFilter,
+ (int32_t *)hAudioIn.RightRecBuff,
+ (hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /* Call the Media layer start function for left channel */
+ if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter,
+ (int32_t *)hAudioIn.LeftRecBuff,
+ (hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ }
+ else
+ {
+ /* INPUT_DEVICE_ANALOG_MIC */
+ /* Resume DMA transfer of PCM samples towards the serial audio interface */
+ if (HAL_SAI_DMAResume(&BSP_AUDIO_hSai_Rx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief register user callback functions
+ * @param ErrorCallback: pointer to the error callback function
+ * @param HalfTransferCallback: pointer to the half transfer callback function
+ * @param TransferCompleteCallback: pointer to the transfer complete callback function
+ * @retval None
+ */
+void BSP_AUDIO_IN_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
+ Audio_CallbackTypeDef HalfTransferCallback,
+ Audio_CallbackTypeDef TransferCompleteCallback)
+{
+ hAudioIn.CbError = ErrorCallback;
+ hAudioIn.CbHalfTransfer = HalfTransferCallback;
+ hAudioIn.CbTransferComplete = TransferCompleteCallback;
+}
+/**
+ * @}
+ */
+
+/* private functions --------------------------------------------------------*/
+/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Private_Functions
+ * @{
+ */
+/**
+ * @brief Initializes the Audio Codec audio interface (SAI).
+ * @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
+ * @retval BSP AUDIO status
+ */
+static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq)
+{
+ uint8_t TxData[2] = {0x00, 0x00};
+
+ /* Initialize the BSP_AUDIO_hSai_Xx instances parameter */
+ BSP_AUDIO_hSai_Tx.Instance = SAI1_Block_A;
+ BSP_AUDIO_hSai_Rx.Instance = SAI1_Block_B;
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
+
+ /*******************************/
+ /* SAI block used for playback */
+ /*******************************/
+ /* Configure SAI_Block_x used for transmit
+ LSBFirst: Disabled
+ DataSize: 16 */
+ BSP_AUDIO_hSai_Tx.Init.AudioMode = SAI_MODEMASTER_TX;
+ BSP_AUDIO_hSai_Tx.Init.Synchro = SAI_ASYNCHRONOUS;
+ BSP_AUDIO_hSai_Tx.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
+ BSP_AUDIO_hSai_Tx.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
+ BSP_AUDIO_hSai_Tx.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
+ BSP_AUDIO_hSai_Tx.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
+ BSP_AUDIO_hSai_Tx.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
+ BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_STEREOMODE;
+ BSP_AUDIO_hSai_Tx.Init.CompandingMode = SAI_NOCOMPANDING;
+ BSP_AUDIO_hSai_Tx.Init.TriState = SAI_OUTPUT_NOTRELEASED;
+ BSP_AUDIO_hSai_Tx.Init.Protocol = SAI_FREE_PROTOCOL;
+ BSP_AUDIO_hSai_Tx.Init.DataSize = SAI_DATASIZE_16;
+ BSP_AUDIO_hSai_Tx.Init.FirstBit = SAI_FIRSTBIT_MSB;
+ BSP_AUDIO_hSai_Tx.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
+
+ /* Configure SAI_Block_x Frame
+ Frame Length: 32
+ Frame active Length: 16
+ FS Definition: Start frame + Channel Side identification
+ FS Polarity: FS active Low
+ FS Offset: FS asserted one bit before the first bit of slot 0 */
+ BSP_AUDIO_hSai_Tx.FrameInit.FrameLength = 32;
+ BSP_AUDIO_hSai_Tx.FrameInit.ActiveFrameLength = 16;
+ BSP_AUDIO_hSai_Tx.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
+ BSP_AUDIO_hSai_Tx.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
+ BSP_AUDIO_hSai_Tx.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
+
+ /* Configure SAI Block_x Slot
+ Slot First Bit Offset: 0
+ Slot Size : 16
+ Slot Number: 2
+ Slot Active: Slots 0 and 1 actives */
+ BSP_AUDIO_hSai_Tx.SlotInit.FirstBitOffset = 0;
+ BSP_AUDIO_hSai_Tx.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
+ BSP_AUDIO_hSai_Tx.SlotInit.SlotNumber = 2;
+ BSP_AUDIO_hSai_Tx.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
+
+ /*****************************/
+ /* SAI block used for record */
+ /*****************************/
+ /* Configure SAI_Block_x used for receive
+ LSBFirst: Disabled
+ DataSize: 16 */
+ BSP_AUDIO_hSai_Rx.Init.AudioMode = SAI_MODESLAVE_RX;
+ BSP_AUDIO_hSai_Rx.Init.Synchro = SAI_SYNCHRONOUS;
+ BSP_AUDIO_hSai_Rx.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
+ BSP_AUDIO_hSai_Rx.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
+ BSP_AUDIO_hSai_Rx.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
+ BSP_AUDIO_hSai_Rx.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
+ BSP_AUDIO_hSai_Rx.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
+ BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
+ BSP_AUDIO_hSai_Rx.Init.MonoStereoMode = SAI_MONOMODE;
+ BSP_AUDIO_hSai_Rx.Init.CompandingMode = SAI_NOCOMPANDING;
+ BSP_AUDIO_hSai_Rx.Init.TriState = SAI_OUTPUT_NOTRELEASED;
+ BSP_AUDIO_hSai_Rx.Init.Protocol = SAI_FREE_PROTOCOL;
+ BSP_AUDIO_hSai_Rx.Init.DataSize = SAI_DATASIZE_16;
+ BSP_AUDIO_hSai_Rx.Init.FirstBit = SAI_FIRSTBIT_MSB;
+ BSP_AUDIO_hSai_Rx.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
+
+ /* Configure SAI_Block_x Frame
+ Frame Length: 32
+ Frame active Length: 16
+ FS Definition: Start frame + Channel Side identification
+ FS Polarity: FS active Low
+ FS Offset: FS asserted one bit before the first bit of slot 0 */
+ BSP_AUDIO_hSai_Rx.FrameInit.FrameLength = 32;
+ BSP_AUDIO_hSai_Rx.FrameInit.ActiveFrameLength = 16;
+ BSP_AUDIO_hSai_Rx.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
+ BSP_AUDIO_hSai_Rx.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
+ BSP_AUDIO_hSai_Rx.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
+
+ /* Configure SAI Block_x Slot
+ Slot First Bit Offset: 0
+ Slot Size : 16
+ Slot Number: 2
+ Slot Active: Slots 0 and 1 actives */
+ BSP_AUDIO_hSai_Rx.SlotInit.FirstBitOffset = 0;
+ BSP_AUDIO_hSai_Rx.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
+ BSP_AUDIO_hSai_Rx.SlotInit.SlotNumber = 2;
+ BSP_AUDIO_hSai_Rx.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
+
+ /*********************************/
+ /* Initializes the SAI peripheral*/
+ /*********************************/
+ if (HAL_SAI_Init(&BSP_AUDIO_hSai_Tx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ if (HAL_SAI_Init(&BSP_AUDIO_hSai_Rx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /******************************************/
+ /* Enable SAI peripheral to generate MCLK */
+ /******************************************/
+ __HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
+ /* Transmit one byte to start FS generation */
+ if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief De-initializes the Audio Codec audio interface (SAI).
+ * @retval BSP AUDIO status
+ */
+static uint8_t AUDIO_SAIx_DeInit(void)
+{
+ /* Disable the SAI audio block */
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
+ __HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
+
+ /* De-initializes the SAI peripheral */
+ if (HAL_SAI_DeInit(&BSP_AUDIO_hSai_Tx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ if (HAL_SAI_DeInit(&BSP_AUDIO_hSai_Rx) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief SAI MSP Init
+ * @param hsai : pointer to a SAI_HandleTypeDef structure
+ * @retval None
+ */
+void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable SAI clock */
+ __HAL_RCC_SAI1_CLK_ENABLE();
+
+ if (hsai->Instance == SAI1_Block_A)
+ {
+ /* SAI pins configuration: FS, SCK, MCLK and SD pins */
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
+ GPIO_InitStruct.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_MCLK_A */
+ GPIO_InitStruct.Pin = GPIO_PIN_4;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_FS_A */
+ GPIO_InitStruct.Pin = GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* SAI1_SCK_A */
+ GPIO_InitStruct.Pin = GPIO_PIN_6;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_SD_A */
+
+ /* Configure the hDmaSaiTx handle parameters */
+ __HAL_RCC_DMA2_CLK_ENABLE();
+ hDmaSaiTx.Init.Request = DMA_REQUEST_1;
+ hDmaSaiTx.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hDmaSaiTx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaSaiTx.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaSaiTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ hDmaSaiTx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ hDmaSaiTx.Init.Mode = DMA_CIRCULAR;
+ hDmaSaiTx.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaSaiTx.Instance = DMA2_Channel1;
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsai, hdmatx, hDmaSaiTx);
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&hDmaSaiTx);
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&hDmaSaiTx);
+ /* SAI DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
+ }
+ else /* SAI1_BlockB */
+ {
+ /* SAI pins configuration: SD pin */
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
+ GPIO_InitStruct.Pin = GPIO_PIN_3;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_SD_B */
+
+ /* Configure the hDmaSaiRx handle parameters */
+ __HAL_RCC_DMA2_CLK_ENABLE();
+ hDmaSaiRx.Init.Request = DMA_REQUEST_1;
+ hDmaSaiRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hDmaSaiRx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaSaiRx.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaSaiRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ hDmaSaiRx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ hDmaSaiRx.Init.Mode = DMA_CIRCULAR;
+ hDmaSaiRx.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaSaiRx.Instance = DMA2_Channel2;
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsai, hdmarx, hDmaSaiRx);
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&hDmaSaiRx);
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&hDmaSaiRx);
+ /* SAI DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(DMA2_Channel2_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(DMA2_Channel2_IRQn);
+ }
+}
+
+/**
+ * @brief SAI MSP De-init
+ * @param hsai : pointer to a SAI_HandleTypeDef structure
+ * @retval None
+ */
+void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
+{
+ if (hsai->Instance == SAI1_Block_A)
+ {
+ /* Disable SAI DMA Channel IRQ */
+ HAL_NVIC_DisableIRQ(DMA2_Channel1_IRQn);
+
+ /* Reset the DMA Stream configuration*/
+ HAL_DMA_DeInit(&hDmaSaiTx);
+
+ /* De-initialize FS, SCK, MCK and SD pins*/
+ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2); /* SAI1_MCLK_A */
+ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4); /* SAI1_FS_A */
+ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10); /* SAI1_SCK_A */
+ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_6); /* SAI1_SD_A */
+
+ /* Don't disable SAI clock used for other SAI block */
+ /*__HAL_RCC_SAI1_CLK_DISABLE(); */
+ }
+ else /* SAI1_BlockB */
+ {
+ /* Disable SAI DMA Channel IRQ */
+ HAL_NVIC_DisableIRQ(DMA2_Channel2_IRQn);
+
+ /* Reset the DMA Stream configuration*/
+ HAL_DMA_DeInit(&hDmaSaiRx);
+
+ /* De-initialize SD pin */
+ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_3); /* SAI1_SD_B */
+
+ /* Disable SAI clock */
+ __HAL_RCC_SAI1_CLK_DISABLE();
+ }
+}
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
+ * @param AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral.
+ * @retval BSP AUDIO status
+ */
+static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq)
+{
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /*####CHANNEL 3####*/
+ hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Divider = DFSDMClockDivider(AudioFreq);
+ hAudioIn.hDfsdmLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioIn.hDfsdmLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioIn.hDfsdmLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
+ /* Request to sample stable data for LEFT micro on Rising edge */
+ hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
+ hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioIn.hDfsdmLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
+ hAudioIn.hDfsdmLeftChannel.Init.Awd.Oversampling = 10;
+ hAudioIn.hDfsdmLeftChannel.Init.Offset = 0;
+ hAudioIn.hDfsdmLeftChannel.Init.RightBitShift = DFSDMRightBitShift(AudioFreq);
+ hAudioIn.hDfsdmLeftChannel.Instance = DFSDM1_Channel3;
+
+ /* Init the DFSDM Channel */
+ if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /*####CHANNEL 2####*/
+ hAudioIn.hDfsdmRightChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioIn.hDfsdmRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioIn.hDfsdmRightChannel.Init.OutputClock.Divider = DFSDMClockDivider(AudioFreq);
+ hAudioIn.hDfsdmRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioIn.hDfsdmRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioIn.hDfsdmRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS;
+ /* Request to sample stable data for LEFT micro on Rising edge */
+ hAudioIn.hDfsdmRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING;
+ hAudioIn.hDfsdmRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioIn.hDfsdmRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
+ hAudioIn.hDfsdmRightChannel.Init.Awd.Oversampling = 10;
+ hAudioIn.hDfsdmRightChannel.Init.Offset = 0;
+ hAudioIn.hDfsdmRightChannel.Init.RightBitShift = DFSDMRightBitShift(AudioFreq);
+ hAudioIn.hDfsdmRightChannel.Instance = DFSDM1_Channel2;
+
+ /* Init the DFSDM Channel */
+ if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmRightChannel) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ /*####FILTER 0####*/
+ BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.FastMode = ENABLE;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.DmaMode = ENABLE;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ScanMode = DISABLE;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.DmaMode = DISABLE;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
+ BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.SincOrder = DFSDMFilterOrder(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.Oversampling = DFSDMOverSampling(AudioFreq);
+ BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.IntOversampling = 1;
+ BSP_AUDIO_hDfsdmLeftFilter.Instance = DFSDM1_Filter0;
+
+ /* Init the DFSDM Filter */
+ if (HAL_DFSDM_FilterInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Configure regular channel */
+ if (HAL_DFSDM_FilterConfigRegChannel(&BSP_AUDIO_hDfsdmLeftFilter,
+ DFSDM_CHANNEL_3,
+ DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /*####FILTER 1####*/
+ if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ }
+ else
+ {
+ BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER;
+ }
+ BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.FastMode = ENABLE;
+ BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.DmaMode = ENABLE;
+ BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ScanMode = DISABLE;
+ BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.DmaMode = DISABLE;
+ BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
+ BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
+ BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.SincOrder = DFSDMFilterOrder(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.Oversampling = DFSDMOverSampling(AudioFreq);
+ BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.IntOversampling = 1;
+ BSP_AUDIO_hDfsdmRightFilter.Instance = DFSDM1_Filter1;
+
+ /* Init the DFSDM Filter */
+ if (HAL_DFSDM_FilterInit(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Configure regular channel */
+ if (HAL_DFSDM_FilterConfigRegChannel(&BSP_AUDIO_hDfsdmRightFilter,
+ DFSDM_CHANNEL_2,
+ DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief De-initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
+ * @retval BSP AUDIO status
+ */
+static uint8_t AUDIO_DFSDMx_DeInit(void)
+{
+ /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ if (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ if (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmRightChannel) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
+ {
+ if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* DFSDM reset */
+ __HAL_RCC_DFSDM1_FORCE_RESET();
+ __HAL_RCC_DFSDM1_RELEASE_RESET();
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Initializes the DFSDM channel MSP.
+ * @param hdfsdm_channel : DFSDM channel handle.
+ * @retval None
+ */
+void HAL_DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
+{
+ if (((hdfsdm_channel->Instance == DFSDM1_Channel3) && ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) != 0)) || \
+ ((hdfsdm_channel->Instance == DFSDM1_Channel2) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
+ {
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable DFSDM clock */
+ __HAL_RCC_DFSDM1_CLK_ENABLE();
+
+ /* DFSDM pins configuration: DFSDM1_CKOUT, DFSDM1_DATIN3 pins */
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF6_DFSDM1;
+ GPIO_InitStruct.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* DFSDM1_CKOUT */
+ GPIO_InitStruct.Pin = GPIO_PIN_7;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* DFSDM1_DATIN3 */
+
+ /* Enable MIC_VDD (PH1) */
+ __HAL_RCC_GPIOH_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Pin = GPIO_PIN_1;
+ HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
+ HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_SET);
+ }
+}
+
+/**
+ * @brief De-initializes the DFSDM channel MSP.
+ * @param hdfsdm_channel : DFSDM channel handle.
+ * @retval None
+ */
+void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
+{
+ if (((hdfsdm_channel->Instance == DFSDM1_Channel3) && ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) != 0)) || \
+ ((hdfsdm_channel->Instance == DFSDM1_Channel2) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
+ {
+ /* Disable MIC_VDD (PH1) */
+ HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_RESET);
+ HAL_GPIO_DeInit(GPIOH, GPIO_PIN_1);
+
+ /* De-initialize DFSDM1_CKOUT, DFSDM1_DATIN3 pins */
+ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2); /* DFSDM1_CKOUT */
+ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_7); /* DFSDM1_DATIN3 */
+
+ /* Disable DFSDM1 */
+ __HAL_RCC_DFSDM1_CLK_DISABLE();
+ }
+}
+
+/**
+ * @brief Initializes the DFSDM filter MSP.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ if (hdfsdm_filter->Instance == DFSDM1_Filter0)
+ {
+ /* Enable the DMA clock */
+ __HAL_RCC_DMA1_CLK_ENABLE();
+
+ /* Configure the hAudioIn.hDmaDfsdmLeft handle parameters */
+ hAudioIn.hDmaDfsdmLeft.Init.Request = DMA_REQUEST_0;
+ hAudioIn.hDmaDfsdmLeft.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hAudioIn.hDmaDfsdmLeft.Init.PeriphInc = DMA_PINC_DISABLE;
+ hAudioIn.hDmaDfsdmLeft.Init.MemInc = DMA_MINC_ENABLE;
+ hAudioIn.hDmaDfsdmLeft.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hAudioIn.hDmaDfsdmLeft.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hAudioIn.hDmaDfsdmLeft.Init.Mode = DMA_CIRCULAR;
+ hAudioIn.hDmaDfsdmLeft.Init.Priority = DMA_PRIORITY_HIGH;
+ hAudioIn.hDmaDfsdmLeft.Instance = DMA1_Channel4;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hdfsdm_filter, hdmaReg, hAudioIn.hDmaDfsdmLeft);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hAudioIn.hDmaDfsdmLeft);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hAudioIn.hDmaDfsdmLeft);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
+ }
+ else /* DFSDM1_Filter1 */
+ {
+ if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
+ {
+ /* Enable the DMA clock needed if only MIC2 is used */
+ __HAL_RCC_DMA1_CLK_ENABLE();
+ }
+
+ /* Configure the hAudioIn.hDmaDfsdmRight handle parameters */
+ hAudioIn.hDmaDfsdmRight.Init.Request = DMA_REQUEST_0;
+ hAudioIn.hDmaDfsdmRight.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hAudioIn.hDmaDfsdmRight.Init.PeriphInc = DMA_PINC_DISABLE;
+ hAudioIn.hDmaDfsdmRight.Init.MemInc = DMA_MINC_ENABLE;
+ hAudioIn.hDmaDfsdmRight.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hAudioIn.hDmaDfsdmRight.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hAudioIn.hDmaDfsdmRight.Init.Mode = DMA_CIRCULAR;
+ hAudioIn.hDmaDfsdmRight.Init.Priority = DMA_PRIORITY_HIGH;
+ hAudioIn.hDmaDfsdmRight.Instance = DMA1_Channel5;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hdfsdm_filter, hdmaReg, hAudioIn.hDmaDfsdmRight);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hAudioIn.hDmaDfsdmRight);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hAudioIn.hDmaDfsdmRight);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
+ }
+}
+
+/**
+ * @brief De-initializes the DFSDM filter MSP.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ if (hdfsdm_filter->Instance == DFSDM1_Filter0)
+ {
+ /* Disable DMA Channel IRQ */
+ HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn);
+
+ /* De-initialize the DMA Channel */
+ HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmLeft);
+ }
+ else /* DFSDM1_Filter1 */
+ {
+ /* Disable DMA Channel IRQ */
+ HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);
+
+ /* De-initialize the DMA Channel */
+ HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmRight);
+ }
+}
+
+/**
+ * @brief Configures the SAI PLL clock according to the required audio frequency.
+ * @param Frequency: Audio frequency.
+ * @retval BSP AUDIO status
+ * @note The SAI PLL input clock must be configured in the user application.
+ * The SAI PLL configuration done within this function assumes that
+ * the SAI PLL input clock runs at 8 MHz.
+ */
+static uint8_t AUDIO_SAIPLLConfig(uint32_t Frequency)
+{
+ RCC_PeriphCLKInitTypeDef RCC_ExCLKInitStruct;
+
+ /* Retrieve actual RCC configuration */
+ HAL_RCCEx_GetPeriphCLKConfig(&RCC_ExCLKInitStruct);
+
+ if ((Frequency == AUDIO_FREQUENCY_11K)
+ || (Frequency == AUDIO_FREQUENCY_22K)
+ || (Frequency == AUDIO_FREQUENCY_44K))
+ {
+ /* Configure PLLSAI prescalers */
+ /* SAI clock config
+ PLLSAI2_VCO= 8 Mhz * PLLSAI1N = 8 * 24 = VCO_192M
+ SAI_CK_x = PLLSAI2_VCO/PLLSAI1P = 192/17 = 11.294 Mhz */
+ RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2N = 24;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2P = 17;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2ClockOut = RCC_PLLSAI2_SAI2CLK;
+ RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI2;
+ }
+ else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
+ {
+ /* SAI clock config
+ PLLSAI2_VCO= 8 Mhz * PLLSAI1N = 8 * 43 = VCO_344M
+ SAI_CK_x = PLLSAI1_VCO/PLLSAI2P = 344/7 = 49.142 Mhz */
+ RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2N = 43;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2P = 7;
+ RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2ClockOut = RCC_PLLSAI2_SAI2CLK;
+ RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI2;
+ }
+
+ if (HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct) != HAL_OK)
+ {
+ return AUDIO_ERROR;
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.h
new file mode 100644
index 0000000..925f135
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_audio.h
@@ -0,0 +1,270 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_audio.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_audio.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_AUDIO_H
+#define __STM32L496G_DISCOVERY_AUDIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#if defined(BSP_AUDIO_USE_RTOS)
+#include "k_mem.h"
+#else
+#include
+#endif
+/* Include audio component Driver */
+#include "../Components/cs42l51/cs42l51.h"
+#include "stm32l496g_discovery.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_AUDIO
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Types Exported Types
+ * @{
+ */
+typedef void (*Audio_CallbackTypeDef)(void);
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Constants Exported Constants
+ * @{
+ */
+/** @defgroup BSP_Audio_Out_Option BSP Audio Out Option
+ * @{
+ */
+#define BSP_AUDIO_OUT_CIRCULARMODE ((uint32_t)0x00000001) /* BUFFER CIRCULAR MODE */
+#define BSP_AUDIO_OUT_NORMALMODE ((uint32_t)0x00000002) /* BUFFER NORMAL MODE */
+#define BSP_AUDIO_OUT_STEREOMODE ((uint32_t)0x00000004) /* STEREO MODE */
+#define BSP_AUDIO_OUT_MONOMODE ((uint32_t)0x00000008) /* MONO MODE */
+/**
+ * @}
+ */
+
+/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate
+ * @{
+ */
+#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K
+#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K
+#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K
+#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K
+#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K
+#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K
+#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K
+#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K
+/**
+ * @}
+ */
+/*------------------------------------------------------------------------------
+ USER SAI defines parameters
+ -----------------------------------------------------------------------------*/
+/* SAI peripheral configuration defines */
+#define AUDIO_SAIx_TX_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE()
+#define AUDIO_SAIx_TX_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE()
+#define AUDIO_SAIx_TX_MCK_SCK_SD_FS_AF GPIO_AF13_SAI1
+
+#define AUDIO_SAIx_TX_MCK_SCK_SD_FS_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
+#define AUDIO_SAIx_TX_MCK_SCK_SD_FS_DISABLE() __HAL_RCC_GPIOE_CLK_DISABLE()
+#define AUDIO_SAIx_TX_FS_PIN GPIO_PIN_4
+#define AUDIO_SAIx_TX_SCK_PIN GPIO_PIN_5
+#define AUDIO_SAIx_TX_SD_PIN GPIO_PIN_6
+#define AUDIO_SAIx_TX_MCK_PIN GPIO_PIN_2
+#define AUDIO_SAIx_TX_MCK_SCK_SD_FS_GPIO_PORT GPIOE
+
+/* SAI DMA Channel definitions */
+#define AUDIO_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE()
+#define AUDIO_SAIx_DMAx_CLK_DISABLE() __HAL_RCC_DMA2_CLK_DISABLE()
+#define AUDIO_SAIx_DMAx_CHANNEL DMA2_Channel1
+#define AUDIO_SAIx_DMAx_IRQ DMA2_Channel1_IRQn
+#define AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD
+#define AUDIO_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD
+#define DMA_MAX_SZE (uint32_t)0xFFFF
+
+#define AUDIO_SAIx_DMAx_IRQHandler DMA2_Channel1_IRQHandler
+
+/* Select the interrupt preemption priority for the DMA interrupt */
+#define AUDIO_OUT_IRQ_PREPRIO 5 /* Select the preemption priority level(0 is the highest) */
+
+/* Disable SAIx PLL */
+#define AUDIO_SAIx_PLL_DISABLE() HAL_RCCEx_DisablePLLSAI2()
+
+/*------------------------------------------------------------------------------
+ AUDIO IN CONFIGURATION
+------------------------------------------------------------------------------*/
+/* DFSDM Configuration defines */
+#define AUDIO_DFSDMx_LEFT_CHANNEL DFSDM1_Channel2
+#define AUDIO_DFSDMx_LEFT_FILTER DFSDM1_Filter0
+#define AUDIO_DFSDMx_CLK_ENABLE() __HAL_RCC_DFSDM1_CLK_ENABLE()
+#define AUDIO_DFSDMx_CLK_DISABLE() __HAL_RCC_DFSDM1_CLK_DISABLE()
+#define AUDIO_DFSDMx_CKOUT_PIN GPIO_PIN_9
+#define AUDIO_DFSDMx_DMIC_DATIN_PIN GPIO_PIN_7
+#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT GPIOE
+#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
+#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_DISABLE() __HAL_RCC_GPIOE_CLK_DISABLE()
+#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_AF GPIO_AF6_DFSDM1
+
+/* DFSDM DMA Right and Left channels definitions */
+#define AUDIO_DFSDMx_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define AUDIO_DFSDMx_DMAx_CLK_DISABLE() __HAL_RCC_DMA1_CLK_DISABLE()
+#define AUDIO_DFSDMx_DMAx_LEFT_CHANNEL DMA1_Channel4
+#define AUDIO_DFSDMx_DMAx_LEFT_IRQ DMA1_Channel4_IRQn
+#define AUDIO_DFSDM_DMAx_LEFT_IRQHandler DMA1_Channel4_IRQHandler
+#define AUDIO_DFSDMx_DMAx_RIGHT_CHANNEL DMA1_Channel5
+#define AUDIO_DFSDMx_DMAx_RIGHT_IRQ DMA1_Channel5_IRQn
+#define AUDIO_DFSDM_DMAx_RIGHT_IRQHandler DMA1_Channel5_IRQHandler
+#define AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_WORD
+#define AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_WORD
+
+
+/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */
+#define AUDIO_IN_IRQ_PREPRIO 6 /* Select the preemption priority level(0 is the highest) */
+
+/*------------------------------------------------------------------------------
+ CONFIGURATION: Audio Driver Configuration parameters
+------------------------------------------------------------------------------*/
+
+#define AUDIODATA_SIZE 2 /* 16-bits audio data size */
+
+/* Audio status definition */
+#define AUDIO_OK 0
+#define AUDIO_ERROR 1
+#define AUDIO_TIMEOUT 2
+
+/* Audio out parameters */
+#define DEFAULT_AUDIO_OUT_FREQ BSP_AUDIO_FREQUENCY_48K
+#define DEFAULT_AUDIO_OUT_BIT_RESOLUTION ((uint8_t)16)
+#define DEFAULT_AUDIO_OUT_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */
+#define DEFAULT_AUDIO_OUT_VOLUME ((uint16_t)80)
+
+/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */
+#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K
+#define DEFAULT_AUDIO_IN_BIT_RESOLUTION 16
+#define DEFAULT_AUDIO_IN_CHANNEL_NBR 1 /* Mono = 1, Stereo = 2 */
+#define DEFAULT_AUDIO_IN_VOLUME 80
+
+/*------------------------------------------------------------------------------
+ OPTIONAL Configuration defines parameters
+------------------------------------------------------------------------------*/
+
+/* Delay for the Codec to be correctly reset */
+#define CODEC_RESET_DELAY 5
+
+/*------------------------------------------------------------------------------
+ INPUT DEVICES definition
+------------------------------------------------------------------------------*/
+/* MP34DT01TR digital microphone on PCB top side */
+#define INPUT_DEVICE_DIGITAL_MIC1 0x20 /* Left microphone */
+#define INPUT_DEVICE_DIGITAL_MIC2 0x40 /* Right microphone */
+#define INPUT_DEVICE_DIGITAL_MIC (INPUT_DEVICE_DIGITAL_MIC1 | INPUT_DEVICE_DIGITAL_MIC2)
+/* Analog microphone input from 3.5 audio jack connector */
+#define INPUT_DEVICE_ANALOG_MIC INPUT_DEVICE_MIC1
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Variables Exported Variables
+ * @{
+ */
+extern SAI_HandleTypeDef BSP_AUDIO_hSai_Tx;
+extern SAI_HandleTypeDef BSP_AUDIO_hSai_Rx;
+extern DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmLeftFilter;
+extern DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmRightFilter;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Macros Exported Macros
+ * @{
+ */
+#define DMA_MAX(_X_) (((_X_) <= DMA_MAX_SZE)? (_X_):DMA_MAX_SZE)
+
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Functions Exported Functions
+ * @{
+ */
+uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq);
+uint8_t BSP_AUDIO_OUT_DeInit(void);
+uint8_t BSP_AUDIO_OUT_Play(uint16_t *pData, uint32_t Size);
+uint8_t BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size);
+uint8_t BSP_AUDIO_OUT_Pause(void);
+uint8_t BSP_AUDIO_OUT_Resume(void);
+uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option);
+uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume);
+uint8_t BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq);
+void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption);
+uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd);
+uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output);
+void BSP_AUDIO_OUT_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
+ Audio_CallbackTypeDef HalfTransferCallback,
+ Audio_CallbackTypeDef TransferCompleteCallback);
+
+uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr);
+uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr);
+uint8_t BSP_AUDIO_IN_DeInit(void);
+uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size);
+uint8_t BSP_AUDIO_IN_SetFrequency(uint32_t AudioFreq);
+uint8_t BSP_AUDIO_IN_Stop(void);
+uint8_t BSP_AUDIO_IN_Pause(void);
+uint8_t BSP_AUDIO_IN_Resume(void);
+void BSP_AUDIO_IN_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
+ Audio_CallbackTypeDef HalfTransferCallback,
+ Audio_CallbackTypeDef TransferCompleteCallback);
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_AUDIO_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.c
new file mode 100644
index 0000000..2d96122
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.c
@@ -0,0 +1,614 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_camera.c
+ * @author MCD Application Team
+ * @brief This file includes the driver for Camera modules mounted on
+ * STM32L496G-Discovery board.
+ @verbatim
+ How to use this driver:
+ ------------------------
+ - This driver is used to drive the camera.
+ - The OV9655 component driver MUST be included with this driver.
+
+ Driver description:
+ -------------------
+ + Initialization steps:
+ o Initialize the camera using the BSP_CAMERA_Init() function.
+ o Start the camera capture/snapshot using the CAMERA_Start() function.
+ o Suspend, resume or stop the camera capture using the following functions:
+ - BSP_CAMERA_Suspend()
+ - BSP_CAMERA_Resume()
+ - BSP_CAMERA_Stop()
+
+ + Options
+ o Increase or decrease on the fly the brightness and/or contrast
+ using the following function:
+ - BSP_CAMERA_ContrastBrightnessConfig
+ o Add a special effect on the fly using the following functions:
+ - BSP_CAMERA_BlackWhiteConfig()
+ - BSP_CAMERA_ColorEffectConfig()
+ @endverbatim
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_camera.h"
+#include "stm32l496g_discovery.h"
+#include "stm32l496g_discovery_io.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_CAMERA
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Private_TypesDefinitions STM32L496G_DISCOVERY_CAMERA Private Types Definitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Private_Defines STM32L496G_DISCOVERY_CAMERA Private Defines
+ * @{
+ */
+#define CAMERA_VGA_RES_X 640
+#define CAMERA_VGA_RES_Y 480
+#define CAMERA_480x272_RES_X 480
+#define CAMERA_480x272_RES_Y 272
+#define CAMERA_QVGA_RES_X 320
+#define CAMERA_QVGA_RES_Y 240
+#define CAMERA_QQVGA_RES_X 160
+#define CAMERA_QQVGA_RES_Y 120
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Private_Macros STM32L496G_DISCOVERY_CAMERA Private Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Private_Variables STM32L496G_DISCOVERY_CAMERA Private Variables
+ * @{
+ */
+DCMI_HandleTypeDef hDcmiHandler;
+CAMERA_DrvTypeDef *camera_drv;
+/* Camera current resolution naming (QQVGA, VGA, ...) */
+static uint32_t CameraCurrentResolution;
+
+/* Camera module I2C HW address */
+static uint32_t CameraHwAddress;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Private_FunctionPrototypes STM32L496G_DISCOVERY_CAMERA Private Function Prototypes
+ * @{
+ */
+static uint32_t GetSize(uint32_t resolution);
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Exported_Functions STM32L496G_DISCOVERY_CAMERA Exported Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the camera.
+ * @param Resolution : camera sensor requested resolution (x, y) : standard resolution
+ * naming QQVGA, QVGA, VGA ...
+ * @retval Camera status
+ */
+uint8_t BSP_CAMERA_Init(uint32_t Resolution)
+{
+ DCMI_HandleTypeDef *phdcmi;
+ uint8_t status = CAMERA_ERROR;
+
+ /* Get the DCMI handle structure */
+ phdcmi = &hDcmiHandler;
+
+
+ /* Initialize the IO functionalities */
+ BSP_IO_Init();
+
+
+ /*** Configures the DCMI to interface with the camera module ***/
+ /* DCMI configuration */
+ phdcmi->Init.CaptureRate = DCMI_CR_ALL_FRAME;
+ phdcmi->Init.HSPolarity = DCMI_HSPOLARITY_HIGH;
+ phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
+ phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_HIGH;
+ phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
+ phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
+ phdcmi->Init.ByteSelectMode = DCMI_BSM_ALL;
+ phdcmi->Init.LineSelectMode = DCMI_LSM_ALL;
+ phdcmi->Instance = DCMI;
+
+ /* Camera initialization */
+ BSP_CAMERA_MspInit(&hDcmiHandler, NULL);
+
+ /* Read ID of Camera module via I2C */
+ if (ov9655_ReadID(CAMERA_I2C_ADDRESS) == OV9655_ID)
+ {
+ /* Initialize the camera driver structure */
+ camera_drv = &ov9655_drv;
+ CameraHwAddress = CAMERA_I2C_ADDRESS;
+
+ /* DCMI Initialization */
+ HAL_DCMI_Init(phdcmi);
+
+ /* Camera Module Initialization via I2C to the wanted 'Resolution' */
+ if (Resolution == CAMERA_R320x240)
+ {
+ /* For 240x240 resolution, the OV9655 sensor is set to QVGA resolution
+ * as OV9655 doesn't supports 240x240 resolution,
+ * then DCMI is configured to output a 240x240 cropped window */
+ camera_drv->Init(CameraHwAddress, CAMERA_R320x240);
+
+
+ HAL_DCMI_ConfigCROP(phdcmi,
+ 40, /* Crop in the middle of the VGA picture */
+ 0, /* Same height (same number of lines: no need to crop vertically) */
+ (240 * 2) - 1, /* 2 pixels clock needed to capture one pixel */
+ (240 * 1) - 1); /* All 240 lines are captured */
+ HAL_DCMI_EnableCROP(phdcmi);
+
+
+ /* Set the RGB565 mode */
+ MFX_IO_Write(CameraHwAddress, 0x12 /*OV9655_COM7*/, 0x63);
+ MFX_IO_Write(CameraHwAddress, 0x40 /*OV9655_COM15*/, 0x10);
+ /* Invert the HRef signal */
+ MFX_IO_Write(CameraHwAddress, 0x15 /*OV9655_COM10*/, 0x08);
+ HAL_Delay(500);
+ }
+ else
+ {
+ camera_drv->Init(CameraHwAddress, Resolution);
+ HAL_DCMI_DisableCROP(phdcmi);
+ }
+
+ CameraCurrentResolution = Resolution;
+
+ /* Return CAMERA_OK status */
+ status = CAMERA_OK;
+ }
+ else
+ {
+ /* Return CAMERA_NOT_SUPPORTED status */
+ status = CAMERA_NOT_SUPPORTED;
+ }
+
+ return status;
+}
+
+/**
+ * @brief DeInitializes the camera.
+ * @retval Camera status
+ */
+uint8_t BSP_CAMERA_DeInit(void)
+{
+ hDcmiHandler.Instance = DCMI;
+
+ HAL_DCMI_DeInit(&hDcmiHandler);
+ BSP_CAMERA_MspDeInit(&hDcmiHandler, NULL);
+ return CAMERA_OK;
+}
+
+/**
+ * @brief Starts the camera capture in continuous mode.
+ * @param buff: pointer to the camera output buffer
+ * @retval None
+ */
+void BSP_CAMERA_ContinuousStart(uint8_t *buff)
+{
+ /* Start the camera capture */
+ HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution));
+}
+
+/**
+ * @brief Starts the camera capture in snapshot mode.
+ * @param buff: pointer to the camera output buffer
+ * @retval None
+ */
+void BSP_CAMERA_SnapshotStart(uint8_t *buff)
+{
+ /* Start the camera capture */
+ HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution));
+}
+
+/**
+ * @brief Suspend the CAMERA capture
+ * @retval None
+ */
+void BSP_CAMERA_Suspend(void)
+{
+ /* Suspend the Camera Capture */
+ HAL_DCMI_Suspend(&hDcmiHandler);
+}
+
+/**
+ * @brief Resume the CAMERA capture
+ * @retval None
+ */
+void BSP_CAMERA_Resume(void)
+{
+ /* Start the Camera Capture */
+ HAL_DCMI_Resume(&hDcmiHandler);
+}
+
+/**
+ * @brief Stop the CAMERA capture
+ * @retval Camera status
+ */
+uint8_t BSP_CAMERA_Stop(void)
+{
+ uint8_t status = CAMERA_ERROR;
+
+ if (HAL_DCMI_Stop(&hDcmiHandler) == HAL_OK)
+ {
+ status = CAMERA_OK;
+ }
+
+ /* Set Camera in Power Down */
+ BSP_CAMERA_PwrDown();
+
+ return status;
+}
+
+/**
+ * @brief CANERA power up
+ * @retval None
+ */
+void BSP_CAMERA_PwrUp(void)
+{
+ /* De-assert the camera POWER_DOWN pin (active high) */
+ BSP_IO_WritePin(CAMERA_PWR_EN_PIN, GPIO_PIN_RESET);
+
+ HAL_Delay(3); /* POWER_DOWN de-asserted during 3ms */
+}
+
+/**
+ * @brief CAMERA power down
+ * @retval None
+ */
+void BSP_CAMERA_PwrDown(void)
+{
+ /* Assert the camera POWER_DOWN pin (active high) */
+ BSP_IO_WritePin(CAMERA_PWR_EN_PIN, GPIO_PIN_SET);
+}
+
+/**
+ * @brief Configures the camera contrast and brightness.
+ * @param contrast_level: Contrast level
+ * This parameter can be one of the following values:
+ * @arg CAMERA_CONTRAST_LEVEL4: for contrast +2
+ * @arg CAMERA_CONTRAST_LEVEL3: for contrast +1
+ * @arg CAMERA_CONTRAST_LEVEL2: for contrast 0
+ * @arg CAMERA_CONTRAST_LEVEL1: for contrast -1
+ * @arg CAMERA_CONTRAST_LEVEL0: for contrast -2
+ * @param brightness_level: Contrast level
+ * This parameter can be one of the following values:
+ * @arg CAMERA_BRIGHTNESS_LEVEL4: for brightness +2
+ * @arg CAMERA_BRIGHTNESS_LEVEL3: for brightness +1
+ * @arg CAMERA_BRIGHTNESS_LEVEL2: for brightness 0
+ * @arg CAMERA_BRIGHTNESS_LEVEL1: for brightness -1
+ * @arg CAMERA_BRIGHTNESS_LEVEL0: for brightness -2
+ * @retval None
+ */
+void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level)
+{
+ if (camera_drv->Config != NULL)
+ {
+ camera_drv->Config(CameraHwAddress, CAMERA_CONTRAST_BRIGHTNESS, contrast_level, brightness_level);
+ }
+}
+
+/**
+ * @brief Configures the camera white balance.
+ * @param Mode: black_white mode
+ * This parameter can be one of the following values:
+ * @arg CAMERA_BLACK_WHITE_BW
+ * @arg CAMERA_BLACK_WHITE_NEGATIVE
+ * @arg CAMERA_BLACK_WHITE_BW_NEGATIVE
+ * @arg CAMERA_BLACK_WHITE_NORMAL
+ * @retval None
+ */
+void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode)
+{
+ if (camera_drv->Config != NULL)
+ {
+ camera_drv->Config(CameraHwAddress, CAMERA_BLACK_WHITE, Mode, 0);
+ }
+}
+
+/**
+ * @brief Configures the camera color effect.
+ * @param Effect: Color effect
+ * This parameter can be one of the following values:
+ * @arg CAMERA_COLOR_EFFECT_ANTIQUE
+ * @arg CAMERA_COLOR_EFFECT_BLUE
+ * @arg CAMERA_COLOR_EFFECT_GREEN
+ * @arg CAMERA_COLOR_EFFECT_RED
+ * @retval None
+ */
+void BSP_CAMERA_ColorEffectConfig(uint32_t Effect)
+{
+ if (camera_drv->Config != NULL)
+ {
+ camera_drv->Config(CameraHwAddress, CAMERA_COLOR_EFFECT, Effect, 0);
+ }
+}
+
+/**
+ * @brief Get the capture size in pixels unit.
+ * @param resolution: the current resolution.
+ * @retval capture size in pixels unit.
+ */
+static uint32_t GetSize(uint32_t resolution)
+{
+ uint32_t size = 0;
+
+ /* Get capture size */
+ switch (resolution)
+ {
+ case CAMERA_R160x120:
+ {
+ size = 0x2580;
+ }
+ break;
+ case CAMERA_R320x240:
+ {
+ size = 0x9600;
+ }
+ break;
+ case CAMERA_R480x272:
+ {
+ size = 0xFF00;
+ }
+ break;
+ case CAMERA_R640x480:
+ {
+ size = 0x25800;
+ }
+ break;
+ default:
+ {
+ break;
+ }
+ }
+
+ return size;
+}
+
+/**
+ * @brief Initializes the DCMI MSP.
+ * @param hdcmi: HDMI handle
+ * @param Params
+ * @retval None
+ */
+__weak void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params)
+{
+ static DMA_HandleTypeDef hdma_handler;
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /*** Enable peripherals and GPIO clocks ***/
+ /* Enable DCMI clock */
+ __HAL_RCC_DCMI_CLK_ENABLE();
+
+ /* Enable DMA2 clock */
+ __HAL_RCC_DMA2_CLK_ENABLE();
+
+ /* Enable GPIO clocks */
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOH_CLK_ENABLE();
+ __HAL_RCC_GPIOI_CLK_ENABLE();
+
+ HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_4);
+ __HAL_RCC_HSI48_ENABLE();
+ HAL_Delay(10); // HSI48 should start in 10ms
+
+
+ /*** Configure the GPIO ***/
+ /* Configure DCMI GPIO as alternate function */
+ gpio_init_structure.Pin = GPIO_PIN_5;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = GPIO_AF10_DCMI;
+ HAL_GPIO_Init(GPIOE, &gpio_init_structure);
+
+
+ gpio_init_structure.Pin = GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 | \
+ GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = GPIO_AF10_DCMI;
+ HAL_GPIO_Init(GPIOH, &gpio_init_structure);
+
+ gpio_init_structure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = GPIO_AF10_DCMI;
+ HAL_GPIO_Init(GPIOI, &gpio_init_structure);
+
+ /*** Configure the DMA ***/
+ /* Set the parameters to be configured */
+ hdma_handler.Instance = BSP_CAMERA_DMA_INSTANCE;
+
+ hdma_handler.Init.Request = DMA_REQUEST_0;
+ hdma_handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hdma_handler.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_handler.Init.MemInc = DMA_MINC_ENABLE; /* Image captured by the DCMI is stored in memory */
+ hdma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hdma_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hdma_handler.Init.Mode = DMA_CIRCULAR;
+ hdma_handler.Init.Priority = DMA_PRIORITY_HIGH;
+
+ /* Associate the initialized DMA handle to the DCMI handle */
+ __HAL_LINKDMA(hdcmi, DMA_Handle, hdma_handler);
+
+ /*** Configure the NVIC for DCMI and DMA ***/
+ /* NVIC configuration for DCMI transfer complete interrupt */
+ HAL_NVIC_SetPriority(DCMI_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DCMI_IRQn);
+
+ /* NVIC configuration for DMA2D transfer complete interrupt */
+ HAL_NVIC_SetPriority(DMA2_Channel6_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DMA2_Channel6_IRQn);
+
+ /* Configure the DMA stream */
+ HAL_DMA_Init(hdcmi->DMA_Handle);
+}
+
+
+/**
+ * @brief DeInitializes the DCMI MSP.
+ * @param hdcmi: HDMI handle
+ * @param Params
+ * @retval None
+ */
+__weak void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params)
+{
+ /* Disable NVIC for DCMI transfer complete interrupt */
+ HAL_NVIC_DisableIRQ(DCMI_IRQn);
+
+ /* Disable NVIC for DMA2 transfer complete interrupt */
+ HAL_NVIC_DisableIRQ(DMA2_Channel6_IRQn);
+
+ /* Configure the DMA stream */
+ HAL_DMA_DeInit(hdcmi->DMA_Handle);
+
+ /* Disable DCMI clock */
+ __HAL_RCC_DCMI_CLK_DISABLE();
+
+ /* GPIO pins clock and DMA clock can be shut down in the application
+ by surcharging this __weak function */
+}
+
+/**
+ * @brief Line event callback
+ * @param hdcmi: pointer to the DCMI handle
+ * @retval None
+ */
+void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi)
+{
+ BSP_CAMERA_LineEventCallback();
+}
+
+/**
+ * @brief Line Event callback.
+ * @retval None
+ */
+__weak void BSP_CAMERA_LineEventCallback(void)
+{
+ /* NOTE : This function should not be modified; when the callback is needed,
+ the BSP_CAMERA_LineEventCallback can be implemented in the user file
+ */
+}
+
+/**
+ * @brief VSYNC event callback
+ * @param hdcmi: pointer to the DCMI handle
+ * @retval None
+ */
+void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi)
+{
+ BSP_CAMERA_VsyncEventCallback();
+}
+
+/**
+ * @brief VSYNC Event callback.
+ * @retval None
+ */
+__weak void BSP_CAMERA_VsyncEventCallback(void)
+{
+ /* NOTE : This function should not be modified; when the callback is needed,
+ the BSP_CAMERA_VsyncEventCallback can be implemented in the user file
+ */
+}
+
+/**
+ * @brief Frame event callback
+ * @param hdcmi: pointer to the DCMI handle
+ * @retval None
+ */
+void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
+{
+ BSP_CAMERA_FrameEventCallback();
+}
+
+/**
+ * @brief Frame Event callback.
+ * @retval None
+ */
+__weak void BSP_CAMERA_FrameEventCallback(void)
+{
+ /* NOTE : This function should not be modified; when the callback is needed,
+ the BSP_CAMERA_FrameEventCallback can be implemented in the user file
+ */
+}
+
+/**
+ * @brief Error callback
+ * @param hdcmi: pointer to the DCMI handle
+ * @retval None
+ */
+void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi)
+{
+ BSP_CAMERA_ErrorCallback();
+}
+
+/**
+ * @brief Error callback.
+ * @retval None
+ */
+__weak void BSP_CAMERA_ErrorCallback(void)
+{
+ /* NOTE : This function should not be modified; when the callback is needed,
+ the BSP_CAMERA_ErrorCallback can be implemented in the user file
+ */
+}
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.h
new file mode 100644
index 0000000..e9b46be
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_camera.h
@@ -0,0 +1,145 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_camera.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_camera.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_CAMERA_H
+#define __STM32L496G_DISCOVERY_CAMERA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Include Camera component Driver */
+#include "../Components/ov9655/ov9655.h"
+#include "stm32l496g_discovery.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_CAMERA
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Exported_Types STM32L496G_DISCOVERY_CAMERA Exported Types
+ * @{
+ */
+
+/**
+ * @brief Camera State structures definition
+ */
+typedef enum
+{
+ CAMERA_OK = 0x00,
+ CAMERA_ERROR = 0x01,
+ CAMERA_TIMEOUT = 0x02,
+ CAMERA_NOT_DETECTED = 0x03,
+ CAMERA_NOT_SUPPORTED = 0x04
+
+}
+Camera_StatusTypeDef;
+
+#define RESOLUTION_R160x120 CAMERA_R160x120 /* QQVGA Resolution */
+#define RESOLUTION_R320x240 CAMERA_R320x240 /* QVGA Resolution */
+#define RESOLUTION_R480x272 CAMERA_R480x272 /* 480x272 Resolution */
+#define RESOLUTION_R640x480 CAMERA_R640x480 /* VGA Resolution */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_CAMERA_Exported_Constants STM32L496G_DISCOVERY_CAMERA Exported Constants
+ * @{
+ */
+#define BSP_CAMERA_IRQHandler DCMI_IRQHandler
+#define BSP_CAMERA_DMA_IRQHandler DMA2_Channel6_IRQHandler
+#define BSP_CAMERA_DMA_IRQn DMA2_Channel6_IRQn
+#define BSP_CAMERA_DMA_INSTANCE DMA2_Channel6
+
+/**
+ * @}
+ */
+
+/**
+ * @brief Camera special pins
+ */
+/* Camera power up pin */
+#define CAMERA_PWR_EN_PIN IO1_PIN_6
+
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_CAMERA_Exported_Functions
+ * @{
+ */
+uint8_t BSP_CAMERA_Init(uint32_t Resolution);
+uint8_t BSP_CAMERA_DeInit(void);
+void BSP_CAMERA_ContinuousStart(uint8_t *buff);
+void BSP_CAMERA_SnapshotStart(uint8_t *buff);
+void BSP_CAMERA_Suspend(void);
+void BSP_CAMERA_Resume(void);
+uint8_t BSP_CAMERA_Stop(void);
+void BSP_CAMERA_PwrUp(void);
+void BSP_CAMERA_PwrDown(void);
+void BSP_CAMERA_LineEventCallback(void);
+void BSP_CAMERA_VsyncEventCallback(void);
+void BSP_CAMERA_FrameEventCallback(void);
+void BSP_CAMERA_ErrorCallback(void);
+
+/* Camera features functions prototype */
+void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level);
+void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode);
+void BSP_CAMERA_ColorEffectConfig(uint32_t Effect);
+
+/* These functions can be modified in case the current settings (e.g. DMA stream)
+ need to be changed for specific application needs */
+void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params);
+void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params);
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_CAMERA_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.c
new file mode 100644
index 0000000..154d584
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.c
@@ -0,0 +1,379 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_idd.c
+ * @author MCD Application Team
+ * @brief This file provides a set of firmware functions to manage the
+ * Idd measurement driver for STM32L496G-Discovery board.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_idd.h"
+#include "stm32l496g_discovery_io.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD STM32L496G-DISCOVERY IDD
+ * @brief This file includes the Idd driver for STM32L496G-DISCOVERY board.
+ * It allows user to measure MCU Idd current on board, especially in
+ * different low power modes.
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Private_Defines Private Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Private_Variables Private Variables
+ * @{
+ */
+static IDD_DrvTypeDef *IddDrv;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Private_Functions Private Functions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Exported_Functions Exported Functions
+ * @{
+ */
+
+/**
+ * @brief Configures IDD measurement component.
+ * @retval IDD_OK if no problem during initialization
+ */
+uint8_t BSP_IDD_Init(void)
+{
+ IDD_ConfigTypeDef iddconfig = {0};
+ uint8_t mfxstm32l152_id = 0;
+ uint8_t ret = 0;
+
+ /* wake up mfx component in case it went to standby mode */
+ mfxstm32l152_idd_drv.WakeUp(IDD_I2C_ADDRESS);
+ HAL_Delay(5);
+
+ /* Read ID and verify if the MFX is ready */
+ mfxstm32l152_id = mfxstm32l152_idd_drv.ReadID(IDD_I2C_ADDRESS);
+
+ if ((mfxstm32l152_id == MFXSTM32L152_ID_1) || (mfxstm32l152_id == MFXSTM32L152_ID_2))
+ {
+ /* Initialize the Idd driver structure */
+ IddDrv = &mfxstm32l152_idd_drv;
+
+ /* Initialize the Idd driver */
+ if (IddDrv->Init != NULL)
+ {
+ IddDrv->Init(IDD_I2C_ADDRESS);
+ }
+
+ /* Configure Idd component with default values */
+ iddconfig.AmpliGain = DISCOVERY_IDD_AMPLI_GAIN;
+ iddconfig.VddMin = DISCOVERY_IDD_VDD_MIN;
+ iddconfig.Shunt0Value = DISCOVERY_IDD_SHUNT0_VALUE;
+ iddconfig.Shunt1Value = DISCOVERY_IDD_SHUNT1_VALUE;
+ iddconfig.Shunt2Value = DISCOVERY_IDD_SHUNT2_VALUE;
+ iddconfig.Shunt3Value = 0;
+ iddconfig.Shunt4Value = DISCOVERY_IDD_SHUNT4_VALUE;
+ iddconfig.Shunt0StabDelay = DISCOVERY_IDD_SHUNT0_STABDELAY;
+ iddconfig.Shunt1StabDelay = DISCOVERY_IDD_SHUNT1_STABDELAY;
+ iddconfig.Shunt2StabDelay = DISCOVERY_IDD_SHUNT2_STABDELAY;
+ iddconfig.Shunt3StabDelay = 0;
+ iddconfig.Shunt4StabDelay = DISCOVERY_IDD_SHUNT4_STABDELAY;
+ iddconfig.ShuntNbOnBoard = MFXSTM32L152_IDD_SHUNT_NB_4;
+ iddconfig.ShuntNbUsed = MFXSTM32L152_IDD_SHUNT_NB_4;
+ iddconfig.VrefMeasurement = MFXSTM32L152_IDD_VREF_AUTO_MEASUREMENT_ENABLE;
+ iddconfig.Calibration = MFXSTM32L152_IDD_AUTO_CALIBRATION_ENABLE;
+ iddconfig.PreDelayUnit = MFXSTM32L152_IDD_PREDELAY_20_MS;
+ iddconfig.PreDelayValue = 0x7F;
+ iddconfig.MeasureNb = 100;
+ iddconfig.DeltaDelayUnit = MFXSTM32L152_IDD_DELTADELAY_0_5_MS;
+ iddconfig.DeltaDelayValue = 10;
+ BSP_IDD_Config(iddconfig);
+
+ ret = IDD_OK;
+ }
+ else
+ {
+ ret = IDD_ERROR;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Unconfigures IDD measurement component.
+ * @retval IDD_OK if no problem during deinitialization
+ */
+void BSP_IDD_DeInit(void)
+{
+ if (IddDrv->DeInit != NULL)
+ {
+ IddDrv->DeInit(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Reset Idd measurement component.
+ * @retval None
+ */
+void BSP_IDD_Reset(void)
+{
+ if (IddDrv->Reset != NULL)
+ {
+ IddDrv->Reset(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Turn Idd measurement component in low power (standby/sleep) mode
+ * @retval None
+ */
+void BSP_IDD_LowPower(void)
+{
+ if (IddDrv->LowPower != NULL)
+ {
+ IddDrv->LowPower(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Start Measurement campaign
+ * @retval None
+ */
+void BSP_IDD_StartMeasure(void)
+{
+
+ /* Activate the OPAMP used ny the MFX to measure the current consumption */
+ BSP_IO_ConfigPin(IDD_AMP_CONTROL_PIN, IO_MODE_OUTPUT);
+ BSP_IO_WritePin(IDD_AMP_CONTROL_PIN, GPIO_PIN_RESET);
+
+ if (IddDrv->Start != NULL)
+ {
+ IddDrv->Start(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Configure Idd component
+ * @param IddConfig: structure of idd parameters
+ * @retval None
+ */
+void BSP_IDD_Config(IDD_ConfigTypeDef IddConfig)
+{
+ if (IddDrv->Config != NULL)
+ {
+ IddDrv->Config(IDD_I2C_ADDRESS, IddConfig);
+ }
+}
+
+/**
+ * @brief Get Idd current value.
+ * @param IddValue: Pointer on u32 to store Idd. Value unit is 10 nA.
+ * @retval None
+ */
+void BSP_IDD_GetValue(uint32_t *IddValue)
+{
+ /* De-activate the OPAMP used ny the MFX to measure the current consumption */
+ BSP_IO_ConfigPin(IDD_AMP_CONTROL_PIN, IO_MODE_OUTPUT);
+ BSP_IO_WritePin(IDD_AMP_CONTROL_PIN, GPIO_PIN_RESET);
+
+ if (IddDrv->GetValue != NULL)
+ {
+ IddDrv->GetValue(IDD_I2C_ADDRESS, IddValue);
+ }
+}
+
+/**
+ * @brief Enable Idd interrupt that warn end of measurement
+ * @retval None
+ */
+void BSP_IDD_EnableIT(void)
+{
+ if (IddDrv->EnableIT != NULL)
+ {
+ IddDrv->EnableIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Clear Idd interrupt that warn end of measurement
+ * @retval None
+ */
+void BSP_IDD_ClearIT(void)
+{
+ if (IddDrv->ClearIT != NULL)
+ {
+ IddDrv->ClearIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Get Idd interrupt status
+ * @retval status
+ */
+uint8_t BSP_IDD_GetITStatus(void)
+{
+ if (IddDrv->GetITStatus != NULL)
+ {
+ return (IddDrv->GetITStatus(IDD_I2C_ADDRESS));
+ }
+ else
+ {
+ return IDD_ERROR;
+ }
+}
+
+/**
+ * @brief Disable Idd interrupt that warn end of measurement
+ * @retval None
+ */
+void BSP_IDD_DisableIT(void)
+{
+ if (IddDrv->DisableIT != NULL)
+ {
+ IddDrv->DisableIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Get Error Code .
+ * @retval Error code or error status
+ */
+uint8_t BSP_IDD_ErrorGetCode(void)
+{
+ if (IddDrv->ErrorGetSrc != NULL)
+ {
+ if ((IddDrv->ErrorGetSrc(IDD_I2C_ADDRESS) & MFXSTM32L152_IDD_ERROR_SRC) != RESET)
+ {
+ if (IddDrv->ErrorGetCode != NULL)
+ {
+ return IddDrv->ErrorGetCode(IDD_I2C_ADDRESS);
+ }
+ else
+ {
+ return IDD_ERROR;
+ }
+ }
+ else
+ {
+ return IDD_ERROR;
+ }
+ }
+ else
+ {
+ return IDD_ERROR;
+ }
+}
+
+
+/**
+ * @brief Enable error interrupt that warn end of measurement
+ * @retval None
+ */
+void BSP_IDD_ErrorEnableIT(void)
+{
+ if (IddDrv->ErrorEnableIT != NULL)
+ {
+ IddDrv->ErrorEnableIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Clear Error interrupt that warn end of measurement
+ * @retval None
+ */
+void BSP_IDD_ErrorClearIT(void)
+{
+ if (IddDrv->ErrorClearIT != NULL)
+ {
+ IddDrv->ErrorClearIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Get Error interrupt status
+ * @retval Status
+ */
+uint8_t BSP_IDD_ErrorGetITStatus(void)
+{
+ if (IddDrv->ErrorGetITStatus != NULL)
+ {
+ return (IddDrv->ErrorGetITStatus(IDD_I2C_ADDRESS));
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief Disable Error interrupt
+ * @retval None
+ */
+void BSP_IDD_ErrorDisableIT(void)
+{
+ if (IddDrv->ErrorDisableIT != NULL)
+ {
+ IddDrv->ErrorDisableIT(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @brief Wake up Idd measurement component.
+ * @retval None
+ */
+void BSP_IDD_WakeUp(void)
+{
+ if (IddDrv->WakeUp != NULL)
+ {
+ IddDrv->WakeUp(IDD_I2C_ADDRESS);
+ }
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.h
new file mode 100644
index 0000000..b1a504e
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_idd.h
@@ -0,0 +1,145 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_idd.h
+ * @author MCD Application Team
+ * @brief Header file for stm32l496g_discovery_idd.c module.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_IDD_H
+#define __STM32L496G_DISCOVERY_IDD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+/* Include Idd measurement component driver */
+#include "../Components/mfxstm32l152/mfxstm32l152.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_IDD
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Exported_Types Exported Types
+ * @{
+ */
+
+/** @defgroup IDD_Config IDD Config
+ * @{
+ */
+typedef enum
+{
+ IDD_OK = 0,
+ IDD_TIMEOUT = 1,
+ IDD_ZERO_VALUE = 2,
+ IDD_ERROR = 0xFF
+}
+IDD_StatusTypeDef;
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_IDD_Exported_Defines Exported Defines
+ * @{
+ */
+/**
+ * @brief Shunt values on discovery in milli ohms
+ */
+#define DISCOVERY_IDD_SHUNT0_VALUE ((uint16_t) 1000) /*!< value in milliohm */
+#define DISCOVERY_IDD_SHUNT1_VALUE ((uint16_t) 24) /*!< value in ohm */
+#define DISCOVERY_IDD_SHUNT2_VALUE ((uint16_t) 620) /*!< value in ohm */
+#define DISCOVERY_IDD_SHUNT4_VALUE ((uint16_t) 10000) /*!< value in ohm */
+
+/**
+ * @brief Shunt stabilization delay on discovery in milli ohms
+ */
+#define DISCOVERY_IDD_SHUNT0_STABDELAY ((uint8_t) 149) /*!< value in millisec */
+#define DISCOVERY_IDD_SHUNT1_STABDELAY ((uint8_t) 149) /*!< value in millisec */
+#define DISCOVERY_IDD_SHUNT2_STABDELAY ((uint8_t) 149) /*!< value in millisec */
+#define DISCOVERY_IDD_SHUNT4_STABDELAY ((uint8_t) 255) /*!< value in millisec */
+
+/**
+ * @brief IDD Ampli Gain on discovery
+ */
+#define DISCOVERY_IDD_AMPLI_GAIN ((uint16_t) 4967) /*!< value is gain * 100 */
+
+/**
+ * @brief IDD Vdd Min on discovery
+ */
+#define DISCOVERY_IDD_VDD_MIN ((uint16_t) 2000) /*!< value in millivolt */
+
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_IDD_Exported_Functions Exported Functions
+ * @{
+ */
+uint8_t BSP_IDD_Init(void);
+void BSP_IDD_DeInit(void);
+void BSP_IDD_Reset(void);
+void BSP_IDD_LowPower(void);
+void BSP_IDD_WakeUp(void);
+void BSP_IDD_StartMeasure(void);
+void BSP_IDD_Config(IDD_ConfigTypeDef IddConfig);
+void BSP_IDD_GetValue(uint32_t *IddValue);
+void BSP_IDD_EnableIT(void);
+void BSP_IDD_ClearIT(void);
+uint8_t BSP_IDD_GetITStatus(void);
+void BSP_IDD_DisableIT(void);
+uint8_t BSP_IDD_ErrorGetCode(void);
+void BSP_IDD_ErrorEnableIT(void);
+void BSP_IDD_ErrorClearIT(void);
+uint8_t BSP_IDD_ErrorGetITStatus(void);
+void BSP_IDD_ErrorDisableIT(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_IDD_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.c
new file mode 100644
index 0000000..4ed532b
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.c
@@ -0,0 +1,305 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_io.c
+ * @author MCD Application Team
+ * @brief This file provides a set of functions needed to manage the IO pins
+ * on STM32L496G-DISCO evaluation board.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* File Info : -----------------------------------------------------------------
+ User NOTES
+1. How To use this driver:
+--------------------------
+ - This driver is used to drive the IO module of the STM32L496G-DISCO evaluation
+ board.
+ - The STMPE811 and STMPE1600 IO expander device component driver must be included with this
+ driver in order to run the IO functionalities commanded by the IO expander
+ device mounted on the evaluation board.
+
+2. Driver description:
+---------------------
+ + Initialization steps:
+ o Initialize the IO module using the BSP_IO_Init() function. This
+ function includes the MSP layer hardware resources initialization and the
+ communication layer configuration to start the IO functionalities use.
+
+ + IO functionalities use
+ o The IO pin mode is configured when calling the function BSP_IO_ConfigPin(), you
+ must specify the desired IO mode by choosing the "IO_ModeTypedef" parameter
+ predefined value.
+ o If an IO pin is used in interrupt mode, the function BSP_IO_ITGetStatus() is
+ needed to get the interrupt status. To clear the IT pending bits, you should
+ call the function BSP_IO_ITClear() with specifying the IO pending bit to clear.
+ o The IT is handled using the corresponding external interrupt IRQ handler,
+ the user IT callback treatment is implemented on the same external interrupt
+ callback.
+ o To get/set an IO pin combination state you can use the functions
+ BSP_IO_ReadPin()/BSP_IO_WritePin() or the function BSP_IO_TogglePin() to toggle the pin
+ state.
+
+------------------------------------------------------------------------------*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_io.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G-DISCO
+ * @{
+ */
+
+/** @defgroup STM32L496G-DISCO_IO STM32L496G-DISCO IO
+ * @{
+ */
+
+/* Private constants ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G-DISCO_IO_Private_Constants Private Constants
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/* Private macros -------------------------------------------------------------*/
+
+/** @defgroup STM32L496G-DISCO_IO_Private_Macros Private Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/* Private variables ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G-DISCO_IO_Private_Variables Private Variables
+ * @{
+ */
+static IO_DrvTypeDef *io1_driver;
+
+/**
+ * @}
+ */
+
+/* Private function prototypes -----------------------------------------------*/
+
+/** @defgroup STM32L496G-DISCO_IO_Private_Functions Private Functions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/* Private functions ---------------------------------------------------------*/
+
+/** @addtogroup STM32L496G-DISCO_IO_Exported_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes and configures the IO functionalities and configures all
+ * necessary hardware resources (GPIOs, clocks..).
+ * @note BSP_IO_Init() is using HAL_Delay() function to ensure that stmpe811
+ * IO Expander is correctly reset. HAL_Delay() function provides accurate
+ * delay (in milliseconds) based on variable incremented in SysTick ISR.
+ * This implies that if BSP_IO_Init() is called from a peripheral ISR process,
+ * then the SysTick interrupt must have higher priority (numerically lower)
+ * than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
+ * @retval IO_OK: if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_IO_Init(void)
+{
+ uint8_t ret = IO_ERROR;
+ uint8_t mfxstm32l152_id = 0;
+
+ if (io1_driver == NULL) /* Checks if MFX initialization has been already done */
+ {
+ mfxstm32l152_idd_drv.WakeUp(IO1_I2C_ADDRESS);
+
+ HAL_Delay(10);
+
+ /* Read ID and verify the IO expander is ready */
+ mfxstm32l152_id = mfxstm32l152_io_drv.ReadID(IO1_I2C_ADDRESS);
+
+ if ((mfxstm32l152_id == MFXSTM32L152_ID_1) || (mfxstm32l152_id == MFXSTM32L152_ID_2))
+ {
+ /* Initialize the MFX */
+ io1_driver = &mfxstm32l152_io_drv;
+
+ /* Initialize the MFX IO driver structure */
+ if (io1_driver->Init != NULL)
+ {
+ io1_driver->Init(IO1_I2C_ADDRESS);
+ io1_driver->Start(IO1_I2C_ADDRESS, IO1_PIN_ALL >> IO1_PIN_OFFSET);
+
+ ret = IO_OK;
+ }
+ }
+ }
+ else
+ {
+ ret = IO_ALREADY_INITIALIZED;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Gets the selected pins IT status.
+ * @param IO_Pin: Selected pins to check the status.
+ * This parameter can be any combination of the IO pins.
+ * @retval Status of the checked IO pin(s).
+ */
+uint32_t BSP_IO_ITGetStatus(uint32_t IO_Pin)
+{
+ uint32_t status = 0;
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+ /* Return the MFX Pin IT status */
+ status |= (io1_driver->ITStatus(IO1_I2C_ADDRESS, io1_pin)) << IO1_PIN_OFFSET;
+
+ return status;
+}
+
+/**
+ * @brief Clears the selected IO IT pending bit.
+ * @param IO_Pin: Selected pins to check the status.
+ * This parameter can be any combination of the IO pins.
+ * @retval None
+ */
+void BSP_IO_ITClear(uint32_t IO_Pin)
+{
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+ /* Clears the selected IO Expander 1 pin(s) mode */
+ io1_driver->ClearIT(IO1_I2C_ADDRESS, io1_pin);
+
+}
+
+/**
+ * @brief Configures the IO pin(s) according to IO mode structure value.
+ * @param IO_Pin: Output pin to be set or reset.
+ * This parameter can be any combination of the IO pins.
+ * @param IO_Mode: IO pin mode to configure
+ * This parameter can be one of the following values:
+ * @arg IO_MODE_INPUT
+ * @arg IO_MODE_OUTPUT
+ * @arg IO_MODE_IT_RISING_EDGE
+ * @arg IO_MODE_IT_FALLING_EDGE
+ * @arg IO_MODE_IT_LOW_LEVEL
+ * @arg IO_MODE_IT_HIGH_LEVEL
+ * @retval IO_OK: if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_IO_ConfigPin(uint32_t IO_Pin, IO_ModeTypedef IO_Mode)
+{
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+
+ /* Configure the selected IO Expander 1 pin(s) mode */
+ io1_driver->Config(IO1_I2C_ADDRESS, io1_pin, IO_Mode);
+
+ return IO_OK;
+}
+
+/**
+ * @brief Sets the selected pins state.
+ * @param IO_Pin: Selected pins to write.
+ * This parameter can be any combination of the IO pins.
+ * @param PinState: New pins state to write
+ * @retval None
+ */
+void BSP_IO_WritePin(uint32_t IO_Pin, uint8_t PinState)
+{
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+ /* Sets the IO Expander 1 selected pins state */
+ io1_driver->WritePin(IO1_I2C_ADDRESS, io1_pin, PinState);
+
+}
+
+/**
+ * @brief Gets the selected pins current state.
+ * @param IO_Pin: Selected pins to read.
+ * This parameter can be any combination of the IO pins.
+ * @retval The current pins state
+ */
+uint32_t BSP_IO_ReadPin(uint32_t IO_Pin)
+{
+ uint32_t pin_state = 0;
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+ /* Gets the IO Expander 1 selected pins current state */
+ pin_state |= (io1_driver->ReadPin(IO1_I2C_ADDRESS, io1_pin)) << IO1_PIN_OFFSET;
+
+
+ return pin_state;
+}
+
+/**
+ * @brief Toggles the selected pins state
+ * @param IO_Pin: Selected pins to toggle.
+ * This parameter can be any combination of the IO pins.
+ * @retval None
+ */
+void BSP_IO_TogglePin(uint32_t IO_Pin)
+{
+ uint32_t io1_pin = 0;
+
+ io1_pin = (IO_Pin & IO1_PIN_ALL) >> IO1_PIN_OFFSET;
+
+ /* Toggles the IO Expander 1 selected pins state */
+ if (io1_driver->ReadPin(IO1_I2C_ADDRESS, io1_pin) == RESET) /* Set */
+ {
+ BSP_IO_WritePin(io1_pin, GPIO_PIN_SET); /* Reset */
+ }
+ else
+ {
+ BSP_IO_WritePin(io1_pin, GPIO_PIN_RESET); /* Set */
+ }
+
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.h
new file mode 100644
index 0000000..a03d57c
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_io.h
@@ -0,0 +1,128 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_io.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_eval_io.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCO_IO_H
+#define __STM32L496G_DISCO_IO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+#include "../Components/mfxstm32l152/mfxstm32l152.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCO
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCO_IO
+ * @{
+ */
+
+/* Exported types ------------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCO_IO_Exported_Types Exported Types
+ * @{
+ */
+typedef enum
+{
+ IO_OK = 0x00,
+ IO_ERROR = 0x01,
+ IO_TIMEOUT = 0x02,
+ IO_ALREADY_INITIALIZED = 0x03
+}
+IO_StatusTypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCO_IO_Exported_Constants Exported Constants
+ * @{
+ */
+/* Virtual pin offset IOExpander1 */
+#define IO1_PIN_OFFSET 0
+
+
+/* Pins definition IOExpander */
+#define IO1_PIN_0 (uint32_t)(0x00000001 << IO1_PIN_OFFSET)
+#define IO1_PIN_1 (uint32_t)(0x00000002 << IO1_PIN_OFFSET)
+#define IO1_PIN_2 (uint32_t)(0x00000004 << IO1_PIN_OFFSET)
+#define IO1_PIN_3 (uint32_t)(0x00000008 << IO1_PIN_OFFSET)
+#define IO1_PIN_4 (uint32_t)(0x00000010 << IO1_PIN_OFFSET)
+#define IO1_PIN_5 (uint32_t)(0x00000020 << IO1_PIN_OFFSET)
+#define IO1_PIN_6 (uint32_t)(0x00000040 << IO1_PIN_OFFSET)
+#define IO1_PIN_7 (uint32_t)(0x00000080 << IO1_PIN_OFFSET)
+#define IO1_PIN_8 (uint32_t)(0x00000100 << IO1_PIN_OFFSET)
+#define AGPIO_PIN_0 (uint32_t)(0x00010000 << IO1_PIN_OFFSET)
+#define AGPIO_PIN_1 (uint32_t)(0x00020000 << IO1_PIN_OFFSET)
+
+#define IO1_PIN_ALL (uint32_t)(0x000301FF << IO1_PIN_OFFSET)
+
+
+
+
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCO_IO_Exported_Functions Exported Functions
+ * @{
+ */
+
+uint8_t BSP_IO_Init(void);
+void BSP_IO_ITClear(uint32_t IO_Pin);
+uint32_t BSP_IO_ITGetStatus(uint32_t IO_Pin);
+uint8_t BSP_IO_ConfigPin(uint32_t IO_Pin, IO_ModeTypedef IO_Mode);
+void BSP_IO_WritePin(uint32_t IO_Pin, uint8_t PinState);
+uint32_t BSP_IO_ReadPin(uint32_t IO_Pin);
+void BSP_IO_TogglePin(uint32_t IO_Pin);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCO_IO_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.c
new file mode 100644
index 0000000..4fe05f5
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.c
@@ -0,0 +1,1569 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_lcd.c
+ * @author MCD Application Team
+ * @brief This file includes the driver for Liquid Crystal Display (LCD) module
+ * mounted on STM32L496G-DISCOVERY board.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* File Info : -----------------------------------------------------------------
+ User NOTES
+1. How To use this driver:
+--------------------------
+ - This driver is used to drive indirectly an LCD TFT.
+ - This driver supports the LS016B8UY LCD.
+ - The LS016B8UY and ST7789H2 components driver MUST be included with this driver.
+
+2. Driver description:
+---------------------
+ + Initialization steps:
+ o Initialize the LCD using the BSP_LCD_Init() function.
+
+ + Display on LCD
+ o Clear the hole LCD using BSP_LCD_Clear() function or only one specified string
+ line using the BSP_LCD_ClearStringLine() function.
+ o Display a character on the specified line and column using the BSP_LCD_DisplayChar()
+ function or a complete string line using the BSP_LCD_DisplayStringAtLine() function.
+ o Display a string line on the specified position (x,y in pixel) and align mode
+ using the BSP_LCD_DisplayStringAtLine() function.
+ o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap)
+ on LCD using the available set of functions.
+
+------------------------------------------------------------------------------*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_lcd.h"
+#include "../../../Utilities/Fonts/fonts.h"
+#include "../../../Utilities/Fonts/font24.c"
+#include "../../../Utilities/Fonts/font20.c"
+#include "../../../Utilities/Fonts/font16.c"
+#include "../../../Utilities/Fonts/font12.c"
+#include "../../../Utilities/Fonts/font8.c"
+
+
+static uint32_t bsp_lcd_initialized = 0;
+static uint8_t LCD_orientation = LCD_ORIENTATION_UNDEFINED;
+
+uint32_t dimming_on = 0;
+
+typedef struct dimming_config_s
+{
+ uint8_t ongoing;
+ uint8_t start;
+ uint8_t stop;
+ uint8_t step;
+ uint8_t delay;
+} dimming_config_t;
+
+#define __DIMMING_CYCLE_VALUE(value) (uint32_t)((PERIOD_VALUE * value)/100)
+static dimming_config_t dimming_config = { 0, 25, 5, 1, PULSE_DECREASE_DELAY };
+
+#if defined(LPTIMER_DIMMING)
+LPTIM_HandleTypeDef LCD_LpTimHandle;
+#endif
+/* Timer handler declaration */
+TIM_HandleTypeDef LCD_TimHandle;
+/* Timer Output Compare Configuration Structure declaration */
+TIM_OC_InitTypeDef LCD_sConfig;
+
+#if defined(LPTIMER_DIMMING)
+extern uint32_t dimming_enable;
+#endif
+
+
+extern uint32_t ts_io_init;
+
+/* Use by application to not use backlight */
+FlagStatus WakeUpFromStandby;
+FlagStatus WakeUpFromShutdown;
+
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD STM32L496G-DISCOVERY LCD
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_TypesDefinitions STM32L496G Discovery Lcd Private TypesDef
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_Defines STM32L496G Discovery Lcd Private Defines
+ * @{
+ */
+#define POLY_X(Z) ((int32_t)((Points + Z)->X))
+#define POLY_Y(Z) ((int32_t)((Points + Z)->Y))
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_Macros STM32L496G Discovery Lcd Private Macros
+ * @{
+ */
+#define ABS(X) ((X) > 0 ? (X) : -(X))
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_Variables STM32L496G Discovery Lcd Private Variables
+ * @{
+ */
+LCD_DrawPropTypeDef DrawProp;
+static LCD_DrvTypeDef *LcdDrv;
+
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_FunctionPrototypes STM32L496G Discovery Lcd Private Prototypes
+ * @{
+ */
+static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
+static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height);
+static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3);
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Private_Functions STM32L496G Discovery Lcd Private Functions
+ * @{
+ */
+/**
+ * @brief Initializes the LCD.
+ * @param None
+ * @retval LCD state
+ */
+uint8_t BSP_LCD_Init(void)
+{
+ return (BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE));
+}
+
+/**
+ * @brief Initializes the LCD with a given orientation.
+ * @param orientation: LCD_ORIENTATION_PORTRAIT or LCD_ORIENTATION_LANDSCAPE
+ * @retval LCD state
+ */
+uint8_t BSP_LCD_InitEx(uint32_t orientation)
+{
+ uint8_t ret = LCD_ERROR;
+ uint32_t i = 0;
+
+ if (bsp_lcd_initialized == 1)
+ {
+ ret = LCD_OK;
+ }
+ else
+ {
+ /* Initialize the IO functionalities */
+ if (BSP_IO_Init() == IO_ERROR)
+ {
+ BSP_ErrorHandler();
+ }
+
+ /* Initialize LCD special pins GPIOs */
+ BSP_LCD_MspInit();
+
+ /* LCD Power On */
+ HAL_GPIO_WritePin(LCD_PWR_CTRL_GPIO_PORT, LCD_PWR_CTRL_PIN, GPIO_PIN_RESET);
+
+ /* Default value for draw propriety */
+ DrawProp.BackColor = 0xFFFF;
+ DrawProp.pFont = &Font24;
+ DrawProp.TextColor = 0x0000;
+
+ if ((WakeUpFromStandby == RESET) && (WakeUpFromShutdown == RESET))
+ {
+ /* Backlight control signal assertion */
+ HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET);
+ }
+
+ /* Reset the LCD */
+ BSP_LCD_Reset();
+
+ if (ST7789H2_drv.ReadID() == ST7789H2_ID)
+ {
+ LcdDrv = &ST7789H2_drv;
+
+ /* LCD Init */
+ LcdDrv->Init();
+
+ /* Fill LCD frame memory with white pixels (or black pixels if INIT_BLACK_LCD is enabled) */
+ ST7789H2_WriteReg(ST7789H2_WRITE_RAM, (uint8_t *)NULL, 0); /* RAM Write Data */
+ for (i = 0; i < (ST7789H2_LCD_PIXEL_WIDTH * ST7789H2_LCD_PIXEL_HEIGHT); i++)
+ {
+#if defined(INIT_BLACK_LCD)
+ LCD_IO_WriteData(0x0);
+#else
+ LCD_IO_WriteData(0xFFFF);
+#endif
+ }
+
+ if (orientation == LCD_ORIENTATION_PORTRAIT)
+ {
+ ST7789H2_SetOrientation(ST7789H2_ORIENTATION_PORTRAIT);
+ LCD_orientation = LCD_ORIENTATION_PORTRAIT;
+ }
+ else
+ {
+ LCD_orientation = LCD_ORIENTATION_LANDSCAPE;
+ }
+ /* Initialize the font */
+ BSP_LCD_SetFont(&LCD_DEFAULT_FONT);
+
+ bsp_lcd_initialized = 1;
+ ret = LCD_OK;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Reset the LCD.
+ * @param None
+ * @retval LCD state
+ */
+void BSP_LCD_Reset(void)
+{
+ /* Apply hardware reset according to procedure indicated in FRD154BP2901 documentation */
+ BSP_IO_WritePin(LCD_RST_PIN, GPIO_PIN_RESET);
+ HAL_Delay(5); /* Reset signal asserted during 5ms */
+ BSP_IO_WritePin(LCD_RST_PIN, GPIO_PIN_SET);
+ HAL_Delay(10); /* Reset signal released during 10ms */
+ BSP_IO_WritePin(LCD_RST_PIN, GPIO_PIN_RESET);
+ HAL_Delay(20); /* Reset signal asserted during 20ms */
+ BSP_IO_WritePin(LCD_RST_PIN, GPIO_PIN_SET);
+ HAL_Delay(10); /* Reset signal released during 10ms */
+}
+
+/**
+ * @brief DeInitializes the LCD.
+ * @param None
+ * @retval LCD state
+ */
+uint8_t BSP_LCD_DeInit(void)
+{
+ BSP_LCD_MspDeInit();
+
+ bsp_lcd_initialized = 0;
+ ts_io_init = 0;
+
+ return LCD_OK;
+}
+
+/**
+ * @brief Gets the LCD X size.
+ * @param None
+ * @retval Used LCD X size
+ */
+uint32_t BSP_LCD_GetXSize(void)
+{
+ return (LcdDrv->GetLcdPixelWidth());
+}
+
+/**
+ * @brief Gets the LCD Y size.
+ * @param None
+ * @retval Used LCD Y size
+ */
+uint32_t BSP_LCD_GetYSize(void)
+{
+ return (LcdDrv->GetLcdPixelHeight());
+}
+
+/**
+ * @brief Gets the LCD text color.
+ * @param None
+ * @retval Used text color.
+ */
+uint16_t BSP_LCD_GetTextColor(void)
+{
+ return DrawProp.TextColor;
+}
+
+/**
+ * @brief Gets the LCD background color.
+ * @param None
+ * @retval Used background color
+ */
+uint16_t BSP_LCD_GetBackColor(void)
+{
+ return DrawProp.BackColor;
+}
+
+/**
+ * @brief Sets the LCD text color.
+ * @param Color: Text color code RGB(5-6-5)
+ * @retval None
+ */
+void BSP_LCD_SetTextColor(uint16_t Color)
+{
+ DrawProp.TextColor = Color;
+}
+
+/**
+ * @brief Sets the LCD background color.
+ * @param Color: Background color code RGB(5-6-5)
+ * @retval None
+ */
+void BSP_LCD_SetBackColor(uint16_t Color)
+{
+ DrawProp.BackColor = Color;
+}
+
+/**
+ * @brief Sets the LCD text font.
+ * @param fonts: Font to be used
+ * @retval None
+ */
+void BSP_LCD_SetFont(sFONT *fonts)
+{
+ DrawProp.pFont = fonts;
+}
+
+/**
+ * @brief Gets the LCD text font.
+ * @param None
+ * @retval Used font
+ */
+sFONT *BSP_LCD_GetFont(void)
+{
+ return DrawProp.pFont;
+}
+
+/**
+ * @brief Clears the hole LCD.
+ * @param Color: Color of the background
+ * @retval None
+ */
+void BSP_LCD_Clear(uint16_t Color)
+{
+ uint32_t counter = 0;
+ uint32_t y_size = 0;
+ uint32_t color_backup = DrawProp.TextColor;
+
+ DrawProp.TextColor = Color;
+ y_size = BSP_LCD_GetYSize();
+
+ for (counter = 0; counter < y_size; counter++)
+ {
+ BSP_LCD_DrawHLine(0, counter, BSP_LCD_GetXSize());
+ }
+ DrawProp.TextColor = color_backup;
+ BSP_LCD_SetTextColor(DrawProp.TextColor);
+}
+
+/**
+ * @brief Clears the selected line.
+ * @param Line: Line to be cleared
+ * This parameter can be one of the following values:
+ * @arg 0..9: if the Current fonts is Font16x24
+ * @arg 0..19: if the Current fonts is Font12x12 or Font8x12
+ * @arg 0..29: if the Current fonts is Font8x8
+ * @retval None
+ */
+void BSP_LCD_ClearStringLine(uint16_t Line)
+{
+ uint32_t color_backup = DrawProp.TextColor;
+
+ DrawProp.TextColor = DrawProp.BackColor;;
+
+ /* Draw a rectangle with background color */
+ BSP_LCD_FillRect(0, (Line * DrawProp.pFont->Height), BSP_LCD_GetXSize(), DrawProp.pFont->Height);
+
+ DrawProp.TextColor = color_backup;
+ BSP_LCD_SetTextColor(DrawProp.TextColor);
+}
+
+/**
+ * @brief Displays one character.
+ * @param Xpos: Start column address
+ * @param Ypos: Line where to display the character shape.
+ * @param Ascii: Character ascii code
+ * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E
+ * @retval None
+ */
+void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii)
+{
+ DrawChar(Xpos, Ypos, &DrawProp.pFont->table[(Ascii - ' ') *\
+ DrawProp.pFont->Height * ((DrawProp.pFont->Width + 7) / 8)]);
+}
+
+/**
+ * @brief Displays characters on the LCD.
+ * @param Xpos: X position (in pixel)
+ * @param Ypos: Y position (in pixel)
+ * @param Text: Pointer to string to display on LCD
+ * @param Mode: Display mode
+ * This parameter can be one of the following values:
+ * @arg CENTER_MODE
+ * @arg RIGHT_MODE
+ * @arg LEFT_MODE
+ * @retval None
+ */
+void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode)
+{
+ uint16_t refcolumn = 1, i = 0;
+ uint32_t size = 0, xsize = 0;
+ uint8_t *ptr = Text;
+
+ /* Get the text size */
+ while (*ptr++)
+ {
+ size ++ ;
+ }
+
+ /* Characters number per line */
+ xsize = (BSP_LCD_GetXSize() / DrawProp.pFont->Width);
+
+ switch (Mode)
+ {
+ case CENTER_MODE:
+ {
+ refcolumn = Xpos + ((xsize - size) * DrawProp.pFont->Width) / 2;
+ break;
+ }
+ case LEFT_MODE:
+ {
+ refcolumn = Xpos;
+ break;
+ }
+ case RIGHT_MODE:
+ {
+ refcolumn = - Xpos + ((xsize - size) * DrawProp.pFont->Width);
+ break;
+ }
+ default:
+ {
+ refcolumn = Xpos;
+ break;
+ }
+ }
+
+ /* Check that the Start column is located in the screen */
+ if ((refcolumn < 1) || (refcolumn >= 0x8000))
+ {
+ refcolumn = 1;
+ }
+
+ /* Send the string character by character on lCD */
+ while ((*Text != 0) && (((BSP_LCD_GetXSize() - (i * DrawProp.pFont->Width)) & 0xFFFF) >= DrawProp.pFont->Width))
+ {
+ /* Display one character on LCD */
+ BSP_LCD_DisplayChar(refcolumn, Ypos, *Text);
+ /* Decrement the column position by 16 */
+ refcolumn += DrawProp.pFont->Width;
+ /* Point on the next character */
+ Text++;
+ i++;
+ }
+}
+
+/**
+ * @brief Displays a character on the LCD.
+ * @param Line: Line where to display the character shape
+ * This parameter can be one of the following values:
+ * @arg 0..9: if the Current fonts is Font16x24
+ * @arg 0..19: if the Current fonts is Font12x12 or Font8x12
+ * @arg 0..29: if the Current fonts is Font8x8
+ * @param ptr: Pointer to string to display on LCD
+ * @retval None
+ */
+void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr)
+{
+ BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE);
+}
+
+/**
+ * @brief Reads an LCD pixel.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @retval RGB pixel color
+ */
+uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos)
+{
+ uint16_t ret = 0;
+
+ if (LcdDrv->ReadPixel != NULL)
+ {
+ ret = LcdDrv->ReadPixel(Xpos, Ypos);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Draws a pixel on LCD.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param RGB_Code: Pixel color in RGB mode (5-6-5)
+ * @retval None
+ */
+void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code)
+{
+ if (LcdDrv->WritePixel != NULL)
+ {
+ LcdDrv->WritePixel(Xpos, Ypos, RGB_Code);
+ }
+}
+
+/**
+ * @brief Draws an horizontal line.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Length: Line length
+ * @retval None
+ */
+void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
+{
+ uint32_t index = 0;
+
+ if (LcdDrv->DrawHLine != NULL)
+ {
+ LcdDrv->DrawHLine(DrawProp.TextColor, Xpos, Ypos, Length);
+ }
+ else
+ {
+ for (index = 0; index < Length; index++)
+ {
+ BSP_LCD_DrawPixel((Xpos + index), Ypos, DrawProp.TextColor);
+ }
+ }
+}
+
+/**
+ * @brief Draws a vertical line.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Length: Line length
+ * @retval None
+ */
+void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
+{
+ uint32_t index = 0;
+
+ if (LcdDrv->DrawVLine != NULL)
+ {
+ LcdDrv->DrawVLine(DrawProp.TextColor, Xpos, Ypos, Length);
+ }
+ else
+ {
+ for (index = 0; index < Length; index++)
+ {
+ BSP_LCD_DrawPixel(Xpos, Ypos + index, DrawProp.TextColor);
+ }
+ }
+}
+
+/**
+ * @brief Draws an uni-line (between two points).
+ * @param x1: Point 1 X position
+ * @param y1: Point 1 Y position
+ * @param x2: Point 2 X position
+ * @param y2: Point 2 Y position
+ * @retval None
+ */
+void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
+{
+ int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
+ yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
+ curpixel = 0;
+
+ deltax = ABS(x2 - x1); /* The difference between the x's */
+ deltay = ABS(y2 - y1); /* The difference between the y's */
+ x = x1; /* Start x off at the first pixel */
+ y = y1; /* Start y off at the first pixel */
+
+ if (x2 >= x1) /* The x-values are increasing */
+ {
+ xinc1 = 1;
+ xinc2 = 1;
+ }
+ else /* The x-values are decreasing */
+ {
+ xinc1 = -1;
+ xinc2 = -1;
+ }
+
+ if (y2 >= y1) /* The y-values are increasing */
+ {
+ yinc1 = 1;
+ yinc2 = 1;
+ }
+ else /* The y-values are decreasing */
+ {
+ yinc1 = -1;
+ yinc2 = -1;
+ }
+
+ if (deltax >= deltay) /* There is at least one x-value for every y-value */
+ {
+ xinc1 = 0; /* Don't change the x when numerator >= denominator */
+ yinc2 = 0; /* Don't change the y for every iteration */
+ den = deltax;
+ num = deltax / 2;
+ numadd = deltay;
+ numpixels = deltax; /* There are more x-values than y-values */
+ }
+ else /* There is at least one y-value for every x-value */
+ {
+ xinc2 = 0; /* Don't change the x for every iteration */
+ yinc1 = 0; /* Don't change the y when numerator >= denominator */
+ den = deltay;
+ num = deltay / 2;
+ numadd = deltax;
+ numpixels = deltay; /* There are more y-values than x-values */
+ }
+
+ for (curpixel = 0; curpixel <= numpixels; curpixel++)
+ {
+ BSP_LCD_DrawPixel(x, y, DrawProp.TextColor); /* Draw the current pixel */
+ num += numadd; /* Increase the numerator by the top of the fraction */
+ if (num >= den) /* Check if numerator >= denominator */
+ {
+ num -= den; /* Calculate the new numerator value */
+ x += xinc1; /* Change the x as appropriate */
+ y += yinc1; /* Change the y as appropriate */
+ }
+ x += xinc2; /* Change the x as appropriate */
+ y += yinc2; /* Change the y as appropriate */
+ }
+}
+
+/**
+ * @brief Draws a rectangle.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Width: Rectangle width
+ * @param Height: Rectangle height
+ * @retval None
+ */
+void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
+{
+ /* Draw horizontal lines */
+ BSP_LCD_DrawHLine(Xpos, Ypos, Width);
+ BSP_LCD_DrawHLine(Xpos, (Ypos + Height), Width);
+
+ /* Draw vertical lines */
+ BSP_LCD_DrawVLine(Xpos, Ypos, Height);
+ BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height);
+}
+
+/**
+ * @brief Draws a circle.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Radius: Circle radius
+ * @retval None
+ */
+void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
+{
+ int32_t decision; /* Decision Variable */
+ uint32_t current_x; /* Current X Value */
+ uint32_t current_y; /* Current Y Value */
+
+ decision = 3 - (Radius << 1);
+ current_x = 0;
+ current_y = Radius;
+
+ while (current_x <= current_y)
+ {
+ BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp.TextColor);
+
+ BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp.TextColor);
+
+ /* Initialize the font */
+ BSP_LCD_SetFont(&LCD_DEFAULT_FONT);
+
+ if (decision < 0)
+ {
+ decision += (current_x << 2) + 6;
+ }
+ else
+ {
+ decision += ((current_x - current_y) << 2) + 10;
+ current_y--;
+ }
+ current_x++;
+ }
+}
+
+/**
+ * @brief Draws an poly-line (between many points).
+ * @param Points: Pointer to the points array
+ * @param PointCount: Number of points
+ * @retval None
+ */
+void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount)
+{
+ int16_t x = 0, y = 0;
+
+ if (PointCount < 2)
+ {
+ return;
+ }
+
+ BSP_LCD_DrawLine(Points->X, Points->Y, (Points + PointCount - 1)->X, (Points + PointCount - 1)->Y);
+
+ while (--PointCount)
+ {
+ x = Points->X;
+ y = Points->Y;
+ Points++;
+ BSP_LCD_DrawLine(x, y, Points->X, Points->Y);
+ }
+}
+
+/**
+ * @brief Draws an ellipse on LCD.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param XRadius: Ellipse X radius
+ * @param YRadius: Ellipse Y radius
+ * @retval None
+ */
+void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius)
+{
+ int x = 0, y = -YRadius, err = 2 - 2 * XRadius, e2;
+ float k = 0, rad1 = 0, rad2 = 0;
+
+ rad1 = XRadius;
+ rad2 = YRadius;
+
+ k = (float)(rad2 / rad1);
+
+ do
+ {
+ BSP_LCD_DrawPixel((Xpos - (uint16_t)(x / k)), (Ypos + y), DrawProp.TextColor);
+ BSP_LCD_DrawPixel((Xpos + (uint16_t)(x / k)), (Ypos + y), DrawProp.TextColor);
+ BSP_LCD_DrawPixel((Xpos + (uint16_t)(x / k)), (Ypos - y), DrawProp.TextColor);
+ BSP_LCD_DrawPixel((Xpos - (uint16_t)(x / k)), (Ypos - y), DrawProp.TextColor);
+
+ e2 = err;
+ if (e2 <= x)
+ {
+ err += ++x * 2 + 1;
+ if (-y == x && e2 <= y)
+ {
+ e2 = 0;
+ }
+ }
+ if (e2 > y)
+ {
+ err += ++y * 2 + 1;
+ }
+ }
+ while (y <= 0);
+}
+
+/**
+ * @brief Draws a bitmap picture (16 bpp).
+ * @param Xpos: Bmp X position in the LCD
+ * @param Ypos: Bmp Y position in the LCD
+ * @param pbmp: Pointer to Bmp picture address.
+ * @retval None
+ */
+void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp)
+{
+ uint32_t height = 0;
+ uint32_t width = 0;
+
+
+ /* Read bitmap width */
+ width = *(uint16_t *)(pbmp + 18);
+ width |= (*(uint16_t *)(pbmp + 20)) << 16;
+
+ /* Read bitmap height */
+ height = *(uint16_t *)(pbmp + 22);
+ height |= (*(uint16_t *)(pbmp + 24)) << 16;
+
+ SetDisplayWindow(Xpos, Ypos, width, height);
+
+ if (LcdDrv->DrawBitmap != NULL)
+ {
+ LcdDrv->DrawBitmap(Xpos, Ypos, pbmp);
+ }
+ SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
+}
+
+/**
+ * @brief Draws RGB Image (16 bpp).
+ * @param Xpos: X position in the LCD
+ * @param Ypos: Y position in the LCD
+ * @param Xsize: X size in the LCD
+ * @param Ysize: Y size in the LCD
+ * @param pdata: Pointer to the RGB Image address.
+ * @retval None
+ */
+void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata)
+{
+
+ SetDisplayWindow(Xpos, Ypos, Xsize, Ysize);
+
+ if (LcdDrv->DrawRGBImage != NULL)
+ {
+ LcdDrv->DrawRGBImage(Xpos, Ypos, Xsize, Ysize, pdata);
+ }
+ SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
+}
+
+/**
+ * @brief Draws a full rectangle.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Width: Rectangle width
+ * @param Height: Rectangle height
+ * @retval None
+ */
+void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
+{
+ BSP_LCD_SetTextColor(DrawProp.TextColor);
+ do
+ {
+ BSP_LCD_DrawHLine(Xpos, Ypos++, Width);
+ }
+ while (Height--);
+}
+
+/**
+ * @brief Draws a full circle.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param Radius: Circle radius
+ * @retval None
+ */
+void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
+{
+ int32_t decision; /* Decision Variable */
+ uint32_t current_x; /* Current X Value */
+ uint32_t current_y; /* Current Y Value */
+
+ decision = 3 - (Radius << 1);
+
+ current_x = 0;
+ current_y = Radius;
+
+ BSP_LCD_SetTextColor(DrawProp.TextColor);
+
+ while (current_x <= current_y)
+ {
+ if (current_y > 0)
+ {
+ BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2 * current_y);
+ BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2 * current_y);
+ }
+
+ if (current_x > 0)
+ {
+ BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2 * current_x);
+ BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2 * current_x);
+ }
+ if (decision < 0)
+ {
+ decision += (current_x << 2) + 6;
+ }
+ else
+ {
+ decision += ((current_x - current_y) << 2) + 10;
+ current_y--;
+ }
+ current_x++;
+ }
+
+ BSP_LCD_SetTextColor(DrawProp.TextColor);
+ BSP_LCD_DrawCircle(Xpos, Ypos, Radius);
+}
+
+/**
+ * @brief Draws a full poly-line (between many points).
+ * @param Points: Pointer to the points array
+ * @param PointCount: Number of points
+ * @retval None
+ */
+void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount)
+{
+ int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0;
+ uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0;
+
+ IMAGE_LEFT = IMAGE_RIGHT = Points->X;
+ IMAGE_TOP = IMAGE_BOTTOM = Points->Y;
+
+ for (counter = 1; counter < PointCount; counter++)
+ {
+ pixelX = POLY_X(counter);
+ if (pixelX < IMAGE_LEFT)
+ {
+ IMAGE_LEFT = pixelX;
+ }
+ if (pixelX > IMAGE_RIGHT)
+ {
+ IMAGE_RIGHT = pixelX;
+ }
+
+ pixelY = POLY_Y(counter);
+ if (pixelY < IMAGE_TOP)
+ {
+ IMAGE_TOP = pixelY;
+ }
+ if (pixelY > IMAGE_BOTTOM)
+ {
+ IMAGE_BOTTOM = pixelY;
+ }
+ }
+
+ if (PointCount < 2)
+ {
+ return;
+ }
+
+ X_center = (IMAGE_LEFT + IMAGE_RIGHT) / 2;
+ Y_center = (IMAGE_BOTTOM + IMAGE_TOP) / 2;
+
+ X_first = Points->X;
+ Y_first = Points->Y;
+
+ while (--PointCount)
+ {
+ X = Points->X;
+ Y = Points->Y;
+ Points++;
+ X2 = Points->X;
+ Y2 = Points->Y;
+
+ FillTriangle(X, X2, X_center, Y, Y2, Y_center);
+ FillTriangle(X, X_center, X2, Y, Y_center, Y2);
+ FillTriangle(X_center, X2, X, Y_center, Y2, Y);
+ }
+
+ FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center);
+ FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2);
+ FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first);
+}
+
+/**
+ * @brief Draws a full ellipse.
+ * @param Xpos: X position
+ * @param Ypos: Y position
+ * @param XRadius: Ellipse X radius
+ * @param YRadius: Ellipse Y radius
+ * @retval None
+ */
+void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius)
+{
+ int x = 0, y = -YRadius, err = 2 - 2 * XRadius, e2;
+ float k = 0, rad1 = 0, rad2 = 0;
+
+ rad1 = XRadius;
+ rad2 = YRadius;
+
+ k = (float)(rad2 / rad1);
+
+ do
+ {
+ BSP_LCD_DrawHLine((Xpos - (uint16_t)(x / k)), (Ypos + y), (2 * (uint16_t)(x / k) + 1));
+ BSP_LCD_DrawHLine((Xpos - (uint16_t)(x / k)), (Ypos - y), (2 * (uint16_t)(x / k) + 1));
+
+ e2 = err;
+ if (e2 <= x)
+ {
+ err += ++x * 2 + 1;
+ if (-y == x && e2 <= y)
+ {
+ e2 = 0;
+ }
+ }
+ if (e2 > y)
+ {
+ err += ++y * 2 + 1;
+ }
+ }
+ while (y <= 0);
+}
+
+/**
+ * @brief Enables the display.
+ * @param None
+ * @retval None
+ */
+void BSP_LCD_DisplayOn(void)
+{
+ LcdDrv->DisplayOn();
+}
+
+/**
+ * @brief Disables the display.
+ * @param None
+ * @retval None
+ */
+void BSP_LCD_DisplayOff(void)
+{
+ LcdDrv->DisplayOff();
+}
+
+
+/**
+ * @brief LCD screen dimming enable
+ * @note Screen brightness is gradually decreased
+ * @param start : value in percent to start from
+ * @param stop : value in percent to stop to
+ * @param step : step value in percent
+ * @param delay : delay in milliseconds between each step
+ * @retval None
+ */
+void BSP_LCD_ScreenDimmingConfig(const uint8_t start, const uint8_t stop, const uint8_t step, const uint8_t delay)
+{
+ if ((dimming_config.ongoing == 0)
+ && (start <= 100) && (stop <= 100)
+ && (step > 0) && (step < 100))
+ {
+ dimming_config.start = start;
+ dimming_config.stop = stop;
+ dimming_config.step = step;
+ dimming_config.delay = delay;
+ }
+}
+
+
+/**
+ * @brief LCD screen dimming enable
+ * @note Screen brightness is gradually decreased
+ * @param None
+ * @retval None
+ */
+void BSP_LCD_ScreenDimmingOn(void)
+{
+ static uint32_t i = 0;
+
+#if defined(LPTIMER_DIMMING)
+ /* Set that dim feature is active */
+ if (dimming_on == 0)
+ {
+ dimming_on = 1;
+ i = PULSE_DECREASE_START;
+ /* Always redo the full initialization as there is no apriori knowledge
+ of IO or timer settings at this point (may have been modified by application) */
+
+ __HAL_RCC_LSI_ENABLE();
+ /* Select LSI as LPTIM1 clock source */
+ __HAL_RCC_LPTIM1_CONFIG(RCC_LPTIM1CLKSOURCE_LSI);
+
+
+ LCD_LpTimHandle.Instance = LPTIM1;
+ __HAL_LPTIM_RESET_HANDLE_STATE(&LCD_LpTimHandle); /* to force MSP call */
+
+ LCD_LpTimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
+ LCD_LpTimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
+ LCD_LpTimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
+ LCD_LpTimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
+ LCD_LpTimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
+ LCD_LpTimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
+ LCD_LpTimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_COMP1;
+
+ /* Initialize LPTIM peripheral according to the passed parameters */
+ if (HAL_LPTIM_Init(&LCD_LpTimHandle) != HAL_OK)
+ {
+ /* Initialization Error */
+ BSP_ErrorHandler();
+ }
+
+ if (HAL_LPTIM_PWM_Start(&LCD_LpTimHandle, PERIOD_VALUE, i) != HAL_OK)
+ {
+ BSP_ErrorHandler();
+ }
+
+
+ }
+ else
+ {
+ i++;
+ }
+
+ /* Optional delay to slow down the dimming transition. */
+ HAL_Delay(PULSE_DECREASE_DELAY);
+ if (HAL_LPTIM_PWM_Start(&LCD_LpTimHandle, PERIOD_VALUE, i) != HAL_OK)
+ {
+ BSP_ErrorHandler();
+ }
+ if (i == PULSE_VALUE)
+ {
+ dimming_enable = 0;
+ }
+
+
+#else
+ /* Counter Prescaler value */
+ uint32_t uhPrescalerValue = 0;
+ int32_t step;
+
+ /* Reject this while ongoing dimming */
+ if (dimming_config.ongoing)
+ {
+ return;
+ }
+
+ /* Set that dim feature is active */
+ dimming_on = 1;
+ dimming_config.ongoing = 1;
+
+ if (dimming_config.stop > dimming_config.start)
+ {
+ step = dimming_config.step;
+ }
+ else
+ {
+ step = -dimming_config.step;
+ }
+
+ /* Always redo the full initialization as there is no apriori knowledge
+ of IO or timer settings at this point (may have been modified by application) */
+
+ /* Compute the prescaler value to have TIM1 counter clock equal to 16000000 Hz */
+ uhPrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
+
+ LCD_TimHandle.Instance = TIMx;
+
+ __HAL_TIM_RESET_HANDLE_STATE(&LCD_TimHandle); /* to force MSP call */
+ LCD_TimHandle.Init.Prescaler = uhPrescalerValue;
+ LCD_TimHandle.Init.Period = PERIOD_VALUE;
+ LCD_TimHandle.Init.ClockDivision = 0;
+ LCD_TimHandle.Init.CounterMode = (step > 0 ? TIM_COUNTERMODE_DOWN : TIM_COUNTERMODE_UP);
+ LCD_TimHandle.Init.RepetitionCounter = 0;
+ if (HAL_TIM_PWM_Init(&LCD_TimHandle) != HAL_OK)
+ {
+ /* Initialization Error */
+ BSP_ErrorHandler();
+ }
+
+ /* Common configuration for all channels */
+ LCD_sConfig.OCMode = TIM_OCMODE_PWM1;
+ LCD_sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
+ LCD_sConfig.OCFastMode = TIM_OCFAST_DISABLE;
+ LCD_sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+ LCD_sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+
+ LCD_sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
+
+ /* Set the pulse value for channel */
+ LCD_sConfig.Pulse = __DIMMING_CYCLE_VALUE(dimming_config.start);
+ if (HAL_TIM_PWM_ConfigChannel(&LCD_TimHandle, &LCD_sConfig, TIMx_CHANNEL) != HAL_OK)
+ {
+ /* Configuration Error */
+ BSP_ErrorHandler();
+ }
+
+ /* Start Timer channel */
+ if (HAL_TIM_PWM_Start(&LCD_TimHandle, TIMx_CHANNEL) != HAL_OK)
+ {
+ /* PWM Generation Error */
+ BSP_ErrorHandler();
+ }
+
+ /* Set the pulse value for the timer channel */
+ i = dimming_config.start;
+ while (dimming_config.ongoing)
+ {
+ __HAL_TIM_SET_COMPARE(&LCD_TimHandle, TIMx_CHANNEL, __DIMMING_CYCLE_VALUE(i));
+
+ /* Exit if stop is reached */
+ if (((step > 0) && (i >= dimming_config.stop))
+ || ((step < 0) && (i <= dimming_config.stop)))
+ {
+ dimming_config.ongoing = 0;
+ }
+ else
+ {
+ HAL_Delay(dimming_config.delay);
+ i += step;
+ }
+ }
+#endif
+}
+
+/**
+ * @brief LCD screen dimming disable
+ * @note Screen brightness is immediately set to its highest level
+ * @param None
+ * @retval None
+ */
+void BSP_LCD_ScreenDimmingOff(void)
+{
+#if defined(LPTIMER_DIMMING)
+ GPIO_InitTypeDef GPIO_InitStructure;
+#endif
+
+ if (dimming_on == 1)
+ {
+ /* Stop ongoing dimming */
+ dimming_config.ongoing = 0;
+
+#if defined(LPTIMER_DIMMING)
+
+ /* Restore LCD BL GPIO setting */
+ GPIO_InitStructure.Pin = LCD_BL_CTRL_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &GPIO_InitStructure);
+
+ /* Stop LP Timer channel */
+ if (HAL_LPTIM_PWM_Stop(&LCD_LpTimHandle) != HAL_OK)
+ {
+ /* PWM Generation Error */
+ BSP_ErrorHandler();
+ }
+
+ /* Disable timer clock for power consumption reasons */
+ __HAL_RCC_LPTIM1_CLK_DISABLE();
+#else
+ /* Stop Timer channel */
+ if (HAL_TIM_PWM_Stop(&LCD_TimHandle, TIMx_CHANNEL) != HAL_OK)
+ {
+ /* PWM Generation Error */
+ BSP_ErrorHandler();
+ }
+
+ /* Disable timer clock for power consumption reasons */
+ TIMx_CLK_DISABLE();
+#endif
+
+ dimming_on = 0;
+ }
+}
+
+
+
+/**
+ * @brief TIM MSP Initialization
+ * This function configures the hardware resources used for screen dimming:
+ * - Peripheral's clock enable
+ * - Peripheral's GPIO Configuration
+ * @param htim: TIM handle pointer
+ * @retval None
+ */
+void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* TIMx Peripheral clock enable */
+ TIMx_CLK_ENABLE();
+
+ /* Timer channel configuration */
+
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+
+ GPIO_InitStruct.Alternate = TIMx_CHANNEl_AF;
+ GPIO_InitStruct.Pin = GPIO_PIN_0;
+ HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
+}
+
+
+#if defined(LPTIMER_DIMMING)
+/**
+* @brief LPTIM MSP Init
+* @param hlptim : LPTIM handle
+* @retval None
+*/
+void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef *hlptim)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* ## - 1 - Enable LPTIM clock ############################################ */
+ __HAL_RCC_LPTIM1_CLK_ENABLE();
+
+ /* ## - 2 - Force & Release the LPTIM Periheral Clock Reset ############### */
+ /* Force the LPTIM Periheral Clock Reset */
+ __HAL_RCC_LPTIM1_FORCE_RESET();
+
+ /* Release the LPTIM Periheral Clock Reset */
+ __HAL_RCC_LPTIM1_RELEASE_RESET();
+
+ /* ## - 3 - Enable & Configure LPTIM Ultra Low Power Input ################# */
+ /* Configure PG.15 (LPTIM1_OUT) in alternate function,
+ Low speed push-pull mode and pull-up enabled. */
+
+ /* Enable GPIO PORT(s)*/
+ LCD_BL_CTRL_GPIO_CLK_ENABLE();
+
+ /* Configure Backlight control pin GPIO */
+ GPIO_InitStruct.Pin = LCD_BL_CTRL_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF1_LPTIM1;
+ HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &GPIO_InitStruct);
+}
+#endif /* defined(LPTIMER_DIMMING) */
+
+uint8_t BSP_LCD_GetOrientation(void)
+{
+ return LCD_orientation;
+}
+
+/**
+ * @brief Initializes the LCD GPIO special pins MSP.
+ * @param None
+ * @retval None
+ */
+__weak void BSP_LCD_MspInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ /* Enable GPIOs clock */
+ LCD_TE_GPIO_CLK_ENABLE();
+ LCD_BL_CTRL_GPIO_CLK_ENABLE();
+ LCD_PWR_CTRL_GPIO_CLK_ENABLE();
+
+ /* LCD_RESET GPIO configuration */
+ if (BSP_IO_Init() == IO_ERROR)
+ {
+ BSP_ErrorHandler();
+ }
+ BSP_IO_ConfigPin(LCD_RST_PIN, IO_MODE_OUTPUT);
+
+ /* LCD_BL_CTRL GPIO configuration */
+ GPIO_InitStructure.Pin = LCD_BL_CTRL_PIN; /* LCD_BL_CTRL pin has to be manually controlled */
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &GPIO_InitStructure);
+
+ /* Power on the screen (also done in Touch Screen driver ... */
+ GPIO_InitStructure.Pin = LCD_PWR_CTRL_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP /*GPIO_MODE_OUTPUT_PP*/;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(LCD_PWR_CTRL_GPIO_PORT, &GPIO_InitStructure);
+}
+
+/**
+ * @brief DeInitializes LCD GPIO special pins MSP.
+ * @param None
+ * @retval None
+ */
+__weak void BSP_LCD_MspDeInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ /* LCD_BL_CTRL GPIO deactivation */
+ GPIO_InitStructure.Pin = LCD_BL_CTRL_PIN;
+ HAL_GPIO_DeInit(LCD_BL_CTRL_GPIO_PORT, GPIO_InitStructure.Pin);
+
+ /* LCD_BL_CTRL GPIO deactivation */
+ GPIO_InitStructure.Pin = LCD_PWR_CTRL_PIN;
+ HAL_GPIO_DeInit(LCD_PWR_CTRL_GPIO_PORT, GPIO_InitStructure.Pin);
+
+ /* GPIO pins clock can be shut down in the application
+ by surcharging this __weak function */
+}
+
+/******************************************************************************
+ Static Functions
+*******************************************************************************/
+
+/**
+ * @brief Draws a character on LCD.
+ * @param Xpos: Line where to display the character shape
+ * @param Ypos: Start column address
+ * @param c: Pointer to the character data
+ * @retval None
+ */
+static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c)
+{
+ uint32_t i = 0, j = 0;
+ uint16_t height, width;
+ uint8_t offset;
+ uint8_t *pchar;
+ uint32_t line;
+
+ height = DrawProp.pFont->Height;
+ width = DrawProp.pFont->Width;
+
+ offset = 8 * ((width + 7) / 8) - width ;
+
+ for (i = 0; i < height; i++)
+ {
+ pchar = ((uint8_t *)c + (width + 7) / 8 * i);
+
+ switch (((width + 7) / 8))
+ {
+ case 1:
+ line = pchar[0];
+ break;
+
+ case 2:
+ line = (pchar[0] << 8) | pchar[1];
+ break;
+
+ case 3:
+ default:
+ line = (pchar[0] << 16) | (pchar[1] << 8) | pchar[2];
+ break;
+ }
+
+ for (j = 0; j < width; j++)
+ {
+ if ((line & (1 << (width - j + offset - 1))) != 0)
+ {
+ BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.TextColor);
+ }
+ else
+ {
+ BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.BackColor);
+ }
+ }
+ Ypos++;
+ }
+}
+
+/**
+ * @brief Sets display window.
+ * @param LayerIndex: layer index
+ * @param Xpos: LCD X position
+ * @param Ypos: LCD Y position
+ * @param Width: LCD window width
+ * @param Height: LCD window height
+ * @retval None
+ */
+static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
+{
+ if (LcdDrv->SetDisplayWindow != NULL)
+ {
+ LcdDrv->SetDisplayWindow(Xpos, Ypos, Width, Height);
+ }
+}
+
+/**
+ * @brief Fills a triangle (between 3 points).
+ * @param Points: Pointer to the points array
+ * @param x1: Point 1 X position
+ * @param y1: Point 1 Y position
+ * @param x2: Point 2 X position
+ * @param y2: Point 2 Y position
+ * @param x3: Point 3 X position
+ * @param y3: Point 3 Y position
+ * @retval None
+ */
+static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3)
+{
+ int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
+ yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
+ curpixel = 0;
+
+ deltax = ABS(x2 - x1); /* The difference between the x's */
+ deltay = ABS(y2 - y1); /* The difference between the y's */
+ x = x1; /* Start x off at the first pixel */
+ y = y1; /* Start y off at the first pixel */
+
+ if (x2 >= x1) /* The x-values are increasing */
+ {
+ xinc1 = 1;
+ xinc2 = 1;
+ }
+ else /* The x-values are decreasing */
+ {
+ xinc1 = -1;
+ xinc2 = -1;
+ }
+
+ if (y2 >= y1) /* The y-values are increasing */
+ {
+ yinc1 = 1;
+ yinc2 = 1;
+ }
+ else /* The y-values are decreasing */
+ {
+ yinc1 = -1;
+ yinc2 = -1;
+ }
+
+ if (deltax >= deltay) /* There is at least one x-value for every y-value */
+ {
+ xinc1 = 0; /* Don't change the x when numerator >= denominator */
+ yinc2 = 0; /* Don't change the y for every iteration */
+ den = deltax;
+ num = deltax / 2;
+ numadd = deltay;
+ numpixels = deltax; /* There are more x-values than y-values */
+ }
+ else /* There is at least one y-value for every x-value */
+ {
+ xinc2 = 0; /* Don't change the x for every iteration */
+ yinc1 = 0; /* Don't change the y when numerator >= denominator */
+ den = deltay;
+ num = deltay / 2;
+ numadd = deltax;
+ numpixels = deltay; /* There are more y-values than x-values */
+ }
+
+ for (curpixel = 0; curpixel <= numpixels; curpixel++)
+ {
+ BSP_LCD_DrawLine(x, y, x3, y3);
+
+ num += numadd; /* Increase the numerator by the top of the fraction */
+ if (num >= den) /* Check if numerator >= denominator */
+ {
+ num -= den; /* Calculate the new numerator value */
+ x += xinc1; /* Change the x as appropriate */
+ y += yinc1; /* Change the y as appropriate */
+ }
+ x += xinc2; /* Change the x as appropriate */
+ y += yinc2; /* Change the y as appropriate */
+ }
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.h
new file mode 100644
index 0000000..73dec4c
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_lcd.h
@@ -0,0 +1,262 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_lcd.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_lcd.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_LCD_H
+#define __STM32L496G_DISCOVERY_LCD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+#include "stm32l496g_discovery_io.h"
+/*#include "../Components/ls016b8uy/ls016b8uy.h"*/
+#include "../Components/st7789h2/st7789h2.h"
+#include "../../../Utilities/Fonts/fonts.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD STM32L496G-DISCOVERY LCD
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Exported_Types STM32L496G DISCOVERY LCD Exported Types
+ * @{
+ */
+typedef struct
+{
+ uint32_t TextColor;
+ uint32_t BackColor;
+ sFONT *pFont;
+} LCD_DrawPropTypeDef;
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Exported_Constants STM32L496G DISCOVERY LCD Exported Constants
+ * @{
+ */
+/**
+ * @brief LCD status structure definition
+ */
+#define LCD_OK ((uint8_t)0x00)
+#define LCD_ERROR ((uint8_t)0x01)
+#define LCD_TIMEOUT ((uint8_t)0x02)
+
+typedef struct
+{
+ int16_t X;
+ int16_t Y;
+} Point, * pPoint;
+
+/**
+ * @brief Line mode structures definition
+ */
+typedef enum
+{
+ CENTER_MODE = 0x01, /* Center mode */
+ RIGHT_MODE = 0x02, /* Right mode */
+ LEFT_MODE = 0x03 /* Left mode */
+} Line_ModeTypdef;
+
+
+#define LCD_ORIENTATION_PORTRAIT ((uint8_t)0x00) /*!< Portrait orientation choice of LCD screen */
+#define LCD_ORIENTATION_LANDSCAPE ((uint8_t)0x01) /*!< Landscape orientation choice of LCD screen */
+#define LCD_ORIENTATION_UNDEFINED ((uint8_t)0x02) /*!< Undefined LCD screen orientation */
+
+
+/**
+ * @brief LCD color
+ */
+#define LCD_COLOR_BLUE ((uint16_t)0x001F)
+#define LCD_COLOR_GREEN ((uint16_t)0x07E0)
+#define LCD_COLOR_RED ((uint16_t)0xF800)
+#define LCD_COLOR_CYAN ((uint16_t)0x07FF)
+#define LCD_COLOR_MAGENTA ((uint16_t)0xF81F)
+#define LCD_COLOR_YELLOW ((uint16_t)0xFFE0)
+#define LCD_COLOR_LIGHTBLUE ((uint16_t)0x841F)
+#define LCD_COLOR_LIGHTGREEN ((uint16_t)0x87F0)
+#define LCD_COLOR_LIGHTRED ((uint16_t)0xFC10)
+#define LCD_COLOR_LIGHTMAGENTA ((uint16_t)0xFC1F)
+#define LCD_COLOR_LIGHTYELLOW ((uint16_t)0xFFF0)
+#define LCD_COLOR_DARKBLUE ((uint16_t)0x0010)
+#define LCD_COLOR_DARKGREEN ((uint16_t)0x0400)
+#define LCD_COLOR_DARKRED ((uint16_t)0x8000)
+#define LCD_COLOR_DARKCYAN ((uint16_t)0x0410)
+#define LCD_COLOR_DARKMAGENTA ((uint16_t)0x8010)
+#define LCD_COLOR_DARKYELLOW ((uint16_t)0x8400)
+#define LCD_COLOR_WHITE ((uint16_t)0xFFFF)
+#define LCD_COLOR_LIGHTGRAY ((uint16_t)0xD69A)
+#define LCD_COLOR_GRAY ((uint16_t)0x8410)
+#define LCD_COLOR_DARKGRAY ((uint16_t)0x4208)
+#define LCD_COLOR_BLACK ((uint16_t)0x0000)
+#define LCD_COLOR_BROWN ((uint16_t)0xA145)
+#define LCD_COLOR_ORANGE ((uint16_t)0xFD20)
+
+/**
+ * @brief LCD default font
+ */
+#define LCD_DEFAULT_FONT Font12
+
+/**
+ * @brief LCD special pins
+ */
+/* LCD reset pin */
+/* LCD reset is accessed thru the MFX */
+#define LCD_RST_PIN IO1_PIN_2
+
+/* LCD tearing effect pin */
+#define LCD_TE_PIN GPIO_PIN_7
+#define LCD_TE_GPIO_PORT GPIOH
+#define LCD_TE_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define LCD_TE_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+
+/* Backlight control pin */
+#if defined(LPTIMER_DIMMING)
+#define LCD_BL_CTRL_PIN GPIO_PIN_15
+#define LCD_BL_CTRL_GPIO_PORT GPIOG
+#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
+#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()
+#else
+#define LCD_BL_CTRL_PIN GPIO_PIN_0
+#define LCD_BL_CTRL_GPIO_PORT GPIOI
+#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#endif
+
+
+/* Power on control pin */
+#define LCD_PWR_CTRL_PIN GPIO_PIN_0
+#define LCD_PWR_CTRL_GPIO_PORT GPIOH
+#define LCD_PWR_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
+#define LCD_PWR_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE()
+
+/* Use by application to not use backlight */
+extern FlagStatus WakeUpFromStandby;
+extern FlagStatus WakeUpFromShutdown;
+
+
+/* Screen dimming parameters */
+/* Definition for TIMx clock resources */
+#define TIMx TIM5
+#define TIMx_CLK_ENABLE() __HAL_RCC_TIM5_CLK_ENABLE()
+#define TIMx_CLK_DISABLE() __HAL_RCC_TIM5_CLK_DISABLE()
+#define TIMx_CHANNEL TIM_CHANNEL_4
+#define TIMx_CHANNEl_AF GPIO_AF2_TIM5
+#if defined(LPTIMER_DIMMING)
+#define PERIOD_VALUE (uint32_t)(99) /* Period Value */
+#define PULSE_VALUE (uint32_t)(95) /* 5% cycle */
+#define PULSE_DECREASE_START (uint32_t)(45) /* cycle start level when starting to dim the screen */
+#define PULSE_DECREASE_DELAY (uint32_t)(40) /* gradually decrease cycle level every 40 milliseconds */
+#else
+#define PERIOD_VALUE (uint32_t)(666 - 1) /* Period Value */
+#define PULSE_VALUE (uint32_t)((PERIOD_VALUE*5)/100) /* 5% cycle */
+#define PULSE_DECREASE_START (uint32_t)(PULSE_VALUE + 120) /* cycle start level when starting to dim the screen */
+#define PULSE_DECREASE_DELAY (uint32_t)(20) /* gradually decrease cycle level every 20 milliseconds */
+#endif
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_LCD_Exported_Functions STM32L496G DISCOVERY LCD Exported Functions
+ * @{
+ */
+uint8_t BSP_LCD_Init(void);
+uint8_t BSP_LCD_InitEx(uint32_t orientation);
+void BSP_LCD_Reset(void);
+uint8_t BSP_LCD_DeInit(void);
+uint32_t BSP_LCD_GetXSize(void);
+uint32_t BSP_LCD_GetYSize(void);
+
+uint16_t BSP_LCD_GetTextColor(void);
+uint16_t BSP_LCD_GetBackColor(void);
+void BSP_LCD_SetTextColor(__IO uint16_t Color);
+void BSP_LCD_SetBackColor(__IO uint16_t Color);
+void BSP_LCD_SetFont(sFONT *fonts);
+sFONT *BSP_LCD_GetFont(void);
+
+void BSP_LCD_Clear(uint16_t Color);
+void BSP_LCD_ClearStringLine(uint16_t Line);
+void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr);
+void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode);
+void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii);
+
+uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos);
+void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code);
+void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length);
+void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length);
+void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
+void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height);
+void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius);
+void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount);
+void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius);
+void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp);
+void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pbmp);
+void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height);
+void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius);
+void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount);
+void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius);
+
+void BSP_LCD_DisplayOff(void);
+void BSP_LCD_DisplayOn(void);
+
+void BSP_LCD_ScreenDimmingOn(void);
+void BSP_LCD_ScreenDimmingOff(void);
+void BSP_LCD_ScreenDimmingConfig(const uint8_t start, const uint8_t stop, const uint8_t step, const uint8_t delay);
+
+uint8_t BSP_LCD_GetOrientation(void);
+
+/* These functions can be modified in case the current settings
+ need to be changed for specific application needs */
+__weak void BSP_LCD_MspInit(void);
+__weak void BSP_LCD_MspDeInit(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_LCD_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.c
new file mode 100644
index 0000000..18f5bda
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.c
@@ -0,0 +1,1133 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_qspi.c
+ * @author MCD Application Team
+ * @brief This file includes a standard driver for the MX25R6435F QSPI
+ * memory mounted on STM32L496G-Discovery board.
+ @verbatim
+ ==============================================================================
+ ##### How to use this driver #####
+ ==============================================================================
+ [..]
+ (#) This driver is used to drive the MX25R6435F QSPI external
+ memory mounted on STM32L496G-DISCO evaluation board.
+
+ (#) This driver need a specific component driver (MX25R6435F) to be included with.
+
+ (#) Initialization steps:
+ (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This
+ function includes the MSP layer hardware resources initialization and the
+ QSPI interface with the external memory. The BSP_QSPI_DeInit() can be used
+ to deactivate the QSPI interface.
+
+ (#) QSPI memory operations
+ (++) QSPI memory can be accessed with read/write operations once it is
+ initialized.
+ Read/write operation can be performed with AHB access using the functions
+ BSP_QSPI_Read()/BSP_QSPI_Write().
+ (++) The function to the QSPI memory in memory-mapped mode is possible after
+ the call of the function BSP_QSPI_EnableMemoryMappedMode().
+ (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory.
+ (see the QSPI memory data sheet)
+ (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by
+ specifying the block address. You can perform an erase operation of the whole
+ chip by calling the function BSP_QSPI_Erase_Chip().
+ (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory.
+ (see the QSPI memory data sheet)
+ (++) Perform erase sector operation using the function BSP_QSPI_Erase_Sector()
+ which is not blocking. So the function BSP_QSPI_GetStatus() should be used
+ to check if the memory is busy, and the functions BSP_QSPI_SuspendErase()/
+ BSP_QSPI_ResumeErase() can be used to perform other operations during the
+ sector erase.
+ (++) Deep power down of the QSPI memory is managed with the call of the functions
+ BSP_QSPI_EnterDeepPowerDown()/BSP_QSPI_LeaveDeepPowerDown()
+ @endverbatim
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_qspi.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_QSPI STM32L496G-DISCOVERY QSPI
+ * @{
+ */
+
+/* Private constants --------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Constants Private Constants
+ * @{
+ */
+#define QSPI_QUAD_DISABLE 0x0
+#define QSPI_QUAD_ENABLE 0x1
+
+#define QSPI_HIGH_PERF_DISABLE 0x0
+#define QSPI_HIGH_PERF_ENABLE 0x1
+/**
+ * @}
+ */
+/* Private variables ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Variables Private Variables
+ * @{
+ */
+QSPI_HandleTypeDef QSPIHandle;
+
+/**
+ * @}
+ */
+
+
+/* Private functions ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Functions Private Functions
+ * @{
+ */
+static void QSPI_MspInit(void);
+static void QSPI_MspDeInit(void);
+static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi);
+static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi);
+static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout);
+static uint8_t QSPI_QuadMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation);
+static uint8_t QSPI_HighPerfMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation);
+
+/**
+ * @}
+ */
+
+/* Exported functions ---------------------------------------------------------*/
+
+/** @addtogroup STM32L496G_DISCOVERY_QSPI_Exported_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the QSPI interface.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_Init(void)
+{
+ QSPIHandle.Instance = QUADSPI;
+
+ /* Call the DeInit function to reset the driver */
+ if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* System level initialization */
+ QSPI_MspInit();
+
+ /* QSPI initialization */
+ QSPIHandle.Init.ClockPrescaler = 2; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 26.67MHz */
+ QSPIHandle.Init.FifoThreshold = 4;
+ QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
+ QSPIHandle.Init.FlashSize = POSITION_VAL(MX25R6435F_FLASH_SIZE) - 1;
+ QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
+ QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
+
+ if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* QSPI memory reset */
+ if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_NOT_SUPPORTED;
+ }
+
+ /* QSPI quad enable */
+ if (QSPI_QuadMode(&QSPIHandle, QSPI_QUAD_ENABLE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* High performance mode enable */
+ if (QSPI_HighPerfMode(&QSPIHandle, QSPI_HIGH_PERF_ENABLE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Re-configure the clock for the high performance mode */
+ QSPIHandle.Init.ClockPrescaler = 1; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 40MHz */
+
+ if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief De-Initializes the QSPI interface.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_DeInit(void)
+{
+ QSPIHandle.Instance = QUADSPI;
+
+ /* Call the DeInit function to reset the driver */
+ if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* System level De-initialization */
+ QSPI_MspDeInit();
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Reads an amount of data from the QSPI memory.
+ * @param pData : Pointer to data to be read
+ * @param ReadAddr : Read start address
+ * @param Size : Size of data to read
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the read command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = QUAD_INOUT_READ_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
+ sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
+ sCommand.Address = ReadAddr;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
+ sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
+ sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE;
+ sCommand.DataMode = QSPI_DATA_4_LINES;
+ sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD;
+ sCommand.NbData = Size;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Configure the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Reception of the data */
+ if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Writes an amount of data to the QSPI memory.
+ * @param pData : Pointer to data to be written
+ * @param WriteAddr : Write start address
+ * @param Size : Size of data to write
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_Write(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
+{
+ QSPI_CommandTypeDef sCommand;
+ uint32_t end_addr, current_size, current_addr;
+
+ /* Calculation of the size between the write address and the end of the page */
+ current_size = MX25R6435F_PAGE_SIZE - (WriteAddr % MX25R6435F_PAGE_SIZE);
+
+ /* Check if the size of the data is less than the remaining place in the page */
+ if (current_size > Size)
+ {
+ current_size = Size;
+ }
+
+ /* Initialize the address variables */
+ current_addr = WriteAddr;
+ end_addr = WriteAddr + Size;
+
+ /* Initialize the program command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = QUAD_PAGE_PROG_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
+ sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_4_LINES;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Perform the write page by page */
+ do
+ {
+ sCommand.Address = current_addr;
+ sCommand.NbData = current_size;
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Transmission of the data */
+ if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure automatic polling mode to wait for end of program */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Update the address and size variables for next page programming */
+ current_addr += current_size;
+ pData += current_size;
+ current_size = ((current_addr + MX25R6435F_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25R6435F_PAGE_SIZE;
+ }
+ while (current_addr < end_addr);
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Erases the specified block of the QSPI memory.
+ * @param BlockAddress : Block address to erase
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = BLOCK_ERASE_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
+ sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
+ sCommand.Address = BlockAddress;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure automatic polling mode to wait for end of erase */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_BLOCK_ERASE_MAX_TIME) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Erases the specified sector of the QSPI memory.
+ * @param Sector : Sector address to erase (0 to 255)
+ * @retval QSPI memory status
+ * @note This function is non blocking meaning that sector erase
+ * operation is started but not completed when the function
+ * returns. Application has to call BSP_QSPI_GetStatus()
+ * to know when the device is available again (i.e. erase operation
+ * completed).
+ */
+uint8_t BSP_QSPI_Erase_Sector(uint32_t Sector)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ if (Sector >= (uint32_t)(MX25R6435F_FLASH_SIZE / MX25R6435F_SECTOR_SIZE))
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = SECTOR_ERASE_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
+ sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
+ sCommand.Address = (Sector * MX25R6435F_SECTOR_SIZE);
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Erases the entire QSPI memory.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_Erase_Chip(void)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = CHIP_ERASE_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure automatic polling mode to wait for end of erase */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_CHIP_ERASE_MAX_TIME) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Reads current status of the QSPI memory.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_GetStatus(void)
+{
+ QSPI_CommandTypeDef sCommand;
+ uint8_t reg;
+
+ /* Initialize the read security register command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = READ_SEC_REG_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_1_LINE;
+ sCommand.DummyCycles = 0;
+ sCommand.NbData = 1;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Configure the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Reception of the data */
+ if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Check the value of the register */
+ if ((reg & (MX25R6435F_SECR_P_FAIL | MX25R6435F_SECR_E_FAIL)) != 0)
+ {
+ return QSPI_ERROR;
+ }
+ else if ((reg & (MX25R6435F_SECR_PSB | MX25R6435F_SECR_ESB)) != 0)
+ {
+ return QSPI_SUSPENDED;
+ }
+
+ /* Initialize the read status register command */
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+
+ /* Configure the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Reception of the data */
+ if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Check the value of the register */
+ if ((reg & MX25R6435F_SR_WIP) != 0)
+ {
+ return QSPI_BUSY;
+ }
+ else
+ {
+ return QSPI_OK;
+ }
+}
+
+/**
+ * @brief Return the configuration of the QSPI memory.
+ * @param pInfo : pointer on the configuration structure
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_GetInfo(QSPI_Info *pInfo)
+{
+ /* Configure the structure with the memory configuration */
+ pInfo->FlashSize = MX25R6435F_FLASH_SIZE;
+ pInfo->EraseSectorSize = MX25R6435F_SECTOR_SIZE;
+ pInfo->EraseSectorsNumber = (MX25R6435F_FLASH_SIZE / MX25R6435F_SECTOR_SIZE);
+ pInfo->ProgPageSize = MX25R6435F_PAGE_SIZE;
+ pInfo->ProgPagesNumber = (MX25R6435F_FLASH_SIZE / MX25R6435F_PAGE_SIZE);
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief Configure the QSPI in memory-mapped mode
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_EnableMemoryMappedMode(void)
+{
+ QSPI_CommandTypeDef sCommand;
+ QSPI_MemoryMappedTypeDef sMemMappedCfg;
+
+ /* Configure the command for the read instruction */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = QUAD_INOUT_READ_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
+ sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
+ sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
+ sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE;
+ sCommand.DataMode = QSPI_DATA_4_LINES;
+ sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Configure the memory mapped mode */
+ sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
+
+ if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function suspends an ongoing erase command.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_SuspendErase(void)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Check whether the device is busy (erase operation is
+ in progress).
+ */
+ if (BSP_QSPI_GetStatus() == QSPI_BUSY)
+ {
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = PROG_ERASE_SUSPEND_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED)
+ {
+ return QSPI_OK;
+ }
+
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function resumes a paused erase command.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_ResumeErase(void)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Check whether the device is in suspended state */
+ if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED)
+ {
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = PROG_ERASE_RESUME_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /*
+ When this command is executed, the status register write in progress bit is set to 1, and
+ the flag status register program erase controller bit is set to 0. This command is ignored
+ if the device is not in a suspended state.
+ */
+
+ if (BSP_QSPI_GetStatus() == QSPI_BUSY)
+ {
+ return QSPI_OK;
+ }
+
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function enter the QSPI memory in deep power down mode.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_EnterDeepPowerDown(void)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the deep power down command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = DEEP_POWER_DOWN_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* --- Memory takes 10us max to enter deep power down --- */
+ /* --- At least 30us should be respected before leaving deep power down --- */
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function leave the QSPI memory from deep power down mode.
+ * @retval QSPI memory status
+ */
+uint8_t BSP_QSPI_LeaveDeepPowerDown(void)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the erase command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = NO_OPERATION_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* --- A NOP command is sent to the memory, as the nCS should be low for at least 20 ns --- */
+ /* --- Memory takes 35us min to leave deep power down --- */
+
+ return QSPI_OK;
+}
+/**
+ * @}
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_QSPI_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the QSPI MSP.
+ * @retval None
+ */
+static void QSPI_MspInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable the QuadSPI memory interface clock */
+ __HAL_RCC_QSPI_CLK_ENABLE();
+
+ /* Reset the QuadSPI memory interface */
+ __HAL_RCC_QSPI_FORCE_RESET();
+ __HAL_RCC_QSPI_RELEASE_RESET();
+
+ /* Enable GPIO clocks */
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+
+ /* QSPI CS GPIO pin configuration */
+ GPIO_InitStruct.Pin = GPIO_PIN_11;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+ /* QSPI CLK, D0, D1, D2 and D3 GPIO pins configuration */
+ GPIO_InitStruct.Pin = (GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7);
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = (GPIO_PIN_0 | GPIO_PIN_1);
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+}
+
+/**
+ * @brief De-Initializes the QSPI MSP.
+ * @retval None
+ */
+static void QSPI_MspDeInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* QSPI CLK, CS, D0-D3 GPIO pins de-configuration */
+
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+
+ HAL_GPIO_DeInit(GPIOA, (GPIO_PIN_6 | GPIO_PIN_7));
+ HAL_GPIO_DeInit(GPIOB, (GPIO_PIN_0 | GPIO_PIN_1));
+
+ /* Set GPIOB pin 11 in pull up mode (optimum default setting) */
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pin = GPIO_PIN_11;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+ /* Set GPIOA pin 3 in no pull, low state (optimum default setting) */
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP ;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Pin = GPIO_PIN_3;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
+
+ /* Reset the QuadSPI memory interface */
+ __HAL_RCC_QSPI_FORCE_RESET();
+ __HAL_RCC_QSPI_RELEASE_RESET();
+
+ /* Disable the QuadSPI memory interface clock */
+ __HAL_RCC_QSPI_CLK_DISABLE();
+}
+
+/**
+ * @brief This function reset the QSPI memory.
+ * @param hqspi : QSPI handle
+ * @retval None
+ */
+static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi)
+{
+ QSPI_CommandTypeDef sCommand;
+
+ /* Initialize the reset enable command */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = RESET_ENABLE_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ /* Send the command */
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Send the reset memory command */
+ sCommand.Instruction = RESET_MEMORY_CMD;
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure automatic polling mode to wait the memory is ready */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function send a Write Enable and wait it is effective.
+ * @param hqspi : QSPI handle
+ * @retval None
+ */
+static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
+{
+ QSPI_CommandTypeDef sCommand;
+ QSPI_AutoPollingTypeDef sConfig;
+
+ /* Enable write operations */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = WRITE_ENABLE_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_NONE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Configure automatic polling mode to wait for write enabling */
+ sConfig.Match = MX25R6435F_SR_WEL;
+ sConfig.Mask = MX25R6435F_SR_WEL;
+ sConfig.MatchMode = QSPI_MATCH_MODE_AND;
+ sConfig.StatusBytesSize = 1;
+ sConfig.Interval = 0x10;
+ sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
+
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+ sCommand.DataMode = QSPI_DATA_1_LINE;
+
+ if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function read the SR of the memory and wait the EOP.
+ * @param hqspi : QSPI handle
+ * @param Timeout : Timeout for auto-polling
+ * @retval None
+ */
+static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout)
+{
+ QSPI_CommandTypeDef sCommand;
+ QSPI_AutoPollingTypeDef sConfig;
+
+ /* Configure automatic polling mode to wait for memory ready */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_1_LINE;
+ sCommand.DummyCycles = 0;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ sConfig.Match = 0;
+ sConfig.Mask = MX25R6435F_SR_WIP;
+ sConfig.MatchMode = QSPI_MATCH_MODE_AND;
+ sConfig.StatusBytesSize = 1;
+ sConfig.Interval = 0x10;
+ sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
+
+ if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, Timeout) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function enables/disables the Quad mode of the memory.
+ * @param hqspi : QSPI handle
+ * @param Operation : QSPI_QUAD_ENABLE or QSPI_QUAD_DISABLE mode
+ * @retval None
+ */
+static uint8_t QSPI_QuadMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation)
+{
+ QSPI_CommandTypeDef sCommand;
+ uint8_t reg;
+
+ /* Read status register */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_1_LINE;
+ sCommand.DummyCycles = 0;
+ sCommand.NbData = 1;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Activate/deactivate the Quad mode */
+ if (Operation == QSPI_QUAD_ENABLE)
+ {
+ SET_BIT(reg, MX25R6435F_SR_QE);
+ }
+ else
+ {
+ CLEAR_BIT(reg, MX25R6435F_SR_QE);
+ }
+
+ sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Transmit(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Wait that memory is ready */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Check the configuration has been correctly done */
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if ((((reg & MX25R6435F_SR_QE) == 0) && (Operation == QSPI_QUAD_ENABLE)) ||
+ (((reg & MX25R6435F_SR_QE) != 0) && (Operation == QSPI_QUAD_DISABLE)))
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @brief This function enables/disables the high performance mode of the memory.
+ * @param hqspi : QSPI handle
+ * @param Operation : QSPI_HIGH_PERF_ENABLE or QSPI_HIGH_PERF_DISABLE high performance mode
+ * @retval None
+ */
+static uint8_t QSPI_HighPerfMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation)
+{
+ QSPI_CommandTypeDef sCommand;
+ uint8_t reg[3];
+
+ /* Read status register */
+ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
+ sCommand.Instruction = READ_STATUS_REG_CMD;
+ sCommand.AddressMode = QSPI_ADDRESS_NONE;
+ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
+ sCommand.DataMode = QSPI_DATA_1_LINE;
+ sCommand.DummyCycles = 0;
+ sCommand.NbData = 1;
+ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
+ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
+ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Read configuration registers */
+ sCommand.Instruction = READ_CFG_REG_CMD;
+ sCommand.NbData = 2;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Receive(&QSPIHandle, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Enable write operations */
+ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Activate/deactivate the Quad mode */
+ if (Operation == QSPI_HIGH_PERF_ENABLE)
+ {
+ SET_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH);
+ }
+ else
+ {
+ CLEAR_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH);
+ }
+
+ sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD;
+ sCommand.NbData = 3;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Transmit(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Wait that memory is ready */
+ if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ /* Check the configuration has been correctly done */
+ sCommand.Instruction = READ_CFG_REG_CMD;
+ sCommand.NbData = 2;
+
+ if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
+ {
+ return QSPI_ERROR;
+ }
+
+ if ((((reg[1] & MX25R6435F_CR2_LH_SWITCH) == 0) && (Operation == QSPI_HIGH_PERF_ENABLE)) ||
+ (((reg[1] & MX25R6435F_CR2_LH_SWITCH) != 0) && (Operation == QSPI_HIGH_PERF_DISABLE)))
+ {
+ return QSPI_ERROR;
+ }
+
+ return QSPI_OK;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.h
new file mode 100644
index 0000000..5d1ab3b
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_qspi.h
@@ -0,0 +1,119 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_qspi.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_qspi.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_QSPI_H
+#define __STM32L496G_DISCOVERY_QSPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l4xx_hal.h"
+#include "../Components/mx25r6435f/mx25r6435f.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_QSPI
+ * @{
+ */
+
+/* Exported constants --------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Exported_Constants Exported Constants
+ * @{
+ */
+/* QSPI Error codes */
+#define QSPI_OK ((uint8_t)0x00)
+#define QSPI_ERROR ((uint8_t)0x01)
+#define QSPI_BUSY ((uint8_t)0x02)
+#define QSPI_NOT_SUPPORTED ((uint8_t)0x04)
+#define QSPI_SUSPENDED ((uint8_t)0x08)
+
+/**
+ * @}
+ */
+
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Exported_Types Exported Types
+ * @{
+ */
+/* QSPI Info */
+typedef struct
+{
+ uint32_t FlashSize; /*!< Size of the flash */
+ uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */
+ uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */
+ uint32_t ProgPageSize; /*!< Size of pages for the program operation */
+ uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */
+} QSPI_Info;
+
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup STM32L496G_DISCOVERY_QSPI_Exported_Functions Exported Functions
+ * @{
+ */
+uint8_t BSP_QSPI_Init(void);
+uint8_t BSP_QSPI_DeInit(void);
+uint8_t BSP_QSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
+uint8_t BSP_QSPI_Write(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
+uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress);
+uint8_t BSP_QSPI_Erase_Sector(uint32_t Sector);
+uint8_t BSP_QSPI_Erase_Chip(void);
+uint8_t BSP_QSPI_GetStatus(void);
+uint8_t BSP_QSPI_GetInfo(QSPI_Info *pInfo);
+uint8_t BSP_QSPI_EnableMemoryMappedMode(void);
+uint8_t BSP_QSPI_SuspendErase(void);
+uint8_t BSP_QSPI_ResumeErase(void);
+uint8_t BSP_QSPI_EnterDeepPowerDown(void);
+uint8_t BSP_QSPI_LeaveDeepPowerDown(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_QSPI_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.c
new file mode 100644
index 0000000..0b064f9
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.c
@@ -0,0 +1,716 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_sd.c
+ * @author MCD Application Team
+ * @brief This file includes the uSD card driver.
+ @verbatim
+ ==============================================================================
+ ##### How to use this driver #####
+ ==============================================================================
+ (#) This driver is used to drive the micro SD external card mounted on STM32L496G-DISCOVERY
+ evaluation board.
+
+ (#) This driver does not need a specific component driver for the micro SD device
+ to be included with.
+
+ (#) Initialization steps:
+ (++) Initialize the micro SD card using the BSP_SD_Init() function. This
+ function includes the MSP layer hardware resources initialization and the
+ SDMMC1 interface configuration to interface with the external micro SD. It
+ also includes the micro SD initialization sequence.
+ (++) To check the SD card presence you can use the function BSP_SD_IsDetected() which
+ returns the detection status.
+ (++) The function BSP_SD_GetCardInfo() is used to get the micro SD card information
+ which is stored in the structure "HAL_SD_CardInfoTypedef".
+
+ (#) Micro SD card operations
+ (++) The micro SD card can be accessed with read/write block(s) operations once
+ it is reay for access. The access cand be performed whether using the polling
+ mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA
+ transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA()
+ (++) The DMA transfer complete is used with interrupt mode. Once the SD transfer
+ is complete, the SD interrupt is handled using the function BSP_SD_IRQHandler(),
+ the DMA Tx/Rx transfer complete are handled using the functions
+ BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks
+ are implemented by the user at application level.
+ (++) The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying
+ the number of blocks to erase.
+ (++) The SD runtime status is returned when calling the function BSP_SD_GetStatus().
+ [..]
+ @endverbatim
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_io.h"
+#include "stm32l496g_discovery_sd.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_SD STM32L496G_DISCOVERY SD
+ * @{
+ */
+
+/* Private variables ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_SD_Private_Variables Private Variables
+ * @{
+ */
+SD_HandleTypeDef uSdHandle;
+/**
+ * @}
+ */
+
+/* Private function prototypes -----------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SD_Private_Functions Private Functions
+ * @{
+ */
+static void SD_Detect_MspInit(void);
+static void SD_Detect_MspDeInit(void);
+static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd);
+static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd);
+
+/**
+ * @}
+ */
+
+/* Exported functions ---------------------------------------------------------*/
+
+/** @addtogroup STM32L496G_DISCOVERY_SD_Exported_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the SD card device.
+ * @param None
+ * @retval SD status
+ */
+uint8_t BSP_SD_Init(void)
+{
+ uint8_t sd_state = MSD_OK;
+
+ /* uSD device interface configuration */
+ uSdHandle.Instance = SDMMC1;
+ uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
+ uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
+ uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
+ uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B;
+ uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
+ uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV;
+
+ /* Msp SD Detect pin initialization */
+ SD_Detect_MspInit();
+
+ /* Check if the SD card is plugged in the slot */
+ if (BSP_SD_IsDetected() != SD_PRESENT)
+ {
+ return MSD_ERROR_SD_NOT_PRESENT;
+ }
+
+ /* Msp SD initialization */
+ BSP_SD_MspInit(&uSdHandle, NULL);
+
+ /* HAL SD initialization */
+ if (HAL_SD_Init(&uSdHandle) != HAL_OK)
+ {
+ sd_state = MSD_ERROR;
+ }
+
+ /* Configure SD Bus width */
+ if (sd_state == MSD_OK)
+ {
+ /* Enable wide operation */
+ if (HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B) != HAL_OK)
+ {
+ sd_state = MSD_ERROR;
+ }
+ else
+ {
+ sd_state = MSD_OK;
+ }
+ }
+
+ return sd_state;
+}
+
+/**
+ * @brief DeInitializes the SD card device.
+ * @param None
+ * @retval SD status
+ */
+uint8_t BSP_SD_DeInit(void)
+{
+ uint8_t sd_state = MSD_OK;
+
+ uSdHandle.Instance = SDMMC1;
+ /* HAL SD deinitialization */
+ if (HAL_SD_DeInit(&uSdHandle) != HAL_OK)
+ {
+ sd_state = MSD_ERROR;
+ }
+
+ /* Msp SD deinitialization */
+ BSP_SD_MspDeInit(&uSdHandle, NULL);
+
+ SD_Detect_MspDeInit();
+
+ return sd_state;
+}
+
+/**
+ * @brief Configures Interrupt mode for SD detection pin.
+ * @param None
+ * @retval IO_OK: if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_SD_ITConfig(void)
+{
+ /* Check SD card detect pin */
+ if (BSP_IO_ReadPin(SD_DETECT_PIN) != SD_DETECT_PIN)
+ {
+ return BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_IT_RISING_EDGE_PU);
+ }
+ else
+ {
+ return BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_IT_FALLING_EDGE_PU);
+ }
+}
+
+
+
+/**
+ * @brief Detects if SD card is correctly plugged in the memory slot or not.
+ * @param None
+ * @retval Returns if SD is detected or not
+ */
+uint8_t BSP_SD_IsDetected(void)
+{
+ __IO uint8_t status = SD_PRESENT;
+
+ /* Check SD card detect pin */
+ if (BSP_IO_ReadPin(SD_DETECT_PIN) != GPIO_PIN_RESET)
+ {
+ status = SD_NOT_PRESENT;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Reads block(s) from a specified address in an SD card, in polling mode.
+ * @param pData: Pointer to the buffer that will contain the data to transmit
+ * @param ReadAddr: Address from where data is to be read
+ * @param NumOfBlocks: Number of SD blocks to read
+ * @param Timeout: Timeout for read operation
+ * @retval SD status
+ */
+uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout)
+{
+ HAL_StatusTypeDef sd_state = HAL_OK;
+
+ sd_state = HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout);
+
+ if (sd_state == HAL_OK)
+ {
+ return MSD_OK;
+ }
+ else
+ {
+ return MSD_ERROR;
+ }
+}
+
+/**
+ * @brief Writes block(s) to a specified address in an SD card, in polling mode.
+ * @param pData: Pointer to the buffer that will contain the data to transmit
+ * @param WriteAddr: Address from where data is to be written
+ * @param NumOfBlocks: Number of SD blocks to write
+ * @param Timeout: Timeout for write operation
+ * @retval SD status
+ */
+uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout)
+{
+ HAL_StatusTypeDef sd_state = HAL_OK;
+
+ sd_state = HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout);
+
+ if (sd_state == HAL_OK)
+ {
+ return MSD_OK;
+ }
+ else
+ {
+ return MSD_ERROR;
+ }
+}
+
+/**
+ * @brief Reads block(s) from a specified address in an SD card, in DMA mode.
+ * @param pData: Pointer to the buffer that will contain the data to transmit
+ * @param ReadAddr: Address from where data is to be read
+ * @param NumOfBlocks: Number of SD blocks to read
+ * @retval SD status
+ */
+uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
+{
+ HAL_StatusTypeDef sd_state = HAL_OK;
+
+ /* Invalidate the dma tx handle*/
+ uSdHandle.hdmatx = NULL;
+
+ /* Prepare the dma channel for a read operation */
+ sd_state = SD_DMAConfigRx(&uSdHandle);
+
+ if (sd_state == HAL_OK)
+ {
+ /* Read block(s) in DMA transfer mode */
+ sd_state = HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks);
+ }
+
+ if (sd_state == HAL_OK)
+ {
+ return MSD_OK;
+ }
+ else
+ {
+ return MSD_ERROR;
+ }
+}
+
+/**
+ * @brief Writes block(s) to a specified address in an SD card, in DMA mode.
+ * @param pData: Pointer to the buffer that will contain the data to transmit
+ * @param WriteAddr: Address from where data is to be written
+ * @param NumOfBlocks: Number of SD blocks to write
+ * @retval SD status
+ */
+uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
+{
+ HAL_StatusTypeDef sd_state = HAL_OK;
+
+ /* Invalidate the dma rx handle*/
+ uSdHandle.hdmarx = NULL;
+
+ /* Prepare the dma channel for a read operation */
+ sd_state = SD_DMAConfigTx(&uSdHandle);
+
+ if (sd_state == HAL_OK)
+ {
+ /* Write block(s) in DMA transfer mode */
+ sd_state = HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks);
+ }
+
+ if (sd_state == HAL_OK)
+ {
+ return MSD_OK;
+ }
+ else
+ {
+ return MSD_ERROR;
+ }
+}
+
+/**
+ * @brief Erases the specified memory area of the given SD card.
+ * @param StartAddr: Start byte address
+ * @param EndAddr: End byte address
+ * @retval SD status
+ */
+uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr)
+{
+ HAL_StatusTypeDef sd_state = HAL_OK;
+
+ sd_state = HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr);
+
+ if (sd_state == HAL_OK)
+ {
+ return MSD_OK;
+ }
+ else
+ {
+ return MSD_ERROR;
+ }
+}
+
+/**
+ * @brief Handles SD card interrupt request.
+ * @retval None
+ */
+void BSP_SD_IRQHandler(void)
+{
+ HAL_SD_IRQHandler(&uSdHandle);
+}
+
+/**
+ * @brief Handles SD DMA Tx transfer interrupt request.
+ * @retval None
+ */
+void BSP_SD_DMA_Tx_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(uSdHandle.hdmatx);
+}
+
+/**
+ * @brief Handles SD DMA Rx transfer interrupt request.
+ * @retval None
+ */
+void BSP_SD_DMA_Rx_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(uSdHandle.hdmarx);
+}
+
+/**
+ * @brief Gets the current SD card data status.
+ * @param None
+ * @retval Data transfer state.
+ */
+uint8_t BSP_SD_GetCardState(void)
+{
+ HAL_SD_CardStateTypedef card_state;
+ card_state = HAL_SD_GetCardState(&uSdHandle);
+
+ if (card_state == HAL_SD_CARD_TRANSFER)
+ {
+ return (SD_TRANSFER_OK);
+ }
+ else if ((card_state == HAL_SD_CARD_SENDING) ||
+ (card_state == HAL_SD_CARD_RECEIVING) ||
+ (card_state == HAL_SD_CARD_PROGRAMMING))
+ {
+ return (SD_TRANSFER_BUSY);
+ }
+ else
+ {
+ return (SD_TRANSFER_ERROR);
+ }
+}
+
+/**
+ * @brief Get SD information about specific SD card.
+ * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure
+ * @retval None
+ */
+void BSP_SD_GetCardInfo(BSP_SD_CardInfo *CardInfo)
+{
+ /* Get SD card Information */
+ HAL_SD_GetCardInfo(&uSdHandle, CardInfo);
+}
+
+/**
+ * @brief Initializes the SD MSP.
+ * @note The SDMMC clock configuration done within this function assumes that
+ * the PLLSAI1 input clock runs at 8 MHz.
+ * @param hsd: SD handle
+ * @param Params: Additional parameters
+ * @retval None
+ */
+__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params)
+{
+ GPIO_InitTypeDef gpioinitstruct = {0};
+ RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
+
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(Params);
+
+ HAL_RCCEx_GetPeriphCLKConfig(&RCC_PeriphClkInit);
+
+ /* Configure the SDMMC1 clock source. The clock is derived from the PLLSAI1 */
+ /* Hypothesis is that PLLSAI1 VCO input is 8Mhz */
+ RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1;
+ RCC_PeriphClkInit.PLLSAI1.PLLSAI1N = 24;
+ RCC_PeriphClkInit.PLLSAI1.PLLSAI1Q = 4;
+ RCC_PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_48M2CLK;
+ RCC_PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
+ if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK)
+ {
+ while (1) {}
+ }
+
+ /* Enable SDMMC1 clock */
+ __HAL_RCC_SDMMC1_CLK_ENABLE();
+
+ /* Enable DMA2 clocks */
+ SD_DMAx_CLK_ENABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+
+ /* Common GPIO configuration */
+ gpioinitstruct.Mode = GPIO_MODE_AF_PP;
+ gpioinitstruct.Pull = GPIO_NOPULL;
+ gpioinitstruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ gpioinitstruct.Alternate = GPIO_AF12_SDMMC1;
+
+ /* GPIOC configuration */
+ gpioinitstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
+
+ HAL_GPIO_Init(GPIOC, &gpioinitstruct);
+
+ /* GPIOD configuration */
+ gpioinitstruct.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOD, &gpioinitstruct);
+
+ /* NVIC configuration for SDMMC1 interrupts */
+ HAL_NVIC_SetPriority(SDMMCx_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(SDMMCx_IRQn);
+
+ /* DMA initialization should be done here but , as there is only one channel for RX and TX it is configured and done directly when required*/
+}
+
+/**
+ * @brief De-Initializes the SD MSP.
+ * @param hsd: SD handle
+ * @param Params: Additional parameters
+ * @retval None
+ */
+__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params)
+{
+ GPIO_InitTypeDef gpioinitstruct = {0};
+
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(Params);
+
+ /* Enable SDMMC1 clock */
+ __HAL_RCC_SDMMC1_CLK_DISABLE();
+
+ /* Enable DMA2 clocks */
+ SD_DMAx_CLK_DISABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+
+ /* Common GPIO configuration */
+ gpioinitstruct.Mode = GPIO_MODE_ANALOG;
+ gpioinitstruct.Pull = GPIO_NOPULL;
+ gpioinitstruct.Speed = GPIO_SPEED_FREQ_LOW;
+ gpioinitstruct.Alternate = 0;
+
+ /* GPIOC configuration */
+ gpioinitstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
+
+ HAL_GPIO_Init(GPIOC, &gpioinitstruct);
+
+ /* GPIOD configuration */
+ gpioinitstruct.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOD, &gpioinitstruct);
+
+ /* NVIC configuration for SDMMC1 interrupts */
+ HAL_NVIC_DisableIRQ(SDMMCx_IRQn);
+
+}
+
+/**
+ * @brief BSP SD Abort callback
+ * @retval None
+ */
+__weak void BSP_SD_AbortCallback(void)
+{
+
+}
+
+/**
+ * @brief BSP Tx Transfer completed callback
+ * @retval None
+ */
+__weak void BSP_SD_WriteCpltCallback(void)
+{
+
+}
+
+/**
+ * @brief BSP Rx Transfer completed callback
+ * @retval None
+ */
+__weak void BSP_SD_ReadCpltCallback(void)
+{
+
+}
+
+/**
+ * @brief SD Abort callback
+ * @param hsd: SD handle
+ * @retval None
+ */
+void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd)
+{
+ BSP_SD_AbortCallback();
+}
+
+/**
+ * @brief Tx Transfer completed callback
+ * @param hsd: SD handle
+ * @retval None
+ */
+void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
+{
+ BSP_SD_WriteCpltCallback();
+}
+
+/**
+ * @brief Rx Transfer completed callback
+ * @param hsd: SD handle
+ * @retval None
+ */
+void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
+{
+ BSP_SD_ReadCpltCallback();
+}
+
+/**
+ * @}
+ */
+
+
+/** @addtogroup STM32L496G_DISCOVERY_SD_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the SD Detect pin MSP.
+ * @param hsd: SD handle
+ * @param Params
+ * @retval None
+ */
+static void SD_Detect_MspInit(void)
+{
+ if (BSP_IO_Init() == IO_ERROR)
+ {
+ BSP_ErrorHandler();
+ }
+ BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_INPUT_PU);
+}
+
+/**
+ * @brief Initializes the SD Detect pin MSP.
+ * @param hsd: SD handle
+ * @param Params
+ * @retval None
+ */
+static void SD_Detect_MspDeInit(void)
+{
+ /* Disable all interrupts */
+ /*HAL_NVIC_DisableIRQ(MFX_INT_EXTI_IRQn);*/
+
+ if (BSP_IO_Init() == IO_ERROR)
+ {
+ BSP_ErrorHandler();
+ }
+ BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_ANALOG);
+}
+
+/**
+ * @brief Configure the DMA to receive data from the SD card
+ * @retval
+ * HAL_ERROR or HAL_OK
+ */
+static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd)
+{
+ static DMA_HandleTypeDef hdma_rx;
+ HAL_StatusTypeDef status = HAL_ERROR;
+
+ /* Configure DMA Rx parameters */
+ hdma_rx.Init.Request = DMA_REQUEST_7;
+ hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hdma_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
+
+ hdma_rx.Instance = SD_DMAx_STREAM;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsd, hdmarx, hdma_rx);
+
+ /* Stop any ongoing transfer and reset the state*/
+ HAL_DMA_Abort(&hdma_rx);
+
+ /* Deinitialize the Channel for new transfer */
+ HAL_DMA_DeInit(&hdma_rx);
+
+ /* Configure the DMA Channel */
+ status = HAL_DMA_Init(&hdma_rx);
+
+ /* NVIC configuration for DMA transfer complete interrupt */
+ HAL_NVIC_SetPriority(SD_DMAx_IRQn, 6, 0);
+ HAL_NVIC_EnableIRQ(SD_DMAx_IRQn);
+
+ return (status);
+}
+
+/**
+ * @brief Configure the DMA to transmit data to the SD card
+ * @retval
+ * HAL_ERROR or HAL_OK
+ */
+static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
+{
+ static DMA_HandleTypeDef hdma_tx;
+ HAL_StatusTypeDef status;
+
+ /* Configure DMA Tx parameters */
+ hdma_tx.Init.Request = DMA_REQUEST_7;
+ hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hdma_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
+
+ hdma_tx.Instance = SD_DMAx_STREAM;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsd, hdmatx, hdma_tx);
+
+ /* Stop any ongoing transfer and reset the state*/
+ HAL_DMA_Abort(&hdma_tx);
+
+ /* Deinitialize the Channel for new transfer */
+ HAL_DMA_DeInit(&hdma_tx);
+
+ /* Configure the DMA Channel */
+ status = HAL_DMA_Init(&hdma_tx);
+
+ /* NVIC configuration for DMA transfer complete interrupt */
+ HAL_NVIC_SetPriority(SD_DMAx_IRQn, 6, 0);
+ HAL_NVIC_EnableIRQ(SD_DMAx_IRQn);
+
+ return (status);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.h
new file mode 100644
index 0000000..934330e
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sd.h
@@ -0,0 +1,149 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_sd.h
+ * @author MCD Application Team
+ * @brief This file includes the uSD card driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_SD_H
+#define __STM32L496G_DISCOVERY_SD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l4xx_hal.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY_SD
+ * @{
+ */
+
+/* Exported types ------------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SD_Exported_Types Exported Types
+ * @{
+ */
+
+/**
+ * @brief SD Card information structure
+ */
+#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef
+/**
+ * @}
+ */
+
+/**
+ * @brief SD status structure definition
+ */
+#define MSD_OK ((uint8_t)0x00)
+#define MSD_ERROR ((uint8_t)0x01)
+#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02)
+
+/**
+ * @brief SD transfer state definition
+ */
+#define SD_TRANSFER_OK ((uint8_t)0x00)
+#define SD_TRANSFER_BUSY ((uint8_t)0x01)
+#define SD_TRANSFER_ERROR ((uint8_t)0x02)
+
+/* Exported constants --------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SD_Exported_Constants Exported Constants
+ * @{
+ */
+#define SD_DETECT_PIN IO1_PIN_8
+
+#define SD_DATATIMEOUT ((uint32_t)100000000)
+
+#define SD_PRESENT ((uint8_t)0x01)
+#define SD_NOT_PRESENT ((uint8_t)0x00)
+
+/* SD IRQ handler */
+#define SDMMCx_IRQHandler SDMMC1_IRQHandler
+#define SDMMCx_IRQn SDMMC1_IRQn
+
+
+/* DMA definitions for SD DMA transfer */
+#define SD_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE
+#define SD_DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE
+#define SD_DMAx_STREAM DMA2_Channel5
+#define SD_DMAx_IRQn DMA2_Channel5_IRQn
+#define SD_DMAx_IRQHandler DMA2_Channel5_IRQHandler
+
+/**
+ * @}
+ */
+
+/* Exported functions --------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SD_Exported_Functions Exported Functions
+ * @{
+ */
+uint8_t BSP_SD_Init(void);
+uint8_t BSP_SD_DeInit(void);
+uint8_t BSP_SD_ITConfig(void);
+uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout);
+uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout);
+uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks);
+uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks);
+uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr);
+void BSP_SD_IRQHandler(void);
+void BSP_SD_DMA_Tx_IRQHandler(void);
+void BSP_SD_DMA_Rx_IRQHandler(void);
+uint8_t BSP_SD_GetCardState(void);
+void BSP_SD_GetCardInfo(BSP_SD_CardInfo *CardInfo);
+uint8_t BSP_SD_IsDetected(void);
+
+/* These __weak functions can be surcharged by application code in case the current settings
+ (eg. interrupt priority, callbacks implementation) need to be changed for specific application needs */
+void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params);
+void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params);
+void BSP_SD_AbortCallback(void);
+void BSP_SD_WriteCpltCallback(void);
+void BSP_SD_ReadCpltCallback(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_SD_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.c
new file mode 100644
index 0000000..e180154
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.c
@@ -0,0 +1,358 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_sram.c
+ * @author MCD Application Team
+ * @brief This file provides a set of functions needed to drive the
+ * IS66WV51216EBLL SRAM memory mounted on STM32L496G-Discovery board.
+ @verbatim
+ ==============================================================================
+ ##### How to use this driver #####
+ ==============================================================================
+ [..]
+ (#) This driver is used to drive the IS66WV51216EBLL-70BLI SRAM external memory mounted
+ on STM32L496G-Discovery evaluation board.
+
+ (#) This driver does not need a specific component driver for the SRAM device
+ to be included with.
+
+ (#) Initialization steps:
+ (++) Initialize the SRAM external memory using the BSP_SRAM_Init() function. This
+ function includes the MSP layer hardware resources initialization and the
+ FMC controller configuration to interface with the external SRAM memory.
+
+ (#) SRAM read/write operations
+ (++) SRAM external memory can be accessed with read/write operations once it is
+ initialized.
+ Read/write operation can be performed with AHB access using the functions
+ BSP_SRAM_ReadData()/BSP_SRAM_WriteData(), or by DMA transfer using the functions
+ BSP_SRAM_ReadData_DMA()/BSP_SRAM_WriteData_DMA().
+ (++) The AHB access is performed with 16-bit width transaction, the DMA transfer
+ configuration is fixed at single (no burst) halfword transfer
+ (see the SRAM_MspInit() static function).
+ (++) User can implement his own functions for read/write access with his desired
+ configurations.
+ (++) If interrupt mode is used for DMA transfer, the function BSP_SRAM_DMA_IRQHandler()
+ is called in IRQ handler file, to serve the generated interrupt once the DMA
+ transfer is complete.
+ @endverbatim
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery_sram.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM STM32L496G-DISCOVERY SRAM
+ * @{
+ */
+
+
+/* Private variables ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM_Private_Variables Private Variables
+ * @{
+ */
+static SRAM_HandleTypeDef sramHandle;
+static FMC_NORSRAM_TimingTypeDef Timing;
+
+/**
+ * @}
+ */
+
+/* Private macros ------------------------------------------------------------*/
+/* Private constants ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM_Private_Constants Private Constants
+ * @{
+ */
+/* Timings for SRAM IS66WV51216EBLL-70BLI */
+#define SRAM_ADDR_SETUP_TIME 5 /* 60ns with a clock at 80 MHz (period of 12.5 ns) */
+#define SRAM_DATA_SETUP_TIME 3 /* 30ns with a clock at 80 MHz (period of 12.5 ns) */
+#define SRAM_TURN_AROUND_TIME 1 /* 5ns with a clock at 80 MHz (perido of 12.5 ns) */
+
+/**
+ * @}
+ */
+
+/* Private function prototypes -----------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM_Private_Functions Private Functions
+ * @{
+ */
+static void SRAM_MspInit(void);
+
+/**
+ * @}
+ */
+
+/* Private functions ---------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM_Exported_Functions Exported Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the SRAM device.
+ * @retval SRAM status
+ */
+uint8_t BSP_SRAM_Init(void)
+{
+ sramHandle.Instance = FMC_NORSRAM_DEVICE;
+ sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
+
+ /* SRAM device configuration */
+ Timing.AddressSetupTime = SRAM_ADDR_SETUP_TIME;
+ Timing.DataSetupTime = SRAM_DATA_SETUP_TIME;
+ Timing.BusTurnAroundDuration = SRAM_TURN_AROUND_TIME;
+ Timing.AccessMode = FMC_ACCESS_MODE_A;
+
+ sramHandle.Init.NSBank = FMC_NORSRAM_BANK2;
+ sramHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
+ sramHandle.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
+ sramHandle.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
+ sramHandle.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
+ sramHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
+ sramHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+ sramHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
+ sramHandle.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
+ sramHandle.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
+ sramHandle.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
+ sramHandle.Init.PageSize = FMC_PAGE_SIZE_NONE;
+
+ /* SRAM controller initialization */
+ SRAM_MspInit();
+ if (HAL_SRAM_Init(&sramHandle, &Timing, &Timing) != HAL_OK)
+ {
+ return SRAM_ERROR;
+ }
+ else
+ {
+ return SRAM_OK;
+ }
+}
+
+/**
+ * @brief Reads an amount of data from the SRAM device in polling mode.
+ * @param uwStartAddress: Read start address
+ * @param pData: Pointer to data to be read
+ * @param uwDataSize: Size of read data from the memory
+ * @retval SRAM status
+ */
+uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize)
+{
+ if (HAL_SRAM_Read_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK)
+ {
+ return SRAM_ERROR;
+ }
+ else
+ {
+ return SRAM_OK;
+ }
+}
+
+/**
+ * @brief Reads an amount of data from the SRAM device in DMA mode.
+ * @param uwStartAddress: Read start address
+ * @param pData: Pointer to data to be read
+ * @param uwDataSize: Size of read data from the memory
+ * @retval SRAM status
+ */
+uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize)
+{
+ if (HAL_SRAM_Read_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK)
+ {
+ return SRAM_ERROR;
+ }
+ else
+ {
+ return SRAM_OK;
+ }
+}
+
+/**
+ * @brief Writes an amount of data from the SRAM device in polling mode.
+ * @param uwStartAddress: Write start address
+ * @param pData: Pointer to data to be written
+ * @param uwDataSize: Size of written data from the memory
+ * @retval SRAM status
+ */
+uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize)
+{
+ if (HAL_SRAM_Write_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK)
+ {
+ return SRAM_ERROR;
+ }
+ else
+ {
+ return SRAM_OK;
+ }
+}
+
+/**
+ * @brief Writes an amount of data from the SRAM device in DMA mode.
+ * @param uwStartAddress: Write start address
+ * @param pData: Pointer to data to be written
+ * @param uwDataSize: Size of written data from the memory
+ * @retval SRAM status
+ */
+uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize)
+{
+ if (HAL_SRAM_Write_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK)
+ {
+ return SRAM_ERROR;
+ }
+ else
+ {
+ return SRAM_OK;
+ }
+}
+
+/**
+ * @brief Handles SRAM DMA transfer interrupt request.
+ * @retval None
+ */
+void BSP_SRAM_DMA_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(sramHandle.hdma);
+}
+
+/** @addtogroup STM32L476G_EVAL_SRAM_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes SRAM MSP.
+ * @retval None
+ */
+static void SRAM_MspInit(void)
+{
+ static DMA_HandleTypeDef dmaHandle;
+ GPIO_InitTypeDef gpioinitstruct;
+ SRAM_HandleTypeDef *hsram = &sramHandle;
+
+ /* Enable FMC clock */
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ /* Enable chosen DMAx clock */
+ SRAM_DMAx_CLK_ENABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ HAL_PWREx_EnableVddIO2();
+
+ /* Common GPIO configuration */
+ gpioinitstruct.Mode = GPIO_MODE_AF_PP;
+ gpioinitstruct.Pull = GPIO_NOPULL;
+ gpioinitstruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ gpioinitstruct.Alternate = GPIO_AF12_FMC;
+
+ /*## Data Bus #######*/
+ /* GPIOD configuration */
+ gpioinitstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
+ GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
+ HAL_GPIO_Init(GPIOD, &gpioinitstruct);
+
+ /* GPIOE configuration */
+ gpioinitstruct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
+ GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 |
+ GPIO_PIN_14 | GPIO_PIN_15;
+ HAL_GPIO_Init(GPIOE, &gpioinitstruct);
+
+ /*## Address Bus #######*/
+ /* GPIOD configuration */
+ gpioinitstruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
+ HAL_GPIO_Init(GPIOD, &gpioinitstruct);
+
+ /* GPIOF configuration */
+ gpioinitstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
+ GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 |
+ GPIO_PIN_14 | GPIO_PIN_15;
+ HAL_GPIO_Init(GPIOF, &gpioinitstruct);
+
+ /* GPIOG configuration */
+ gpioinitstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 |
+ GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
+ HAL_GPIO_Init(GPIOG, &gpioinitstruct);
+
+ /*## NOE and NWE configuration #######*/
+ gpioinitstruct.Pull = GPIO_PULLUP;
+ gpioinitstruct.Pin = GPIO_PIN_4 | GPIO_PIN_5;
+ HAL_GPIO_Init(GPIOD, &gpioinitstruct);
+ HAL_Delay(1);
+
+ /*## NBL0, NBL1 configuration #######*/
+ gpioinitstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
+ HAL_GPIO_Init(GPIOE, &gpioinitstruct);
+
+ /*## NE configuration #######*/
+ gpioinitstruct.Pin = GPIO_PIN_9;
+ HAL_GPIO_Init(GPIOG, &gpioinitstruct);
+
+ /* Configure common DMA parameters */
+ dmaHandle.Init.Direction = DMA_MEMORY_TO_MEMORY;
+ dmaHandle.Init.PeriphInc = DMA_PINC_ENABLE;
+ dmaHandle.Init.MemInc = DMA_MINC_ENABLE;
+ dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ dmaHandle.Init.Mode = DMA_NORMAL;
+ dmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
+
+ dmaHandle.Instance = SRAM_DMAx_CHANNEL;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsram, hdma, dmaHandle);
+
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&dmaHandle);
+
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&dmaHandle);
+
+ /* NVIC configuration for DMA transfer complete interrupt */
+ HAL_NVIC_SetPriority(SRAM_DMAx_IRQn, 5, 0);
+ HAL_NVIC_EnableIRQ(SRAM_DMAx_IRQn);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.h
new file mode 100644
index 0000000..3d7a12b
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_sram.h
@@ -0,0 +1,114 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_sram.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_sram.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G_DISCOVERY
+ * @{
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_SRAM_H
+#define __STM32L496G_DISCOVERY_SRAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l4xx_hal.h"
+
+/** @addtogroup STM32L496G_DISCOVERY_SRAM
+ * @{
+ */
+
+
+/* Exported constants --------------------------------------------------------*/
+
+/** @defgroup STM32L496G_DISCOVERY_SRAM_Exported_Constants Exported Constants
+ * @{
+ */
+
+/**
+ * @brief SRAM status structure definition
+ */
+#define SRAM_OK 0x00
+#define SRAM_ERROR 0x01
+
+#define SRAM_DEVICE_ADDR ((uint32_t)0x64000000)
+#define SRAM_DEVICE_SIZE ((uint32_t)0x80000) /* SRAM device size in MBytes */
+
+/* #define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8 */
+#define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16
+
+#define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE
+/* #define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/
+
+#define SRAM_WRITEBURST FMC_WRITE_BURST_DISABLE
+/* #define SRAM_WRITEBURST FMC_WRITE_BURST_ENABLE */
+
+/* DMA definitions for SRAM DMA transfer */
+#define SRAM_DMAx_CLK_ENABLE __HAL_RCC_DMA1_CLK_ENABLE
+#define SRAM_DMAx_CHANNEL DMA1_Channel1
+#define SRAM_DMAx_IRQn DMA1_Channel1_IRQn
+#define SRAM_DMAx_IRQHandler DMA1_Channel1_IRQHandler
+
+/**
+ * @}
+ */
+
+
+/* Exported functions --------------------------------------------------------*/
+
+/** @addtogroup STM32L496G_DISCOVERY_SRAM_Exported_Functions
+ * @{
+ */
+uint8_t BSP_SRAM_Init(void);
+uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize);
+uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize);
+uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize);
+uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize);
+void BSP_SRAM_DMA_IRQHandler(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_SRAM_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.c b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.c
new file mode 100644
index 0000000..6e75e1f
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.c
@@ -0,0 +1,517 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_ts.c
+ * @author MCD Application Team
+ * @brief This file provides a set of functions needed to manage the Touch
+ * Screen on STM32L496G-DISCOVERY evaluation board.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* File Info : -----------------------------------------------------------------
+ User NOTES
+1. How To use this driver:
+--------------------------
+ - This driver is used to drive the touch screen module of the STM32L496G-DISCOVERY
+ evaluation board on the FRIDA LCD mounted on MB1261 daughter board.
+ The touch screen driver IC is a FT6x36 type which share the same register naming
+ with FT6206 type.
+
+2. Driver description:
+---------------------
+ + Initialization steps:
+ o Initialize the TS module using the BSP_TS_Init() function. This
+ function includes the MSP layer hardware resources initialization and the
+ communication layer configuration to start the TS use. The LCD size properties
+ (x and y) are passed as parameters.
+ o If TS interrupt mode is desired, you must configure the TS interrupt mode
+ by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated
+ as an external interrupt whenever a touch is detected.
+
+ + Touch screen use
+ o The touch screen state is captured whenever the function BSP_TS_GetState() is
+ used. This function returns information about the last LCD touch occurred
+ in the TS_StateTypeDef structure.
+------------------------------------------------------------------------------*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+#include "stm32l496g_discovery_ts.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G-DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS STM32L496G-DISCOVERY TS
+ * @{
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Types_Definitions TS Private Types Definitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Defines TS Private Types Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Macros TS Private Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Imported_Variables TS Imported Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Variables TS Private Variables
+ * @{
+ */
+static TS_DrvTypeDef *tsDriver;
+static uint8_t I2C_Address = 0;
+static uint8_t tsOrientation = TS_SWAP_NONE;
+static uint8_t TS_orientation = TS_ORIENTATION_UNDEFINED;
+
+/* Table for touchscreen event information display on LCD : table indexed on enum @ref TS_TouchEventTypeDef information */
+char *ts_event_string_tab[TOUCH_EVENT_NB_MAX] = { "None",
+ "Press down",
+ "Lift up",
+ "Contact"
+ };
+
+/* Table for touchscreen gesture Id information display on LCD : table indexed on enum @ref TS_GestureIdTypeDef information */
+char *ts_gesture_id_string_tab[GEST_ID_NB_MAX] = { "None",
+ "Move Up",
+ "Move Right",
+ "Move Down",
+ "Move Left",
+ "Zoom In",
+ "Zoom Out"
+ };
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Function_Prototypes TS Private Function Prototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Public_Functions TS Public Functions
+ * @{
+ */
+/**
+ * @brief Initializes and configures the touch screen functionalities and
+ * configures all necessary hardware resources (GPIOs, I2C, clocks..).
+ * @param ts_SizeX : Maximum X size of the TS area on LCD
+ * @param ts_SizeY : Maximum Y size of the TS area on LCD
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY)
+{
+ return (BSP_TS_InitEx(ts_SizeX, ts_SizeY, TS_ORIENTATION_LANDSCAPE));
+}
+
+/**
+ * @brief Initializes and configures the touch screen functionalities and
+ * configures all necessary hardware resources (GPIOs, I2C, clocks..)
+ * with a given orientation
+ * @param ts_SizeX : Maximum X size of the TS area on LCD
+ * @param ts_SizeY : Maximum Y size of the TS area on LCD
+ * @param orientation : TS_ORIENTATION_LANDSCAPE or TS_ORIENTATION_PORTRAIT
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation)
+{
+ uint8_t ts_status = TS_OK;
+ uint16_t read_id = 0;
+
+ /* Note : I2C_Address is un-initialized here, but is not used at all in init function */
+ /* but the prototype of Init() is like that in template and should be respected */
+
+ /* Initialize the communication channel to sensor (I2C) if necessary */
+ /* that is initialization is done only once after a power up */
+ ft6x06_ts_drv.Init(I2C_Address);
+
+ /* Scan FT6x36 TouchScreen IC controller ID register by I2C Read */
+ /* Verify this is a FT6x36, otherwise this is an error case */
+
+ read_id = ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS);
+
+ if (read_id == FT6x36_ID_VALUE)
+ {
+ /* Found FT6x36 : Initialize the TS driver structure */
+ tsDriver = &ft6x06_ts_drv;
+
+ I2C_Address = TS_I2C_ADDRESS;
+
+ /* Get LCD chosen orientation */
+ if (orientation == TS_ORIENTATION_PORTRAIT)
+ {
+ tsOrientation = TS_SWAP_X | TS_SWAP_Y;
+ TS_orientation = TS_ORIENTATION_PORTRAIT;
+ }
+ else
+ {
+ tsOrientation = TS_SWAP_XY | TS_SWAP_Y;
+ TS_orientation = TS_ORIENTATION_LANDSCAPE;
+ }
+
+ if (ts_status == TS_OK)
+ {
+ /* Software reset the TouchScreen */
+ tsDriver->Reset(I2C_Address);
+
+ /* Calibrate, Configure and Start the TouchScreen driver */
+ tsDriver->Start(I2C_Address);
+
+ return TS_OK;
+
+ } /* of if(ts_status == TS_OK) */
+ }
+
+ return TS_DEVICE_NOT_FOUND;
+
+
+}
+
+/**
+ * @brief Configures and enables the touch screen interrupts.
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_ITConfig(void)
+{
+ uint8_t ts_status = TS_OK;
+
+ /* Msp Init of GPIO used for TS_INT pin coming from TouchScreen driver IC FT6x36 */
+ /* When touchscreen is operated in interrupt mode */
+ BSP_TS_INT_MspInit();
+
+ /* Enable the TS in interrupt mode */
+ /* In that case the INT output of FT6206 when new touch is available */
+ /* is active on low level and directed on EXTI */
+ tsDriver->EnableIT(I2C_Address);
+
+ return (ts_status);
+}
+
+/**
+ * @brief deConfigures and enables the touch screen interrupts.
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_ITDeConfig(void)
+{
+ uint8_t ts_status = TS_OK;
+
+ /* Msp Init of GPIO used for TS_INT pin coming from TouchScreen driver IC FT6x36 */
+ /* When touchscreen is operated in interrupt mode */
+ BSP_TS_INT_MspDeInit();
+
+ /* Enable the TS in interrupt mode */
+ /* In that case the INT output of FT6206 when new touch is available */
+ /* is active on low level and directed on EXTI */
+ tsDriver->DisableIT(I2C_Address);
+
+ return (ts_status);
+}
+
+
+/**
+ * @brief Returns status and positions of the touch screen.
+ * @param TS_State: Pointer to touch screen current state structure
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State)
+{
+ static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0};
+ static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0};
+ uint8_t ts_status = TS_OK;
+ uint16_t tmp;
+ uint16_t Raw_x[TS_MAX_NB_TOUCH];
+ uint16_t Raw_y[TS_MAX_NB_TOUCH];
+ uint16_t xDiff;
+ uint16_t yDiff;
+ uint32_t index;
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+ uint32_t weight = 0;
+ uint32_t area = 0;
+ uint32_t event = 0;
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+ /* Check and update the number of touches active detected */
+ TS_State->touchDetected = tsDriver->DetectTouch(I2C_Address);
+ if (TS_State->touchDetected)
+ {
+ for (index = 0; index < TS_State->touchDetected; index++)
+ {
+ /* Get each touch coordinates */
+ tsDriver->GetXY(I2C_Address, &(Raw_x[index]), &(Raw_y[index]));
+
+ if (tsOrientation & TS_SWAP_XY)
+ {
+ tmp = Raw_x[index];
+ Raw_x[index] = Raw_y[index];
+ Raw_y[index] = tmp;
+ }
+
+ if (tsOrientation & TS_SWAP_X)
+ {
+ Raw_x[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_x[index];
+ }
+
+ if (tsOrientation & TS_SWAP_Y)
+ {
+ Raw_y[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_y[index];
+ }
+
+ xDiff = Raw_x[index] > _x[index] ? (Raw_x[index] - _x[index]) : (_x[index] - Raw_x[index]);
+ yDiff = Raw_y[index] > _y[index] ? (Raw_y[index] - _y[index]) : (_y[index] - Raw_y[index]);
+
+ if ((xDiff + yDiff) > 5)
+ {
+ _x[index] = Raw_x[index];
+ _y[index] = Raw_y[index];
+ }
+
+
+ TS_State->touchX[index] = _x[index];
+ TS_State->touchY[index] = _y[index];
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+
+ /* Get touch info related to the current touch */
+ ft6x06_TS_GetTouchInfo(I2C_Address, index, &weight, &area, &event);
+
+ /* Update TS_State structure */
+ TS_State->touchWeight[index] = weight;
+ TS_State->touchArea[index] = area;
+
+ /* Remap touch event */
+ switch (event)
+ {
+ case FT6206_TOUCH_EVT_FLAG_PRESS_DOWN :
+ TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN;
+ break;
+ case FT6206_TOUCH_EVT_FLAG_LIFT_UP :
+ TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP;
+ break;
+ case FT6206_TOUCH_EVT_FLAG_CONTACT :
+ TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT;
+ break;
+ case FT6206_TOUCH_EVT_FLAG_NO_EVENT :
+ TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT;
+ break;
+ default :
+ ts_status = TS_ERROR;
+ break;
+ } /* of switch(event) */
+
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+ } /* of for(index=0; index < TS_State->touchDetected; index++) */
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+ /* Get gesture Id */
+ ts_status = BSP_TS_Get_GestureId(TS_State);
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+ } /* end of if(TS_State->touchDetected != 0) */
+
+ return (ts_status);
+}
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+/**
+ * @brief Update gesture Id following a touch detected.
+ * @param TS_State: Pointer to touch screen current state structure
+ * @retval TS_OK if all initializations are OK. Other value if error.
+ */
+uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State)
+{
+ uint32_t gestureId = 0;
+ uint8_t ts_status = TS_OK;
+
+ /* Get gesture Id */
+ ft6x06_TS_GetGestureID(I2C_Address, &gestureId);
+
+ /* Remap gesture Id to a TS_GestureIdTypeDef value */
+ switch (gestureId)
+ {
+ case FT6206_GEST_ID_NO_GESTURE :
+ TS_State->gestureId = GEST_ID_NO_GESTURE;
+ break;
+ case FT6206_GEST_ID_MOVE_UP :
+ TS_State->gestureId = GEST_ID_MOVE_UP;
+ break;
+ case FT6206_GEST_ID_MOVE_RIGHT :
+ TS_State->gestureId = GEST_ID_MOVE_RIGHT;
+ break;
+ case FT6206_GEST_ID_MOVE_DOWN :
+ TS_State->gestureId = GEST_ID_MOVE_DOWN;
+ break;
+ case FT6206_GEST_ID_MOVE_LEFT :
+ TS_State->gestureId = GEST_ID_MOVE_LEFT;
+ break;
+ case FT6206_GEST_ID_ZOOM_IN :
+ TS_State->gestureId = GEST_ID_ZOOM_IN;
+ break;
+ case FT6206_GEST_ID_ZOOM_OUT :
+ TS_State->gestureId = GEST_ID_ZOOM_OUT;
+ break;
+ default :
+ ts_status = TS_ERROR;
+ break;
+ } /* of switch(gestureId) */
+
+ return (ts_status);
+}
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Private_Functions TS Private Functions
+ * @{
+ */
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+/**
+ * @brief Function used to reset all touch data before a new acquisition
+ * of touch information.
+ * @param TS_State: Pointer to touch screen current state structure
+ * @retval TS_OK if OK, TE_ERROR if problem found.
+ */
+uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State)
+{
+ uint8_t ts_status = TS_ERROR;
+ uint32_t index;
+
+ if (TS_State != (TS_StateTypeDef *)NULL)
+ {
+ TS_State->gestureId = GEST_ID_NO_GESTURE;
+ TS_State->touchDetected = 0;
+
+ for (index = 0; index < TS_MAX_NB_TOUCH; index++)
+ {
+ TS_State->touchX[index] = 0;
+ TS_State->touchY[index] = 0;
+ TS_State->touchArea[index] = 0;
+ TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT;
+ TS_State->touchWeight[index] = 0;
+ }
+
+ ts_status = TS_OK;
+
+ } /* of if (TS_State != (TS_StateTypeDef *)NULL) */
+
+ return (ts_status);
+}
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+
+uint8_t BSP_TS_GetOrientation(void)
+{
+ return TS_orientation;
+}
+
+/**
+ * @brief Initializes the TS_INT pin MSP.
+ * @param None
+ * @retval None
+ */
+__weak void BSP_TS_INT_MspInit(void)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ __HAL_RCC_PWR_CLK_ENABLE();
+ SET_BIT(PWR->CR2, PWR_CR2_IOSV);
+
+ TS_INT_GPIO_CLK_ENABLE();
+
+ /* GPIO configuration in input for TouchScreen interrupt signal on TS_INT pin */
+ gpio_init_structure.Pin = TS_INT_PIN;
+
+ /* Configure Interrupt mode for TS_INT pin falling edge : when a new touch is available */
+ /* TS_INT pin is active on low level on new touch available */
+ gpio_init_structure.Pin = TS_INT_PIN;
+ gpio_init_structure.Pull = GPIO_PULLUP;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ gpio_init_structure.Mode = GPIO_MODE_IT_FALLING;
+ HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure);
+
+ /* Enable and set the TS_INT EXTI Interrupt to an intermediate priority */
+ HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x08, 0x00);
+ HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn));
+}
+
+/**
+ * @brief Initializes the TS_INT pin MSP.
+ * @param None
+ * @retval None
+ */
+__weak void BSP_TS_INT_MspDeInit(void)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ __HAL_RCC_PWR_CLK_ENABLE();
+ SET_BIT(PWR->CR2, PWR_CR2_IOSV);
+
+ TS_INT_GPIO_CLK_ENABLE();
+
+ /* GPIO configuration in input for TouchScreen interrupt signal on TS_INT pin */
+ gpio_init_structure.Pin = TS_INT_PIN;
+
+ gpio_init_structure.Pin = GPIO_PIN_All;
+ gpio_init_structure.Mode = GPIO_MODE_ANALOG;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure);
+
+ HAL_NVIC_DisableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn));
+}
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.h b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.h
new file mode 100644
index 0000000..f9491b7
--- /dev/null
+++ b/Drivers/BSP/STM32L496G-Discovery/stm32l496g_discovery_ts.h
@@ -0,0 +1,203 @@
+/**
+ ******************************************************************************
+ * @file stm32l496g_discovery_ts.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32l496g_discovery_ts.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L496G_DISCOVERY_TS_H
+#define __STM32L496G_DISCOVERY_TS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l496g_discovery.h"
+#include "stm32l496g_discovery_lcd.h"
+
+/* Include TouchScreen component driver */
+#include "../Components/ft6x06/ft6x06.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32L496G-DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS STM32L496G-DISCOVERY TS
+ * @{
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Exported_Constants TS Exported Constants
+ * @{
+ */
+/** @brief With FT6206 : maximum 2 touches detected simultaneously
+ */
+#define TS_MAX_NB_TOUCH ((uint32_t) FT6206_MAX_DETECTABLE_TOUCH)
+
+#define TS_NO_IRQ_PENDING ((uint8_t) 0)
+#define TS_IRQ_PENDING ((uint8_t) 1)
+
+#define TS_SWAP_NONE ((uint8_t) 0x01)
+#define TS_SWAP_X ((uint8_t) 0x02)
+#define TS_SWAP_Y ((uint8_t) 0x04)
+#define TS_SWAP_XY ((uint8_t) 0x08)
+
+#define TS_ORIENTATION_PORTRAIT ((uint8_t) 0)
+#define TS_ORIENTATION_LANDSCAPE ((uint8_t) 1)
+#define TS_ORIENTATION_UNDEFINED ((uint8_t) 2)
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Exported_Types TS Exported Types
+ * @{
+ */
+/**
+* @brief TS_StateTypeDef
+* Define TS State structure
+*/
+typedef struct
+{
+ uint8_t touchDetected; /*!< Total number of active touches detected at last scan */
+ uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */
+ uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+ uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */
+ uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */
+ uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */
+ uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+} TS_StateTypeDef;
+
+/**
+ * @brief TS_StatusTypeDef
+ * Define BSP_TS_xxx() functions possible return value,
+ * when status is returned by those functions.
+ */
+typedef enum
+{
+ TS_OK = 0x00, /*!< Touch Ok */
+ TS_ERROR = 0x01, /*!< Touch Error */
+ TS_TIMEOUT = 0x02, /*!< Touch Timeout */
+ TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */
+} TS_StatusTypeDef;
+
+/**
+ * @brief TS_GestureIdTypeDef
+ * Define Possible managed gesture identification values returned by touch screen
+ * driver.
+ */
+typedef enum
+{
+ GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */
+ GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */
+ GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */
+ GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */
+ GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */
+ GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */
+ GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */
+ GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */
+} TS_GestureIdTypeDef;
+
+/**
+ * @brief TS_TouchEventTypeDef
+ * Define Possible touch events kind as returned values
+ * by touch screen IC Driver.
+ */
+typedef enum
+{
+ TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */
+ TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */
+ TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */
+ TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */
+ TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */
+} TS_TouchEventTypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Imported_Variables STM32L496G DISCOVERY TS Imported Variables
+ * @{
+ */
+/**
+ * @brief Table for touchscreen event information display on LCD :
+ * table indexed on enum @ref TS_TouchEventTypeDef information
+ */
+extern char *ts_event_string_tab[TOUCH_EVENT_NB_MAX];
+
+/**
+ * @brief Table for touchscreen gesture Id information display on LCD : table indexed
+ * on enum @ref TS_GestureIdTypeDef information
+ */
+extern char *ts_gesture_id_string_tab[GEST_ID_NB_MAX];
+/**
+ * @}
+ */
+
+/** @defgroup STM32L496G-DISCOVERY_TS_Exported_Functions TS Exported Functions
+ * @{
+ */
+uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY);
+uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation);
+uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State);
+uint8_t BSP_TS_GetOrientation(void);
+
+#if (TS_MULTI_TOUCH_SUPPORTED == 1)
+uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State);
+uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State);
+#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */
+
+uint8_t BSP_TS_ITConfig(void);
+uint8_t BSP_TS_ITDeConfig(void);
+
+/* These __weak function can be surcharged by application code in case the current settings
+ need to be changed for specific (example GPIO allocation) */
+void BSP_TS_INT_MspInit(void);
+void BSP_TS_INT_MspDeInit(void);
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L496G_DISCOVERY_TS_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/