KDocs 研发资料库
  • 音频技术应用文档入口汇总
  • 杰理WINDOWS环境安装及其他事项
  • LINUX安装和编译
  • Linux环境编译SDK教程(ubuntu18.04)
  • 音频类补丁汇总表
  • 认证资料获取汇总(最新资料后台会更新)
  • 《Hi-Res申请指南v1.0》
  • FreeRTOS 开源协议版本
  • uCOS 开源协议版本信息
  • 各个模块关键资料汇总
  • 软件调试方法
  • Makefile编译
  • 提bug的规范
  • 常规设备使用指导
  • 对外特别发布开发注意点信息汇总
  • AD697X软件问题整理
  • AC700N软件问题整理
  • AC701X耳机软件问题整理
  • 951&961软件问题整理
  • AC104X软件问题整理
  • AC128N问题整理文档
  • 可视化工具调试问题整理
  • 耳机资料汇总
  • AC704N、 AC705N相关应用
  • AC695N&AC696N&AC608N音箱问题整理
  • JL701N音箱问题整理
  • AC692X软件问题整理
  • AC706N音箱问题整理
  • JL701N音箱问题整理(可视化工具SDK)
  • JL703N音箱问题整理
  • JL709N(JL689N)音箱问题整理
  • JL7094系列-入门到进阶开发指导
  • AC210N音箱问题整理
  • 无线麦系列版本支持指南
  • AW32N无线麦问题整理
  • lAD697X&JL701X 无线麦软件共性问题整理
  • AC706N无线麦问题整理
  • AW36N无线麦问题整理
  • AC710X无线麦问题整理
  • 唤醒源获取及唤醒IO设置
  • 电源
  • LVD
  • 长按复位配置方法
  • 低功耗应用
  • TIMER
  • UART
  • SPI
  • 内部FLASH空间添加用户自定义区域
  • IIC
  • GPIO
  • MCPWM
  • SD&U盘
  • 时钟&晶振
  • GPCNT
  • IO口crossbar映射功能
  • 文件系统使用总结
  • 复用应用
  • LINEIN_AUX相关应用
  • IIS音频接口应用
  • SPDIF模式相关(HDMI_ARC、光纤、同轴)
  • PDM LINK
  • 外设相关应用
  • 蓝牙相关
  • 杰理蓝牙距离调试文档
  • TWS耳机配对方式使用及生产把控指南
  • GFP谷歌快连及其认证流程指引
  • 蓝牙发射器(bt_emitter)相关
  • BLE应用
  • 关于提升BLE传输速率说明
  • BLE测试数据
  • MUSIC 模式相关应用
  • MIDI音乐实现
  • PC相关应用
  • FM相关应用
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20250107
  • fm应用详细设计说明书
  • 杰理FM硬件指南-20230315
  • ADC模块
  • AUDIO相关应用
  • 新Tools的音效调试使用
  • 混响应用使用说明
  • 音效调式
  • 音箱耳机低音小音量增强实现方法
  • DAC输出功率调试
  • DAC性能测试指南
  • 针对各类底噪、电流声分析流程
  • 录音相关应用
  • OPUS编解码相关
  • RTC相关应用
  • 升级相关
  • UI相关应用
  • 通话调试流程指南
  • 通话相关应用
  • 省电容mic使用手册
  • 如何测试验证手表通话系统的语音失真 V1.0
  • AC695X_AC696X_AD697X 常见通话问题处理参考资料
  • 通话调试问题确定步骤
  • 内置触摸调试指南
  • 低功耗内置触摸介绍V2.2
  • 触摸相关文档
  • AC697X、AC698X内置触摸调试及整改方法V1.0
  • 产测相关应用
  • AC63X BLE DUT测试介绍
  • 兆华序列使用简易说明
  • JL_1T2蓝牙测试盒音频文件更换说明
  • ENC相关应用入口汇总
  • ANC相关应用入口汇总
  • JL DMS通话调试手册-V3.9.4
  • ANC-ENC结构设计要点-20240407
  • 半入耳式ANC耳机器件选型与结构设计指南V1.0
  • JL 耳道自适应调试指南
  • ANC相关问题处理
  • ANC调试文档
  • 评估蓝牙耳机通话上行降噪性能的方法 V1.0 (2)
  • FCC 或者 BQB 认证相关应用
  • BQB profile 测试中常遇到的问题点汇总
  • 蓝牙参数整理20210811
  • 杰理科技认证问题参考
  • 无线音频产品开发指南
  • 无线麦系列从入门到进阶开发指导
  • 量产烧录相关说明
  • 一拖八烧录器远程过程调用说明
  • 量产相关建议
  • EffectTool(eq)调试工具说明文档
  • AC897AD697系列的EQ调试方法-V3
  • 杰理调音指南-20220622
  • 音效模块总结
  • 简要调音步骤指引(可视化)
  • 耳机充电与通信调试指南
  • 充电仓硬件调试指南
  • 充电仓软件问题整理
  • AC951常用说明
  • AC951_AC961_开发板使用说明V1.0
  • 彩屏仓AC982 入门指导及FAQ
  • 蓝牙音频APP相关应用
  • 手机APP的简介和开发流程
  • 蓝牙音频系列-硬件设计指南
  • 静电测试及整改方法-20220706
  • TWS耳机底噪整改指南V1.2
  • 杰理蓝牙距离调试文档
  • 蓝牙RF硬件设计与调试V1.1-20250219
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20241228
  • 音效调试指南
  • 无线话筒K歌音箱标准开发流程
  • 杰理科技 700N TWS耳机产品标准-202303
  • 杰理科技 701N 广播产品标准-202303
  • JL-HAT ANC高效产测自适应
  • 无线话筒测试板使用介绍
  • 一拖八频偏校准使用说明
  • 领夹麦产测工具使用介绍
  • Dongle量产测试说明
  • Dongle+Tws或头戴式 SDK通过工具绑定配对功能说明文档
  • 双麦ENC产测宏配置验证方法 V1.0
  • JL耳机方案麦克风声学测试指令_V1.0
  • JL耳机方案麦克风声学测试指令_V2.0
  • JL_ENC自动测试命令_V0.0.1
  • JL蓝牙测试盒用例说明
  • LDAC自测环境搭建_ubuntu
  • 延迟小板使用手册
  • 杰理库文件的制作及添加实现过程
  • 关于 AC635N&AC636N系列免晶振兼容性补丁 说明
  • 关于 AC63系列VM兼容性修复补丁_20250224 说明
  • 关于 AC632N &AE632N_ 蓝牙& 低功耗兼容性修复补丁 说明
  • AD698N和AC638N电压优化补丁V3说明
  • 关于 AC635N&AC636N漏电和E&G版兼容联合补丁 说明
  • AD698N和AC638N电压优化补丁V2说明
  • 702相关应用
  • 2024-4-30 发布歌词显示SDK开发注意事项
  • BQB RF & FCC 认证测试固件问题汇总及源码
  • BQB profile 测试中常遇到的问题点汇总
  • 进dut测试模式方法及固件
  • 704-频偏修改bin文件合集
  • 701手表BQB PROFILE认证注意事项
  • 认证的干扰规避整改
  • 海外CRA认证报告生成说明
  • JL700N可视化工具问题处理文档
  • JL701X可视化工具问题处理文档
  • JL701N_earphone_release_v1.6.0_ANC 低功耗问题补丁
  • JL708X可视化工具问题处理文档
  • JL709N可视化工具问题处理文档
  • JLstudio可视化工具使用说明
  • 一拖二-串口_蓝牙_app在线EQ、通话参数及调试方式和内置触摸调试
  • 可视化JL701M_DONGLE_SDK添加MIC为发射源
  • 可视化JL701M_DONGLE_SDK添加按键切换usb audio与MIC发射源
  • JL701M_DONGLE_SDK_1.0.0_dongle输入linein输出dac
  • 701可视化_a2dp_to_le_demo说明
  • 耳机系列demo汇总
  • JL7018F&JL7006F_7003F AUX IIS
  • 一键连接应用
  • 普通SDK动态开关一拖二功能
  • 蓝牙分析仪(EllisysBluetoothAnalyzer)抓包例程
  • TWS配对常见应用
  • APP自定义按键的demo
  • AC700N 播歌双EQ DEMO示例及说明
  • AC698V164 MIC与蓝牙音乐共同输出DAC demo
  • 添加第三方算法以及多算法授权流程
  • 空间音频配置方法
  • 普通高低电平TWS耳机控制通讯
  • 入耳检测状态更新demo解析
  • 资源优化(非可视化的SDK)
  • 资源优化(可视化SDK)
  • 翻译耳机、语音识别应用demo
  • 耳机抗干扰问题排查和优化
  • AC698D2 抗干扰优化
  • AC696X软件问题整理
  • AC695X软件问题整理
  • AC695X软件问题整理_1722249702
  • AC608X软件问题整理
  • JL701N_2T1_DUPLEX 应用软件问题汇总
  • le_audio_1.0.0_patch05 以及之前的版本IRkey 功能异常修改
  • AC706N-le_audio-200SDK有线_无线麦录音demo
  • jl701n_le_audio_v200patch02 IO串口升级修改串口单次发送字节长度的修改办法
  • 703创建IIS 输入dac输出音频流demo
  • 703将媒体流音频同时上传PC_mic录音demo实现
  • 703四路IIS输入输出demo
  • 底噪调试
  • AW328A烧录说明
  • 文档合集
  • AC706N_wireless_mic_release_PATCH_20240712 补丁 说明
  • AC706N_wireless_mic_release_PATCH_20240726 补丁 说明
  • AC706N_wireless_mic_release_V1.0.0、1.0.1、1.0.2 补丁 说明
  • AC706N_wireless_mic_release_V1.1.2 中的2T1应用 RX端不绑定配对,TX端实现绑定配对的修改方法
  • 各系列省晶振实现方法
  • iis tx rx说明文档
  • spdif信号
  • 蓝牙电话本
  • 安卓手机同步时间补丁
  • CDC配置
  • PC模式下增加Teams唤起功能
  • 杰理HDMIARC开发实现过程
  • AC701N patch06之前的版本用第三方算法节点实现新版本的pcm delay节点功能
  • (K歌音箱)各SDK音效配置相关说明
  • 长文件录音
  • 点阵屏歌词字库相关(蓝牙歌词,普通歌词)
  • 字模提取工具说明
  • 音箱可视化彩屏-入门到进阶开发指导
  • 彩屏LVGL UI设计及工具使用
  • 使用内部UI框架进行UI调试的系列步骤
  • AD101C使用强制升级工具spi 烧录不了问题处理(测试版本)
  • AD161扩展灯板说明文档
  • 歌词显示器开发注意项
  • 使用硬件数字增益控制通话下行音量(可视化)
  • 杰理小牛产测资料
  • ENC配置说明
  • 通话调试流程指引
  • ANC相关功能demo
  • 无线麦硬件资料汇总
  • 无线麦相关应用
  • 无线麦复杂功能补丁包汇总
  • 无线话筒形态SDK程序&开发经验&问题点分享
  • 双模式结合应用问题汇总
  • 无线麦距离优化案例
  • 无线麦系列中的双工形态(duplex)演变开发对讲机方案开发资料
  • 音箱入门到进阶指导文档(编写中)
  • 蓝牙耳机品控和生产技巧
  • 982过_欠压标志获取异常
  • 如何获取最新涂鸦SDK及库文件
  • 无线话筒K歌音响-调音标准流程
  • 无线话筒产测流程

TIMER

📎 原始文档:https://www.kdocs.cn/l/clz7XRyAheQk TIMER

  1. 概述 Timer是一个集合了定时/计数/捕获功能于一体的多功能定时器。
    它的驱动源可以选择片内时钟或片外信号。
    它带有一个可配置的最高达 64 的异步预分频器, 用于扩展定时时间或片外信号的最高频率。
    它还具有上升沿/下降沿捕获功能,可以方便的对片外信号的高电平/低电平宽度进行测量。
  • 芯片产品介绍
芯片位数捕获模式反向输出IOMAP
AC695X16向上/向下有支持
AC696X16向上/向下有支持
AC701X32向上/向下有支持
  1. 寄存器说明

  2. 寄存器说明,此处以695数据手册举例 imageimageimage

  3. 定时器应用

  4. 定时功能 (此处以696,led7_timer.c文件举例)

static void timer2_isr()
{
    //local_irq_disable();     //需要极准确的定时效果时开启
    TIMER_CON |= BIT(14);      //清中断标志位
    //用户自定义代码
    //......
    //local_irq_enable();      //需要极准确的定时效果时开启
}

int led7_timer_init()
{
    u32 prd_cnt;
    u8 index;

    printf("------------%s :%d", __func__, __LINE__);

    for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
        prd_cnt = TIMER_UNIT_MS * (APP_TIMER_CLK / 1000) / timer_div[index];
        if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
            break;
        }
    }
    __this->index   = index;
    __this->prd     = prd_cnt;

    TIMER_CNT = 0;
    TIMER_PRD = prd_cnt; //1ms
    request_irq(TIMER_VETOR, 6, timer2_isr, 0); //最高优先级7,需要极准确的定时效果时开启
    TIMER_CON = (index << 4) | BIT(0) | BIT(3);

    printf("PRD : 0x%x / %d", TIMER_PRD, clk_get("timer"));

    return 0;
}

701N V160 timer demo

extern const int CONFIG_CPU_UNMASK_IRQ_ENABLE;//需要极准确的定时效果时开启不可屏蔽中断
static JL_TIMER_TypeDef *TIMER = NULL;
static int irq_id = -1;
#define TIMER_UNIT_US           100//设置中断时间,单位us
#define MAX_TIME_CNT 0x7fff //分频准确范围,更具实际情况调整
#define MIN_TIME_CNT 0x0030
static const u16 timer_div[] = {
    /*0000*/    1,
    /*0001*/    4,
    /*0010*/    16,
    /*0011*/    64,
    /*0100*/    2,
    /*0101*/    8,
    /*0110*/    32,
    /*0111*/    128,
    /*1000*/    256,
    /*1001*/    4 * 256,
    /*1010*/    16 * 256,
    /*1011*/    64 * 256,
    /*1100*/    2 * 256,
    /*1101*/    8 * 256,
    /*1110*/    32 * 256,
    /*1111*/    128 * 256,
};

static u32 time_tick_cnt = 0;

SET_INTERRUPT
static void user_timer_isr()
{
    if(CONFIG_CPU_UNMASK_IRQ_ENABLE){
        unmask_enter_critical();
    }
    else{
        local_irq_disable();
    }
    TIMER->CON |= BIT(14);      //清中断标志位
    //用户自定义代码
    //......
    time_tick_cnt++;
    if(CONFIG_CPU_UNMASK_IRQ_ENABLE){
        unmask_exit_critical();
    }
    else{
        local_irq_enable();
    }
    if (time_tick_cnt % 10000 == 0)
    {
        printf("time_tick_cnt:%d\n", time_tick_cnt);
    }
}

static u8 timer_idle_query(void)
{
    return TIMER == NULL;
}

REGISTER_LP_TARGET(timer_lp_target) = {
    .name = "tiemr",
    .is_idle = timer_idle_query,
};

int user_timer_uninit();
int user_timer_init()
{
    u32 prd_cnt;
    u8 index;
    u32 app_timer_clk = 24000000;//时钟用STD24M

    user_timer_uninit();

    printf("------------%s :%d", __func__, __LINE__);
    printf("%d %d %d %d %d %d\n", JL_TIMER0->CON, JL_TIMER1->CON, JL_TIMER2->CON, 
                                  JL_TIMER3->CON, JL_TIMER4->CON, JL_TIMER5->CON);

    /*if((JL_TIMER0->CON & 0x3) == 0) {
        TIMER = JL_TIMER0;
        irq_id = IRQ_TIME0_IDX;
    }
    else */if((JL_TIMER1->CON & 0x3) == 0) {
        TIMER = JL_TIMER1;
        irq_id = IRQ_TIME1_IDX;
    }
    else if((JL_TIMER2->CON & 0x3) == 0) {
        TIMER = JL_TIMER2;
        irq_id = IRQ_TIME2_IDX;
    }
    else if((JL_TIMER3->CON & 0x3) == 0) {
        TIMER = JL_TIMER3;
        irq_id = IRQ_TIME3_IDX;
    }
    else if((JL_TIMER4->CON & 0x3) == 0) {
        TIMER = JL_TIMER4;
        irq_id = IRQ_TIME4_IDX;
    }
    else if((JL_TIMER5->CON & 0x3) == 0) {
        TIMER = JL_TIMER5;
        irq_id = IRQ_TIME5_IDX;
    }
    else{
        return -1;
    }

    for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
        prd_cnt = TIMER_UNIT_US * (app_timer_clk / 1000000) / timer_div[index];
        if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
            break;
        }
    }
    printf("irq_id %d PRD : 0x%x / %d", irq_id, prd_cnt, app_timer_clk);

    TIMER->CNT = 0;
    TIMER->PRD = prd_cnt - 1;
    request_irq(irq_id, 2, user_timer_isr, 0);
    if(CONFIG_CPU_UNMASK_IRQ_ENABLE){
        irq_unmask_set(irq_id, 1, 0);
    }
    TIMER->CON = (index << 4) | BIT(0) | BIT(11)| BIT(12);//BIT(11)| BIT(12):时钟用STD24M

    printf("PRD : 0x%x / %d", prd_cnt, app_timer_clk);

    return 0;
}

int user_timer_uninit()
{
    if(TIMER == NULL){
        return 0;
    }
    TIMER->CON = BIT(14);
    unrequest_irq(irq_id);
    time_tick_cnt = 0;
    TIMER = NULL;
    return 0;
}

可视化timer demo
不可屏蔽中断(700N不支持)的修改见:项目帮助文档->7. 操作系统->7.10. 不可屏蔽中断demo

void timerx_irq_callback(int tid)
{
    static int count = 0;
    count++;
    if(count % 10000 == 0){
        printf("timerx_irq_callback\n");
    }
}

#include "gptimer.h"
static int tid = -1;
void user_timer_init(void)
{
    const struct gptimer_config gptimer = {
        .resolution_us = 100,//100us中断
        .irq_cb = timerx_irq_callback,//中断回调函数
        .irq_priority = 2,//中断优先级
        .tid = -1,//指定定时器id,-1为驱动自动选择空闲定时器
    };
    tid = gptimer_init(&gptimer);
    gptimer_start(tid);
}

int user_timer_uninit()
{
    if(tid != -1){
        gptimer_deinit(tid);
    }
}

拓展:定时器us级延时功能

  1. 捕捉功能
  • 701NDemo 双边沿捕获功能
    代码:JL701N音箱问题整理.otl
#include "asm/includes.h"
#include "timer.h"
#include "generic/gpio.h"
#include "asm/mcpwm.h"

static u8 timer_io_port = IO_PORTC_08;
static u32 timer5_clk_set;

___interrupt void timer5_double_edge_isr(void)
{
    JL_TIMER5->CON |= BIT(14);  // 清中断标志位
    u32 timer_cnt = JL_TIMER5->PRD;
    JL_TIMER5->CNT = 0;         // 清计数器

    u32 cur_level_sustain_us = (u64)timer_cnt * 1000000 / timer5_clk_set;

    if(gpio_read(timer_io_port))
    {
        JL_TIMER5->CON |= (BIT(1) | BIT(0));// 如果当前为上升沿,则配置为下降沿触发
        printf("low_level cnt=%d, us=%d\n", timer_cnt, cur_level_sustain_us);
    }
    else
    {
        JL_TIMER5->CON &= ~BIT(0); // 如果当前为下降沿,则配置为上升沿触发
        printf("high_level cnt=%d, us=%d\n", timer_cnt, cur_level_sustain_us);

    }

}

void user_timer5_edge_capture_init(void)
{
    gpio_ich_sel_iutput_signal(timer_io_port, INPUT_CH_SIGNAL_TIMER5_CAPTURE, INPUT_CH_TYPE_GP_ICH);
    gpio_set_direction(timer_io_port, 1);
    gpio_set_die(timer_io_port, 1);
    gpio_set_pull_up(timer_io_port, 1);
    gpio_set_pull_down(timer_io_port, 0);

    request_irq(IRQ_TIME5_IDX, 5, timer5_double_edge_isr, 0);

    // 配置时钟源STD_24M为时钟源,配置分频系数为4,配置捕获模式端口为 IO Mux In,初始化为下降沿触发
    JL_TIMER5->CON = ((0b0110 << 10) | (0b0001 << 4) | BIT(1) | BIT(0));
    timer5_clk_set = 24000000 / 4;

    printf("timer5_edge_capture_init, timer5_clk_set=%d\n", timer5_clk_set);

    // 初始化一个mcpwm通道,用于测试验证用
    timer_pwm_init(JL_TIMER3, IO_PORTG_07, 1000, 2000);
}
  • 696NDemo 代码:AC695N&AC696N&AC608N音箱问题整理.otl
//基于696程序  存在一些IO口无法做此功能,先测试,再画板 !!!!!!
#define TIMER5                      7 //见irflt.h
#define CATCH_TIMER                 TIMER5
#define CATCH_IRQ_TIME_IDX          IRQ_TIME5_IDX
#define CATCH_TIME_REG              JL_TIMER5
#define CATCH_GPIO                  IO_PORTB_06
int num = 0;
void timer_ms()
{
    static int flag = 0;
    if(flag){
        gpio_set_pull_down(IO_PORTA_02,0);
        gpio_set_pull_up(IO_PORTA_02,0);
        gpio_set_direction(IO_PORTA_02,1);
        flag = 0;
    }
    else{
        gpio_set_pull_down(IO_PORTA_02,0);
        gpio_set_pull_up(IO_PORTA_02,0);
        gpio_set_direction(IO_PORTA_02,0);
        gpio_set_output_value(IO_PORTA_02,0);
        putchar('0');
        flag = 1;        
    }
}
___interrupt
void timer_catch_isr(void)
{
    CATCH_TIME_REG->CON |= BIT(14);
    u16 bCap1 = CATCH_TIME_REG->PRD;     //上次中断到这次的时间,可以用于计时
    CATCH_TIME_REG->CNT = 0;
    num++;                               //计数
}

void timer_100ms()
{
    printf("num == %d\n",num);
    num = 0;
}

void timer_catch_init()
{
    printf("timer_catch_init\n");
    //IO口配置
    gpio_irflt_in(CATCH_GPIO);
    gpio_set_direction(CATCH_GPIO, 1);
    gpio_set_die(CATCH_GPIO, 1);
    gpio_set_pull_up(CATCH_GPIO, 1);
    gpio_set_pull_down(CATCH_GPIO, 0);
    //设置时钟
    SFR(JL_IOMAP->CON0, 5, 3, CATCH_TIMER);                           //TIMER5:7  irflt.h
    CATCH_TIME_REG->CON = 0;
    CATCH_TIME_REG->CON |= (0b10 << 2);                        //选择晶振时钟源:24MHz
    CATCH_TIME_REG->CON |= (0b0001 << 4);                    //时钟源4分频
    //设置周期,初始值,定时器模式
    CATCH_TIME_REG->PRD = OSC_Hz / (4 * 1000);
    CATCH_TIME_REG->CNT = CATCH_TIME_REG->PRD;
    CATCH_TIME_REG->CON |= BIT(14);
    CATCH_TIME_REG->CON |= (0b11 << 0);
    request_irq(CATCH_IRQ_TIME_IDX, 5, timer_catch_isr, 0);
    sys_timer_add(NULL,timer_100ms,100);                    //定时读取中断次数
    sys_timer_add(NULL,timer_ms,1);                         //设置生成波形,供中断采集,不准,非1ms
}

701_sdk

void io_ext_interrupt_test(void)
{
    set_io_ext_interrupt_cbfun(my_io_isr_cbfun);
    io_ext_interrupt_init(0, IO_PORTA_04, 1);
    io_ext_interrupt_init(1, IO_PORTB_01, 1);
    io_ext_interrupt_init(2, IO_PORTC_02, 1);
    io_ext_interrupt_init(3, IO_PORTG_01, 1);
    extern void wdt_clear();
    while (1) {
        wdt_clear();
    }
}

  • 695NDemo 代码:AC695N&AC696N&AC608N音箱问题整理.otl
  1. 微秒延时使用的定时器 701_sdk
//ums timer
#define USER_UDELAY_TIMER JL_TIMER3//微秒延时使用的定时器 地址 可以其他的定时器
#define USER_UDELAY_TIMER_IRQ IRQ_TIME3_IDX//微秒延时使用的定时器 终端号

/**
 * @brief 初始化 自定义微秒延时定时器
 *
 */
void user_udelay_init(void){
    bit_clr_ie(USER_UDELAY_TIMER_IRQ);
}

/**
 * @brief 自定义微秒延时接口
 *
 * @param usec 延时时间 单位微秒
 */
__attribute__((weak)) void user_udelay(u32 usec){
    USER_UDELAY_TIMER->CON = BIT(14);//0x4000;
    USER_UDELAY_TIMER->CNT = 0;
    USER_UDELAY_TIMER->PRD = (24* usec/4)  ;//延时时间=时钟源频率/分频系数*计数次数
    USER_UDELAY_TIMER->CON = BIT(0)|BIT(3)|BIT(4);//BIT(0)定时计数模式 BIT(3):晶振为时钟源 BIT(4):4分频
    while ((USER_UDELAY_TIMER->CON & BIT(15)) == 0);
    USER_UDELAY_TIMER->CON = BIT(14);
}

void user_delay_us(u32 usec)
{
    user_udelay(usec);
}
  1. PWM 重要参数介绍:占空比、频率
  • 占空比: 一个周期内高电平占整个周期的时间比。
    image

以AC695N为例子(下图寄存器):输出的占空比取决于设置的我们两个寄存器Tx_PR,Tx_PWM的值。其Tx_PWM实际取决高电平的宽度(0~Tx_PR:0为占空比为0,一直低电平)。

占空比计算公式 N = (Tx_PWM / Tx_PR) * 100%

image

  • 频率: PWM波形一般由一个固定的时钟控制产生,一般时钟的频率是固定的,所以有以下关系: 时钟 = 频率 * 周期时间。
    周期时间:就是一个周期内可以改变的精度,如果一个周期内有100个时间点,那占空比控制的精度就是1/100。
    所以当提高频率时,占空比控制的精度就会下降。

参考代码:
使用mcpwm.c文件的timer_pwm_init函数产生。
timer_pwm_init函数介绍:

#define     OSC_Hz      24000000
/**
 * @param JL_TIMERx : JL_TIMER0/1/2/3/4/5
 * @param fre : 频率,单位Hz,不小于95
 * @param duty : 初始占空比,0~10000对应0~100%
 * @param port : pwm脚,可选硬件脚,也可选非硬件脚。(建议选择硬件引脚)
 * @param output_ch : 映射通道,当pwm脚选择非硬件脚时有效,这时我们给他分配output_channel 0/1/2
 */
int timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 fre, u32 duty, u32 port, int output_ch)
{
    u32 hw_port;
    switch ((u32)JL_TIMERx) {
    case (u32)JL_TIMER0 :
        hw_port = IO_PORTA_05;
        break;
    case (u32)JL_TIMER1 :
        hw_port = IO_PORTC_04;
        break;
    case (u32)JL_TIMER2 :
        hw_port = IO_PORTB_03;
        break;
    case (u32)JL_TIMER3 :
        bit_clr_ie(IRQ_TIME3_IDX);
        hw_port = IO_PORTB_05;
        break;
    case (u32)JL_TIMER4 :
        hw_port = IO_PORTA_01;
        break;
    case (u32)JL_TIMER5 :
        hw_port = IO_PORTB_07;
        break;
    default:
        return (-1);
    }
    if ((output_ch == (-1)) && (hw_port != port)) {
        //not support output_ch
        return (-1);
    }
​
    //初始化timer
    JL_TIMERx->CON = 0;
    JL_TIMERx->CON |= (0b10 << 2);                      //选择晶振时钟源:24MHz
    JL_TIMERx->CON |= (0b0001 << 4);                    //时钟源4分频
    JL_TIMERx->PRD = OSC_Hz / (4 * fre);                //设置周期
    JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / fre; //0~10000对应0~100g
    JL_TIMERx->CNT = 0;                                 //清计数值
    JL_TIMERx->CON |= (0b01 << 0);                      //计数模式
​
    if (hw_port == port) {
        gpio_set_die(hw_port, 1);
        gpio_set_pull_up(hw_port, 0);
        gpio_set_pull_down(hw_port, 0);
        gpio_set_direction(hw_port, 0);
        JL_TIMERx->CON |= BIT(8);                       //PWM使能
    } else {
        gpio_output_channle(port, output_ch);
        return 1;
    }
    return 0;
}​

参数输入如上图所示,注意点如下:

  1. 每个定时器都对应一个固定的IO口,如TIMER1->IO_PORTA_12,如果在芯片上能找到对应定时器的对应脚则优先使用。没有对应IO口的情况下,则可以任选一个IO口,然后通过通道映射的方式来使选择的IO口产生PWM。 示例:
    timer_pwm_init(JL_TIMER3, 2000, 5000, IO_PORTB_05, 0); //对应IO口产生
    timer_pwm_init(JL_TIMER3, 2000, 5000, IO_PORTB_04, CH2_T3_PWM_OUT); //通道映射
    通道可以在gpio.h文件查询到,CHx_Tn_PWM_OUT,x代表通道x,n代表定时器,每个通道只能映射一个IO口,定时器必须跟选择的定时器一致。
    备注:定时器无论是正常对应IO口输出,映射输出都只会产生一个PWM波形,由最后执行的函数为准,且映射输出时,定时器对应的IO口也会产生对应波形,所以最优先选择定时器对应的IO口,避免造成IO口浪费。

  2. 占空比,公版代码的占空比输入不是0-1000控制0-100%,如果需要改成此效果改此处: JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%

  3. 时钟选择: JL_TIMERx->CON |= (0b10 << 2); //选择晶振时钟源:24MHz
    公版SDK默认选择晶振时钟源,695,696均为24MHZ,608由于不带晶振的缘故需要选择系统时钟源,配置如下:
    JL_TIMERx->CON |= (0b00 << 2); //选择系统时钟源
    695,696的系统时钟源一般会比晶振时钟源的时钟高,695为60MHZ,如果需要产生高频率的PWM波形时可以改为系统时钟源。

DEMO

  • AC696X 对于使用 AC696X 需要 PWM 功能的, 可以见如下参考例子, 详情请见网盘链接:
    链接: https://pan.baidu.com/s/166ibbi08er-tHo5LVHr11Q
    提取码: s2qq
    image

FAQ

Prev
低功耗应用
Next
UART