• ADSP-21479的开发详解五(AD1939 C Block-Based Talkthru 48 or 96 kHz)音频直通


    硬件准备

    ADSP-21479EVB开发板

    产品链接:https://item.taobao.com/item.htm?id=555500952801&spm=a1z10.5-c.w4002-5192690539.11.151441a3Z16RLU

    在这里插入图片描述

    AD-HP530ICE仿真器

    产品链接:https://item.taobao.com/item.htm?id=38007242820&spm=a1z10.5-c.w4002-5192690539.11.59ae4901jeWaOn

    软件准备

    Visual DSP++5.1.2
    CCES2.11.1

    音频开发: 21479 AD1939 C Block-Based Talkthru 48 or 96 kHz(4 进 8 出)

    这个程序,我们将会在开发板上实现 48Khz 或 96Khz 采样率的音频直通程序。原理上来 讲,手机或者 PC 的音源通过 1 分 2 音频线接入 21479 开发板的模拟输入接插件,将模拟音 频导入,通过 AD1938 进行模拟转数字,数字音频信号进入 21479 数字音频 DSP 中,不做任何处理,交给 AD1938 再进行数字转模拟,将模拟的音频信号送到对应的通道,实现多 通道输出。

    硬件连接如下图:

    在这里插入图片描述

    在这里插入图片描述

    为什么输入接 2/3 通道,输出接 2/3 通道(通道号在板子的背面的丝印),这是因为 程序就是这么写的的,我们来看看程序是怎么写的: 把工程拖入 VDSP 中,编译,运行,手机播放音源,输出到音响听到音乐,完成这个例程。

    在这里插入图片描述

    看看这个程序的 Readme,代码实现了 ADC 从 2/3 进,DAC 从 0/1 和 2/3 出。ADC 从 0/1 进,DAC 从 4/5 和 6/7 出。用户可以换一下输入输出接口,听一下效果。至于板子上哪个接 口是 0/1,哪个是 2/3?请看下图,红色的接插件是输入,2 个黑色的接插件是输出:

    在这里插入图片描述

    这个工程里,音频处理都在 DSP Audio Processing Routines 里,想要了解如何实现这种 直通,可以看里面的程序去理解。 程序里都有备注,比较容易看得懂,这里说的就是 4 进 8 出,1 左右声道进对应 12 左 右声道出,2 左右声道进对应 34 左右声道出。而 1 左右声道 IN 就是板子上的 0/1 IN,2 左右声道 IN 就是板子上的 2/3 IN。

    核心代码分析

    DSP

    ///
    // //
    // NAME: blockProcess_audio.c (Block-based Talkthrough) //
    // DATE: 02/06/10 //
    // PURPOSE: Process incoming AD1939 ADC data and prepare outgoing blocks for DAC. //
    // //
    // USAGE: This file contains the subroutines that float and fix the serial data, //
    // and copy from the inputs to the outputs. //
    // //
    ///

    #include “ADDS_21479_EzKit.h”

    // Define a structure to represent buffers for all 12 floating-point data channels of the AD1939
    typedef struct{
    float Rx_L1[NUM_SAMPLES];
    float Rx_R1[NUM_SAMPLES];
    float Rx_L2[NUM_SAMPLES];
    float Rx_R2[NUM_SAMPLES];

    float Tx_L1[NUM_SAMPLES];
    float Tx_R1[NUM_SAMPLES];
    float Tx_L2[NUM_SAMPLES];
    float Tx_R2[NUM_SAMPLES];
    float Tx_L3[NUM_SAMPLES];
    float Tx_R3[NUM_SAMPLES];
    float Tx_L4[NUM_SAMPLES];
    float Tx_R4[NUM_SAMPLES];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    } ad1939_float_data;

    // SPORT Ping/Pong Data buffers
    extern int TxBlock_A0[];
    extern int TxBlock_A1[];

    extern int RxBlock_A0[];
    extern int RxBlock_A1[];

    //Pointer to the blocks
    int *rx_block_pointer[2] = {RxBlock_A0, RxBlock_A1};
    int *tx_block_pointer[2] = {TxBlock_A0, TxBlock_A1};

    // Structures to hold floating point data for each AD1939
    ad1939_float_data fBlockA;

    void process_audioBlocks(void);

    // Unoptimized function to convert the incoming fixed-point data to 32-bit floating-point format.
    // This function assumes that the incoming fixed point data is in 1.31 format
    void floatData(float *output, int *input, unsigned int instep, unsigned int length)
    {
    int i;

    for(i = 0; i < length; i++)
    {
        output[i] = __builtin_conv_RtoF(input[instep*i]);
    }
    
    • 1
    • 2
    • 3
    • 4

    }

    // Unoptimized function to convert the outgoing floating-point data to 1.31 fixed-point format.
    void fixData(int *output, float *input, unsigned int outstep, unsigned int length)
    {
    int i;

    for(i = 0; i < length; i++)
    {
        output[outstep*i] = __builtin_conv_FtoR(input[i]);
    }
    
    • 1
    • 2
    • 3
    • 4

    }

    // Unoptimized function to copy from one floating-point buffer to another
    void memcopy(float *input, float *output, unsigned int number)
    {
    int i;

    for(i = 0; i < number; i++)
    {
        output[i] = input[i];
    }
    
    • 1
    • 2
    • 3
    • 4

    }

    /
    // Audio Block Processing Algorithm for 4 IN x 8 OUT Audio System

    // The inputs and outputs are held in a structure for the AD1939
    // fBlockA holds stereo input (AIN) channels 0-3 and stereo output (AOUT) channels 0-7

    // This function copys the data without any processing as follows
    // AOUT1L <- AIN1L
    // AOUT1R <- AIN1R
    // AOUT2L <- AIN1L
    // AOUT2R <- AIN1R

    // AOUT3L <- AIN2L
    // AOUT3R <- AIN2R
    // AOUT4L <- AIN2L
    // AOUT4R <- AIN2R
    /

    void process_audioBlocks()
    {
    memcopy(fBlockA.Rx_L1, fBlockA.Tx_L1, NUM_SAMPLES);
    memcopy(fBlockA.Rx_R1, fBlockA.Tx_R1, NUM_SAMPLES);
    memcopy(fBlockA.Rx_L1, fBlockA.Tx_L2, NUM_SAMPLES);
    memcopy(fBlockA.Rx_R1, fBlockA.Tx_R2, NUM_SAMPLES);
    memcopy(fBlockA.Rx_L2, fBlockA.Tx_R3, NUM_SAMPLES);
    memcopy(fBlockA.Rx_R2, fBlockA.Tx_L3, NUM_SAMPLES);
    memcopy(fBlockA.Rx_L2, fBlockA.Tx_L4, NUM_SAMPLES);
    memcopy(fBlockA.Rx_R2, fBlockA.Tx_R4, NUM_SAMPLES);
    }

    /
    // This function handles the Codec data in the following 3 steps…
    // 1. Converts all ADC data to 32-bit floating-point, and copies this
    // from the current RX DMA buffer into fBlockA & fBlockB
    // 2. Calls the audio processing function (processBlocks)
    // 3. Converts all DAC to 1.31 fixed point, and copies this from
    // fBlockA & fBlockB into the current TX DMA buffer
    /

    void handleCodecData(unsigned int blockIndex)
    {
    //Clear the Block Ready Semaphore
    inputReady = 0;

    //Set the Processing Active Semaphore before starting processing
    isProcessing = 1;
    
    // Float ADC data from AD1939
    floatData(fBlockA.Rx_L1, rx_block_pointer[blockIndex]+0, NUM_RX_SLOTS, NUM_SAMPLES);
    floatData(fBlockA.Rx_R1, rx_block_pointer[blockIndex]+1, NUM_RX_SLOTS, NUM_SAMPLES);
    floatData(fBlockA.Rx_L2, rx_block_pointer[blockIndex]+2, NUM_RX_SLOTS, NUM_SAMPLES);
    floatData(fBlockA.Rx_R2, rx_block_pointer[blockIndex]+3, NUM_RX_SLOTS, NUM_SAMPLES);
    
    // Place the audio processing algorithm here. 
    process_audioBlocks();
    
    // Fix DAC data for AD1939
    fixData(tx_block_pointer[blockIndex]+0, fBlockA.Tx_L1, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+1, fBlockA.Tx_R1, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+2, fBlockA.Tx_L2, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+3, fBlockA.Tx_R2, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+4, fBlockA.Tx_L3, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+5, fBlockA.Tx_R3, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+6, fBlockA.Tx_L4, NUM_TX_SLOTS, NUM_SAMPLES);
    fixData(tx_block_pointer[blockIndex]+7, fBlockA.Tx_R4, NUM_TX_SLOTS, NUM_SAMPLES);
    
    
    //Clear the Processing Active Semaphore after processing is complete
    isProcessing = 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    }

    SPORT

    ///
    //NAME: SPORT1_isr.c (Block-based Talkthrough)
    //DATE: 02/06/10
    //PURPOSE: Talkthrough framework for sending and receiving samples to the AD1939.
    //
    //USAGE: This file contains SPORT1 Interrupt Service Routine. Four buffers are used
    // for this example: Two input buffers, and two output buffers.
    ///
    /*
    Here is the mapping between the SPORTS and the ADCs/DACs
    For AD1939
    ADC1 -> DSP : SPORT1A : TDM Channel 0,1
    ADC2 -> DSP : SPORT1A : TDM Channel 2,3
    DSP -> DAC1 : SPORT0A : TDM Channel 0,1
    DSP -> DAC2 : SPORT0A : TDM Channel 2,3
    DSP -> DAC3 : SPORT0A : TDM Channel 4,5
    DSP -> DAC4 : SPORT0A : TDM Channel 6,7
    */

    #include “ADDS_21479_EzKit.h”
    #include

    // Counter to choose which buffer to process
    int buffer_cntr = 1;
    // Semaphore to indicate to main that a block is ready for processing
    int inputReady = 0;
    // Semaphore to indicate to the isr that the processing has not completed before the
    // buffer will be overwritten.
    int isProcessing = 0;

    //If the processing takes too long, the program will be stuck in this infinite loop.
    void ProcessingTooLong(void)
    {
    while(1);
    }

    void TalkThroughISR(int sig_int)
    {
    int i;

    if(isProcessing)
        ProcessingTooLong();
    
    //Increment the block pointer
    buffer_cntr++;
    buffer_cntr %= 2;
    inputReady = 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    }

    MAIN

    /

    #include “ADDS_21479_EzKit.h”

    void main()
    {

    initPLL_SDRAM(); //Initialize the PLL and SDRAM controller
    
    // Initialize DAI because the SPORT and SPI signals
    // need to be routed
    InitDAI();
    
    // This function will configure the AD1939 codec on the 21479 EZ-KIT
    Init1939viaSPI();
    
    // Turn on SPORT0 TX and SPORT1 RX for Multichannel Operation
    InitSPORT();
    
    // Unmask SPORT1 RX ISR Interrupt 
    interrupt(SIG_SP1,TalkThroughISR);
    
    // Be in infinite loop and do nothing until done.
    while(1)
    {
    	if(inputReady)
    		handleCodecData(buffer_cntr);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    }

  • 相关阅读:
    建模杂谈系列162 APIFunc: 可靠的复杂函数开发3
    unity属性之UnityEditor
    行业资讯 | 入门revit软件需要理清哪些概念。
    [论文阅读] Unpaired Image-to-Image Translation Using Adversarial Consistency Loss
    Python海龟turtle基础知识大全与画图集合
    Linux---su:鉴定故障
    Ceph(L版本)部署及相关概念
    uni-app 微信小程序支付/公众号支付/h5支付宝/h5微信/支付宝app支付/微信app支付
    Docker容器网络安全性最佳实践:防止容器间攻击
    Vue中的ref 和$refs的使用
  • 原文地址:https://blog.csdn.net/ADI_OP/article/details/137913366