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

+
+ +
+

Main Changes

+
    +
  • Minor update of Release Notes template
  • +
  • Add License.md file for GitHub publication
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Remove useless assignment in BSP_COM_Init() function
  • +
  • Update common GPIO configuration in BSP_SD_MspInit() to remove internal pull-up
  • +
+
+
+
+ +
+

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
  • +
+
+
+
+ +
+

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
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32l496g_discovery.c +
      +
    • Correct logical test in DrawChar()
    • +
    • Comment minor correction
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Release notes update to new format
  • +
+
+
+
+ +
+

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()
      • +
    • +
  • +
+
+
+
+ +
+

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****/