美文网首页
20151127:研究I2S中时钟的生成

20151127:研究I2S中时钟的生成

作者: skylaugher | 来源:发表于2018-11-11 13:41 被阅读0次

一:makefile中用到的模组:

USED_MODULES = 
module_usb_shared             :
module_usb_device             :
module_usb_audio              :很重要的应用程序都在这儿,包括main()函数,以及EP0。
module_xud                    :很重要的底层核心库,不能改动
module_spdif_tx               :spdif发送功能本项目不用
module_spdif_rx               :如果spdif接收连接到DAC上,则此功能也不用。而且xMOS的工程师建议不要用xMOS上的SPDIF接收功能,原因:(1)效果不如直连DAC的好;(2)节省SPDIF RX占用的两个core,省电,降功耗;
module_usb_midi               :本项目不用midi功能
module_dfu                    :升级功能
module_i2c_shared             :已分析
module_i2c_single_port        :已分析
module_adat_txmodule_adat_rx  :本项目不用adat功能

二:标准库的帮助文档位置

在Program Files\XMOS\xTIMEcomposer\Community_14.1.1\doc\libs\html下有各种库的帮助网页

三:Main函数的大致结构

->Main()                  //module_usb_audio:main.xc
    ->usb_audio_core     //CoreUSB Audio functions
        ->XUD_Manager    //This performs the low-level USB I/O operations
        ->buffer         //Endpointbuffer:Buffers data from audio endpoints
        ->Endpoint0      //Handles all requests to the device
        ->decouple       //Manage the data transfer between theUSB audio buffer 
                        //and the Audio I/O driver.
    ->usb_audio_io
        ->mixer         //Digitalsample mixer
                        //The thread mixes audio streams between the decouple() 
                        //thread and the audio() thread
        ->audio         //Audio driver thread
                        //This function drivers I2S ports and handles samples 
                        //to/from other digital I/O threads.
            ->configure_clock_src(clk_audio_mclk, p_mclk_in);
            ->start_clock(clk_audio_mclk);
            ->AudioHwInit(c_config);    //Thisfunction is called when the audio core starts 
                        //after the device boots up and should initialize 
                        //the external audio harware e.g. clocking, DAC, ADC etc
            ->while(1)
                ->ConfigAudioPortsWrapper
                    ->ConfigAudioPorts
                ->AudioHwConfig //This function is called when the audiocore starts 
                                //or changes sample rate. It should configure the 
                                //extenal audio hardware to run at the specified 
                                //sample rate given the supplied master clock frequency.
                ->deliver
                    ->DoSampleTransfer
                        ->outuint(c_out, samplesIn_0[i]);
                    ->InitPorts(divide);
                    ->while(1)
                        ->p_lrclk <: 0x80000000,0x7FFFFFFF
                        ->doI2SClocks
                            ->p_bclk <: 0xF0F0F0F0 etc.
                        ->DoSampleTransfer
        ->clockGen      //for SPDIF RX or ADAT RX
    ->iAP

20151204添加:decouple和audio之间的channel关系

Decouple Audio
Decouple只有一个chanend,与mixer或audio交换信息和数据 ;Decouple与buffer通过全局变量aud_to_host_flag等和全局数组outAudioBuffer、audioBuffIn交换数据和信息 audio只有一个chanend,要么decouble交换信息和样本,要么跟mixer交换信息和样本
初始化各种全局变量或从全局变量中获得各种信息 配置i2s的时钟源
非常重要的中断处理函数: set_interrupt_handler(handle_audio_request, 1, c_mix_out, 0); 配置硬件ADC/DAC/PLL等AudioHwInit
While(1) While(1)
如果g_freqChange_flag==SET_SAMPLE_FREQ 根据采样率\样本分辨率等信息计算bclk用的divide值;
则 inuint(c_mix_out);
outct(c_mix_out, SET_SAMPLE_FREQ);
outuint(c_mix_out, sampFreq);
全局变量
如果g_freqChange_flag==SET_SAMPLE_FORMAT_IN 根据divide及输入方式dsdmode等信息配置bclk;
则 全局变量
如果g_freqChange_flag==SET_SAMPLE_FORMAT_OUT 则 全局变量 配置ADC/DAC/PLL,AudioHWConfig
inuint(c_mix_out);
outct(c_mix_out, SET_STREAM_FORMAT_OUT);
outuint(c_mix_out, dsdMode);
outuint(c_mix_out, sampRes);
后面语句全部是各种全局变量、指针计算 调用command=deliver()
返回while 如果command==SET_SAMPLE_FREQ;
则从c中读入curSamFreq(inuint)
如果command==SET_STREAM_FORMAT_OUT
则从c中读入dsdmode和curSamRes_DAC (inuint)
deliver  
调用DosampleTransfer(),如果是命令,则返回  
如果不是命令,则  
      初始化I2S:InitPorts(divide)  
      While(1)  
         ADC:从I2S总线上读入样本值,存入数组samplesIn_1或samplesIn_0          
         DAC:将samplesOut中输出到I2S总线          
         调用DosampleTransder(),如果是命令则返回,否则重新while  
handle_audio_request DoSampleTransfer
underflowSample=inuint(c) Outintc(c,underflowword)
outuint(c,0) Testct(c)检查是否是控制令牌
如果是,则读出控制命令intc(c),返回命令
如果不是:
Inuint; 没有定义MIXER时有;
ADC输入: 从c中获取各通道样本:inuint(c),放到全局数组中 ADC:则将样本从数组samplesIn_0samplesIn_1输出到decouple(outuint)
DAC输出: 从全局数组中读出样本输出到c中,outuint DAC:则从decouple读入样本到数组samplesOut中(inuint)
之后全是调整全局变量、指针等运算。

四:I2S时钟的设置路径

1、在audio()函数的开始将inport : PORT_MCLK_IN设置为audio clock block的源

configure_clock_src(clk_audio_mclk,p_mclk_in);
start_clock(clk_audio_mclk);               //Puts a clock into a running state.

2、在while(1)循环中,首先计算

a) 如果当前采样率能整除512*44100,则mCLK=512*44100
b) 如果当前采样率能整除512*48000,则mCLK=512*48000
c) I2S中一个样本32bit,一个通道两个声道,因此左右声道两个样本的总比特数为numbits=64
d) divide = mCLK/(当前采样率*numbits)
e) 调用函数ConfigAudioPortsWrapper()设置I2S的位时钟、帧始终
    i. 当divide=1时,直接设置位时钟=audio clock block(clk_audio_mclk)
        1.configure_port_clock_output(p_bclk,clk_audio_mclk);位时钟=audio clock block
        2.configure_clock_src(clk_audio_bclk,p_mclk_in); clk_audio_bclk=p_mclk_in
    ii. 当divide为其它值时,
        1. configure_out_port_no_ready(p_bclk,clk_audio_mclk, 0)将位时钟port配置给一个clockedoutput,注意本函数不是赋值,而是将一个port与时钟化的port进行相关
        2. configure_clock_src(clk_audio_bclk,p_bclk);  clk_audio_bclk=p_bclk
    iii.将I2S的帧时钟与clk_audio_bclk相关
        1. configure_out_port_no_ready(p_lrclk,clk_audio_bclk, 0);
    iv. 将I2S的各个数据线与clk_audio_bclk相关
        for(int i = 0; i < numPortsDac; i++)
        {             //DAC
            configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
        }
        for(int i = 0; i < numPortsAdc; i++)
        {             //ADC
            configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
        }
    v. 启动clk_audio_bclk时钟,也就意味着启动了位时钟、帧时钟以及各信号线。
        start_clock(clk_audio_bclk);
f) 调用函数AudioHwConfig(),根据采样率和mCLK两个数据对PLL芯片和ADC/DAC进行设置
    i. 根据mCLK的值,设置MCLK_FSL=0,输出22.5792MHz;MCLK_FSL=1,24.576MHz
    ii.设置ADC/DAC的寄存器;
g) 调用函数deliver(),该函数返回值获取的命令command
    i. 调用函数command=DoSampleTransfer(c_out, readBuffNo, underflowWord);
        1.Outuint(c_out,underflowWord);将underflowWord输出到c_out;
        2.Testct(c_out);检测c_out的下一个字节是否是控制token
            a)如果是,则将控制token赋给command;
            b)拉低帧时钟和位时钟信号线;
            c)返回command;
        3.如果NUM_USB_CHAN_OUT>0,从c_out中读入NUM_USB_CHAN_OUT个字节到samplesOut[];
        4.如果NUM_USB_CHAN_IN>0,将I2S_CHAN_ADC个字节samplesIn[]输出到c_out;
    ii.InitPorts(divide);
        1.如果divide不等于1,则输出0x80000000,b_clk开始必须为高;然后同步p_bclk
        2.清除帧时钟、数据线使用的缓冲buffer
        3.如果divide==1,预充填0到数据线和帧时钟
            a)调用doI2SClock(divide),根据divide,输出不同的值到p_bclk生成位时钟
        4.如果divide!=1,预充填0到数据线和帧时钟
            a)调用doI2SClock(divide),根据divide,输出不同的值到p_bclk生成位时钟
    iii.while(1)
        1.如果是ADC,那么从I2S中读数据到数组samplesIn_1[]或samplesIn_2[],输出帧时钟0x800000000 (LEFT channel)
        2.如果是DAC,将数组samplesOut[]输出到数据线;然后调用doI2SClock(divide)
        3.如果是ADC,那么从I2S中读数据到数组samplesIn_1[]或samplesIn_2[],输出帧时钟0x7FFFFFFF (RIGHT channel)
        4.如果是DAC,将数组samplesOut[]输出到数据线;然后调用doI2SClock(divide)
h)如果command==SET_SAMPLE_FREQ,则从c_mix_out中读入当前采样频率;
i)如果command==SET_STREAM_FORMAT_OUT,则从c_mix_out中读入dsdmode和curSamRes_DAC

相关文章

  • 20151127:研究I2S中时钟的生成

    一:makefile中用到的模组: 二:标准库的帮助文档位置 在Program Files\XMOS\xTIMEc...

  • 关于I2S

    I2S信号定义 MCLK---主时钟,即系统时钟(设计中并未必须),一般是采用频率的256倍或384倍 SCLK(...

  • I2S_RX 音频接收通用设计

    I2S简介 如上图所示: SCLK :位时钟,数据单bit反转。 频率=2 * 采样频率 * 采样位...

  • I2S_TX 音频发送通用设计

    I2S简介 如上图所示: SCLK :位时钟,数据单bit反转。 频率=2 * 采样频率 * 采样位...

  • 20151127

    我希望可以找回曾经那种对待每一件事都认真的态度,用细心来处理任何一个细节,包括任何一个人。昨天不是看到一句话,不要...

  • MTK平台-如何输出80KHZ频率的PWM信号

    综述 传音项目的需求,因为smartpa在调试的时候,噪音很大,原因是i2s给的时钟信号不稳定,硬件工程师说能不能...

  • 2. I2S接口

    1. I2S接口概述 I2S全称Inter-IC Sound, Integrated Interchip Soun...

  • 读书笔记《给教师的68条写作建议》10

    《给教师的68条写作建议》中的第33条建议:赵开中的学生成长研究。 在文章中作者介绍了赵开中老师对学生成长研究...

  • iOS深入理解定时器

    软件是何以监听到时钟的 硬件时钟生成信号,按照固定频率发出信号,操作系统接收到时钟信号之后将其转换为时钟计数,然后...

  • 早晨(20151127)

    不念过去,不畏将来,珍惜当下! 以前一直回去想自己的将来会是什么样子的,发现这个是没有办法解答的问题,人生际遇,我...

网友评论

      本文标题:20151127:研究I2S中时钟的生成

      本文链接:https://www.haomeiwen.com/subject/yfmxfqtx.html