{"id":2553,"date":"2024-05-31T09:20:29","date_gmt":"2024-05-31T09:20:29","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2553"},"modified":"2024-05-31T09:20:31","modified_gmt":"2024-05-31T09:20:31","slug":"working-with-stm32-and-i2s-part-1-introduction","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2553","title":{"rendered":"Working with STM32 and I2S Part 1 : Introduction"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"200\" height=\"150\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Inter-IC-Sound-1.jpg\" alt=\"\" class=\"wp-image-2555\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide series, we shall cover the I2S peripheral of STM32F407 and its feature.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall covet the following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>What is I2S.<\/li><li>Feature of I2S of STM32F407.<\/li><li>Feature of CS43L22.<\/li><li>Environment Setup.<\/li><li>Set the core speed to 168MHz.<\/li><li>Delay funciton.<\/li><li>I2C Peripheral initialization.<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. What  is I2S:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>I\u00b2S<\/strong>&nbsp;(Inter-IC Sound), pronounced \u201ceye-squared-ess,\u201d is an electrical serial bus interface standard used for connecting digital audio devices together. It facilitates the communication of&nbsp;<strong>PCM (pulse-code modulated)<\/strong>&nbsp;audio data between integrated circuits within an electronic device. Here are some key details about I\u00b2S:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li><strong>Bus Configuration<\/strong>:<ul><li>The I\u00b2S bus consists of at least three lines:<ul><li><strong>Bit Clock (BCLK)<\/strong>: Also known as the \u201ccontinuous serial clock,\u201d this line synchronizes the data transmission. It pulses once for each discrete bit of data on the data lines.<\/li><li><strong>Word Clock (WS)<\/strong>: Indicates whether channel 1 (WS = 0) or channel 2 (WS = 1) is being transmitted. I\u00b2S allows two channels to be sent on the same data line.<\/li><li><strong>Multiplexed Data Line (SD)<\/strong>: Carries the actual audio data. It can be called by various names such as SDATA, SDIN, SDOUT, DACDAT, or ADCDAT.<\/li><\/ul><\/li><li>Optionally, there may be a\u00a0<strong>Master Clock<\/strong>(typically 256 times the LRCLK) for synchronizing analog\/digital converters.<\/li><\/ul><\/li><li><strong>Timing and Synchronization<\/strong>:<ul><li>The word select clock (WS) has a 50% duty cycle and the same frequency as the sample rate. For stereo material, left audio is transmitted during the low cycle of WS, and the right channel during the high cycle.<\/li><li>Data is latched on the rising edge of the serial clock (SCK).<\/li><\/ul><\/li><li><strong>History<\/strong>:<ul><li>Introduced by Philips Semiconductor (now NXP Semiconductors) in 1986.<\/li><li>Last revised in February 2022, updating terms from \u201cmaster\u201d and \u201cslave\u201d to \u201ccontroller\u201d and \u201ctarget\u201d.<\/li><\/ul><\/li><\/ol>\n\n\n\n<p>I\u00b2S is commonly used in audio codecs, microcontrollers, digital signal processors, and other sound-processing devices.\u00a0<a href=\"https:\/\/piembsystech.com\/i2s-protocol-framing-working-applications\/\">It provides high-quality audio transmission, precise synchronization, and efficient data transfer, making it a preferred choice for digital audio communication\u00a0<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Feature of I2S of STM32F407:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Full duplex communication<\/p>\n\n\n\n<p>\u2022 Half-duplex communication (only transmitter or receiver)<\/p>\n\n\n\n<p>\u2022 Master or slave operations<\/p>\n\n\n\n<p>\u2022 8-bit programmable linear prescaler to reach accurate audio sample frequencies (from 8 kHz to 192 kHz)<\/p>\n\n\n\n<p>\u2022 Data format may be 16-bit, 24-bit or 32-bit<\/p>\n\n\n\n<p>\u2022 Packet frame is fixed to 16-bit (16-bit data frame) or 32-bit (16-bit, 24-bit, 32-bit data frame) by audio channel<\/p>\n\n\n\n<p>\u2022 Programmable clock polarity (steady state)<\/p>\n\n\n\n<p>\u2022 Underrun flag in slave transmission mode, overrun flag in reception mode (master and slave), and Frame Error flag in reception and transmission mode (slave only)<\/p>\n\n\n\n<p>\u2022 16-bit register for transmission and reception with one data register for both channel sides<\/p>\n\n\n\n<p>\u2022 Supported I 2 S protocols:<\/p>\n\n\n\n<p>\u2013 I 2 S Phillps standard<\/p>\n\n\n\n<p>\u2013 MSB-justified standard (left-justified)<\/p>\n\n\n\n<p>\u2013 LSB-justified standard (right-justified)<\/p>\n\n\n\n<p>\u2013 PCM standard (with short and long frame synchronization on 16-bit channel frame or 16-bit data frame extended to 32-bit channel frame)<\/p>\n\n\n\n<p>\u2022 Data direction is always MSB first<\/p>\n\n\n\n<p>\u2022 DMA capability for transmission and reception (16-bit wide)<\/p>\n\n\n\n<p>\u2022 Master clock may be output to drive an external audio component. Ratio is fixed at 256 \u00d7 F S (where F S is the audio sampling frequency)<\/p>\n\n\n\n<p>\u2022 Both I 2 S (I2S2 and I2S3) have a dedicated PLL (PLLI2S) to generate an even more accurate clock.<\/p>\n\n\n\n<p>\u2022 I 2 S (I2S2 and I2S3) clock can be derived from an external clock mapped on the I2S_CKIN pin.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"966\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-966x1024.png\" alt=\"\" class=\"wp-image-2556\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-966x1024.png 966w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-283x300.png 283w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-768x814.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-1450x1536.png 1450w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-1150x1218.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-750x795.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-400x424.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM-250x265.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.00.17\u202fPM.png 1646w\" sizes=\"(max-width: 966px) 100vw, 966px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Feature of CS43L22:<\/h2>\n\n\n\n<p>The&nbsp;<strong>CS43L22<\/strong>&nbsp;is a low-power stereo digital\/analog converter (DAC) manufactured by&nbsp;<strong>Cirrus Logic<\/strong>. Let\u2019s explore its key features:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li><strong>DAC and Amplifiers<\/strong>:<ul><li>The CS43L22 integrates both a&nbsp;<strong>headphone amplifier<\/strong>&nbsp;and a&nbsp;<strong>Class D speaker amplifier<\/strong>.<\/li><li>The&nbsp;<strong>DAC output path<\/strong>&nbsp;includes a digital signal processing engine with various fixed-function controls, such as&nbsp;<strong>tone and volume control<\/strong>.<\/li><li>It also includes&nbsp;<strong>de-emphasis<\/strong>,&nbsp;<strong>limiting functions<\/strong>, and a&nbsp;<strong>beep generator<\/strong>&nbsp;that delivers tones selectable across a range of two octaves.<\/li><\/ul><\/li><li><strong>Headphone Amplifier<\/strong>:<ul><li>The headphone amplifier is&nbsp;<strong>GND-centered<\/strong>, which means it doesn\u2019t require&nbsp;<strong>DC-blocking capacitors<\/strong>.<\/li><li>It is powered from a separate positive supply.<\/li><li>Output power:<ul><li><strong>2 x 23 mW into 16 \u03a9 @ 1.8 V<\/strong><\/li><li><strong>2 x 44 mW into 16 \u03a9 @ 2.5 V<\/strong><\/li><\/ul><\/li><\/ul><\/li><li><strong>Class D Speaker Amplifier<\/strong>:<ul><li>The Class D stereo speaker amplifier does&nbsp;<strong>not require an external filter<\/strong>.<\/li><li>It can be powered directly from a battery.<\/li><li>Efficiency:&nbsp;<strong>82% at 800 mW<\/strong><\/li><\/ul><\/li><li><strong>System Features<\/strong>:<ul><li>Clock support:&nbsp;<strong>12, 24, and 27 MHz main clock<\/strong>&nbsp;in addition to typical audio clock rates.<\/li><li>Low power operation:<ul><li><strong>Stereo analog pass-through<\/strong>: 10 mW @ 1.8 V<\/li><li><strong>Stereo playback<\/strong>: 14 mW @ 1.8 V<\/li><\/ul><\/li><li>Variable power supplies:<ul><li>Digital and analog:&nbsp;<strong>1.8 V to 2.5 V<\/strong><\/li><li>Class D amplifier:&nbsp;<strong>2.5 V to 5 V<\/strong><\/li><li>Headphone amplifier:&nbsp;<strong>1.8 V to 2.5 V<\/strong><\/li><li>Interface logic:&nbsp;<strong>1.8 V to 3.3 V<\/strong><\/li><\/ul><\/li><li>Other features include&nbsp;<strong>battery level monitoring<\/strong>,&nbsp;<strong>compensation<\/strong>, and&nbsp;<strong>flexible clocking options<\/strong>.<\/li><\/ul><\/li><\/ol>\n\n\n\n<p>The CS43L22 is commonly used in audio codecs, portable devices, and other applications where efficient audio processing is essential.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"575\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-1024x575.png\" alt=\"\" class=\"wp-image-2557\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-1024x575.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-300x168.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-768x431.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-1536x862.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-2048x1149.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-1150x647.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-750x422.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-400x225.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/Screenshot-2024-05-31-at-12.02.51\u202fPM-250x141.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Environment Setup:<\/h2>\n\n\n\n<p>For detailed environment setup, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a>.<\/p>\n\n\n\n<p>The only thing to make sure is to select the correct chip, replace STM32F411xE with the following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">STM32F407xx<\/pre><\/div>\n\n\n\n<p>Now, the environment is ready for the STM32F407.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Set the core to 168MHz:<\/h2>\n\n\n\n<p>Create new source file with name of sys_init.c.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the source:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stm32f4xx.h&quot;\n\nvoid SystemInit(void)\n{\n#define PLL_M      4\n#define PLL_N      168\n#define PLL_P      2\n#define PLL_Q      9\n\n__IO uint32_t StartUpCounter = 0, HSEStatus = 0;\n\n\n  RCC-&gt;CR |= ((uint32_t)RCC_CR_HSEON);\n\n\n  do\n  {\n\tHSEStatus = RCC-&gt;CR &amp; RCC_CR_HSERDY;\n\tStartUpCounter++;\n  } while((HSEStatus == 0) &amp;&amp; (StartUpCounter != 3000));\n\n  if ((RCC-&gt;CR &amp; RCC_CR_HSERDY) != RESET)\n  {\n\tHSEStatus = (uint32_t)0x01;\n  }\n  else\n  {\n\tHSEStatus = (uint32_t)0x00;\n  }\n\n  if (HSEStatus == (uint32_t)0x01)\n  {\n\n\tRCC-&gt;APB1ENR |= RCC_APB1ENR_PWREN;\n\tPWR-&gt;CR &amp;= (uint32_t)~(PWR_CR_VOS);\n\n\n\tRCC-&gt;CFGR |= RCC_CFGR_HPRE_DIV1;\n\n\n\tRCC-&gt;CFGR |= RCC_CFGR_PPRE2_DIV1;\n\n\n\tRCC-&gt;CFGR |= RCC_CFGR_PPRE1_DIV2;\n\n\n\tRCC-&gt;PLLCFGR = PLL_M | (PLL_N &lt;&lt; 6) | (((PLL_P &gt;&gt; 1) -1) &lt;&lt; 16) |\n\t\t\t\t   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q &lt;&lt; 24);\n\n\n\tRCC-&gt;CR |= RCC_CR_PLLON;\n\n\n\twhile((RCC-&gt;CR &amp; RCC_CR_PLLRDY) == 0)\n\t{\n\t}\n\n\t\/* Configure Flash prefetch, Instruction cache, Data cache and wait state *\/\n\tFLASH-&gt;ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;\n\n\n\t\/* Select the main PLL as system clock source *\/\n\tRCC-&gt;CFGR &amp;= (uint32_t)((uint32_t)~(RCC_CFGR_SW));\n\tRCC-&gt;CFGR |= RCC_CFGR_SW_PLL;\n\n\t\/* Wait till the main PLL is used as system clock source *\/\n\twhile ((RCC-&gt;CFGR &amp; (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL)\n\t{;}\n  }\n  else\n  { \/* If HSE fails to start-up, the application will have wrong clock\n\t\t configuration. User can add here some code to deal with this error *\/\n  }\n\n  \/*Enable FPU*\/\n  SCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\n  \/*Enable cell compensation*\/\n  RCC-&gt;APB2ENR|=RCC_APB2ENR_SYSCFGEN ;\n  SYSCFG-&gt;CMPCR|=(1&lt;&lt;0);\n  while(!((SYSCFG-&gt;CMPCR)&amp;(1&lt;&lt;8))){;}\n\n\n}\n<\/pre><\/div>\n\n\n\n<p>For more information how to set the core frequency, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=454\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=454\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Delay Function:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new source and header files with name of delay.c and delay.h respectively.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the header file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef __delay__H__\n#define __delay__H__\n\n#include &quot;stdint.h&quot;\n\n\/*\n * @brief This function will initialize SysTick\n * to generate 1ms interrupt.\n * @param freq source frequency of SysTick.\n * @return nothing.\n * @see Generic ARM CortexM4 user guide.\n * *\/\n\nvoid delay_init(uint32_t freq);\n\n\/*\n * @brief This function will return the current millis.\n *\n * @param nothing.\n * @return current millis.\n * *\/\nuint64_t millis();\n\n\n\/*\n * @brief This function will spin lock the CPU to delay for the required\n * amount\n * @param time to be delayed in milliseconds.\n * @return nothing.\n * *\/\nvoid delay(uint32_t time);\n\n\n#endif \/* DELAY_H_ *\/\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the source file:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &lt;delay.h&gt;\n#include &quot;stm32f4xx.h&quot;\n\n\n#define\tCTRL_ENABLE\t\t\t\t\t(1U&lt;&lt;0) \/*Enable SysTick Timer*\/\n#define CTRL_CLKSRC\t\t\t\t\t(1U&lt;&lt;2) \/*Clock source selection*\/\n#define CTRL_COUNTFLAG\t\t\t\t(1U&lt;&lt;16) \/*Count flag bit*\/\n#define CTRL_TICKINT\t\t\t\t(1U&lt;&lt;1) \/*Interrupt enable bit*\/\n\n\nvolatile uint64_t mil; \/*volatile variable to hold the ms counter*\/\n\nvoid delay_init(uint32_t freq)\n{\n\n\t\/*Set period to be 1ms*\/\n\tSysTick-&gt;LOAD  = (freq\/1000) - 1;\n\n\t\/*Clear systick current value register *\/\n\tSysTick-&gt;VAL = 0;\n\n\t\/*Enable systick and select internal clk src*\/\n\tSysTick-&gt;CTRL = CTRL_ENABLE | CTRL_CLKSRC ;\n\n\t\/*Enable systick interrupt*\/\n\tSysTick-&gt;CTRL  |= CTRL_TICKINT;\n\n}\n\n\n\nuint64_t millis()\n\t{\n\n\t__disable_irq(); \/*Disable global interrupt*\/\n\n\tuint64_t ml=mil; \/*Get the current millis values and store in ml*\/\n\n\t__enable_irq(); \/*Enable global interrupt*\/\n\n\treturn ml;\t\t\/*Return the stored value*\/\n\t}\n\n\n\/*Spin lock the CPU to delay*\/\nvoid delay(uint32_t time)\n{\n\n\tuint64_t start=millis();\n\twhile((millis() - start) &lt; (time+1));\n}\n\n\/*Interrupt handler of SysTick*\/\nvoid SysTick_Handler(void)\n{\n\t\/*Increment the counter with every interrupt*\/\n\tmil++;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. I2C configuration:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Since the audio chip requires configuration over I2C bus, we shall initialize it accordingly.<\/p>\n\n\n\n<p>From the STM32F407-discovery, we can find that PB6 and PB9 are connected to I2C bus:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"469\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-1024x469.jpg\" alt=\"\" class=\"wp-image-2558\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-1024x469.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-300x137.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-768x352.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-1536x704.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-2048x938.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-1150x527.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-750x344.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-400x183.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-31_12-11-30-250x115.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Now, create new source and header file with name of i2c.c and i2c.h respectively.<\/p>\n\n\n\n<p>Within the header file:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\n#ifndef I2C_H_\n#define I2C_H_\n\n\n#include &quot;stm32f4xx.h&quot;                  \/\/ Device header\n#include &quot;delay.h&quot;\n#include &quot;stdint.h&quot;\n\n\n\nvoid i2c_init(void);\nchar i2c_readByte(char saddr,char maddr,char *data);\nvoid i2c_writeByte(char saddr,char maddr,char data);\nvoid i2c_WriteMulti(char saddr,char maddr,char *buffer, uint8_t length);\nvoid i2c_ReadMulti(char saddr,char maddr, int n, char* data);\n\n\n\n#endif\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the source file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;i2c.h&quot;\n\nuint8_t inited=0;\n\nvoid i2c_init(void)\n{\n\t#define I2C1_AF 0x04\n\n\tif(inited==0)\n\t{\n\t\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN; \/\/enable gpiob clock\n\t\tRCC-&gt;APB1ENR|=RCC_APB1ENR_I2C1EN; \/\/enable i2c1 clock\n\n\t\t\/\/set PB6 and PB9 to alternative function\n\t\tGPIOB-&gt;MODER|=GPIO_MODER_MODE6_1|GPIO_MODER_MODE9_1;\n\t\tGPIOB-&gt;MODER&amp;=~(GPIO_MODER_MODE6_0|GPIO_MODER_MODE9_0);\n\n\t\tGPIOB-&gt;AFR[0]|=(I2C1_AF&lt;&lt;GPIO_AFRL_AFSEL6_Pos);\n\n\t\tGPIOB-&gt;AFR[1]|=(I2C1_AF&lt;&lt;GPIO_AFRH_AFSEL9_Pos);\n\n\t\tGPIOB-&gt;OTYPER|=GPIO_OTYPER_OT6|GPIO_OTYPER_OT9; \/\/set pb8 and pb9 as open drain\n\n\t\tI2C1-&gt;CR1=I2C_CR1_SWRST;\n\n\t\tI2C1-&gt;CR1&amp;=~I2C_CR1_SWRST;\n\n\t\tI2C1-&gt;CR2|=50;\n\n\t\tI2C1-&gt;CCR=0xd2;\n\n\t\tI2C1-&gt;TRISE=0x2b; \/\/output max rise\n\n\t\tI2C1-&gt;CR1|=I2C_CR1_PE;\n\n\t\tinited=1;\n\t}\n}\nchar i2c_readByte(char saddr,char maddr, char *data)\n{\n\n\n\twhile(I2C1-&gt;SR2&amp;I2C_SR2_BUSY){;}\n\tI2C1-&gt;CR1|=I2C_CR1_START;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_SB)){;}\n\tI2C1-&gt;DR=saddr&lt;&lt;1;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}\n\t(void)I2C1-&gt;SR2;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\n\tI2C1-&gt;DR=maddr;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\n\tI2C1-&gt;CR1|=I2C_CR1_START;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_SB)){;}\n\tI2C1-&gt;DR=saddr&lt;&lt;1|1;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}\n\tI2C1-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t(void)I2C1-&gt;SR2;\n\tI2C1-&gt;CR1|=I2C_CR1_STOP;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_RXNE)){;}\n\t*data++=I2C1-&gt;DR;\n\treturn 0;\n}\n\nvoid i2c_writeByte(char saddr,char maddr,char data)\n{\n\n\n\n\twhile(I2C1-&gt;SR2&amp;I2C_SR2_BUSY){;}          \/*wait until bus not busy*\/\n\tI2C1-&gt;CR1|=I2C_CR1_START;                 \/*generate start*\/\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_SB)){;}         \/*wait until start bit is set*\/\n\tI2C1-&gt;DR = saddr&lt;&lt; 1;                 \t \/* Send slave address*\/\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}      \/*wait until address flag is set*\/\n\t(void)I2C1-&gt;SR2; \t\t\t\t\t\t\t\t\t\t\t \/*clear SR2 by reading it *\/\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}       \/*Wait until Data register empty*\/\n\tI2C1-&gt;DR = maddr;                        \/* send memory address*\/\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}       \/*wait until data register empty*\/\n\tI2C1-&gt;DR = data;\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));      \/*wait until transfer finished*\/\n\tI2C1-&gt;CR1 |=I2C_CR1_STOP;\t\t\t\t\t\t\t\t \/*Generate Stop*\/\n\n}\n\nvoid i2c_WriteMulti(char saddr,char maddr,char *buffer, uint8_t length)\n{\n\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                   \/\/generate start\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t\t\t\t\t\/\/wait until start is generated\n\tI2C1-&gt;DR = saddr&lt;&lt; 1;                 \t \t\t\t\/\/ Send slave address\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\tI2C1-&gt;DR = maddr;                      \t\t\t\t\/\/ send memory address\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/wait until data register empty\n\t\/\/sending the data\n\tfor (uint8_t i=0;i&lt;length;i++)\n\t {\n\t I2C1-&gt;DR=buffer[i]; \t\t\t\t\t\t\t\t\t\t\t\t\t\/\/filling buffer with command or data\n\t\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));\n\t }\n\n\tI2C1-&gt;CR1 |= I2C_CR1_STOP;\t\t\t\t\t\t\t\t\t\t\/\/wait until transfer finished\n}\n\n\nvoid i2c_ReadMulti(char saddr,char maddr, int n, char* data)\n{\n\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY){;}\n\tI2C1-&gt;CR1|=I2C_CR1_START;\n\twhile(!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\n\tI2C1-&gt;DR=saddr&lt;&lt;1;\n\twhile(!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}\n\t(void)I2C1-&gt;SR2;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\n\tI2C1-&gt;DR = maddr;\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\n\tI2C1-&gt;CR1|=I2C_CR1_START;\n\twhile(!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\n\tI2C1-&gt;DR=saddr&lt;&lt;1|1;\n\twhile(!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}\n\t(void)I2C1-&gt;SR2;\n\tI2C1-&gt;CR1|=I2C_CR1_ACK;\n\twhile(n&gt;0U)\n\t\t{\n\t\tif(n==1U)\n\t\t\t\t{\n\t\t\t\tI2C1-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t\t\t\t\tI2C1-&gt;CR1|=I2C_CR1_STOP;\n\t\t\t\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_RXNE)){;}\n\t\t\t\t\t*data++=I2C1-&gt;DR;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t\t{\n\n\t\t\t\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_RXNE)){;}\n\t\t\t\t\t\t(*data++)=I2C1-&gt;DR;\n\t\t\t\t\t\t\tn--;\n\t\t\t\t}\n}\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next part, we shall configure the I2S and start generating the clocks and send some data over I2S bus.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide series, we shall cover the I2S peripheral of STM32F407 and its feature. In this guide, we shall covet the following: What is I2S. Feature of I2S of STM32F407. Feature of CS43L22. Environment Setup. Set the core speed to 168MHz. Delay funciton. I2C Peripheral initialization. 1. What is I2S: I\u00b2S&nbsp;(Inter-IC Sound), pronounced \u201ceye-squared-ess,\u201d [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-2553","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2553"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2553"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2553\/revisions"}],"predecessor-version":[{"id":2559,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2553\/revisions\/2559"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2553"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2553"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}