查看: 5040|回复: 2

[分享] 【LPC54114】+DMIC学习

[复制链接]
  • TA的每日心情
    郁闷
    2022-4-4 11:28
  • 签到天数: 351 天

    [LV.8]以坛为家I

    141

    主题

    8054

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    5740
    最后登录
    2022-4-4
    发表于 2017-4-23 10:29:18 | 显示全部楼层 |阅读模式
    本帖最后由 wambob 于 2017-4-24 17:33 编辑

          1.数字麦克风。
          声音在自然界无处不在。物理学上描述为一种振动波,
    频率在20HZ~20kHz之间的声波,人耳可以听到。为了记录美妙的声音,无论是模拟还是数字,都需要一个采集声音的传感器。
         数字麦克风,既然称数字,输出的信号就是是数字了。
         特性:
         .64dB的高信噪比。
         .低功耗模式低电流为235uA
         .多种模式(睡眠、低功耗、标准和超声模式)
         .平坦的频率响应
         .RF隔离
         .0高度麦克风
         .支持双复用通道
         .标准的SMD回流焊
         .全方向
         .超声支持
         .灵敏度匹配
         .小尺寸
    其工作状态图:
    无标题.png
    从图中可以看出,改变时钟频率在某个范围,就改变了工作模式。
    电路原理图
    无标题1.png
    时序图
    无标题2.png
    其输出的数据是1bit PDM格式的数字数据,用软件处理起来比较麻烦。LPC54114片上提供了DMIC子系统,可以通过配置寄存器将PDM
    (Pulse-Density Modulation) 数据转换成PCM(Pulse Code Modulation)数据,经I2S总线传送到解码器,播放声音。
    2.DMIC子系统
         包括双通道数字PDM麦克风接口和硬件声音活动检测器(
    HWVAD)。
    4.png


    • DMIC (双/立体声数字麦克风接口)
    PDM (Pulse-Density Modulation) 数据输入
    灵活的抽取.
    每通道16 个 FIFO
    可选DC blocking
    无需唤醒CPU ,
    使用DMA 从深度睡眠模式发送数据,然后自动返回深度睡眠模式.
    数据可直接到通讯接口7 I2S.
    • HWVAD (基于硬件的声音检测器):
    用 16 kHz 采样率优化PCM信号.
    可配置检测水平.
    噪声包络估计寄存器输出进一步软件分析

    3.例程中DMIC的初始化代码
    1. uint8_t dmic_init(void)
    2. {        
    3.         uint8_t ret = 0;
    4.         uint32_t i = 0;
    5.         dmic_channel_config_t dmic_channel_cfg;
    6.         
    7.         /* PDM interface */
    8.         IOCON_PinMuxSet(IOCON, 1, 15, IOCON_FUNC1 | IOCON_DIGITAL_EN);  /* PDM CLK  0 */
    9.         IOCON_PinMuxSet(IOCON, 1, 16, IOCON_FUNC1 | IOCON_DIGITAL_EN);  /* PDM DATA 0 */
    10.         
    11.         /* DMIC uses 12MHz FRO clock */
    12.         CLOCK_AttachClk(kFRO12M_to_DMIC);
    13.         /*12MHz divided by 15 = 800KHz PDM clock */
    14.         CLOCK_SetClkDiv(kCLOCK_DivDmicClk, 15, false);
    15.         dmic_channel_cfg.divhfclk = kDMIC_PdmDiv1;
    16.         dmic_channel_cfg.osr = 25U;
    17.         dmic_channel_cfg.gainshft = 3U;
    18.         dmic_channel_cfg.preac2coef = kDMIC_CompValueZero;
    19.         dmic_channel_cfg.preac4coef = kDMIC_CompValueZero;
    20.         dmic_channel_cfg.dc_cut_level = kDMIC_DcCut155;
    21.         dmic_channel_cfg.post_dc_gain_reduce = 0U;
    22.         dmic_channel_cfg.saturate16bit = 1U;
    23.         dmic_channel_cfg.sample_rate = kDMIC_PhyFullSpeed;
    24.         DMIC_Init(DMIC0);
    25.         
    26.         DMIC_ConfigIO(DMIC0, kDMIC_PdmStereo);
    27.         DMIC_Use2fs(DMIC0, true);
    28.         DMIC_SetOperationMode(DMIC0, kDMIC_OperationModeInterrupt);
    29.         DMIC_ConfigChannel(DMIC0, kDMIC_Channel0, kDMIC_Left, &dmic_channel_cfg);
    30.         DMIC_ConfigChannel(DMIC0, kDMIC_Channel1, kDMIC_Right, &dmic_channel_cfg);
    31.         DMIC_FifoChannel(DMIC0, kDMIC_Channel0, FIFO_DEPTH, true, true);
    32.         DMIC_FifoChannel(DMIC0, kDMIC_Channel1, FIFO_DEPTH, true, true);
    33.         
    34.         /*Gain of the noise estimator */
    35.         DMIC_SetGainNoiseEstHwvad(DMIC0, 0x02U);
    36.         /*Gain of the signal estimator */
    37.         DMIC_SetGainSignalEstHwvad(DMIC0, 0x01U);
    38.         /* 00 = first filter by-pass, 01 = hpf_shifter=1, 10 = hpf_shifter=4 */
    39.         DMIC_SetFilterCtrlHwvad(DMIC0, 0x01U);
    40.         /*input right-shift of (GAIN x 2 -10) bits (from -10bits (0000) to +14bits (1100)) */
    41.         DMIC_SetInputGainHwvad(DMIC0, 0x04U);
    42.         DisableDeepSleepIRQ(HWVAD0_IRQn);
    43.         DMIC_HwvadEnableIntCallback(DMIC0, DMIC0_HWVAD_Callback);
    44.         DMIC_EnableChannnel(DMIC0, (DMIC_CHANEN_EN_CH0(1) | DMIC_CHANEN_EN_CH1(1)));
    45.         /* reset hwvad internal interrupt */
    46.         DMIC_CtrlClrIntrHwvad(DMIC0, true);
    47.         /* To clear first spurious interrupt */
    48.         for (i = 0; i < 0xFFFFU; i++)
    49.         {
    50.         }
    51.         /*HWVAD Normal operation */
    52.         DMIC_CtrlClrIntrHwvad(DMIC0, false);
    53.         NVIC_ClearPendingIRQ(HWVAD0_IRQn);
    54.         EnableDeepSleepIRQ(HWVAD0_IRQn);

    55.         ret = 1;
    56.         
    57.         return ret;
    58. }
    复制代码
    首先定义了一个DMIC通道配置变量,这是一个结构体类型,结构成员包括DMIC 时钟预分频值、过采样率、4FS PCM增益控制、2FS预加重滤波器系数值、4FS预加重滤波器系数值、DMIC DC滤波器控制值、增益调整、DMIC和抽取器采样率、16bit饱和度状态。
    1. typedef struct _dmic_channel_config
    2. {
    3.     pdm_div_t divhfclk;                 /*!< DMIC Clock pre-divider values */
    4.     uint32_t osr;                       /*!< oversampling rate(CIC decimation rate) for PCM */
    5.     int32_t gainshft;                   /*!< 4FS PCM data gain control */
    6.     compensation_t preac2coef;          /*!< Pre-emphasis Filter coefficient value for 2FS */
    7.     compensation_t preac4coef;          /*!< Pre-emphasis Filter coefficient value for 4FS */
    8.     dc_removal_t dc_cut_level;          /*!< DMIC DC filter control values. */
    9.     uint32_t post_dc_gain_reduce;       /*!< Fine gain adjustment in the form of a number of bits to downshift */
    10.     dmic_phy_sample_rate_t sample_rate; /*!< DMIC and decimator sample rates */
    11.     bool saturate16bit; /*!< Selects 16-bit saturation. 0 means results roll over if out range and do not saturate.
    12.                 1 means if the result overflows, it saturates at 0xFFFF for positive overflow and
    13.                 0x8000 for negative overflow.*/
    14. } dmic_channel_config_t;
    复制代码
    接着初始化了两个管脚PIO1口测15、16管脚复用功能1,并且数字输出。
    无标题.png
    无标题1.png
    接着配置时钟。
    1. CLOCK_AttachClk(kFRO12M_to_DMIC);
    复制代码
    参数是个枚举类型的,元素值为MUX_A(CM_DMICCLKSEL, 0),其中#define CM_DMICCLKSEL 27    #define MUX_A(m, choice) (((m) << 0) | ((choice + 1) << 8))
    展开为0x11B。
    1. void CLOCK_AttachClk(clock_attach_id_t connection)
    2. {
    3.     bool final_descriptor = false;
    4.     uint8_t mux;
    5.     uint8_t pos;
    6.     uint32_t i;
    7.     volatile uint32_t *pClkSel;

    8.     pClkSel = &(SYSCON->MAINCLKSELA);

    9.     for (i = 0U; (i <= 2U) && (!final_descriptor); i++)
    10.     {
    11.         connection = (clock_attach_id_t)(connection >> (i * 12U)); /* pick up next descriptor */
    12.         mux = (uint8_t)connection;
    13.         if (connection)
    14.         {
    15.             pos = ((connection & 0xf00U) >> 8U) - 1U;
    16.             if (mux == CM_ASYNCAPB)
    17.             {
    18.                 ASYNC_SYSCON->ASYNCAPBCLKSELA = pos;
    19.             }
    20.             else
    21.             {
    22.                 pClkSel[mux] = pos;
    23.             }
    24.         }
    25.         else
    26.         {
    27.             final_descriptor = true;
    28.         }
    29.     }
    30. }
    复制代码
    i=0时。
    无标题3.png
    往下为时钟分频 ,参数(42,14,false)
    1. void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset)
    2. {
    3.     volatile uint32_t *pClkDiv;

    4.     pClkDiv = &(SYSCON->SYSTICKCLKDIV);
    5.     if (reset)
    6.     {
    7.         pClkDiv[div_name] = 1U << 29U;
    8.     }
    9.     if (divided_by_value == 0U) /* halt */
    10.     {
    11.         pClkDiv[div_name] = 1U << 30U;
    12.     }
    13.     else
    14.     {
    15.         pClkDiv[div_name] = (divided_by_value - 1U);
    16.     }
    17. }
    复制代码
    算出来的值为为13,即0x0D (1101b),给寄存器赋值,如何为15分频?而不是12分频呢?
    无标题4.png
    接着初始化了DMIC0。
    1. void DMIC_Init(DMIC_Type *base)
    2. {
    3.     assert(base);

    4.     /* Enable the clock to the register interface */
    5.     CLOCK_EnableClock(s_dmicClock[DMIC_GetInstance(base)]);

    6.     /* Reset the peripheral */
    7.     RESET_PeripheralReset(kDMIC_RST_SHIFT_RSTn);

    8.     /* Disable DMA request*/
    9.     base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);
    10.     base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);

    11.     /* Disable DMIC interrupt. */
    12.     base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
    13.     base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
    14. }
    复制代码
    使能了AHB时钟
    无标题5.png
    三个复位。
    在初始化后,配置DMIC的一些设置、双通道、2FS、传输模式、FIFO。
    往下是一些HWVAD的一些设置。


    总结,例程有问题,只好一步步分析,解决例程麦克风没声音的问题。首先要注意DMIC数据输出的三种工作模式方式
    1. typedef enum _operation_mode
    2. {
    3.     kDMIC_OperationModePoll = 0U,      /*!< Polling mode */
    4.     kDMIC_OperationModeInterrupt = 1U, /*!< Interrupt mode */
    5.     kDMIC_OperationModeDma = 2U,       /*!< DMA mode */
    6. } operation_mode_t;
    复制代码
    原例程里使用中断方式,但在解码器中使用DMA模式。存在问题。






         

         

    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-10-17 08:07
  • 签到天数: 273 天

    [LV.8]以坛为家I

    74

    主题

    2338

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    7361
    最后登录
    2021-8-30
    发表于 2017-5-27 16:35:00 | 显示全部楼层
    不错,谢谢分享
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2019-4-1 22:48
  • 签到天数: 302 天

    [LV.8]以坛为家I

    87

    主题

    7322

    帖子

    4

    金牌会员

    Rank: 6Rank: 6

    积分
    4433
    最后登录
    2021-1-25
    发表于 2017-11-29 13:46:10 | 显示全部楼层
                                                                。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-10 18:34 , Processed in 0.120857 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表