This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1402156/tas2563-mcu-integration
器件型号:TAS2563工具与软件:
在获取在定制 ESP32-S3板上播放音频时遇到问题。 器件通过 I2C 和 I2S 的接线和通信均按预期工作、我认为通过各种寄存器进行器件配置时存在问题。
在另一个论坛博文中、我们提供了一些简单的 MCU 实现代码。
此代码具有一些编辑功能、但仍不能播放音频。 我尝试打开模块的音调发生器、但仍然没有声音。
要从扬声器简单扬声器进行单声道音频输出、最少需要哪些寄存器设置? I2S 数据在16bps 时的采样率为44100。
我也对这方面的解决方案感兴趣。
尊敬的 Halen:
您能否在播放尝试前后读取 IRQ 标志寄存器? 这是簿0页0上的寄存器0x24到0x27。
在器件运行期间停止输入时钟(SBCLK 和/或 FSYNC)会导致器件触发时钟错误检测并自动关闭、是否会在不播放音频时停止时钟? 如果确实如此、请确保在停止时钟之前将器件设置为 SW SHUTDOWN、并仅在时钟重新开启后将器件设置为 ACTIVE 模式。 软件关断和工作模式由寄存器0x02控制。
此致、
伊万·萨拉扎尔
应用工程师
我将尝试它。
IRQ 寄存器有几个标志。
PLL 锁定
器件上电
器件断电
尊敬的 Halen:
在尝试播放之前和之后是否相同?
这些特定的标志应该是可以的、这些只是通知标志、而不是错误标志。
还请根据我上一篇文章中提出的问题来评论时钟序列。
此致、
伊万·萨拉扎尔
应用工程师
这些 IRQ 标志在回放之前、期间和之后显示。
我设置的时钟时序应该是正确的。 这是我的设置代码和寄存器配置。
忽略下面的格式、这些是正在设置的页面和寄存器
尊敬的 Halen:
您写入到器件中的逻辑是什么? 您也使用任何头文件或二进制文件吗?
此致、
伊万·萨拉扎尔
应用工程师
不、我的程序要长得多。 这是设置代码中最有可能发生问题的重要部分。
这是我的完整 AmplifierController.cpp 代码。 要启动程序,请调用 amp_init ();然后调用 amp_play_wav ();
#include "AmplifierController.h" bool amp_init() { // I2S setup i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), .sample_rate = 44100, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = 0, // Default interrupt priority .dma_buf_count = 8, .dma_buf_len = 512, .use_apll = false, .tx_desc_auto_clear = true, // Auto clear if underflow .fixed_mclk = 0}; // I2S pin configuration i2s_pin_config_t pin_config = { .bck_io_num = I2S_BCLK, .ws_io_num = I2S_WORD, .data_out_num = I2S_SDO, .data_in_num = I2S_SDI}; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM_0, &pin_config); i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); // TAS2563 Setup tas2563_config_registers(TAS2563_LEFT_I2C_ADDRESS, 1); // power down reset tas2563_config_registers(TAS2563_LEFT_I2C_ADDRESS, 2); // program tas2563_config_registers(TAS2563_LEFT_I2C_ADDRESS, 3); // config tas2563_config_registers(TAS2563_LEFT_I2C_ADDRESS, 4); // power up tas2563_config_registers(TAS2563_LEFT_I2C_ADDRESS, 5); // unmute return true; } void amp_play_wav() { readRegister(TAS2563_TDM_DET); readRegister(TAS2563_TDM_CONFIG_REG0); readRegister(TAS2563_INT_LTCH0); readRegister(TAS2563_INT_LTCH1); readRegister(TAS2563_INT_LTCH2); readRegister(TAS2563_INT_LTCH3); // Open the .wav file File wavFile = SD.open("/Lord of the Rangs Short.wav"); if (!wavFile) { Serial.println("Failed to open file for reading"); return; } // Skip the WAV header (typically 44 bytes) wavFile.seek(44); // Buffer for reading WAV data byte buffer[512]; size_t bytes_written; int num = 0; while (wavFile.available()) { int bytesRead = wavFile.read(buffer, sizeof(buffer)); // Write the buffer to the I2S interface i2s_write(I2S_NUM_0, buffer, bytesRead, &bytes_written, portMAX_DELAY); if (num % 1000 == 0) { readRegister(TAS2563_TDM_DET); readRegister(TAS2563_TDM_CONFIG_REG0); readRegister(TAS2563_INT_LTCH0); readRegister(TAS2563_INT_LTCH1); readRegister(TAS2563_INT_LTCH2); readRegister(TAS2563_INT_LTCH3); } // Check if the bytes written match the bytes read from the file if (bytes_written != bytesRead) { Serial.println("I2S write error"); } num++; } wavFile.close(); Serial.println("Playback finished"); readRegister(TAS2563_TDM_DET); readRegister(TAS2563_TDM_CONFIG_REG0); } // Function to write to a TAS2563 register void writeRegister(uint8_t reg, uint8_t value) { Wire.beginTransmission(TAS2563_LEFT_I2C_ADDRESS); // Begin I2C communication with TAS2563 Wire.write(reg); // Send the register address Wire.write(value); // Send the data to write to the register Wire.endTransmission(); // End transmission // Optionally, print out the operation for debugging Serial.print("Wrote to reg 0x"); Serial.print(reg, HEX); Serial.print(": 0x"); Serial.println(value, HEX); } // Function to read from a TAS2563 register (for debugging) uint8_t readRegister(uint8_t reg) { Wire.beginTransmission(TAS2563_LEFT_I2C_ADDRESS); // Begin I2C communication with TAS2563 Wire.write(reg); // Send the register address Wire.endTransmission(false); // End transmission but keep the connection alive Wire.requestFrom(TAS2563_LEFT_I2C_ADDRESS, (uint8_t)1); // Request 1 byte of data from the register uint8_t value = Wire.read(); // Read the byte // Optionally, print out the operation for debugging Serial.print("Read from reg 0x"); Serial.print(reg, HEX); Serial.print(": 0x"); Serial.println(value, HEX); return value; } // I2C Transfer Function (Stub for actual I2C implementation) uint16 PltI2cTransfer(uint8 address, uint8 *tx, uint16 tx_len, uint8 *rx, uint16 rx_len) { Wire.beginTransmission(address >> 1); // Arduino Wire library uses 7-bit address Wire.write(tx, tx_len); Wire.endTransmission(); if (rx_len > 0) { uint8_t response = Wire.requestFrom(address >> 1, rx_len); for (int i = 0; i < rx_len && Wire.available(); i++) { rx[i] = Wire.read(); } } return I2C_TEST_PASSED; } uint16 tas2563_write_reg(uint8 SlaveAddr, uint8 *regValue, uint16 count) { SlaveAddr = (SlaveAddr << 1) | WRITE_I2C; Serial.println("Writing"); return PltI2cTransfer(SlaveAddr, regValue, count, 0, 0); } uint16 tas2563_read_reg(uint8 SlaveAddr, uint8 *regValue, uint16 count) { SlaveAddr = (SlaveAddr << 1) | READ_I2C; Serial.println("Reading"); return PltI2cTransfer(SlaveAddr, 0, 0, regValue, count); } void tas2563_transmit_registers(uint8 SlaveAddr, cfg_reg *r, int n) { int i = 0; while (i < n) { switch (r[i].command) { case CFG_META_SWITCH: // Used in legacy applications. Ignored here. break; case CFG_META_DELAY: delay(r[i].param); break; case CFG_META_BURST: tas2563_write_reg(SlaveAddr, (unsigned char *)&r[i + 1], r[i].param); i += (r[i].param / 2) + 1; break; default: tas2563_write_reg(SlaveAddr, (unsigned char *)&r[i], 1); break; } i++; } } void tas2563_config_registers(uint8 SlaveAddr, uint8 id) { if (id == 1) tas2563_transmit_registers(SlaveAddr, power_down_reset, power_down_reset_size); if (id == 2) tas2563_transmit_registers(SlaveAddr, program, program_size); if (id == 3) tas2563_transmit_registers(SlaveAddr, configuration, configuration_size); if (id == 4) tas2563_transmit_registers(SlaveAddr, powerup, powerup_size); if (id == 5) tas2563_transmit_registers(SlaveAddr, unmute, unmute_size); } void amp_loop() { // nothing }
更进一步的研究。 所有数据都正常、我认为它读取数据正常、因为不存在标志。 我认为这与电源有关。 如果我通过5V USB 线路为此芯片供电、正确的电源引脚配置是什么。 所有数据表和示例显示了连接到外部电池以便使用升压模式的 VBST 和 SW 引脚。 现在、我将这些引脚通过稳压器连接到3V3电源线。 IOVDD 通过稳压器连接到3V3稳压器、VDD 通过稳压器连接到1V8电源线。 这是我的原理图。 请注意、SDZ 引脚未连接、通过焊接连接来固定此引脚、以使芯片保持有效状态。 由于所有 I2C 通信都工作、因此该连接是有效的。
I2C 地址选择是一个简单的2x4引脚接头、可以按预期工作。 扬声器上的 OUT 线使用2x4引脚接头来选择各种铁氧体磁珠滤波器。
我已使用示波器查看 I2S 数据线、它们是否按预期工作。 芯片应正常接收 I2S 数据、这让我认为扬声器输出功率有问题。
尊敬的 Halen:
您是否也可以使用示波器检查输出引脚? 尝试播放音频时、您完全看到任何切换信号吗?
此致、
伊万·萨拉扎尔
应用工程师
没有信号。 线路保持低电平。
尊敬的 Halen:
在两天前的代码中、我注意到寄存器0x02在不同位置设置为0x00、包括加电和取消静音例程。 我希望该寄存器仅针对取消静音设置为0x00、并针对其余设置保持在软件关断状态。
我想知道器件如何无法输出任何内容、但仅触发这3个 IRQ 标志。 您是否在错误处理过程中执行了任何软件复位?
从原理图上看、我唯一关心的是 C16和 C21、它们似乎直接连接在 D 类的输出端 优先在电感/电阻串联元件之后连接任何容性负载。
此致、
伊万·萨拉扎尔
应用工程师
该问题非常奇怪、即使没有 SW 电感器电路、放大器也不会输出任何内容。 设置为0x00的寄存器两次是从我之前提到的示例 MCU 集成和设置代码收集的、更改时没有任何效果。
我对设置代码进行了一些小的更改、现在、IRQ 标志未触发。
对于这些电容器、我可以移除它们、因为它们只是在扬声器之前作为快速滤波器、这也是从示例 PCB 布局数据表中提取的。 我没有看到他们在那里是没有音频播放的原因。
下面有一个建议、如果 SDZ 引脚未激活芯片、它是否仍能响应 I2C 命令? 我的修复方法可能有问题、并且未正确保持芯片处于运行状态。 我想这是因为 I2C 命令仍然可以正常工作、但如果芯片可以在 SDZ 引脚悬空时使用 I2C、则可能是问题所在。
尊敬的 Halen:
我不希望 I2C 在 SDz 被下拉时做出响应、它实际上应该会复位器件寄存器。
不管怎样、我都会仔细检查一下、并在周一早上返回结果。
主机的数据输出连接到 TAS2563上的 SDIN 引脚、是否正确? SDOUT/SDIN 视图的命名有时会导致交换这些名称。
此致、
伊万·萨拉扎尔
应用工程师
谢谢你。 是的、我曾尝试切换 SDIN / SDOUT 引脚只是为了确定、现在仍然没有任何反应。
尊敬的 Halen:
我已经确认、只要下拉 SDz 引脚、器件就不会回复 I2C 事务。
是否可以使用工作台电源进行测试? 这应该有助于排除可能的电源问题。
此致、
伊万·萨拉扎尔
应用工程师
使用工作台电源可得到相同的结果。 当器件播放时、不会有额外的电流消耗。 我认为板载电源调节可能有故障。 现在正在处理。