{"id":4550,"date":"2026-06-25T09:12:34","date_gmt":"2026-06-25T09:12:34","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4550"},"modified":"2026-06-25T09:12:42","modified_gmt":"2026-06-25T09:12:42","slug":"stm32f407-discovery-audio-i2s-dac","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4550","title":{"rendered":"STM32F407 Discovery Audio: I2S DAC"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"559\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-1024x559.png\" alt=\"\" class=\"wp-image-4551\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-1024x559.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-300x164.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-768x419.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-1150x627.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-750x409.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-400x218.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77-250x136.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/Gemini_Generated_Image_ef77asef77asef77.png 1408w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now that the basic DMA transmission pipeline is established, the final part of this guide focuses on interfacing the STM32F407 with the onboard CS43L22 audio DAC to produce real-world audio waveforms. By configuring the DAC via\u00a0$I^2C$\u00a0for control signaling and feeding it continuous audio samples via I2S, you will synthesize stable, audible signals like sine or sawtooth waves directly through the board&#8217;s 3.5mm audio jack.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Introduction.<\/li>\n\n\n\n<li>STM32CubeMX setup.<\/li>\n\n\n\n<li>Firmware Development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Introduction:<\/h2>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing the CS43L22 Audio DAC<\/h2>\n\n\n\n<p>The&nbsp;<strong>CS43L22<\/strong>&nbsp;is a highly integrated, low-power stereo audio DAC and headphone\/speaker amplifier designed by Cirrus Logic. On the STM32F407 Discovery board, this chip acts as the bridge between your raw digital software algorithms and the analog world, turning numbers into real-world sound waves accessible through the onboard 3.5mm blue audio jack.<\/p>\n\n\n\n<p>Equipped with a digital signal processing engine, an onboard multi-bit Delta-Sigma modulator, and a Class-D speaker driver alongside a stereo headphone amplifier, it manages complex digital-to-analog conversions efficiently while minimizing external component requirements.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Real-World Applications<\/h3>\n\n\n\n<p>Integrating an external I2S DAC with an STM32 processing core unlocks a wide variety of embedded audio applications:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Waveform &amp; Function Generators:<\/strong>\u00a0Synthesizing precise, adjustable analog signals (such as sine, square, sawtooth, or triangle waves) for laboratory testing, calibration tools, or musical synthesizers.<\/li>\n\n\n\n<li><strong>Embedded Audio Players:<\/strong>\u00a0Reading compressed or uncompressed audio files (like\u00a0<code>.wav<\/code>\u00a0or\u00a0<code>.mp3<\/code>) from an SD card or external flash memory and streaming them directly to a headset or speaker interface.<\/li>\n\n\n\n<li><strong>Voice Alerts &amp; Industrial Telemetry:<\/strong>\u00a0Adding high-quality spoken voice prompts, alarms, and status indicators to industrial equipment, smart home appliances, or medical devices.<\/li>\n\n\n\n<li><strong>Real-Time Digital Signal Processing (DSP):<\/strong>\u00a0Implementing real-time digital filtering, equalization, audio effects (such as reverb, delay, or pitch shifting), or mixing multiple independent audio channels into a single output stream.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. STM32CubeMX Setup:<\/h2>\n\n\n\n<p>Open the project .ioc file with STM32CubeMX.<\/p>\n\n\n\n<p>Next, we need to find which pins are connected to the I2C of the DAC. From the schematic of the board, we can find the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PB9 for SDA<\/li>\n\n\n\n<li>PB6 for SCL<\/li>\n<\/ul>\n\n\n\n<p>Also, take a note of the address mentioned which is needed later.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"488\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-1024x488.png\" alt=\"\" class=\"wp-image-4552\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-1024x488.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-300x143.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-768x366.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-1536x732.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-2048x976.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-1150x548.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-750x357.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-400x191.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-33-10-250x119.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, from STM32CubeMX, set PB6 and PB9 to I2C1 and enable I2C1 as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"718\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-1024x718.png\" alt=\"\" class=\"wp-image-4553\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-1024x718.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-300x210.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-768x538.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-1536x1077.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-2048x1436.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-1150x806.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-750x526.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-400x280.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-35-27-250x175.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Keep the parameters at the default values since we are only initialize the DAC once.<\/p>\n\n\n\n<p>Next, from I2S section, reduce the Audio frequency from 192 to 96KHz and generate the code as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"718\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-1024x718.png\" alt=\"\" class=\"wp-image-4555\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-1024x718.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-300x210.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-768x538.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-1536x1077.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-2048x1436.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-1150x806.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-750x526.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-400x280.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-25_11-37-24-1-250x175.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Thats all for the STM32CubeMX configuration.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Firmware Development:<\/h2>\n\n\n\n<p>Open the project in STM32CubeIDE.<\/p>\n\n\n\n<p>We start by creating new header and source file with name of CS43L22.h and CS43L22.c respectively.<\/p>\n\n\n\n<p>To create the source file:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"589\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-1024x589.png\" alt=\"\" class=\"wp-image-4556\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-1024x589.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-300x173.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-768x442.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-1536x884.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-2048x1179.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-1150x662.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-750x432.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-400x230.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-08-250x144.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, give it a name and click on Finish.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"734\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-1024x734.png\" alt=\"\" class=\"wp-image-4557\" style=\"width:840px;height:auto\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-1024x734.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-300x215.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-768x550.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-1150x824.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-750x538.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-400x287.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23-250x179.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-23.png 1172w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>To create the header file:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"589\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-1024x589.png\" alt=\"\" class=\"wp-image-4558\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-1024x589.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-300x173.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-768x442.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-1536x884.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-2048x1179.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-1150x662.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-750x432.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-400x230.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-37-250x144.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, give it a name and click on Finish.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"734\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-1024x734.png\" alt=\"\" class=\"wp-image-4560\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-1024x734.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-300x215.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-768x550.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-1150x824.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-750x538.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-400x287.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1-250x179.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/2026-06-20_10-38-50-1.png 1172w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Once the header and source files have been created, open the header.<\/p>\n\n\n\n<p>We start by including the following header files:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stdint.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare the address of the DAC:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define DAC_I2C_ADDR \t\t\t\t(0x94)<\/pre><\/div>\n\n\n\n<p>Next, define all the required registers addresses a<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define POWER_CONTROL1\t\t\t\t0x02\n#define POWER_CONTROL2\t\t\t\t0x04\n#define CLOCKING_CONTROL \t  \t\t0x05\n#define INTERFACE_CONTROL1\t\t\t0x06\n#define INTERFACE_CONTROL2\t\t\t0x07\n#define PASSTHROUGH_A\t\t\t\t0x08\n#define PASSTHROUGH_B\t\t\t\t0x09\n#define MISCELLANEOUS_CONTRLS\t\t0x0E\n#define PLAYBACK_CONTROL\t\t\t0x0F\n#define PASSTHROUGH_VOLUME_A\t\t0x14\n#define PASSTHROUGH_VOLUME_B\t\t0x15\n#define PCM_VOLUME_A\t\t\t\t0x1A\n#define PCM_VOLUME_B\t\t\t\t0x1B\n#define CONFIG_00\t\t\t\t\t0x00\n#define CONFIG_47\t\t\t\t\t0x47\n#define CONFIG_32\t\t\t\t\t0x32\n\n#define CS43L22_REG_MASTER_A_VOL    0x20\n#define CS43L22_REG_MASTER_B_VOL    0x21\n\n#define CS43_MUTE\t\t\t\t \t0x00\n\n#define CS43_RIGHT\t\t\t\t\t0x01\n#define CS43_LEFT\t\t\t\t \t0x02\n#define CS43_RIGHT_LEFT\t \t\t\t0x03\n\n#define VOLUME_CONVERT_A(Volume)    (((Volume) &gt; 100)? 255:((uint8_t)(((Volume) * 255) \/ 100)))\n#define VOLUME_CONVERT_D(Volume)    (((Volume) &gt; 100)? 24:((uint8_t)((((Volume) * 48) \/ 100) - 24)))<\/pre><\/div>\n\n\n\n<p>Next, declare an enumeration to hold the operation mode:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">typedef enum\n{\n\tCS43L22_MODE_I2S = 0,\n\tCS43L22_M\n}CS43_MODE;<\/pre><\/div>\n\n\n\n<p>Declare the following functions:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void CS43_Init(CS43_MODE outputMode);\nvoid CS43_Enable_RightLeft(uint8_t side);\nvoid CS43_SetVolume(uint8_t volume);\nvoid CS43_Start(void);\nvoid CS43_Stop(void);\nvoid CS43L22_RST_Pin_Low(void);\nvoid CS43L22_RST_Pin_High(void);<\/pre><\/div>\n\n\n\n<p>Hence, the header file as follows:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef INC_CS43L22_H_\n#define INC_CS43L22_H_\n\n\n#include &quot;stdint.h&quot;\n\n\n#define DAC_I2C_ADDR \t\t\t\t(0x94)\n\n#define POWER_CONTROL1\t\t\t\t0x02\n#define POWER_CONTROL2\t\t\t\t0x04\n#define CLOCKING_CONTROL \t  \t\t0x05\n#define INTERFACE_CONTROL1\t\t\t0x06\n#define INTERFACE_CONTROL2\t\t\t0x07\n#define PASSTHROUGH_A\t\t\t\t0x08\n#define PASSTHROUGH_B\t\t\t\t0x09\n#define MISCELLANEOUS_CONTRLS\t\t0x0E\n#define PLAYBACK_CONTROL\t\t\t0x0F\n#define PASSTHROUGH_VOLUME_A\t\t0x14\n#define PASSTHROUGH_VOLUME_B\t\t0x15\n#define PCM_VOLUME_A\t\t\t\t0x1A\n#define PCM_VOLUME_B\t\t\t\t0x1B\n#define CONFIG_00\t\t\t\t\t0x00\n#define CONFIG_47\t\t\t\t\t0x47\n#define CONFIG_32\t\t\t\t\t0x32\n\n#define CS43L22_REG_MASTER_A_VOL    0x20\n#define CS43L22_REG_MASTER_B_VOL    0x21\n\n#define CS43_MUTE\t\t\t\t \t0x00\n\n#define CS43_RIGHT\t\t\t\t\t0x01\n#define CS43_LEFT\t\t\t\t \t0x02\n#define CS43_RIGHT_LEFT\t \t\t\t0x03\n\n#define VOLUME_CONVERT_A(Volume)    (((Volume) &gt; 100)? 255:((uint8_t)(((Volume) * 255) \/ 100)))\n#define VOLUME_CONVERT_D(Volume)    (((Volume) &gt; 100)? 24:((uint8_t)((((Volume) * 48) \/ 100) - 24)))\n\ntypedef enum\n{\n\tCS43L22_MODE_I2S = 0,\n\tCS43L22_MODE_ANALOG,\n}CS43_MODE;\n\nvoid CS43_Init(CS43_MODE outputMode);\nvoid CS43_Enable_RightLeft(uint8_t side);\nvoid CS43_SetVolume(uint8_t volume);\nvoid CS43_Start(void);\nvoid CS43_Stop(void);\nvoid CS43L22_RST_Pin_Low(void);\nvoid CS43L22_RST_Pin_High(void);\n\n\n\n\n\n#endif \/* INC_CS43L22_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, open CS43L22.c  source file:<\/p>\n\n\n\n<p>Include the following header diles:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;CS43L22.h&quot;\n\n#include &quot;i2c.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare an array to hold the configuration data to be sent as follows:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static uint8_t iData[2];<\/pre><\/div>\n\n\n\n<p>Next, declare functions that will allow us to write\/read to\/from a register as follows:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ Function(1): Write to register\nstatic void write_register(uint8_t reg, uint8_t *data)\n{\n\tiData[0] = reg;\n\n\n\tHAL_I2C_Mem_Write(&amp;hi2c1, DAC_I2C_ADDR, reg, 1, data, 1, 10);\n\n\n\n}\n\/\/ Function(2): Read from register\nstatic void read_register(uint8_t reg, uint8_t *data)\n{\n\tuint8_t tempData=0;\n\n\tHAL_I2C_Mem_Read(&amp;hi2c1, DAC_I2C_ADDR, reg, 1, &amp;tempData, 1, 10);\n\n\t*data=tempData;\n}<\/pre><\/div>\n\n\n\n<p>Next, helper function to set the RST pin state:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void CS43L22_RST_Pin_Low(void)\n{\n\tHAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, RESET);\n}\n\nvoid CS43L22_RST_Pin_High(void)\n{\n\tHAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, SET);\n}<\/pre><\/div>\n\n\n\n<p>Next, the initialization sequence:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void CS43_Init(CS43_MODE outputMode)\n{\n\n\n\tCS43L22_RST_Pin_High();\n\n\t\/\/(2): Power down\n\tiData[1] = 0x01;\n\twrite_register(POWER_CONTROL1,iData);\n\n\t\/\/(3): Enable Right and Left headphones\n\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\tiData[1] |= (3 &lt;&lt; 2);  \/\/ PDN_SPKB[0:1] = 11 (Speaker B always off)\n\tiData[1] |= (3 &lt;&lt; 0);  \/\/ PDN_SPKA[0:1] = 11 (Speaker A always off)\n\twrite_register(POWER_CONTROL2,&amp;iData[1]);\n\n\t\/\/(4): Automatic clock detection\n\tiData[1] = (1 &lt;&lt; 7);\n\twrite_register(CLOCKING_CONTROL,&amp;iData[1]);\n\n\t\/\/(5): Interface control 1\n\tread_register(INTERFACE_CONTROL1, iData);\n\tiData[1] &amp;= (1 &lt;&lt; 5); \/\/ Clear all bits except bit 5 which is reserved\n\tiData[1] &amp;= ~(1 &lt;&lt; 7);  \/\/ Slave\n\tiData[1] &amp;= ~(1 &lt;&lt; 6);  \/\/ Clock polarity: Not inverted\n\tiData[1] &amp;= ~(1 &lt;&lt; 4);  \/\/ No DSP mode\n\tiData[1] &amp;= ~(1 &lt;&lt; 2);  \/\/ Left justified, up to 24 bit (default)\n\tiData[1] |= (1 &lt;&lt; 2);\n\tiData[1] |=  (3 &lt;&lt; 0);  \/\/ 16-bit audio word length for I2S interface\n\twrite_register(INTERFACE_CONTROL1,&amp;iData[1]);\n\n\n\t\/\/(6): Passthrough A settings\n\tread_register(PASSTHROUGH_A, &amp;iData[1]);\n\tiData[1] &amp;= 0xF0;      \/\/ Bits [4-7] are reserved\n\tiData[1] |=  (1 &lt;&lt; 0); \/\/ Use AIN1A as source for passthrough\n\twrite_register(PASSTHROUGH_A,&amp;iData[1]);\n\n\n\t\/\/(7): Passthrough B settings\n\tread_register(PASSTHROUGH_B, &amp;iData[1]);\n\tiData[1] &amp;= 0xF0;      \/\/ Bits [4-7] are reserved\n\tiData[1] |=  (1 &lt;&lt; 0); \/\/ Use AIN1B as source for passthrough\n\twrite_register(PASSTHROUGH_B,&amp;iData[1]);\n\n\n\t\/\/(8): Miscellaneous register settings\n\tread_register(MISCELLANEOUS_CONTRLS, &amp;iData[1]);\n\tif(outputMode == CS43L22_MODE_ANALOG)\n\t{\n\t\tiData[1] |=  (1 &lt;&lt; 7);   \/\/ Enable passthrough for AIN-A\n\t\tiData[1] |=  (1 &lt;&lt; 6);   \/\/ Enable passthrough for AIN-B\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 5);   \/\/ Unmute passthrough on AIN-A\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 4);   \/\/ Unmute passthrough on AIN-B\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 3);   \/\/ Changed settings take affect immediately\n\t}\n\telse if(outputMode == CS43L22_MODE_I2S)\n\t{\n\t\tiData[1] = 0x02;\n\t}\n\twrite_register(MISCELLANEOUS_CONTRLS,&amp;iData[1]);\n\t\/\/(9): Unmute headphone and speaker\n\n\tread_register(PLAYBACK_CONTROL, &amp;iData[1]);\n\tiData[1] = 0x00;\n\twrite_register(PLAYBACK_CONTROL,&amp;iData[1]);\n\n\t\/\/(10): Set volume to default (0dB)\n\tiData[1] = 0x00;\n\twrite_register(PASSTHROUGH_VOLUME_A,&amp;iData[1]);\n\twrite_register(PASSTHROUGH_VOLUME_B,&amp;iData[1]);\n\twrite_register(PCM_VOLUME_A,&amp;iData[1]);\n\twrite_register(PCM_VOLUME_B,&amp;iData[1]);\n}<\/pre><\/div>\n\n\n\n<p>Next, set the channel, either left, right or both:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ Function(2): Enable Right and Left headphones\nvoid CS43_Enable_RightLeft(uint8_t side)\n{\n\tswitch (side)\n\t{\n\t\tcase 0:\n\t\t\tiData[1] =  (3 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (3 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (3 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tiData[1] =  (3 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\tiData[1] |= (3 &lt;&lt; 2);  \/\/ PDN_SPKB[0:1] = 11 (Speaker B always off)\n\tiData[1] |= (3 &lt;&lt; 0);  \/\/ PDN_SPKA[0:1] = 11 (Speaker A always off)\n\twrite_register(POWER_CONTROL2,&amp;iData[1]);\n}<\/pre><\/div>\n\n\n\n<p>Set volume:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void CS43_SetVolume(uint8_t volume)\n{\n\tint8_t tempVol = volume - 50;\n\ttempVol = tempVol*(127\/50);\n\tuint8_t myVolume =  (uint8_t )tempVol;\n\tiData[1] = myVolume;\n\twrite_register(PASSTHROUGH_VOLUME_A,&amp;iData[1]);\n\twrite_register(PASSTHROUGH_VOLUME_B,&amp;iData[1]);\n\n\tiData[1] = VOLUME_CONVERT_D(volume);\n\n\t\/* Set the Master volume *\/\n\twrite_register(CS43L22_REG_MASTER_A_VOL,&amp;iData[1]);\n\twrite_register(CS43L22_REG_MASTER_B_VOL,&amp;iData[1]);\n}<\/pre><\/div>\n\n\n\n<p>Start and stop the DAC:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void CS43_Start(void)\n{\n\t\/\/ Write 0x99 to register 0x00.\n\tiData[1] = 0x99;\n\twrite_register(CONFIG_00,&amp;iData[1]);\n\t\/\/ Write 0x80 to register 0x47.\n\tiData[1] = 0x80;\n\twrite_register(CONFIG_47,&amp;iData[1]);\n\t\/\/ Write '1'b to bit 7 in register 0x32.\n\tread_register(CONFIG_32, &amp;iData[1]);\n\tiData[1] |= 0x80;\n\twrite_register(CONFIG_32,&amp;iData[1]);\n\t\/\/ Write '0'b to bit 7 in register 0x32.\n\tread_register(CONFIG_32, &amp;iData[1]);\n\tiData[1] &amp;= ~(0x80);\n\twrite_register(CONFIG_32,&amp;iData[1]);\n\t\/\/ Write 0x00 to register 0x00.\n\tiData[1] = 0x00;\n\twrite_register(CONFIG_00,&amp;iData[1]);\n\t\/\/Set the &quot;Power Ctl 1&quot; register (0x02) to 0x9E\n\tiData[1] = 0x9E;\n\twrite_register(POWER_CONTROL1,&amp;iData[1]);\n}\n\nvoid CS43_Stop(void)\n{\n\tiData[1] = 0x01;\n\twrite_register(POWER_CONTROL1,&amp;iData[1]);\n}<\/pre><\/div>\n\n\n\n<p>Hence, the entire source code as follows:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;CS43L22.h&quot;\n\n#include &quot;i2c.h&quot;\n\nstatic uint8_t iData[2];\n\n\n\/\/ Function(1): Write to register\nstatic void write_register(uint8_t reg, uint8_t *data)\n{\n\tiData[0] = reg;\n\n\n\tHAL_I2C_Mem_Write(&amp;hi2c1, DAC_I2C_ADDR, reg, 1, data, 1, 10);\n\n\n\n}\n\/\/ Function(2): Read from register\nstatic void read_register(uint8_t reg, uint8_t *data)\n{\n\tuint8_t tempData=0;\n\n\tHAL_I2C_Mem_Read(&amp;hi2c1, DAC_I2C_ADDR, reg, 1, &amp;tempData, 1, 10);\n\n\t*data=tempData;\n}\n\n\n\nvoid CS43L22_RST_Pin_Low(void)\n{\n\tHAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, RESET);\n}\n\nvoid CS43L22_RST_Pin_High(void)\n{\n\tHAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, SET);\n}\n\nvoid CS43_Init(CS43_MODE outputMode)\n{\n\n\n\tCS43L22_RST_Pin_High();\n\n\t\/\/(2): Power down\n\tiData[1] = 0x01;\n\twrite_register(POWER_CONTROL1,iData);\n\n\t\/\/(3): Enable Right and Left headphones\n\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\tiData[1] |= (3 &lt;&lt; 2);  \/\/ PDN_SPKB[0:1] = 11 (Speaker B always off)\n\tiData[1] |= (3 &lt;&lt; 0);  \/\/ PDN_SPKA[0:1] = 11 (Speaker A always off)\n\twrite_register(POWER_CONTROL2,&amp;iData[1]);\n\n\t\/\/(4): Automatic clock detection\n\tiData[1] = (1 &lt;&lt; 7);\n\twrite_register(CLOCKING_CONTROL,&amp;iData[1]);\n\n\t\/\/(5): Interface control 1\n\tread_register(INTERFACE_CONTROL1, iData);\n\tiData[1] &amp;= (1 &lt;&lt; 5); \/\/ Clear all bits except bit 5 which is reserved\n\tiData[1] &amp;= ~(1 &lt;&lt; 7);  \/\/ Slave\n\tiData[1] &amp;= ~(1 &lt;&lt; 6);  \/\/ Clock polarity: Not inverted\n\tiData[1] &amp;= ~(1 &lt;&lt; 4);  \/\/ No DSP mode\n\tiData[1] &amp;= ~(1 &lt;&lt; 2);  \/\/ Left justified, up to 24 bit (default)\n\tiData[1] |= (1 &lt;&lt; 2);\n\tiData[1] |=  (3 &lt;&lt; 0);  \/\/ 16-bit audio word length for I2S interface\n\twrite_register(INTERFACE_CONTROL1,&amp;iData[1]);\n\n\n\t\/\/(6): Passthrough A settings\n\tread_register(PASSTHROUGH_A, &amp;iData[1]);\n\tiData[1] &amp;= 0xF0;      \/\/ Bits [4-7] are reserved\n\tiData[1] |=  (1 &lt;&lt; 0); \/\/ Use AIN1A as source for passthrough\n\twrite_register(PASSTHROUGH_A,&amp;iData[1]);\n\n\n\t\/\/(7): Passthrough B settings\n\tread_register(PASSTHROUGH_B, &amp;iData[1]);\n\tiData[1] &amp;= 0xF0;      \/\/ Bits [4-7] are reserved\n\tiData[1] |=  (1 &lt;&lt; 0); \/\/ Use AIN1B as source for passthrough\n\twrite_register(PASSTHROUGH_B,&amp;iData[1]);\n\n\n\t\/\/(8): Miscellaneous register settings\n\tread_register(MISCELLANEOUS_CONTRLS, &amp;iData[1]);\n\tif(outputMode == CS43L22_MODE_ANALOG)\n\t{\n\t\tiData[1] |=  (1 &lt;&lt; 7);   \/\/ Enable passthrough for AIN-A\n\t\tiData[1] |=  (1 &lt;&lt; 6);   \/\/ Enable passthrough for AIN-B\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 5);   \/\/ Unmute passthrough on AIN-A\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 4);   \/\/ Unmute passthrough on AIN-B\n\t\tiData[1] &amp;= ~(1 &lt;&lt; 3);   \/\/ Changed settings take affect immediately\n\t}\n\telse if(outputMode == CS43L22_MODE_I2S)\n\t{\n\t\tiData[1] = 0x02;\n\t}\n\twrite_register(MISCELLANEOUS_CONTRLS,&amp;iData[1]);\n\t\/\/(9): Unmute headphone and speaker\n\n\tread_register(PLAYBACK_CONTROL, &amp;iData[1]);\n\tiData[1] = 0x00;\n\twrite_register(PLAYBACK_CONTROL,&amp;iData[1]);\n\n\t\/\/(10): Set volume to default (0dB)\n\tiData[1] = 0x00;\n\twrite_register(PASSTHROUGH_VOLUME_A,&amp;iData[1]);\n\twrite_register(PASSTHROUGH_VOLUME_B,&amp;iData[1]);\n\twrite_register(PCM_VOLUME_A,&amp;iData[1]);\n\twrite_register(PCM_VOLUME_B,&amp;iData[1]);\n}\n\n\/\/ Function(2): Enable Right and Left headphones\nvoid CS43_Enable_RightLeft(uint8_t side)\n{\n\tswitch (side)\n\t{\n\t\tcase 0:\n\t\t\tiData[1] =  (3 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (3 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (3 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tiData[1] =  (3 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tiData[1] =  (2 &lt;&lt; 6);  \/\/ PDN_HPB[0:1]  = 10 (HP-B always onCon)\n\t\t\tiData[1] |= (2 &lt;&lt; 4);  \/\/ PDN_HPA[0:1]  = 10 (HP-A always on)\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\tiData[1] |= (3 &lt;&lt; 2);  \/\/ PDN_SPKB[0:1] = 11 (Speaker B always off)\n\tiData[1] |= (3 &lt;&lt; 0);  \/\/ PDN_SPKA[0:1] = 11 (Speaker A always off)\n\twrite_register(POWER_CONTROL2,&amp;iData[1]);\n}\n\n\/\/ Function(3): Set Volume Level\nvoid CS43_SetVolume(uint8_t volume)\n{\n\tint8_t tempVol = volume - 50;\n\ttempVol = tempVol*(127\/50);\n\tuint8_t myVolume =  (uint8_t )tempVol;\n\tiData[1] = myVolume;\n\twrite_register(PASSTHROUGH_VOLUME_A,&amp;iData[1]);\n\twrite_register(PASSTHROUGH_VOLUME_B,&amp;iData[1]);\n\n\tiData[1] = VOLUME_CONVERT_D(volume);\n\n\t\/* Set the Master volume *\/\n\twrite_register(CS43L22_REG_MASTER_A_VOL,&amp;iData[1]);\n\twrite_register(CS43L22_REG_MASTER_B_VOL,&amp;iData[1]);\n}\n\n\/\/ Function(4): Start the Audio DAC\nvoid CS43_Start(void)\n{\n\t\/\/ Write 0x99 to register 0x00.\n\tiData[1] = 0x99;\n\twrite_register(CONFIG_00,&amp;iData[1]);\n\t\/\/ Write 0x80 to register 0x47.\n\tiData[1] = 0x80;\n\twrite_register(CONFIG_47,&amp;iData[1]);\n\t\/\/ Write '1'b to bit 7 in register 0x32.\n\tread_register(CONFIG_32, &amp;iData[1]);\n\tiData[1] |= 0x80;\n\twrite_register(CONFIG_32,&amp;iData[1]);\n\t\/\/ Write '0'b to bit 7 in register 0x32.\n\tread_register(CONFIG_32, &amp;iData[1]);\n\tiData[1] &amp;= ~(0x80);\n\twrite_register(CONFIG_32,&amp;iData[1]);\n\t\/\/ Write 0x00 to register 0x00.\n\tiData[1] = 0x00;\n\twrite_register(CONFIG_00,&amp;iData[1]);\n\t\/\/Set the &quot;Power Ctl 1&quot; register (0x02) to 0x9E\n\tiData[1] = 0x9E;\n\twrite_register(POWER_CONTROL1,&amp;iData[1]);\n}\n\nvoid CS43_Stop(void)\n{\n\tiData[1] = 0x01;\n\twrite_register(POWER_CONTROL1,&amp;iData[1]);\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, open main.c.<\/p>\n\n\n\n<p>In user include begin, include the following header files:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;math.h&quot;\n#include &quot;CS43L22.h&quot;<\/pre><\/div>\n\n\n\n<p>In user code begin PD:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define F_SAMPLE\t96000.0f\n#define F_OUT\t\t4000.0f\n#define PI \t\t\t3.14159f\n\n#define SAMPLES_PER_CYCLE\t(F_SAMPLE \/ F_OUT)  \/\/ 24.0\n#define NUM_CYCLES\t\t\t10\n#define BUFFER_SIZE\t\t\t((int)(SAMPLES_PER_CYCLE * NUM_CYCLES) * 2)  \/\/ *2 for stereo\n\nuint16_t dataI2S[BUFFER_SIZE];  \/\/ 480 elements for 10 cycles\n\nfloat phase_increment = 2.0f * PI \/ SAMPLES_PER_CYCLE;\nfloat current_phase = 0.0f;<\/pre><\/div>\n\n\n\n<p>In user code begin code 2 in main function:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Initialize the DAC in I2S mode.<\/li>\n\n\n\n<li>Set volume to maximum.<\/li>\n\n\n\n<li>Set both channel.<\/li>\n\n\n\n<li>Start the DAC.<\/li>\n<\/ul>\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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">CS43_Init(CS43L22_MODE_I2S);\nCS43_SetVolume(100);\nCS43_Enable_RightLeft(CS43_RIGHT_LEFT);\nCS43_Start();<\/pre><\/div>\n\n\n\n<p>Next, fill the array:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">float phase_increment = 2.0f * PI \/ SAMPLES_PER_CYCLE;\nfloat current_phase = 0.0f;\n\nfor(uint16_t i=0; i&lt;BUFFER_SIZE\/2; i++)  \/\/ 240 stereo pairs\n{\n  float mySinVal = sinf(current_phase);\n\n  \/\/ Scale to 16-bit signed range\n  int16_t right_value = (int16_t)(mySinVal * 32000.0f);\n  int16_t left_value = -right_value;  \/\/ Inverted signal\n\n  dataI2S[i*2] = right_value;      \/\/ Right channel\n  dataI2S[i*2 + 1] = left_value;   \/\/ Left channel (inverted)\n\n  current_phase += phase_increment;\n\n  \/\/ Keep phase in 0 to 2*PI range to prevent floating point drift\n  if(current_phase &gt;= 2.0f * PI) {\n    current_phase -= 2.0f * PI;\n  }\n}<\/pre><\/div>\n\n\n\n<p>Transfer the data over DMA:<\/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;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">HAL_I2S_Transmit_DMA(&amp;hi2s3, dataI2S, BUFFER_SIZE);<\/pre><\/div>\n\n\n\n<p>Thats all for the firmware.<\/p>\n\n\n\n<p>Save, build the project and run it as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"34\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1024x34.png\" alt=\"\" class=\"wp-image-4349\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1024x34.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-300x10.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-768x26.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1536x51.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1150x38.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-750x25.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-400x13.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-250x8.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1.png 1986w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>You may download the project from <a href=\"https:\/\/github.com\/hussamaldean\/Embedded-Expert-Post-Projects\/tree\/main\/Projects\/STM32_I2S_Polling\" data-type=\"link\" data-id=\"https:\/\/github.com\/hussamaldean\/Embedded-Expert-Post-Projects\/tree\/main\/Projects\/STM32_I2S_Polling\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>By probing both channels, you should get the following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14.png\" alt=\"\" class=\"wp-image-4561\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/06\/RigolDS14-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Note that we are generating saturated sinewave. <br>If you know the reason, let me know in the comments and I will update the guide.<\/p>\n\n\n\n<p>Next, we shall acquire sound data from the microphone.<\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Now that the basic DMA transmission pipeline is established, the final part of this guide focuses on interfacing the STM32F407 with the onboard CS43L22 audio DAC to produce real-world audio waveforms. By configuring the DAC via\u00a0$I^2C$\u00a0for control signaling and feeding it continuous audio samples via I2S, you will synthesize stable, audible signals like sine or [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4550","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4550"}],"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=4550"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4550\/revisions"}],"predecessor-version":[{"id":4562,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4550\/revisions\/4562"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4550"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4550"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4550"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}