一、TLV320AIC3204录音测试
/**
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "ns_sdk_hal.h"
#include "psram_cfg_x16.h"
#define I2C0_SPEED (400000)
// Define page size, extended to 2K for X16 1K bank wrap issue test
#define PAGESIZE 2048
#define TLV320AIC3204_ADDRESS (0x18)
#define SAI0_S0_BASE_A SAI0_S0_CFG_A_BASE
#define SAI0_S0_BASE_B SAI0_S0_CFG_B_BASE
#define ARR_SIZE_B (160)
#define ARR_SIZE_A 2*(2*16000*2)
#define FIFO_RDAT 0x14
volatile uint16_t *SAI0_S0_A_Send_buffer = (volatile uint16_t *)0x88000000;
volatile uint16_t *SAI0_S0_B_Receive_buffer = (volatile uint16_t *)0x89000000;
uint8_t state0 = 0;
//#define CONTINUOS_MODE 1
void UDMA0_IRQHandler(void)
{
static int count = 0;
static int hcount = 0;
if (UDMA_PA2M_GetITStatus(SAI0_SAI_0_B_RX_DMA_DMA_IRQ, PA2M_HTRANS_IRQ_STAT) == SET) {
UDMA_PA2M_ClearITStatus(SAI0_SAI_0_B_RX_DMA_DMA_IRQ, PA2M_HTRANS_IRQ_CLEAR_STAT);
hcount++;
}
if (UDMA_PA2M_GetITStatus(SAI0_SAI_0_B_RX_DMA_DMA_IRQ, PA2M_FTRANS_IRQ_STAT) == SET) {
UDMA_PA2M_ClearITStatus(SAI0_SAI_0_B_RX_DMA_DMA_IRQ, PA2M_FTRANS_IRQ_CLEAR_STAT);
if (count > ARR_SIZE_A/ARR_SIZE_B) {
UDMA_Cmd(SAI0_SAI_0_B_RX_DMA_DMA_CH, DISABLE);
state0 = 1;
printf("fint = %d\r\n", count);
printf("hint = %d\r\n", hcount);
}
else {
memcpy((uint16_t *)&(SAI0_S0_A_Send_buffer[count*ARR_SIZE_B]), (uint16_t *)SAI0_S0_B_Receive_buffer, ARR_SIZE_B*2);
UDMA_Cmd(SAI0_SAI_0_B_RX_DMA_DMA_CH, ENABLE);
}
count++;
}
if (UDMA_PA2M_GetITStatus(SAI0_SAI_0_A_TX_DMA_DMA_IRQ, PA2M_FTRANS_IRQ_STAT) == SET) {
state0 = 2;
UDMA_Cmd(SAI0_SAI_0_A_TX_DMA_DMA_CH, DISABLE);
SAI_Config(SAI0_S0_CFG_A,DISABLE);
SAI_Config(SAI0_S0_CFG_B,DISABLE);
printf("playback int\r\n");
UDMA_PA2M_ClearITStatus(SAI0_SAI_0_A_TX_DMA_DMA_IRQ, PA2M_FTRANS_IRQ_CLEAR_STAT);
}
}
/**
* @brief Test PSRAM by writing and reading data.
*
* @param argc Number of command - line arguments.
* @param argv Array of command - line arguments.
*/
void psram_test()
{
uint8_t *write = malloc(PAGESIZE);
if (write == NULL) {
printf("out of memory\n");
return;
}
uint8_t *read = malloc(PAGESIZE);
if (read == NULL) {
free(read);
printf("out of memory\n");
return;
}
uint16_t value = 0;
bool isX16 = false;
printf("Reg dump:\n");
// Disable XIP mode
PSRAM_XIP_Disable();
for (int i = 0; i < 9; i++) {
SPI_Psram_RegRead(i, (uint8_t *)&value);
printf("MR[%d %d] = %02x, %02x\n", i, i + 1, value & 0xff, (value >> 8) & 0xff);
}
if ((value & (0x01 << 6)) != 0) {
isX16 = true;
}
// Enable XIP mode
PSRAM_XIP_Enable();
// Write & Read test
for (int i = 0; i < PAGESIZE; i++) {
write[i] = (i / 256) + (i & 0xff) ;
}
memset(read, 0x00, PAGESIZE);
memcpy((void*)QSPI_XIP1_MEM_BASE, write, PAGESIZE);
memcpy(read, (void*)QSPI_XIP1_MEM_BASE, PAGESIZE);
if (0 == memcmp(write, read, PAGESIZE)) {
printf("%d line XIP W/R test pass\n", isX16 ? 16 : 8);
} else {
printf("%d line XIP data cmp failed\n", isX16 ? 16 : 8);
printf("data dump:\n");
for(int i = 0; i < PAGESIZE; i++) {
if (i % 16 == 0)
printf("\n%p: ", &read[i]);
printf("%02x ", read[i]);
}
printf("\n");
}
free(write);
free(read);
}
/**
* \brief cofigure the I2C1 interfaces
*/
void I2C_Config(void)
{
I2C_InitTypeDef init = {0};
init.duty = I2C_50_DUTY;
init.clk = I2C0_SPEED;
init.mode = I2C_MASTER_MODE;
init.scl_pull = ENABLE;
init.sda_pull = ENABLE;
I2C_Init(I2C0, &init);
}
void tlv320aic_select_page(uint8_t page_num)
{
uint32_t timeout = 0xFFFFFFFF;
I2C_ACK(I2C0, DISABLE);
I2C_Start(I2C0);
I2C_Send_SlaveAddr(I2C0, TLV320AIC3204_ADDRESS, I2C_DIR_WRITE, timeout);
/* wait until I2C recv ack */
while (!I2C_Get_Status(I2C0, I2C_STATUS_ADDR_ACK)) {}
I2C_Clear_Status(I2C0, I2C_STATUS_ADDR_ACK);
I2C_Write(I2C0, 0x00, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Write(I2C0, page_num, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Stop(I2C0);
}
void tlv320aic_reset()
{
uint32_t timeout = 0xFFFFFFFF;
I2C_ACK(I2C0, DISABLE);
I2C_Start(I2C0);
I2C_Send_SlaveAddr(I2C0, TLV320AIC3204_ADDRESS, I2C_DIR_WRITE, timeout);
/* wait until I2C recv ack */
while (!I2C_Get_Status(I2C0, I2C_STATUS_ADDR_ACK)) {}
I2C_Clear_Status(I2C0, I2C_STATUS_ADDR_ACK);
I2C_Write(I2C0, 0x01, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Write(I2C0, 0x01, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Stop(I2C0);
}
void tlv320aic_write_reg(uint8_t reg, uint8_t val)
{
uint32_t timeout = 0xFFFFFFFF;
I2C_ACK(I2C0, DISABLE);
I2C_Start(I2C0);
I2C_Send_SlaveAddr(I2C0, TLV320AIC3204_ADDRESS, I2C_DIR_WRITE, timeout);
/* wait until I2C recv ack */
while (!I2C_Get_Status(I2C0, I2C_STATUS_ADDR_ACK)) {}
I2C_Clear_Status(I2C0, I2C_STATUS_ADDR_ACK);
I2C_Write(I2C0, reg, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Write(I2C0, val, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Stop(I2C0);
}
void tlv320aic_read_reg(uint8_t reg, uint8_t *dat)
{
uint8_t temp = 0;
uint32_t timeout = 0xFFFFFFFF;
I2C_ACK(I2C0, DISABLE);
I2C_Start(I2C0);
I2C_Send_SlaveAddr(I2C0, TLV320AIC3204_ADDRESS, I2C_DIR_WRITE, timeout);
/* wait until I2C recv ack */
while (!I2C_Get_Status(I2C0, I2C_STATUS_ADDR_ACK)) {}
I2C_Clear_Status(I2C0, I2C_STATUS_ADDR_ACK);
I2C_Write(I2C0, reg, timeout);
/* wait until I2C recv ack */
while (I2C_Get_Status(I2C0, I2C_STATUS_ACK)) {}
I2C_Restart(I2C0);
I2C_Send_SlaveAddr(I2C0, TLV320AIC3204_ADDRESS, I2C_DIR_READ, timeout);
/* wait until I2C recv ack */
while (!I2C_Get_Status(I2C0, I2C_STATUS_ADDR_ACK)) {}
I2C_Clear_Status(I2C0, I2C_STATUS_ADDR_ACK);
I2C_ACK(I2C0, ENABLE);
I2C_ACK(I2C0, DISABLE);
I2C_Read(I2C0, dat, timeout);
I2C_Stop(I2C0);
}
#if 0
void init_recording()
{
// ========== 切换到 Page 0 ==========
tlv320aic_select_page(0);
tlv320aic_reset();
delay_1ms(10);
// ========== 时钟配置 (无 PLL,CODEC_CLKIN = MCLK = 8.192 MHz) ==========
tlv320aic_write_reg(0x04, 0x00); // CODEC_CLKIN = MCLK, PLL输入 = MCLK
tlv320aic_write_reg(0x05, 0x00); // PLL 关闭
// 采样率 16 kHz 配置:fs = MCLK / (NADC × MADC × AOSR)
// 8,192,000 / (1 × 2 × 256) = 16,000 Hz
tlv320aic_write_reg(0x12, 0x81); // NADC = 1, 使能
tlv320aic_write_reg(0x13, 0x82); // MADC = 2, 使能
tlv320aic_write_reg(0x14, 0x80); // AOSR = 256 (0x00代表256,提供更好的SNR)
// ========== 音频接口配置 (I²S 从机,16 位) ==========
tlv320aic_write_reg(0x1B, 0x00); // I²S 格式,16 位,BCLK/WCLK 从机
tlv320aic_write_reg(0x1C, 0x00); // 数据偏移 = 0
tlv320aic_write_reg(0x27, 0x00); // 数据路径设置
// ========== ADC 配置 ==========
tlv320aic_write_reg(0x3D, 0x01); // PRB_R1 处理块
// ========== 切换到 Page 1(模拟控制) ==========
tlv320aic_select_page(1);
// 电源和参考配置
tlv320aic_write_reg(0x01, 0x08); // 使能主模拟电源
tlv320aic_write_reg(0x02, 0x01); // 参考快速充电
tlv320aic_write_reg(0x7B, 0x01); // 使能参考充电
delay_1ms(100); // 等待参考电压稳定(至少40ms)
// MICBIAS 配置 (2.5V for WMM7027ATSN1)
tlv320aic_write_reg(0x33, 0x60); // MICBIAS 使能,2.5V (bit[6]=1, bit[5:4]=10)
// ========== 模拟输入路由(差分:IN2_L/IN2_R 到左 PGA,IN1_R/IN1_L 到右 PGA) ==========
// 左声道
tlv320aic_write_reg(0x34, 0x10); // 左正:IN2_L 10 kΩ
tlv320aic_write_reg(0x36, 0x10); // 左负:IN2_R 10 kΩ (实现差分)
// 右声道
tlv320aic_write_reg(0x37, 0x40); // 右正:IN1_R 10 kΩ
tlv320aic_write_reg(0x39, 0x40); // 右负:IN1_L 10 kΩ (实现差分)
// ========== MicPGA 增益配置 ==========
// MEMS麦克风通常需要一定增益,建议从20dB开始测试
tlv320aic_write_reg(0x3B, 0x28); // 左 PGA 增益 = 20 dB (0x28 = 40, 每步0.5dB)
tlv320aic_write_reg(0x3C, 0x28); // 右 PGA 增益 = 20 dB
// 使能 MicPGA
tlv320aic_write_reg(0x47, 0x32); // MicPGA 启动延时 3.1 ms
tlv320aic_write_reg(0x01, 0x0A); // 使能左右 MicPGA (bit[1]=1左,bit[3]=1右)
delay_1ms(10); // 等待启动
// ========== 切换回 Page 0 ==========
tlv320aic_select_page(0);
// ========== 使能和解除静音 ADC ==========
tlv320aic_write_reg(0x51, 0xC0); // 上电左右 ADC (bit[7]=1左,bit[6]=1右)
tlv320aic_write_reg(0x52, 0x00); // 解除 ADC 静音
// 设置 ADC 音量 (0dB = 0x00, 范围-12dB到20dB)
tlv320aic_write_reg(0x53, 0x00); // 左 ADC 音量 0 dB
tlv320aic_write_reg(0x54, 0x00); // 右 ADC 音量 0 dB
delay_1ms(10); // 等待ADC稳定
}
#endif
#if 0//LR OK有底噪电流声
void init_recording()
{
// ========== 切换到 Page 0 ==========
tlv320aic_select_page(0);
tlv320aic_reset();
delay_1ms(10);
// ========== 时钟配置 (无 PLL,CODEC_CLKIN = MCLK = 8.192 MHz) ==========
tlv320aic_write_reg(0x04, 0x00); // CODEC_CLKIN = MCLK, PLL输入 = MCLK
tlv320aic_write_reg(0x05, 0x00); // PLL 关闭
// 采样率 16 kHz 配置:fs = MCLK / (NADC × MADC × AOSR)
// 8,192,000 / (1 × 2 × 256) = 16,000 Hz
tlv320aic_write_reg(0x12, 0x81); // NADC = 1, 使能
tlv320aic_write_reg(0x13, 0x82); // MADC = 2, 使能
tlv320aic_write_reg(0x14, 0x80); // AOSR = 256 (0x00代表256,提供更好的SNR)
// ========== 音频接口配置 (I²S 从机,16 位) ==========
tlv320aic_write_reg(0x1B, 0x00); // I²S 格式,16 位,BCLK/WCLK 从机
tlv320aic_write_reg(0x1C, 0x00); // 数据偏移 = 0
tlv320aic_write_reg(0x27, 0x00); // 数据路径设置
// ========== ADC 配置 ==========
tlv320aic_write_reg(0x3D, 0x01); // PRB_R1 处理块
// ========== 切换到 Page 1(模拟控制) ==========
tlv320aic_select_page(1);
// 电源和参考配置
tlv320aic_write_reg(0x01, 0x08); // 使能主模拟电源
tlv320aic_write_reg(0x02, 0x01); // 参考快速充电
tlv320aic_write_reg(0x7B, 0x01); // 使能参考充电
delay_1ms(100); // 等待参考电压稳定(至少40ms)
// MICBIAS 配置 (2.5V for WMM7027ATSN1)
tlv320aic_write_reg(0x33, 0x60); // MICBIAS 使能,2.5V (bit[6]=1, bit[5:4]=10)
// ========== 模拟输入路由(差分:IN2_L/IN2_R 到左 PGA,IN1_R/IN1_L 到右 PGA) ==========
// 左声道
tlv320aic_write_reg(0x34, 0x10); // 左正:IN2_L 10 kΩ
tlv320aic_write_reg(0x36, 0x10); // 左负:IN2_R 10 kΩ (实现差分)
// 右声道
tlv320aic_write_reg(0x37, 0x10); // 右正:IN1_R 10 kΩ
tlv320aic_write_reg(0x39, 0x10); // 右负:IN1_L 10 kΩ (实现差分)
// ========== MicPGA 增益配置 ==========
// MEMS麦克风通常需要一定增益,建议从20dB开始测试
tlv320aic_write_reg(0x3B, 0x10); // 左 PGA 增益 = 20 dB (0x28 = 40, 每步0.5dB)
tlv320aic_write_reg(0x3C, 0x10); // 右 PGA 增益 = 20 dB
// 使能 MicPGA
tlv320aic_write_reg(0x47, 0x32); // MicPGA 启动延时 3.1 ms
tlv320aic_write_reg(0x01, 0x0A); // 使能左右 MicPGA (bit[1]=1左,bit[3]=1右)
delay_1ms(10); // 等待启动
// ========== 切换回 Page 0 ==========
tlv320aic_select_page(0);
// ========== 使能和解除静音 ADC ==========
tlv320aic_write_reg(0x51, 0xC0); // 上电左右 ADC (bit[7]=1左,bit[6]=1右)
tlv320aic_write_reg(0x52, 0x00); // 解除 ADC 静音
// 设置 ADC 音量 (0dB = 0x00, 范围-12dB到20dB)
tlv320aic_write_reg(0x53, 0x00); // 左 ADC 音量 0 dB
tlv320aic_write_reg(0x54, 0x00); // 右 ADC 音量 0 dB
delay_1ms(10); // 等待ADC稳定
}
#endif
//LR OK
void init_recording()
{
// ========== 切换到 Page 0 ==========
tlv320aic_select_page(0);
tlv320aic_reset();
delay_1ms(10);
// ========== 时钟配置 (无 PLL,CODEC_CLKIN = MCLK = 8.192 MHz) ==========
tlv320aic_write_reg(0x04, 0x00); // CODEC_CLKIN = MCLK, PLL输入 = MCLK
tlv320aic_write_reg(0x05, 0x00); // PLL 关闭
// 采样率 16 kHz 配置:fs = MCLK / (NADC × MADC × AOSR)
// 8,192,000 / (1 × 2 × 256) = 16,000 Hz
tlv320aic_write_reg(0x12, 0x81); // NADC = 1, 使能
tlv320aic_write_reg(0x13, 0x82); // MADC = 2, 使能
tlv320aic_write_reg(0x14, 0x80); // AOSR = 256 (0x00代表256,提供更好的SNR)
// ========== 音频接口配置 (I²S 从机,16 位) ==========
tlv320aic_write_reg(0x1B, 0x00); // I²S 格式,16 位,BCLK/WCLK 从机
tlv320aic_write_reg(0x1C, 0x00); // 数据偏移 = 0
tlv320aic_write_reg(0x27, 0x00); // 数据路径设置
// ========== ADC 配置 ==========
tlv320aic_write_reg(0x3D, 0x01); // PRB_R1 处理块
// ========== 切换到 Page 1(模拟控制) ==========
tlv320aic_select_page(1);
// 电源和参考配置
tlv320aic_write_reg(0x01, 0x08); // 使能主模拟电源
tlv320aic_write_reg(0x02, 0x01); // 参考快速充电
tlv320aic_write_reg(0x7B, 0x01); // 使能参考充电
delay_1ms(100); // 等待参考电压稳定(至少40ms)
// MICBIAS 配置 (2.5V for WMM7027ATSN1)
tlv320aic_write_reg(0x33, 0x60); // MICBIAS 使能,2.5V (bit[6]=1, bit[5:4]=10)
// ========== 模拟输入路由(差分:IN2_L/IN2_R 到左 PGA,IN1_R/IN1_L 到右 PGA) ==========
// 左声道
tlv320aic_write_reg(0x34, 0x10); // 左正:IN2_L 10 kΩ
tlv320aic_write_reg(0x36, 0x10); // 左负:IN2_R 10 kΩ (实现差分)
// 右声道
tlv320aic_write_reg(0x37, 0x10); // 右正:IN1_R 10 kΩ
tlv320aic_write_reg(0x39, 0x10); // 右负:IN1_L 10 kΩ (实现差分)
// ========== MicPGA 增益配置 ==========
// MEMS麦克风通常需要一定增益,建议从20dB开始测试
tlv320aic_write_reg(0x3B, 0x8); // 左 PGA 增益 = 20 dB (0x28 = 40, 每步0.5dB)
tlv320aic_write_reg(0x3C, 0x8); // 右 PGA 增益 = 20 dB
// 使能 MicPGA
tlv320aic_write_reg(0x47, 0x32); // MicPGA 启动延时 3.1 ms
tlv320aic_write_reg(0x01, 0x0A); // 使能左右 MicPGA (bit[1]=1左,bit[3]=1右)
delay_1ms(10); // 等待启动
// ========== 切换回 Page 0 ==========
tlv320aic_select_page(0);
// ========== 使能和解除静音 ADC ==========
tlv320aic_write_reg(0x51, 0xC0); // 上电左右 ADC (bit[7]=1左,bit[6]=1右)
tlv320aic_write_reg(0x52, 0x00); // 解除 ADC 静音
// 设置 ADC 音量 (0dB = 0x00, 范围-12dB到20dB)
tlv320aic_write_reg(0x53, 0x00); // 左 ADC 音量 0 dB
tlv320aic_write_reg(0x54, 0x00); // 右 ADC 音量 0 dB
tlv320aic_write_reg(0x55, 0x04); // 使能ADC自动静音检测和信号处理
delay_1ms(10); // 等待ADC稳定
}
// 1. 读取并显示所有关键寄存器
void dump_tlv320_registers(void)
{
uint8_t val;
printf("\n========== TLV320AIC3204 寄存器转储 ==========\n");
// Page 0 - 数字控制
tlv320aic_select_page(0);
printf("\n[Page 0 - 数字控制]\n");
tlv320aic_read_reg(0x01, &val);
printf("0x01 (复位): 0x%02X\n", val);
tlv320aic_read_reg(0x04, &val);
printf("0x04 (时钟源): 0x%02X (期望 0x00 = MCLK)\n", val);
tlv320aic_read_reg(0x05, &val);
printf("0x05 (PLL): 0x%02X (期望 0x00 = 禁用)\n", val);
tlv320aic_read_reg(0x12, &val);
printf("0x12 (NADC): 0x%02X (期望 0x81)\n", val);
tlv320aic_read_reg(0x13, &val);
printf("0x13 (MADC): 0x%02X (期望 0x82)\n", val);
tlv320aic_read_reg(0x14, &val);
printf("0x14 (AOSR): 0x%02X (期望 0x00=256 或 0x80=128)\n", val);
tlv320aic_read_reg(0x1B, &val);
printf("0x1B (接口): 0x%02X (期望 0x00 = I²S, 16bit, Slave)\n", val);
tlv320aic_read_reg(0x3D, &val);
printf("0x3D (PRB): 0x%02X (期望 0x01)\n", val);
tlv320aic_read_reg(0x51, &val);
printf("0x51 (ADC使能): 0x%02X (期望 0xC0) ", val);
if (val == 0xC0) printf("✓\n"); else printf("❌\n");
tlv320aic_read_reg(0x52, &val);
printf("0x52 (ADC静音): 0x%02X (期望 0x00) ", val);
if (val == 0x00) printf("✓\n"); else printf("❌\n");
tlv320aic_read_reg(0x53, &val);
printf("0x53 (左ADC音量): 0x%02X\n", val);
tlv320aic_read_reg(0x54, &val);
printf("0x54 (右ADC音量): 0x%02X\n", val);
// Page 1 - 模拟控制
tlv320aic_select_page(1);
printf("\n[Page 1 - 模拟控制]\n");
tlv320aic_read_reg(0x01, &val);
printf("0x01 (电源): 0x%02X (期望 0x0A = PGA使能) ", val);
if (val == 0x0A) printf("✓\n"); else printf("❌\n");
tlv320aic_read_reg(0x33, &val);
printf("0x33 (MICBIAS): 0x%02X (期望 0x60 = 2.5V) ", val);
if (val == 0x60) printf("✓\n"); else printf("❌\n");
tlv320aic_read_reg(0x34, &val);
printf("0x34 (左+路由): 0x%02X (期望 0x10 = IN2_L)\n", val);
tlv320aic_read_reg(0x36, &val);
printf("0x36 (左-路由): 0x%02X (期望 0x10 = IN2_R)\n", val);
tlv320aic_read_reg(0x37, &val);
printf("0x37 (右+路由): 0x%02X (期望 0x40 = IN1_R)\n", val);
tlv320aic_read_reg(0x39, &val);
printf("0x39 (右-路由): 0x%02X (期望 0x40 = IN1_L)\n", val);
tlv320aic_read_reg(0x3B, &val);
printf("0x3B (左PGA增益): 0x%02X (每0.5dB = %d.%d dB)\n",
val, val/2, (val%2)*5);
tlv320aic_read_reg(0x3C, &val);
printf("0x3C (右PGA增益): 0x%02X (每0.5dB = %d.%d dB)\n",
val, val/2, (val%2)*5);
tlv320aic_select_page(0);
printf("========================================\n\n");
}
void tlv320aic_init_recording_16k(void)
{
// 1. 切换到 Page 0 (控制寄存器)
tlv320aic_select_page(0);
tlv320aic_reset();
delay_1ms(10); // 等待复位完成
// ---------------------------------------------------------
// 2. 时钟配置 (关键修改:使用 BCLK 作为 PLL 源)
// 目标: fs = 16kHz, AOSR = 128 (高质量)
// BCLK = 512kHz -> PLL -> ADC_MOD_CLK = 2.048MHz
// ---------------------------------------------------------
// P0_R4: 时钟源选择
// bit 1-0 = 01 (PLL_CLKIN = BCLK, range 512k-20M)
// bit 3-2 = 01 (CODEC_CLKIN = PLL_CLK)
tlv320aic_write_reg(0x04, 0x05);
// P0_R5: PLL 设置 P & R
// PLL Power Up (bit 7=1), P=1 (bit 6-4=001), R=4 (bit 3-0=0100)
// PLL_IN = 512k * 4 = 2.048MHz
tlv320aic_write_reg(0x05, 0x94);
// P0_R6: PLL 设置 J
// J=40 (0x28). VCO = 2.048M * 40 = 81.92MHz
tlv320aic_write_reg(0x06, 0x28);
// P0_R7/R8: PLL 设置 D (D=0000)
tlv320aic_write_reg(0x07, 0x00);
tlv320aic_write_reg(0x08, 0x00);
// P0_R18: NADC 设置
// Power Up (bit 7=1), NADC=4 (bit 6-0=4). Clk = 81.92M / 4 = 20.48MHz
tlv320aic_write_reg(0x12, 0x84);
// P0_R19: MADC 设置
// Power Up (bit 7=1), MADC=10 (bit 6-0=10). Clk = 20.48M / 10 = 2.048MHz
tlv320aic_write_reg(0x13, 0x8A);
// P0_R20: AOSR 设置
// AOSR = 128. fs = 2.048M / 128 = 16kHz (Bingo!)
tlv320aic_write_reg(0x14, 0x80);
// ---------------------------------------------------------
// 3. 音频接口配置 (I2S, 16-bit, Slave)
// ---------------------------------------------------------
tlv320aic_write_reg(0x1B, 0x00); // I2S, 16bit, BCLK/WCLK 输入(Slave)
tlv320aic_write_reg(0x1C, 0x00); // Data Offset = 0
// ---------------------------------------------------------
// 4. ADC 处理块 (PRB)
// ---------------------------------------------------------
tlv320aic_write_reg(0x3D, 0x01); // PRB_R1 (标准录音处理)
// ---------------------------------------------------------
// 5. 模拟电源与 MICBIAS (Page 1)
// ---------------------------------------------------------
tlv320aic_select_page(1);
tlv320aic_write_reg(0x01, 0x08); // 禁用弱AVDD连接 (根据LDO配置调整)
tlv320aic_write_reg(0x02, 0x01); // 启用 AVDD LDO
tlv320aic_write_reg(0x0A, 0x00); // Common Mode 0.9V
tlv320aic_write_reg(0x7B, 0x01); // 参考电压充电 40ms
delay_1ms(50); // 等待模拟电源稳定
// [重点] WMM7027ATSN1 需要 >1.6V. 设置为 2.5V
// bit 6=1 (Enable), bit 5-4=10 (2.5V), bit 3=0 (Source=AVDD)
tlv320aic_write_reg(0x33, 0x60);
// ---------------------------------------------------------
// 6. 输入路由 (差分输入配置)
// ---------------------------------------------------------
// 左声道: IN2_L (+) 和 IN2_R (-) -> 10kΩ
tlv320aic_write_reg(0x34, 0x10); // P1_R52: Left MicPGA(+) 选 IN2_L (10k)
tlv320aic_write_reg(0x36, 0x10); // P1_R54: Left MicPGA(-) 选 IN2_R (10k)
// 右声道: IN1_R (+) 和 IN1_L (-) -> 10kΩ
// 注意:AIC3204 右声道 PGA 正端只能选 IN1_R, 负端选 IN1_L
tlv320aic_write_reg(0x37, 0x40); // P1_R55: Right MicPGA(+) 选 IN1_R (10k)
tlv320aic_write_reg(0x39, 0x40); // P1_R57: Right MicPGA(-) 选 IN1_L (10k)
// ---------------------------------------------------------
// 7. 增益与使能
// ---------------------------------------------------------
// 设置 MicPGA 增益 (可选调整)
// 0x00 = 0dB, 0x1E = 15dB, 0x3C = 30dB
// 建议先给一点增益,MEMS 麦克风如果不加增益声音可能偏小
tlv320aic_write_reg(0x3B, 0x14); // Left PGA Gain = 10dB
tlv320aic_write_reg(0x3C, 0x14); // Right PGA Gain = 10dB
tlv320aic_select_page(0); // 切回 Page 0 准备开启 ADC
// 开启 ADC
tlv320aic_write_reg(0x51, 0xC0); // Power Up Left & Right ADC
tlv320aic_write_reg(0x52, 0x00); // Unmute ADC
}
void init_playback()
{
// 切换到 Page 0
tlv320aic_select_page(0);
tlv320aic_reset();
delay_1ms(10); // 等待重置完成
// 时钟配置(无 PLL,CODEC_CLKIN = MCLK)
tlv320aic_write_reg(0x04, 0x00); // CODEC_CLKIN = MCLK, PLL 输入 = MCLK
tlv320aic_write_reg(0x05, 0x00); // PLL 关闭
tlv320aic_write_reg(0x0B, 0x81); // NDAC = 1, 启用
tlv320aic_write_reg(0x0C, 0x82); // MDAC = 2, 启用(调整为匹配 fs = MCLK / (NDAC * MDAC * DOSR))
tlv320aic_write_reg(0x0D, 0x00); // DOSR MSB = 0
tlv320aic_write_reg(0x0E, 0x80); // DOSR LSB = 128
// 音频接口配置(I²S 从机,16 位)
tlv320aic_write_reg(0x1B, 0x00); // I²S 格式,16 位,BCLK/WCLK 从机
tlv320aic_write_reg(0x1C, 0x00); // 数据偏移 = 0
tlv320aic_write_reg(0x27, 0x00); // 接口模式
tlv320aic_write_reg(0x28, 0x00); // 字长 16 位
tlv320aic_write_reg(0x29, 0x00); // WCLK 输入
// DAC 配置(PRB_P1,数字音量 0 dB)
tlv320aic_write_reg(0x3C, 0x01); // PRB_P1 处理块
tlv320aic_write_reg(0x3F, 0xC0); // 启用左右 DAC
tlv320aic_write_reg(0x40, 0x00); // 软步进
tlv320aic_write_reg(0x41, 0x00); // 左 DAC 音量 0 dB
tlv320aic_write_reg(0x42, 0x00); // 右 DAC 音量 0 dB
// 切换到 Page 1(模拟控制)
tlv320aic_select_page(1);
// 电源和参考配置
tlv320aic_write_reg(0x01, 0x08); // 启用主模拟电源
tlv320aic_write_reg(0x02, 0x01); // 参考快速充电
tlv320aic_write_reg(0x0A, 0x00); // 输入/输出 CM = 0.9V
tlv320aic_write_reg(0x7B, 0x01); // 启用参考充电
delay_1ms(1000); // 等待参考电压稳定(~1s)
// 输出路由(左 DAC 到 LOL,右 DAC 到 LOR)
tlv320aic_write_reg(0x0E, 0x02); // LOL 路由:左 DAC
tlv320aic_write_reg(0x0F, 0x02); // LOR 路由:右 DAC
// 输出驱动器配置(增益 0 dB,启用 LOL/LOR)
tlv320aic_write_reg(0x09, 0x30); // 启用 LOL/LOR 电源
tlv320aic_write_reg(0x12, 0x06); // LOL 增益 0 dB
tlv320aic_write_reg(0x13, 0x06); // LOR 增益 0 dB
tlv320aic_write_reg(0x14, 0x00); // 无耳机启动(仅线输出)
delay_1ms(10); // 等待启动
// 切换回 Page 0
tlv320aic_select_page(0);
}
/**
* \brief main
*
* \return int
*/
int main(void)
{
printf("TVL320AIC TEST\n\r");
uint8_t val = 0;
// Initial PSRAM
PSRAM_Mode_X16_Init();
psram_test();
#ifdef MISC_HAS_I2C1_HAS_CLK
i2c0_clk_en(ENABLE);
#endif
#ifdef MISC_HAS_I2C1_RST
i2c0_set_rst(DISABLE);
i2c0_set_rst(ENABLE);
#endif
#ifdef CFG_SIMULATION
#ifdef MISC_HAS_I2C1_CLK_DIV
i2c0_clk_div(0);
#endif
#endif
/* configure I2C */
I2C_Config();
#ifdef MISC_HAS_SAI0_HAS_CLK
sai0_clk_en(ENABLE);
#endif
#ifdef MISC_HAS_UDMA0_HAS_CLK
udma0_clk_en(ENABLE);
udma0_set_rst(DISABLE);
udma0_set_rst(ENABLE);
#endif
#ifdef MISC_HAS_SAI0_RST
sai0_set_rst(DISABLE);
sai0_set_rst(ENABLE);
#endif
__enable_irq();
SAI_InitTypeDef sai_init_t = {0};
SAI_FrameInitTypeDef sai_frame_t = {0};
SAI_SlotInitTypeDef sai_slot_t = {0};
SAI_ClockInitTypeDef sai_clock_t = {0};
printf("Write Page 0, Register 0x04 0x1, then read back...\n");
tlv320aic_select_page(0);
tlv320aic_reset();
tlv320aic_write_reg(0x04, 0x01);
tlv320aic_read_reg(0x04, &val);
if (val == 0x01) {
printf("I2C register read/write OK!\n");
} else {
printf("I2C communication abnormal (read back 0x%02X)\n", val);
}
#if 1//Record
init_recording();
uint8_t micbias_reg = 0;
tlv320aic_select_page(1);
tlv320aic_read_reg(0x33, &micbias_reg);
printf("MICBIAS Reg = 0x%02X\n", micbias_reg);
//SAI0 A Record
UDMA_PAM2MTypeDef UDMA_PAM2MStruct2={0};
UDMA_PAM2MStruct2.UDMA_TransEn = PA2M_TRANS_ENABLE;
UDMA_PAM2MStruct2.UDMA_DstBaseAddr = ADDR32(SAI0_S0_B_Receive_buffer);
UDMA_PAM2MStruct2.UDMA_SrcBaseAddr = ADDR32(SAI0_S0_BASE_B + FIFO_RDAT);
UDMA_PAM2MStruct2.UDMA_BufferSize = ARR_SIZE_B*sizeof(uint16_t);//ARR_SIZE;//*sizeof(uint16_t);
UDMA_PAM2MStruct2.UDMA_DstInc = PA2M_MDNA_ENABLE;
UDMA_PAM2MStruct2.UDMA_SrcInc = PA2M_MSNA_DISABLE;
UDMA_PAM2MStruct2.UDMA_Width = PA2M_MDWIDTH_16BIT;//PA2M_MDWIDTH_8BIT;
UDMA_PAM2MStruct2.UDMA_Mode = PA2M_MODE_CONTINUOUS;
UDMA_PAM2MStruct2.UDMA_PER_SEL = UDMA_SEL_SAI0_SAI_0_B_RX_DMA;
UDMA_PAM2MStruct2.UDMA_SrcBaseAddr_H = (uint32_t)(ADDR64(SAI0_S0_BASE_B + FIFO_RDAT) >> 32) ;
UDMA_PAM2MStruct2.UDMA_DstBaseAddr_H = (uint32_t)(ADDR64(SAI0_S0_B_Receive_buffer) >> 32) ;
UDMA_PAM2M_Init(SAI0_SAI_0_B_RX_DMA_DMA_CH, &UDMA_PAM2MStruct2);
/* DMA interrupt request */
ECLIC_Register_IRQ(UDMA0_IRQn, ECLIC_NON_VECTOR_INTERRUPT,
ECLIC_LEVEL_TRIGGER, 1, 0,
UDMA0_IRQHandler);
UDMA_PA2M_ITConfig(SAI0_SAI_0_B_RX_DMA_DMA_IRQ, PA2M_FTRANS_IRQ_EN, ENABLE);
sai_init_t.Synchro = SAI_AUDIOCTRL_SYNCEN_INNER_SYNCHRONOUS;//SAI_AUDIOCTRL_SYNCEN_ASYNCH;//SAI_AUDIOCTRL_SYNCEN_INNER_SYNCHRONOUS;
sai_init_t.ClockPolarity = SAI_AUDIOCTRL_CKPOL_NEGEDGE;
sai_init_t.PortNum = SAI_AUDIOCTRL_PORTN_PORT0_ENABLE;
sai_init_t.SAIProtocol = SAI_AUDIOCTRL_PRTCFG_FREE_PROTOCOL;
sai_init_t.MonoStereoMode = SAI_AUDIOCTRL_MONO_DISABLE;
sai_init_t.FirstBit = SAI_GEN_CFG0_LSBFIRST_DISABLE;//SAI_GEN_CFG0_LSBFIRST_ENABLE;
sai_init_t.ClockStrobingEdge = SAI_GEN_CFG0_CKSTR_ENABLE;
sai_init_t.TriState = SAI_GEN_CFG0_TRIS_DISABLE;
sai_init_t.AudioMode = SAI_AUDIOCTRL_MODE_MASTER_RX;
sai_init_t.Syncin = SAI_AUDIOCTRL_SYNCIN_NOSYNCIN;
sai_init_t.Syncout = SAI_AUDIOCTRL_SYNCOUT_ENABLE;
sai_frame_t.FrameLength = SAI_GEN_CFG0_FRL(31);//SAI_GEN_CFG0_FRL(15);
sai_frame_t.ActiveFrameLength = SAI_GEN_CFG0_FSALL(15);//SAI_GEN_CFG0_FSALL(7);
sai_frame_t.FSDefinition = SAI_GEN_CFG0_FSDEF_ENABLE;
sai_frame_t.FSPolarity = SAI_GEN_CFG0_FSPOL_DISABLE;
sai_frame_t.FSOffset = SAI_GEN_CFG0_FSOFF_ENABLE;//;
sai_slot_t.FirstBitOffset = SAI_GEN_CFG1_FBOFF(0);
sai_slot_t.SlotSize = SAI_GEN_CFG1_SLOTSZ_16B;//SAI_GEN_CFG1_SLOTSZ_DATASIZE;
sai_slot_t.SlotNumber = SAI_GEN_CFG1_NBSLOT(1);//SAI_GEN_CFG1_NBSLOT(1);
sai_slot_t.SlotActive = SAI_GEN_CFG1_SLOTEN_ACTIVE_ALL;//SAI_GEN_CFG1_SLOTEN_ACTIVE_0 | SAI_GEN_CFG1_SLOTEN_ACTIVE_1;
sai_slot_t.DataSize = SAI_GEN_CFG1_DS_16;//SAI_GEN_CFG1_DS_8;
sai_slot_t.RestoreSize = SAI_FIFOCTRL_FTH_SIZE_EMPTY;//SAI_FIFOCTRL_FTH_SIZE_8;
sai_slot_t.DmaState = SAI_FIFOCTRL_DMAEN_ENABLE;
SAI_Init(SAI0_S0_CFG_B, &sai_init_t,&sai_frame_t,&sai_slot_t);
/* SAI1 A reg init */
sai_init_t.AudioMode = SAI_AUDIOCTRL_MODE_MASTER_TX;
sai_init_t.Syncin = SAI_AUDIOCTRL_SYNCIN_NOSYNCIN;
sai_init_t.Syncout = SAI_AUDIOCTRL_SYNCOUT_ENABLE;
SAI_Init(SAI0_S0_CFG_A, &sai_init_t,&sai_frame_t,&sai_slot_t);
sai_clock_t.Mckdiv = 12 << 2;//kestrel2 12 = 16KHz kestrel 48 = 16KHz
sai_clock_t.NoDivider = 0;
sai_clock_t.OverSamplingRatio = 1;
SAI_ClockInit(SAI0_S0_CFG_B, &sai_clock_t);
sai_clock_t.Mckdiv = 12 << 2;//kestrel2 12 = 16KHz kestrel 48 = 16KHz
sai_clock_t.NoDivider = 0;
sai_clock_t.OverSamplingRatio = 1;
SAI_ClockInit(SAI0_S0_CFG_A, &sai_clock_t);
/* SAI0_S0_A start */
SAI_Config(SAI0_S0_CFG_A,ENABLE);
SAI_Config(SAI0_S0_CFG_B,ENABLE);
// dump_tlv320_registers();
while(1) {
if(state0 == 0)
delay_1ms(10);
else
{
state0 = 0;
break;
}
}
for(int i=0; i<100; i++) {
if(i%8==0) printf("\n");
printf("0x%x ", SAI0_S0_B_Receive_buffer[i]);
}
printf("\r\n");
printf("recording end\r\n");
#endif
delay_1ms(5000);
delay_1ms(5000);
while(1) {}
}
录音到PSRAM数组,然后memory窗口导出二进制PCM数据到AUDACITY
332

被折叠的 条评论
为什么被折叠?



