导语:此主题为ULM300系列项目开发中遇到的一些问题以及它们的解决方式。
一,IA2E芯片无法直接输出RSSI信号强度信息
- IA2E芯片是一款2.4G频段的无线音频芯片,属于10年前的产品,芯片原厂的技术支持较弱,芯片文档简单;
- 该芯片推荐电路方案中,开发的源代码是汇编由供应商提供,外围电路指示信号强度的4个灯,若要用该芯片直接接灯并修改底层程序来实现指示信号强度的功能则困难较大;
- 公司前期产品USB300里通过加第三方MCU接收IA2E的音频数据流实现了USB可插拔播放音乐的功能和一些其它的IA2E无法实现的功能,由此若IA2E芯片能够在工作时把其RSSI数据传输给第三方MCU、由MCU控制指示灯来显示产品工作时的信号强度则可达到所开发产品的功能设计目的。
解决思路
在上一代产品USB300中发现,若发送端(TX)改变了音量大小,则TX会发送一个代表音量大小的值(比如0xd7)到接收端(RX),这个值只会在音量大小有改变的时候发送一次。
-
人为模拟RSSI信号发送过程
人为假定一个信号发送周期T(实际测试周期T=1080ms)、TX端在这个周期T内重复发送音量大小值(比如0xd7)、据统计大概发送了Ntx=168个、每个间隔6.4ms左右,然后在RX端统计接收到的该音量值的个数(比如Nrx=80个),那么误码率BER=Ntx/Nrx=50%,根据不同的BER值来显示满格、两格或者一格信号强度,具体代码如下。
#define BER_FULL_VALUE 168//在一个周期里总共可以接收168个数据
#define BER_COUNT_CYCLE 108 /*set the PER count cycle 1080ms*/
void RSSI_Process(uint8_t PER_CODE){
if((PER_CODE==0xee)||(PER_CODE==0xf1)||(PER_CODE==0xf4)||(PER_CODE==0x0f7)\
||(PER_CODE==0xfa)||(PER_CODE==0xfd)||(PER_CODE==0x00)){
ANT_RSSI.ber_count++;
if(ANT_RSSI.ber_count_time>=BER_COUNT_CYCLE){/*set the BER count cycle 1080ms*/
ANT_RSSI.ber_count_time=0;
ANT_RSSI.BER=((ANT_RSSI.ber_count*100)/BER_FULL_VALUE);
if(ANT_RSSI.BER>=80){
Led.RSSI=RSSI_Good;
}
if((ANT_RSSI.BER>=70)&&(ANT_RSSI.BER<80)){
Led.RSSI=RSSI_soso;
}
if((ANT_RSSI.BER>=60)&&(ANT_RSSI.BER<70)){
Led.RSSI=RSSI_low;
}
if(ANT_RSSI.BER<60){
Led.RSSI=RSSI_bad;
ANT_RSSI.count++;
if(ANT_RSSI.count==4){//连续5S信号差就切换天线
ANT_RSSI.count=0;
ANT_Switch(); /*switch the ant*/
}
}
ANT_RSSI.ber_count=0;
}
}
}
-
数据包传输给MCU
IA2E接收到音量值数据包package后通过I2C传输给MCU,MCU获得package后处理数据来控制四个LED灯指示信号强度。共5种信号强度等级:good(亮4个绿灯)、soso(亮3个绿灯)、low(亮2个绿灯)、bad(亮1个绿灯)、none(亮1个红灯)相关效果如下图。
二、更改后的软件无MUTE功能
发送端TX长按Down键达3秒以上,接收端RX(只有RX端有第三方MCU)收到后不播放声音来实现MUTE功能。
解决过程
此为纯软件BUG,经过调试软件发现产生此问题的两个原因。
1、IA2E芯片的运行程序存储背景
IA2E芯片的代码是BIN文件(BACHRX_inno_per_vol.bin),由供应商提供;此BIN文件数据作为一个数组
const uint8_t IA2E_ROM[/*6144*/]
合成在MCU程序中。编译MCU软件后,数组
const uint8_t IA2E_ROM[/*6144*/]
成为MCU软件的一部分放置于FLASH中,具体在哪个位置由编译器决定,但可以肯定的是数组const uint8_t IA2E_ROM[/*6144*/]
名代表IA2E软件存储的首地址。RX端MCU发送bin文件给IA2E具体代码如下。
uint8_t EEPROM_TxByte() {
uint8_t tx;
if( byte_addr >= sizeof( IA2E_ROM ) ) {
IA2E_Boot_Complete = SET;
}
if( byte_addr == IA2E_LATENCY_ADDR ) {
byte_addr++;
tx = IA2E_LATENCY_VAL;
} else if( ( byte_addr >= IA2E_ID_ADDR ) &&
( byte_addr < ( IA2E_ID_ADDR + IA2E_ID_SIZE ) ) ) {//三个字节存放MCU的ID号
tx = UID >> ( ( byte_addr++ - IA2E_ID_ADDR ) << 3 );//写固定的MCU的ID号,只写6位
} else {
tx = *( IA2E_ROM + byte_addr++ );
}
return tx;
}
2、无MUTE功能产生的原因
- 修改后的代码如下
void EEPROM_RxByte( uint8_t rx ) {
switch( byte_cnt++ ) {
case 0:
( ( uint8_t *)&byte_addr )[1] = rx; // store MSB
break;
case 1:
( ( uint8_t *)&byte_addr )[0] = rx; // store LSB
break;
default:
// IA2E_ROM[ ( byte_addr++ - 2 ) & 0x1FFF ] = rx;
switch( byte_addr++ ) {
// case SYNIC_EEPROM_PER_ADDR:
// RSSI_Process( rx );
// break;
case SYNIC_EEPROM_STATUS_ADDR:
// SYNIC_STATUS=rx;
SYNIC_SetStatus( rx );
break;
case SYNIC_EEPROM_VOLUME_ADDR:
if(rx==0x06)//衣领夹麦克峰固定发射06值过来表示最大值
rx=0x00;//00表示音量最大值
if(SYNIC_Volume_Mute==0)
{
SYNIC_SetVolume( rx );
}
RSSI_Process( rx );
break;
}
break;
}
}
-
函数
Stream_SetLevel( volume )
实现音量大小的改变,程序case SYNIC_EEPROM_STATUS_ADDR:
和程序case SYNIC_EEPROM_VOLUME_ADDR:
都会调用Stream_SetLevel( volume )
函数; - RX端中IA2E芯片音量状态值放置在地址
#define SYNIC_EEPROM_STATUS_ADDR 0x17DD
上,音量值放置在地址#define SYNIC_EEPROM_VOLUME_ADDR 0x17F0
上,MUTE属于音量状态数据; - 无论status值还是volume值,只有有按键变化TX端才会发送值到RX端且一次只可能发送其中的一种,如此在按了MUTE键后,RX端只会执行
case SYNIC_EEPROM_STATUS_ADDR:
中的程序实现MUTE功能; - 若后续TX端无按键变化,则RX端的IA2E芯片不会通过I2C发送音量值到RX中的MCU中,这样MCU也就不会执行
switch( byte_addr++ )
里面的程序,如此RX端音量状态和音量大小将保持前一状态; - 由于要模拟RSSI功能,产生了以下现象:
- TX端会不断的发送volume值(假设volume=0xD7)到RX,意味着无论TX端有无按键变化都会隔一小段时间(6.4ms)发送volume值给RX,RX端会周期性的执行
case SYNIC_EEPROM_VOLUME_ADDR:
程序实现声音;- 假设某一时刻t=6.4ms内,有一个MUTE值过来(假设此时volume=0xD7,声音正常大小),这时RX端执行
case SYNIC_EEPROM_STATUS_ADDR:
程序实现了MUTE功能,在过t=6.4ms后,TX又发送volume=0xD7数据到RX,之后RX端执行程序case SYNIC_EEPROM_VOLUME_ADDR:
实现声音正常大小,这样MUTE的效果就听不出来了。
3、解决的方法
在
case SYNIC_EEPROM_VOLUME_ADDR:
程序内执行函数SYNIC_SetVolume( rx )
前添加条件if(SYNIC_Volume_Mute==0)
,表示只有在无MUTE情况下,才会执行SYNIC_SetVolume( rx )
函数,这样在MUTE状态不解除的情况下即使有volume值发送到RX端也不会影响MUTE功能。