[I2S][STM32] Can't get output from audio codec's DAC  - Page 1
Forum section: electronics / projects

author: gabrielgcma
author_rank: Newbie
timestamp: May 03, 2025, 10:45:10 pm
content: I am building a guitar pedal using the STM32H743 and currently I'm trying to transmit a fixed DC value to the output of the PCM3060 codec. The output jack goes to my audio interface.The problem is that the DAC_OUTPUT stays fixed on the 2.4V level as the datasheets states (analog output will be centered around 0.5*VCC), as if no signal is being read. I was expecting the signal level to be higher than 2.4V. I'm currently only hearing the raw guitar output.The digital signal is coming out of the I2S2_SDO pin correctly, as shown by the logic analyzer & plot. Schematics, configs and everything else is attached to the post.Code:Code:/* USER CODE BEGIN Header *//********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include "main.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include <math.h>/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD */#define SAMPLE_RATE 44100#define BUFFER_SIZE 512#define DAC_MAX 0x7FFFFF/* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/I2S_HandleTypeDef hi2s2;DMA_HandleTypeDef hdma_spi2_rx;DMA_HandleTypeDef hdma_spi2_tx;QSPI_HandleTypeDef hqspi;/* USER CODE BEGIN PV */int32_t buffer;/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);static void MPU_Config(void);static void MX_GPIO_Init(void);static void MX_DMA_Init(void);static void MX_I2S2_Init(void);static void MX_QUADSPI_Init(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 */void generate_test_tone(void) {for (int i = 0; i < BUFFER_SIZE; i++) {// PCM3060 expects 24 bit data aligned to the left inside a 32 bit wordbuffer = DAC_MAX << 8;}}/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MPU Configuration--------------------------------------------------------*/MPU_Config();/* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_I2S2_Init();MX_QUADSPI_Init();/* USER CODE BEGIN 2 */generate_test_tone();HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*) buffer, BUFFER_SIZE);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1) {/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}/*** @brief System Clock Configuration* @retval None*/void SystemClock_Config(void) {RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };/** Supply configuration update enable*/HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);/** Configure the main internal regulator output voltage*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 5;RCC_OscInitStruct.PLL.PLLN = 160;RCC_OscInitStruct.PLL.PLLP = 2;RCC_OscInitStruct.PLL.PLLQ = 4;RCC_OscInitStruct.PLL.PLLR = 2;RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;RCC_OscInitStruct.PLL.PLLFRACN = 0;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1| RCC_CLOCKTYPE_D1PCLK1;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {Error_Handler();}}/*** @brief I2S2 Initialization Function* @param None* @retval None*/static void MX_I2S2_Init(void) {/* USER CODE BEGIN I2S2_Init 0 *//* USER CODE END I2S2_Init 0 *//* USER CODE BEGIN I2S2_Init 1 *//* USER CODE END I2S2_Init 1 */hi2s2.Instance = SPI2;hi2s2.Init.Mode = I2S_MODE_MASTER_FULLDUPLEX;hi2s2.Init.Standard = I2S_STANDARD_PHILIPS;hi2s2.Init.DataFormat = I2S_DATAFORMAT_24B;hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;hi2s2.Init.CPOL = I2S_CPOL_LOW;hi2s2.Init.FirstBit = I2S_FIRSTBIT_MSB;hi2s2.Init.WSInversion = I2S_WS_INVERSION_DISABLE;hi2s2.Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_LEFT;hi2s2.Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE;if (HAL_I2S_Init(&hi2s2) != HAL_OK) {Error_Handler();}/* USER CODE BEGIN I2S2_Init 2 *//* USER CODE END I2S2_Init 2 */}/*** @brief QUADSPI Initialization Function* @param None* @retval None*/static void MX_QUADSPI_Init(void) {/* USER CODE BEGIN QUADSPI_Init 0 *//* USER CODE END QUADSPI_Init 0 *//* USER CODE BEGIN QUADSPI_Init 1 *//* USER CODE END QUADSPI_Init 1 *//* QUADSPI parameter configuration*/hqspi.Instance = QUADSPI;hqspi.Init.ClockPrescaler = 255;hqspi.Init.FifoThreshold = 1;hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;hqspi.Init.FlashSize = 1;hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;hqspi.Init.FlashID = QSPI_FLASH_ID_1;hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;if (HAL_QSPI_Init(&hqspi) != HAL_OK) {Error_Handler();}/* USER CODE BEGIN QUADSPI_Init 2 *//* USER CODE END QUADSPI_Init 2 */}/*** Enable DMA controller clock*/static void MX_DMA_Init(void) {/* DMA controller clock enable */__HAL_RCC_DMA1_CLK_ENABLE();/* DMA interrupt init *//* DMA1_Stream0_IRQn interrupt configuration */HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);/* DMA1_Stream1_IRQn interrupt configuration */HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);}/*** @brief GPIO Initialization Function* @param None* @retval None*/static void MX_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = { 0 };/* USER CODE BEGIN MX_GPIO_Init_1 *//* USER CODE END MX_GPIO_Init_1 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOB, LED_RED_Pin | LED_GREEN_Pin, GPIO_PIN_RESET);/*Configure GPIO pin : FSWITCH_Pin */GPIO_InitStruct.Pin = FSWITCH_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(FSWITCH_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins : LED_RED_Pin LED_GREEN_Pin */GPIO_InitStruct.Pin = LED_RED_Pin | LED_GREEN_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(FSWITCH_EXTI_IRQn, 0, 0);HAL_NVIC_EnableIRQ(FSWITCH_EXTI_IRQn);/* USER CODE BEGIN MX_GPIO_Init_2 *//* USER CODE END MX_GPIO_Init_2 */}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//* MPU Configuration */void MPU_Config(void) {MPU_Region_InitTypeDef MPU_InitStruct = { 0 };/* Disables the MPU */HAL_MPU_Disable();/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER0;MPU_InitStruct.BaseAddress = 0x0;MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;MPU_InitStruct.SubRegionDisable = 0x87;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Enables the MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);}/*** @brief This function is executed in case of error occurrence.* @retval None*/void Error_Handler(void) {/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1) {}/* USER CODE END Error_Handler_Debug */}#ifdef USE_FULL_ASSERT/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/void assert_failed(uint8_t *file, uint32_t line){/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */

author: moffy
author_rank: Super Contributor
timestamp: May 04, 2025, 04:47:42 am
content: Just some thoughts about the analogue:1. U7A has R3, which is just attenuating the signals, R2 and R5 could feed directly into the -ve input of U7A.2. DC_Bias is effectively the same as the Vcom pin 21, better to use Vcom as that is what the chip uses internally.3. The output of U7A should be AC coupled.Digital:1. It's easier to pick up an AC signal rather than a DC one, if you alternated your code to send 1 sample as 7FFFFF and the next sample as 000000 it might be easier to see.2. In HW mode for the PCM3060 does it default to synchronized?

author: pcprogrammer
author_rank: Super Contributor
timestamp: May 04, 2025, 07:24:24 am
content: Quote from: moffy on May 04, 2025, 04:47:42 amThe datasheet states that the default is "SCKI2, BCK2, LRCK2 enabled for DAC operation (default)" and "SCKI1, BCK1, LRCK1 enabled for ADC operation (default)", so asynchronous operation, which means that both the ADC and the DAC clock signals should be connected.https://www.ti.com/lit/ds/symlink/pcm3060.pdf?ts=1746302169092&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FPCM3060See pages 15, 33 and 37 for more information on this.It can't be stated enough: READ THE FUCKING MANUAL!Almost everything can be solved by doing so.

author: gabrielgcma
author_rank: Newbie
timestamp: May 18, 2025, 05:45:54 am
content: Quote from: pcprogrammer on May 04, 2025, 07:24:24 amThanks, that was really it, I fed the same clock to the DAC and it started working.Quote from: moffy on May 04, 2025, 04:47:42 amThanks for the analog tips! If I remove R3, how can I keep the lowpass filter on U7A?

author: moffy
author_rank: Super Contributor
timestamp: May 18, 2025, 07:43:35 am
content: Quote from: gabrielgcma on May 18, 2025, 05:45:54 amLet me first compliment you on your gracious response, and I am glad that your problem has been solved.The low pass filter is set by R6 in parrallel with C7, all you are affecting by removing R3 is the overall gain, not the frequency response.