20151127:研究I2S中时钟的生成

一: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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容