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歌音响-调音标准流程
  • 无线话筒产测流程

FM相关应用

📎 原始文档:https://www.kdocs.cn/l/cordJVMmoNy3 FM相关应用
本文档旨在指导用户快速使用杰理方案调试FM相关的应用,进行快速初步了解。

概述:

AC692X、AC695X、AC696X系列芯片支持FM功能,FM功能描述可以在“用户手册”中的”复杂设备“中有所描述
AC692X:

  • FM调频立体声接收系统,覆盖范围:76-108MHz,步进50/100KHz(与蓝牙不可同时用) AC696X:
  • FM调频立体声接收系统,覆盖范围:76-108MHz,步进50/100KHz(与蓝牙不可同时用) AC695X:
  • FM调频立体声接收系统,覆盖范围:76-108MHz,步进50/100KHz(与蓝牙可同时用)
  • FM调频立体声发送系统,覆盖范围:76-108MHz,步进50/100/200KHz(与蓝牙可同时用)(FM发射用AC6952E做 )

通常FM接收功能,分内置FM和外置FM两种,内置FM使用杰理芯片内部的射频模块进行数据的解调,最后将数据发送到DAC模块,从而输出声音,外置FM使用类似于RDA5807等芯片,经过该芯片解调后输出到DAC,杰理方案通过LINEIN/AUX的模块采集输出到DAC。

FM功能相应的代码配置,在各板级头文件件中,如apps\soundbox\board\br23\board_ac695x_demo\board_ac695x_demo_cfg.h

//*********************************************************************************//
//                                  fm 配置                                     //
//*********************************************************************************//
#define TCFG_FM_ENABLE                            TCFG_APP_FM_EN // fm 使能
#define TCFG_FM_INSIDE_ENABLE                    ENABLE
#define TCFG_FM_RDA5807_ENABLE                    DISABLE //需要使能软件IIC模块
#define TCFG_FM_BK1080_ENABLE                    DISABLE //需要使能软件IIC模块
#define TCFG_FM_QN8035_ENABLE                    DISABLE //需要使能软件IIC模块

#define TCFG_FMIN_LADC_IDX                1                // linein使用的ladc通道,对应ladc_list
#define TCFG_FMIN_LR_CH                    AUDIO_LIN1_LR
#define TCFG_FM_INPUT_WAY               LINEIN_INPUT_WAY_ANALOG//用于配置FM的输入来源。如模拟,则是内置FM模块,如是ADC则是使用LINEIN模块采集

#if (TCFG_FM_INSIDE_ENABLE && TCFG_FM_ENABLE)
#if (((TCFG_USER_TWS_ENABLE) || (RECORDER_MIX_EN) || (TCFG_MIC_EFFECT_ENABLE)))
#define TCFG_CODE_RUN_RAM_FM_MODE                     DISABLE_THIS_MOUDLE      //FM模式 代码跑ram,用于减少访问内部FLASH的高频干扰,增加FM收音灵敏度
#else
#define TCFG_CODE_RUN_RAM_FM_MODE                     ENABLE_THIS_MOUDLE      //FM模式 代码跑ram,用于减少访问内部FLASH的高频干扰,增加FM收音灵敏度
#endif
#else
#define TCFG_CODE_RUN_RAM_FM_MODE                     DISABLE_THIS_MOUDLE     //FM模式 代码跑ram,用于减少访问内部FLASH的高频干扰,增加FM收音灵敏度
#endif /*(TCFG_FM_INSIDE_ENABLE && TCFG_FM_ENABLE)*/

#if (TCFG_CODE_RUN_RAM_FM_MODE && TCFG_UI_ENABLE)
#undef TCFG_LED7_RUN_RAM
#define TCFG_LED7_RUN_RAM                     ENABLE_THIS_MOUDLE     //led7跑ram 不屏蔽中断(需要占据2k附近ram)
#endif /*(TCFG_CODE_RUN_RAM_FM_MODE && TCFG_UI_ENABLE)*/

//*********************************************************************************//
//                                  fm emitter 配置                                     //
//*********************************************************************************//
#define TCFG_APP_FM_EMITTER_EN                  DISABLE_THIS_MOUDLE
#define TCFG_FM_EMITTER_INSIDE_ENABLE            DISABLE
#define TCFG_FM_EMITTER_AC3433_ENABLE            DISABLE
#define TCFG_FM_EMITTER_QN8007_ENABLE            DISABLE
#define TCFG_FM_EMITTER_QN8027_ENABLE            DISABLE

代码:

  • FM接收: 在app_main.c中会进入到app_fm_task,该模式用于FM接收功能。
    应用端开发重点关注 ..\apps\soundbox\task_manager\fm文件夹下的源文件,
    其中
    fm.c是主要用于接收按键消息,设备消息,公共消息,根据相应的消息进行处理
    fm_api.c提供了频道搜索,频道检索,频道切换,频道增加删除,静音等api接口
    fm_rw.c提供频点存储,读取,检查的api接口
    由于FM接收功能可以通过内置FM模块或外置FM芯片来实现,需要通过fm_manage.c来管理各类的驱动代码。
    路径 ..\apps\common\device\fm 文件夹下有包含各类芯片的驱动,
    fm_manage.c用于管理FM驱动驱动代码,rda5807,qn8035,bk1080,fm_inside是各类驱动的文件夹

  • FM发射: FM发射功能的驱动代码在路径..\apps\common\device\fm_emitter,该文件夹下包含了驱动代码。
    FM数据编码发射源代码在路径..\cpu\br23\audio_common,audio_fmtx.c和audio_fmtx.h包含了编码的代码。

FM接收:

1、内置FM搜台软件调试方法

  1. 用认可的收音机/对比样机先搜一次台,记录下当前位置的清晰台(人声清晰/基本没有雪花声)对应频点 不同天气、不同时间段、不同位置、实际收台效果会有差别,在调试 FM 时要有对比样机做参考,且使用整机测试;(拿笔记录下对比样机的每个电台频点,再记录下样机能收到的每个电台的频点,具体分析是那些频点没有收到)
  2. 确定FM内部AGC的值 值的设定可参考以下规则:(有放大,设最小;没放大,设最大)
    • 加放大电路:建议把AGC的值设置到最小,放大倍数由外部放大电路决定。
    • 没有放大电路:首先把AGC的值设置到最大;然后观察是否存在串台现象。若有串台现象就需要降低内部AGC的值,没有则可以使用最大值。 AC696/AC695 AGC的值(范围:-96 ~ -1)
#define FMSCAN_AGC           -55 //AGC阈值  -55左右
  1. 有条件可以用信号发生器,可以测试一下收音的灵敏度/信噪比。一般灵敏度在 15dBu 以下的,收台效果都比较好。
  2. 对比实际搜台效果。根据前面记录的清晰台频点,对比实际样机少了哪些频点并在样机商听下少掉的频点是否清晰。(例如:你发现88.8MHz这个频点的清晰台没有搜到,就把样机频点设到88.8MHz,听样机的声音。如果声音清晰――可修改搜台判断阈值。如果声音不清晰,软件就没办法了) 备注:在实际调试中,一般只需把清晰台基本搜出来既可,不用太关注不清晰台的数量。因为假台可以通过修改判断阈值进行增加或者减少。
  3. 搜台阈值修改 主要修改以下三个参数:
    • MSCAN_CNR: 台清晰该值越大,调大该值可以过滤大部分假台。
    • FMSCAN_P_DIFFER : 全部台 power 都需要大于该值。agc_noise_avg 较高时要大于 FMSCAN_P_DIFFER+1
    • FMSCAN_N_DIFFER :当台不是十分清晰时,需要 noise 差异值在这个范围之间
  • 参数说明
FMSCAN_SEEK_CNT_MIN         //一段时间内的中频波形最小过零点数

FMSCAN_SEEK_CNT_MAX         //一段时间内的中频波形最大过零点数

FMSCAN_960_CNR              //24M 晶振 96M 谐波的基础 CNR

FMSCAN_1080_CNR             //芯片内部 12M 时钟源 108M 谐波的基础 CNR

FMSCAN_AGC agc_noise_avg    //超过此值,自动降低 FM 内部增益,从最高增益开始降

FMSCAN_ADD_DIFFER agc_noise_avg //低于此值,判定会增加 FMSCAN_N_DIFFER,降低假台率

FMSCAN_CNR                  //信号在中频上的载噪比

FMSCAN_P_DIFFER             //当前频点最小 power 减 上一个频点最大 power

FMSCAN_N_DIFFER             //当前频点最小 noise 减 上一个频点最小 noise

FM_IF                       //FM 听台中频
  • 真台判定条件 ①FMSCAN_SEEK_CNT_MIN <= seek_cnt <= FMSCAN_SEEK_CNT_MAX ②非谐波频点: FMSCAN_CNR <= cnr,谐波频点: FMSCAN_CNR + FMSCAN_960_CNR <= cnr,108M 同理
    ③当 FMSCAN_ADD_DIFFER <= agc_noise_avg 时: FMSCAN_P_DIFFER + 1 <= power_differ FMSCAN_N_DIFFER 无效 当 FMSCAN_ADD_DIFFER > agc_noise_avg 时: FMSCAN_P_DIFFER <= power_differ (-)FMSCAN_N_DIFFER <= noise_differ <=(+) FMSCAN_N_DIFFER 注意:软件只能把搜索到的清晰台给筛选出来,不能把一个不清晰/串台的台变成清晰。
    以上seek_cnt,cnr,agc_noise_avg,power_differ,可以通过串口打印来进行debug,需要把库打印以及相应内置FM驱动底层模块打印打开才会出现。
    需在文件apps\soundbox\include\app_config.h中#define LIB_DEBUG 1
    以及apps\soundbox\log_config\lib_driver_config.c中const char log_tag_const_i_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);

2、内置FM 驱动API函数

void fm_inside_io_ctrl(int ctrl, ...);

void fm_inside_default_config(void);//默认配置参数
void fm_inside_mem_init(void);
void fm_inside_on(void);//内置收音初始化
void fm_inside_off(void);//关闭内置收音
u8 fm_inside_freq_set(u32 freq);//设置频点 87.5M 填 87500
void fm_inside_int_set(u8 mute);//中断开关
u16 fm_inside_id_read(void);//获取内置收音的ID
s8 fm_inside_rssi_read(void); //获取电台的功率 -96 ~ 0 dB
u8 fm_inside_st_read(void);//获取电台的声道 1:立体声;  0: 单声道;
s8 fm_inside_cnr_read(void);//获取当前频点的载噪比  dB
void fm_inside_set_stereo(u8 set);  //set[0,128], 0 mono, 128 stereo。0~128对应0~30dB分离度
void fm_inside_set_abw(u8 set);  //audio bandwidth set //set[0,127] <=>2k~16k
void fm_inside_deempasis_set(u8 set);// set[0/1], 0:50us, 1:75us
void fm_inside_agc_set(u8 lpf_gain, u8 lna_atten, u8 lna_en); //配置fm内部增益

image

3、设置默认FM收音频点方法

clear_all_fm_point();                         //清除FM保存频点
save_fm_point(REAL_FREQ(76));      //874 + 76 = 950 对应95.0Khz
save_fm_point(REAL_FREQ(146));    //874 + 146 = 1020 对应102.0  Khz

4、外置FM

RDA5807

695 demo程序:
链接:https://pan.baidu.com/s/1mJW2w22Zeil4T-WimG-Scw
提取码:8888
【金山文档】 AC7006F4_V121最新补丁_RDA5807_20230620
https://kdocs.cn/l/ci6cTVdg8VVD

FM发射:

  1. 内置FM发射 内置FM发射的产品应用方向有车充点烟器

如何开关FM发射器?

文件路径apps\common\device\fm_emitter\fm_emitter_manage.c

void fm_emitter_manage_stop(void)//关闭发射器
void fm_emitter_manage_start(void)//开启发射器

设置fm发射立体声

fmtx_stereo_onoff(1);//内置fm设置发射立体声
qn8027_write_Bit(QN8027_SYSTEM, 4, 1, 0);//外挂qn8027设置立体声

DAC和FM发射同时输出的时候,只关闭或打开FM发射输出,DAC持续输出声音

目前发布的SDK中FM发射器解码流返回长度0,导致解码流挂机,DAC和FM发射在同一数据流里面,所以DAC会没有声音。
处理方法:

  1. 开4ms定时唤醒解码流功能,路径cpu\br25\audio_dec\audio_dec.c image
  2. 对cpu\br23\audio_common\audio_fmtx.c 进行修改 参考代码如下:
    【金山文档】 AC695N_soundbox_sdk_release_3.1.0
    https://kdocs.cn/l/coOnvKU9rEEI
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "app_config.h"
#include "circular_buf.h"
#include "audio_fmtx.h"
#include "fm_emitter/fm_emitter_manage.h"

#if (TCFG_APP_FM_EMITTER_EN)

#define FMTX_DEBUG_ENABLE      1
#if FMTX_DEBUG_ENABLE
#define fmtx_debug       printf
#else
#define fmtx_debug(...)
#endif

#define FMTX_TX_BUF_LEN     (4*1024)
struct _fmtx_output {
    u32 in_sample_rate;
    u32 out_sample_rate;
    cbuffer_t cbuf;
    u8 buf[FMTX_TX_BUF_LEN];
    struct audio_src_handle *hw_src;
    struct audio_stream_entry entry;
    int sr_cal_timer;
    u32 points_total;
    u32 cnt_total;
    u8 ch : 4;
    u8 flag : 1;
    u8 need_resume : 1;
} *fmtx_output_hdl = NULL;

static u32 fmtx_srI_last = 0;
bool fm_tx_state = 0;

static int audio_stream_fmtx_data_handler(struct audio_stream_entry *entry,  struct audio_data_frame *in, struct audio_data_frame *out)
{
    if(fm_tx_state == 1) {

        if (fmtx_srI_last  != in->sample_rate) {
            fmtx_debug("in:%d ---%d\n", fmtx_srI_last, in->sample_rate);
            audio_fmtx_output_set_srI(in->sample_rate);
        }

        u32 len = audio_fmtx_output_write(in->data, in->data_len);
        if (len != in->data_len) {
            local_irq_disable();
            fmtx_output_hdl->need_resume = 1;
            local_irq_enable();
            // printf("y1");
        }
        return len;

    } else {
        //不处理

        return in->data_len;
    }
}

static void audio_stream_fmtx_data_clear(struct audio_stream_entry *entry)
{
    cbuf_clear(&(fmtx_output_hdl->cbuf));
    fmtx_debug("fmtx clear\n");
}

static void audio_fmtx_src_irq_cb(void *hdl)
{
    if (fmtx_output_hdl) {
        audio_stream_resume(&(fmtx_output_hdl->entry));
    }
}

int audio_fmtx_src_output_handler(void *parm, s16 *data, int len)
{
    int wlen = fmtx_output_hdl->cbuf.total_len - fmtx_output_hdl->cbuf.data_len;
    if (wlen > len) {
        wlen = len;
    }

    wlen = cbuf_write(&(fmtx_output_hdl->cbuf), data, wlen);
    if (wlen != len) {
        local_irq_disable();
        fmtx_output_hdl->need_resume = 1;
        local_irq_enable();
        // printf("y2");
    }
    return wlen;
}

s16 ref_temp_buf[256];
int audio_fmtx_output_write(s16 *data, u32 len)
{
    u32 wlen = 0;
    if (fmtx_output_hdl) {
        if (fmtx_output_hdl->hw_src) {

            wlen = audio_src_resample_write(fmtx_output_hdl->hw_src, data, len);

            if (bt_phone_dec_is_running()) {
                for (int i = 0; i < (len >> 2); i++) {
                    ref_temp_buf[i] = data[2 * i] / 2 + data[2 * i + 1] / 2;
                }
                if (wlen) {
                    audio_aec_refbuf(ref_temp_buf, wlen / 2);
                }
            }

        } else {
            wlen = fmtx_output_hdl->cbuf.total_len - fmtx_output_hdl->cbuf.data_len;
            if (wlen > len) {
                wlen = len;
            }
            wlen = cbuf_write(&(fmtx_output_hdl->cbuf), data, len);
        }
        if (wlen != len) {
            local_irq_disable();
            fmtx_output_hdl->need_resume = 1;
            local_irq_enable();
            // printf("y3");
        }
    }
    return wlen;
}
void audio_fmtx_tx_isr(s16 *data, u32 len)
{
    u32 wlen = 0;
    u32 rlen = 0;

    if (fmtx_output_hdl) {
        local_irq_disable();
        if (fmtx_output_hdl->need_resume) {
            fmtx_output_hdl->need_resume = 0;
            local_irq_enable();
            // printf("n1");
            audio_stream_resume(&(fmtx_output_hdl->entry));
        } else {
            local_irq_enable();
        }

        fmtx_output_hdl->points_total += len >> 2;

        rlen = cbuf_get_data_len(&(fmtx_output_hdl->cbuf));
        if ((fmtx_output_hdl->flag == 0) && (rlen < (FMTX_TX_BUF_LEN / 2))) {
            memset(data, 0x00, len);
            return;
        }
        fmtx_output_hdl->flag = 1;

        if (rlen >= len) {
            wlen = cbuf_read(&(fmtx_output_hdl->cbuf), data, len);
        } else {
            fmtx_debug("fmtx end\n");
            wlen = cbuf_read(&(fmtx_output_hdl->cbuf), data, rlen);
            memset((u8 *)data + rlen, 0x00, len - rlen);
            fmtx_output_hdl->flag = 0;
        }
    }
}

void audio_fmtx_sr_cal_timer(void *param)
{
    if (fmtx_output_hdl) {
        if (fmtx_output_hdl->cnt_total == 0) {
            fmtx_output_hdl->points_total = fmtx_output_hdl->out_sample_rate * 1000;
            fmtx_output_hdl->cnt_total = 999;
        }
        fmtx_output_hdl->cnt_total++;
        fmtx_output_hdl->out_sample_rate = fmtx_output_hdl->points_total / fmtx_output_hdl->cnt_total;

        if ((fmtx_output_hdl->points_total > 0xFFF00000) \
            && ((fmtx_output_hdl->cnt_total % 2) == 0)) {
            fmtx_output_hdl->points_total >>= 1;
            fmtx_output_hdl->cnt_total >>= 1;
        }


        if (fmtx_output_hdl->hw_src && fmtx_output_hdl->out_sample_rate) {
             fmtx_debug("fmtx cal:%d > %d\n",
             fmtx_output_hdl->in_sample_rate,
             fmtx_output_hdl->out_sample_rate); 
            audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
                                  fmtx_output_hdl->in_sample_rate, \
                                  fmtx_output_hdl->out_sample_rate);
        }
    }
}

void audio_fmtx_output_set_srI(u32 sample_rate)
{
    fmtx_debug("audio_fmtx_output_set_srI %d\n", sample_rate);
    fmtx_srI_last = sample_rate;
    if (fmtx_output_hdl) {
        fmtx_output_hdl->points_total = 0;
        fmtx_output_hdl->cnt_total = 0;
        fmtx_output_hdl->in_sample_rate = sample_rate;
        if (fmtx_output_hdl->hw_src) {
            fmtx_debug("fmtx set:%d > %d\n", \
                       fmtx_output_hdl->in_sample_rate, \
                       fmtx_output_hdl->out_sample_rate);
            audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
                                  fmtx_output_hdl->in_sample_rate, \
                                  fmtx_output_hdl->out_sample_rate);
        }
    }
}



void audio_fm_tx_start()
{
    if(fmtx_output_hdl->sr_cal_timer == NULL) {
        fmtx_output_hdl->sr_cal_timer = sys_s_hi_timer_add(NULL, audio_fmtx_sr_cal_timer, 1000);
    }

    fm_tx_state = 1;
}

void audio_fm_tx_stop()
{

    if (fmtx_output_hdl->sr_cal_timer) {
        sys_s_hi_timer_del(fmtx_output_hdl->sr_cal_timer);
        fmtx_output_hdl->points_total = 0;
        fmtx_output_hdl->cnt_total = 0;
        fmtx_output_hdl->out_sample_rate = 41667;
        fmtx_output_hdl->sr_cal_timer = NULL;
    }

    fm_tx_state = 0;
}

void *audio_fmtx_output_start(u16 fre)
{
    if (fmtx_output_hdl == NULL) {
        fmtx_debug("audio_fmtx_output_start\n");
        mem_stats();
        fmtx_output_hdl = zalloc(sizeof(struct _fmtx_output));
        if (fmtx_output_hdl == NULL) {
            fmtx_debug("audio_fmtx_output_start malloc err !\n");
            return NULL;
        }
        /* clk_set("sys", 96 * 1000000L); */
        /* clk_set_en(0); */
        cbuf_init(&(fmtx_output_hdl->cbuf), fmtx_output_hdl->buf, FMTX_TX_BUF_LEN);

        fm_emitter_manage_init(fre, audio_fmtx_tx_isr);
        fm_emitter_manage_start();

        fmtx_output_hdl->in_sample_rate = fmtx_srI_last;
        fmtx_output_hdl->out_sample_rate = 41667;

        if(fmtx_output_hdl->sr_cal_timer == NULL)
            fmtx_output_hdl->sr_cal_timer = sys_s_hi_timer_add(NULL, audio_fmtx_sr_cal_timer, 1000);

        fmtx_output_hdl->hw_src = zalloc(sizeof(struct audio_src_handle));

        if (fmtx_output_hdl->hw_src) {
            audio_hw_src_open(fmtx_output_hdl->hw_src, 2, SRC_TYPE_RESAMPLE);
            audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
                                  fmtx_output_hdl->in_sample_rate, \
                                  fmtx_output_hdl->out_sample_rate);
            fmtx_debug("audio fmtx rate:%d -> %d\n", \
                       fmtx_output_hdl->in_sample_rate, \
                       fmtx_output_hdl->out_sample_rate);
            audio_src_set_output_handler(fmtx_output_hdl->hw_src, NULL, audio_fmtx_src_output_handler);
            audio_src_set_rise_irq_handler(fmtx_output_hdl->hw_src, NULL, audio_fmtx_src_irq_cb);
        } else {
            fmtx_debug("hw_src malloc err ==============\n");
        }

        fmtx_output_hdl->entry.data_handler = audio_stream_fmtx_data_handler;
        fmtx_output_hdl->entry.data_clear = audio_stream_fmtx_data_clear;
        /* mem_stats(); */
        return (&(fmtx_output_hdl->entry));
    }
    return NULL;
}

void audio_fmtx_output_stop()
{
    fmtx_debug("audio_fmtx_output_stop\n");
    if (fmtx_output_hdl) {
        fm_emitter_manage_stop();

        if (fmtx_output_hdl->sr_cal_timer) {
            sys_s_hi_timer_del(fmtx_output_hdl->sr_cal_timer);
        }

        if (fmtx_output_hdl->hw_src) {
            audio_hw_src_stop(fmtx_output_hdl->hw_src);
            audio_hw_src_close(fmtx_output_hdl->hw_src);
            free(fmtx_output_hdl->hw_src);
            fmtx_output_hdl->hw_src = NULL;
        }

        free(fmtx_output_hdl);
        fmtx_output_hdl = NULL;
        /* clk_set_en(1); */
    }
}

#endif


FAQ:

  1. AC695/AC696系列FM收音效果差,基本调试思路: 答:
  2. FM匹配物料放FM天线端,用330nH+4.7PF; image 2、功放跑AB类模式,没有其他DC电路干扰;
    3、软件开跑RAM的宏,AGC设为-1.;
    imageimage 4、电源干净,地回路完整:VBAT、VDDIO的电容地最快最完整回到芯片地,确保地回路的完整性。错误示范及修改:
    imageimage 5、如果FM要加三极管放大电路,参考如下:
    image

2、AC700X:

AC7006F4SDK121外挂收音芯片5807参考DEMO
链接:https://pan.baidu.com/s/1P1djXnYdeZFfmbM_NRO-YQ
提取码:8888

3、696X当使用外挂FM收音芯片接收FM信号,可以选择将主控芯片进入RC模式来减少芯片内部时钟对FM信号的干扰

void enter_hrc_clock(void) 进入RC模式。
void exit_to_pll_clock(void) 退出RC模式。
代码如下

void jump_ticktmr_isr();

extern int ISR_BASE;
#define ISR_ENTRY  (u32)&ISR_BASE
___interrupt
static void SysTickHandler(void){

}
void rc_mode_tick_init(u32 en)
{
    unsigned int *israddr = (unsigned int *)ISR_ENTRY;

    JL_TIMER3->CON = BIT(14);
    israddr[IRQ_TIME3_IDX] = SysTickHandler;
    if(en){
        TICK_CON = BIT(6);
        JL_TIMER3->PRD = 3750;//10ms
        JL_TIMER3->CNT = 0;
        JL_TIMER3->CON = 0x9|(0b0011<<4);
        
        request_irq(IRQ_TIME3_IDX,1,jump_ticktmr_isr,0);
    }
}
void clk_dump()
{
    unsigned int *israddr = (unsigned int *)ISR_ENTRY;
    printf("%x %x",israddr[IRQ_TIME3_IDX],israddr[IRQ_TICK_TMR_IDX]);

    log_info("SPI DIV  : %d",         JL_SFC->BAUD);
    log_debug("SFC_CON  : %08x",       JL_SFC->CON);
    log_debug("SFC_QCNT  : %08x",      JL_SFC->QUCNT);
    log_debug("CACHE_CON  : %04x",     JL_DSP->CON);
    log_info("SYS_DIV  : %08x",       JL_CLOCK->SYS_DIV);
    log_info("CLK_CON0 : %08x",       JL_CLOCK->CLK_CON0);
    log_info("CLK_CON1 : %08x",       JL_CLOCK->CLK_CON1);
    log_info("CLK_CON2 : %08x",       JL_CLOCK->CLK_CON2);
    log_info("CLK_CON3 : %08x",       JL_CLOCK->CLK_CON3);
    log_info("PLL_CON  : %08x",       JL_CLOCK->PLL_CON);
    log_info("PLL_CON1 : %08x",       JL_CLOCK->PLL_CON1);

}

static u8 switch_hrc_flag = 0;

void enter_hrc_clock(void)
{   
    if(switch_hrc_flag == 0) {
        // SFR(JL_CLOCK->CLK_CON0,10,3,0b001);
        clk_set("sys", 24 * 1000000L);
        // clk_dump();
        local_irq_disable();

        extern void switch_to_hrc();
        switch_to_hrc();
        // JL_ANA->WLA_CON8 &= ~BIT(0);

        // SFR(JL_CLOCK->CLK_CON1,10,2,0b01);//uart btosc

        // JL_UART0->BAUD = (24000000 / 1000000) / 4 - 1;
        rc_mode_tick_init(1);
        //TICK_CNT = 0;
        //TICK_PRD = 16000000 / 100;
        //TICK_CON = BIT(0);

        // clk_dump();

        JL_TIMER1->CON = BIT(14);
        JL_TIMER1->PRD = 750;
        JL_TIMER1->CNT = 0;
        JL_TIMER1->CON = 0x9|(0b0011<<4);

        switch_hrc_flag = 1;

        local_irq_enable();
    }      
}
void exit_to_pll_clock(void){
    
    if(switch_hrc_flag == 1) {
        local_irq_disable();
        //reset
        PLL_EN(1);                                                        
        delay(1);       //>10us
        PLL_REST(1);    //复位释放(需在PLL EN使能10us后才能释放)
        delay(10 + 10); //>300us
        
        // clk_dump();
        rc_mode_tick_init(0);
        clk_set("sys", 96 * 1000000L);

        // SFR(JL_CLOCK->CLK_CON1,10,2,0b00);//uart pll48
        // JL_UART0->BAUD = (48000000 / 1000000) / 4 - 1;
         
        JL_TIMER1->CON = BIT(14);
        JL_TIMER1->PRD = 0x2ee0;
        JL_TIMER1->CNT = 0;
        JL_TIMER1->CON = 0x19;

        switch_hrc_flag = 0;

        local_irq_enable();
    }
}

还需要添加.s文件到工程中编译
tick_time.S
image 【金山文档】 tick_time
https://kdocs.cn/l/cgRQ4Hmk4Tuc
提示goto __tick_irq_handler,无法找到源文件目前有V1.1.1版本的修改方法:
system_V1.1.1.rar

4、AC706系列FM收音效果差,基本调试思路:

答:

  1. FM匹配物料放FM天线端,用公版原理图上推荐的匹配参数;
  2. 功放跑AB类模式,没有其他DC电路干扰;
  3. 电源干净,地回路完整:VBAT、VDDIO的电容地最快最完整回到芯片地,确保地回路的完整性。

5、FM模式切换时钟源避开晶振倍频导致的96M干扰(有反馈问题再打)

AC695系列跑LRC时钟补丁说明_20231028175931.rar
701代码SDK修改待补充

本文档包含以下子页面

Prev
PC相关应用
Next
AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20250107