跳转至

时钟配置


1、简介

本文围绕芯片的主频配置、内部晶振和外部晶振的选择,每个外围设备接口的分频如何修改,IIS时钟配置展开说明。


2、主频配置

  • CI13LC系列芯片的主频最大支持210M,如需修改主频,先找到文件(CI13LC_SDK\projects\offline_asr_sample\src\user_config.h)
#define MAIN_FREQUENCY          210000000          //主频宏定义
  • 或者直接调用接口配置主频
#include "ci13lc_dpmu.h"
uint32_t src_frequency = 12288000                 //通常为12.288M
uint32_t main_frequency = 210000000               //主频最大支持210M

dpmu_pll_config(src_frequency, main_frequency);   //根据晶振时钟配置需要的主频

注意

  • 主频最大可以用210M。

3、晶振选择

  • 如果模组外挂了晶振,可以配置选择外部晶振,否则选择内部晶振,作为系统工作频率时钟源。如需修改,先找到文件(CI13LC_SDK\projects\offline_asr_sample\src\user_config.h)配置的板级文件,例如“CI-F32XGT01D-V10.h”
#define BOARD_CONFIG_FILE           "CI-F32XGT01D-V10.h"
  • 找到板级文件(CI13LC_SDK\driver\boards\CI-F32XGT01D-V10.h),修改下面宏定义的值
#define USE_EXTERNAL_CRYSTAL_OSC    1                       //是否使用外部晶振。0:不使用外部晶振时钟;1:使用外部晶振时钟;
  • 或者直接调用接口配置晶振选择
#include "ci13lc_dpmu.h"

dpmu_set_src_source(DPMU_SRC_USE_OUTSIDE_OSC);   //使用外部晶振作为时钟源。

dpmu_set_src_source(DPMU_SRC_USE_INNER_RC);      //使用内部RC作为时钟源

4、外设系统时钟频率配置

  • 先明确几个概念:
  • AHB:Advanced High performance Bus,高级高性能总线,这是一种系统总线。主要用于高性能模块如CPU、DMA、UART等之间的连接
  • APB:是Advanced Peripheral Bus的缩写,这是一种外围总线。主要用于低频率的周围外设之间的连接,例如IIC、GPIO、PWM等
  • IPCORE_CLK:系统主频

  • 下图为时钟分频图,简易说明系统时钟和各外设时钟分频关系。

  • 晶振时钟通常为12.288 MHz
  • 晶振时钟经过倍频后得到PLL时钟。
  • PLL时钟经过一级分频可得到IPCORE_CLK主频,主频最大支持210M。
  • PLL时钟经过两级分频可得到PCLK。

模块框图

图1 时钟分频图
  • 有些外设基于IPCORE_CLK分频,有些外设基于PCLK分频,有些外设也能基于晶振时钟分频,下面会以表格的形式详细说明。
外围设备接口 描述 时钟来源 分频参数宽度 芯片默认分频值
IPCORE_CLK 提供给高速总线AHB的时钟,也是主频 来源于PLL时钟 6bit宽度(值可选 0 ~ 63) 0(1分频)
PCLK 提供给低速总线APB的时钟 来源于IPCORE_CLK 4bit宽度(值可选 0 ~ 15) 2
UART UART时钟决定波特率 来源于IPCORE_CLK 7bit宽度(值可选 0 ~ 127) 8
PWM PWM时钟决定输出频率 来源于PCLK(分频不可配,默认为1分频),或晶振时钟(分频可配) 7bit宽度(值可选 0 ~ 127) 16
TIMER TIMER时钟决定计数值 来源于PCLK(分频不可配,默认为1分频),或晶振时钟(分频可配) 7bit宽度(值可选 0 ~ 127) 16
IWDG IWDG时钟决定计数值 来源于晶振时钟 7bit宽度(值可选 0 ~ 127) 16
DTRFLASH DTRFLASH时钟决定CLK频率 来源于IPCORE_CLK 3bit宽度(值可选 0 ~ 7) 2
IIC IIC时钟决定SCL的频率 来源于PCLK(分频不可配,默认为1分频) - -
GPIO GPIO时钟决定IO翻转的频率 来源于PCLK(分频不可配,默认为1分频) - -
  • 可调用接口得到IPCORE_CLK等时钟的值,再根据分频值去推算每个外围设备接口的默认时钟
#include "ci_system.h"

void device_clk_test()
{
    //获取IPCORE_CLK主频有2种方式
    #if 0
    uint32_t ipcore_clk = dpmu_get_pll_frequency() / 1;      //默认为1分频,从PLL计算得到IPCORE_CLK主频
    #else
    uint32_t ipcore_clk = get_ipcore_clk();                  //从接口读取IPCORE_CLK主频
    #endif

    //获取PCLK时钟有2种方式
    #if 0
    uint32_t pclk = ipcore_clk / 2;                          //默认为2分频,从主频计算得到PCLK
    #else
    uint32_t pclk = get_apb_clk();                           //从接口读取PCLK时钟
    #endif

    //获取UART时钟有2种方式
    #if 0
    uint32_t uart_clk = ipcore_clk / 2;                      //SDK配置的是2分频,从主频计算得到UART时钟
    #else
    uint32_t uart_clk = get_ahb_clk() / 2;                   //AHB时钟和IPCORE_CLK时钟相同
    #endif

    //获取DTRFLASH时钟
    uint32_t system_dtrflash_clk = ipcore_clk / 1 ;          //SDK配置的是1分频,从主频计算得到DTRFLASH系统时钟
    uint32_t dtrflash_out_clk = system_dtrflash_clk / 2      //SDK配置FLASH控制器内部为2分频(2、4、6、8可选),FLASH输出的CLK最大为主频的1半

    //获取PWM或TIMER时钟有2种方式
    #if 0
    uint32_t pwm_timer_clk = pclk;                           //选择时钟源为PCLK时,PWM或timer的系统时钟为PCLK
    #else
    uint32_t pwm_timer_clk = get_src_clk() / 16;             //选择时钟源为晶振时,默认分频为16,计算得到PWM或timer的系统时钟
    #endif

    //获取IWDG的时钟
    uint32_t iwdg_clk = get_src_clk() / 16;                  //默认分频为16,计算得到IWDG的系统时钟

    //获取iic、gpio的时钟
    uint32_t iic_clk = pclk;
    uint32_t gpio_clk = pclk;
}
  • 如需修改各外设的分频值,可参考下列方式调用接口:
#include "ci13lc_scu.h"
#include "ci13lc_dpmu.h"
#include "ci13lc.h"
#include "ci_system.h"

void device_div_test()
{
    scu_set_div_parameter(IPCORE_BASE,2);       //设置IPCORE_CLK为2分频

    uint32_t ipcore_clk = dpmu_get_pll_frequency() / 2;
    set_ipcore_clk(ipcore_clk);                 //设置系统主频全局变量
    set_apb_clk(ipcore_clk);                    

    scu_set_div_parameter(APB_BASE,2);          //设置PCLK为2分频
    set_apb_clk(ipcore_clk/2);                  //设置PCLK全局变量

    scu_set_div_parameter(HAL_UART0_BASE,2);    //设置UART0为2分频
    scu_set_div_parameter(HAL_UART1_BASE,2);    //设置UART1为2分频
    scu_set_div_parameter(HAL_UART2_BASE,2);    //设置UART2为2分频
    scu_set_div_parameter(HAL_PWM0_BASE,4);     //设置PWM0、PWM1、PWM2、PWM3、TIMER0、TIMER1为4分频,共用1个分频器
    scu_set_div_parameter(HAL_IWDG_BASE,6);     //设置IWDG为6分频
    scu_set_div_parameter(HAL_DTRFLASH_BASE,2); //设置DTRFLASH为2分频
}

5、IIS时钟配置

5.1、IIS时钟分频关系介绍

  • 先了解几个IIS的专有名词,以下会用此类名词来说明IIS时钟配置。
  • IIS具有独立的时钟和数据信号,IIS接口由MCLK、SCK、LRCK、SDI、SDO这些信号线组成。
  • MCLK:主时钟,通常为音频采样率(LRCK的频率)的128/192/256/384倍。例如16000的音频采样率,倍频256,可得到4096000的MCLK。
  • SCK:位时钟,一个时钟周期传输一个bit数据,通常为音频采样率(LRCK时钟)的32、64倍。例如16000的音频采样率,倍频64,可得到1024000的SCK。
  • LRCK:帧时钟,用于切换左右声道的数据,IIS格式下LRCK为0表示当前数据帧是左声道数据,为1表示当前数据帧是右声道数据。
  • 更多关于IIS的内容,请参考文档《音频数字传输总线(IIS)》

  • IIS的时钟分频配置,有单独的一套配置接口,且支持多组IIS使用独立的时钟通路,以下仅说明做为master模式时的时钟配置流程。

  • 下图展示了IIS的时钟分频流程

模块框图

图2 IIS时钟分频图
  • 第1级时钟来源选择有4个,分别为:
//位于#include "ci13lc_scu.h"中

/**
 * @brief MCLK 时钟源SRC的 来源选择
 *
 */
typedef enum
{
    //!来源于 IPCORE 主频
    IIS_SRC_SOURCE_IPCORE   = 0,
    //!来源于 EXT_OSC 外部晶振
    IIS_SRC_SOURCE_EXT_OSC  = 1,
    //!来源于 INTERNAL RC 内部晶振
    IIS_SRC_SOURCE_INTER_RC = 2,
    //!来源于 PAD IN 从IIS_MCLK_PAD输入
    IIS_SRC_SOURCE_PAD_IN   = 3,
}IIS_Src_Source_t;
  • 第2级SRC_MCLK选择有3个,前2个可独立配置不同的分频和时钟来源(IIS_Src_Source_t),第3个由PAD输入,这3个SRC_MCLK可作为CODEC、MCLK0~MCLK1的时钟来源:
//位于#include "ci13lc_scu.h"中

/**
 * @brief MCLK 时钟来源选择
 *
 */
typedef enum
{
    //!来源于 SRC0
    IIS_MCLK_SOURCE_SRC0    = 0,  //可配置分频,分频宽度为10bit(0 ~ 1023)
    //!来源于 SRC1
    IIS_MCLK_SOURCE_SRC1    = 1,  //可配置分频,分频宽度为10bit(0 ~ 1023)
    //!来源于 PAD IN,
    IIS_MCLK_SOURCE_PAD_IN  = 3,  //不分频,从IIS_MCLK_PAD输入
}IIS_Mclk_Source_t;
  • 第3级MCLK的选择有2个,可独立配置不同的过采样率和SCK/LRCK比值,支持的过采样率有4个,支持的SCK和LRCK比值有2个
//位于#include "ci13lc_scu.h"中

/**
 * @brief MCLK 选择
 *
 */
typedef enum
{
    //!MCLK0
    IIS_MCLK_MCLK0    = 0,
    //!MCLK1
    IIS_MCLK_MCLK1    = 1,
}IIS_Mclk_t;

/**
 * @brief IIS MCLK 过采样率选择
 *
 */
typedef enum
{
    //!过采样率128
    IIS_MCLK_FS_128   = 0,
    //!过采样率192
    IIS_MCLK_FS_192   = 1,
    //!过采样率256
    IIS_MCLK_FS_256   = 2,
    //!过采样率384
    IIS_MCLK_FS_384   = 3,
}IIS_Mclk_Fs_t;

/**
 * @brief IIS SCK和LRCK的频率关系比值
 *
 */
typedef enum
{
    //!SCK/LRCK=32
    IIS_SCK_LRCK_WID_32  = 0,
    //!SCK/LRCK=64
    IIS_SCK_LRCK_WID_64  = 1,
}IIS_Sck_Lrck_Wid_t;
  • 第4级每个IIS的SCK和LRCK来源选择有5个,也能作为PAD输出SCK和LRCK的来源:
//位于#include "ci13lc_scu.h"中

/**
 * @brief IIS SCK/LRCK输出来源
 *
 */
typedef enum
{
    //!MCLK0产生的SCK/LRCK
    IIS_CLK_SOURCE_MCLK0     = 0,
    //!MCLK1产生的SCK/LRCK
    IIS_CLK_SOURCE_MCLK1     = 1,
    //!PAD输入的SCK/LRCK
    IIS_CLK_SOURCE_PAD_IN    = 3,
    //!codec_ad_sck_in
    IIS_CLK_SOURCE_CODEC_AD  = 4,
    //!codec_da_sck_in
    IIS_CLK_SOURCE_CODEC_DA  = 5,
}IIS_Clk_Source_t;

5.2、IIS时钟示例代码

  • 分一步配置的接口定义:
//位于#include "ci13lc_scu.h"中

void iis_clk_config(IIS_Clk_ConfigTypedef* config);
  • 调用一步配置接口,配置IIS0为master模式的时钟通路示例:
#include "ci13lc_scu.h"
#include "ci_system.h"

void init_iis_clk_sample()
{
    uint32_t sample_rate = 16000;                       //音频采样率
    uint32_t ipcore_clk = get_ipcore_clk();             //时钟源频率
    uint32_t fs = 256;

    float div = ((float)ipcore_clk / (float)sample_rate / (float)fs);  //根据时钟源频率、音频采样率和过采样率,计算分频值

    IIS_Clk_ConfigTypedef config = {0};
    config.device_select = IISNum0;                     //配置IIS0的时钟通路
    config.model_sel = IIS_MASTER;                      //配置为master模式
    config.src_cfg.source = IIS_SRC_SOURCE_IPCORE;      //选择时钟源为IPCORE_CLK主频
    config.mclk_cfg.src = IIS_MCLK_SOURCE_SRC0;         //选择MCLK_SRC0寄存器
    config.mclk_cfg.mclk = IIS_MCLK_MCLK0;              //选择MCLK0寄存器和SCK/LRCK比值
    config.mclk_cfg.fs = IIS_MCLK_FS_256;               //配置过采样率为256
    config.mclk_cfg.sck_lrck = IIS_SCK_LRCK_WID_64;     //配置SCK/LRCK比值为64
    config.clk_cfg = IIS_CLK_SOURCE_MCLK0;              //选择MCLK0产生的SCK和LRCK作为IIS0的时钟
    config.mclk_mode = IIS_MCLK_OUT;                    //通过PAD输出MCLK时钟
    config.clk_mode = IIS_SCKLRCK_OUT;                  //通过PAD输出SCK、LRCK时钟
    config.src_cfg.source_div = (uint16_t)div;          //配置分频参数
    iis_clk_config(&config);

    uint32_t lrck = sample_rate;                        //LRCK的频率
    uint32_t sck = sample_rate * 64;                    //计算得到SCK的频率
    uint32_t mclk = sample_rate * fs;                   //计算得到MCLK的频率
}
  • 分多步配置的接口定义:
//位于#include "ci13lc_scu.h"中

void scu_iis_src_config(IIS_Src_Config_t *config,IIS_Mclk_Source_t src);        //选择MCLK_SRC0/1寄存器,配置时钟来源和分频
void scu_iis_mclk_config(IIS_Mclk_Config_t *config);                            //选择MCLK0/1寄存器,配置过采样率和SCK/LRCK比值
void scu_iis_clk_config(IISNumx device, IIS_Clk_Source_t clk_source);           //配置IIS0/1的SCK、LRCK时钟来源
void scu_iis_codec_mclk_config(Codec_Channel_t channel, IIS_Mclk_Source_t src); //配置CODEC AD或CODEC DA的MCLK时钟来源
void scu_iis_pad_mclk_config(IIS_Mclk_Source_t src, IIS_Clk_Mode_t mode);       //配置MCLK PAD的输入输出模式,为输出时选择输出时钟来源
void scu_iis_pad_clk_config(IIS_Clk_Source_t clk_source, IIS_Clk_Mode_t mode);  //配置SCK、LRCK PAD的输入输出模式,为输出时选择输出时钟来源
  • 其实一步配置接口内,也是调用的分步接口。

6、注意事项

  • 通常配置晶振选项是在配置PLL时钟之前

  • 修改外设分频时,需关闭外设时钟,再修改分频值,再打开时钟。