CC2541的射频系统高度依赖于晶振频率。晶振频率的波动将直接影响射频频率,这关系到系统收发灵敏度,甚至 在一些最坏的情况下,系统可能根本无法工作。根据BLE蓝牙协议规范这一频率偏差不应超过40ppm(百万分之40).除了选择满足这一要求的晶振外, 晶振负载电容(下图C1和C2)也很重要。
晶振需要在准确的负载电容下才能按其标称的频率工作,但实际电路的寄生参数和器件固有的精度限制。为获得准确的振荡频率, 需要对电路调谐。外接负载电容比较难调,只能起粗调作用。好在CC2541内置了一对可调电容,它并在外接电容C1和C2上,通过向FREQTUNE寄存器写入合适的值来改变此电容,进而达到调谐作用。
测量射频频率通常需要昂贵的专业设备,业余条件下很难做到。但要测量晶振时钟是否准确,相对容易得多。我们让待测模块运行 一小段代码,产生一个标称值为100Khz的方波信号。PC上位机运行串口工具,向被测模块发送设置FREQTUNE寄存器的指令。用频率计或示波器就可以测出100Khz 信号的实际值,也就间接测出了晶振频率(系统时钟)。
模块上运行的测试代码如下,也可以直接获取烧录镜像。串口工具以9600波特率,发送一个字节要写入FREQTUNE的数据即可。
#include <string.h> #include "hal_uart.h" #include "hal_types.h" #define TnCTL_DIV_1 (0<<5) #define TnCTL_DIV_2 (1<<5) #define TnCTL_DIV_4 (2<<5) #define TnCTL_DIV_8 (3<<5) #define TnCTL_DIV_16 (4<<5) #define TnCTL_DIV_32 (5<<5) #define TnCTL_DIV_64 (6<<5) #define TnCTL_DIV_128 (7<<5) #define TnCTL_STAR (1<<4) #define TnCTL_CLEAR (1<<3) #define TnCTL_MODE_FREE (0) #define TnCTL_MODE_DWON (1) #define TnCTL_MODE_MODULO (2) #define TnCTL_MODE_UPDWON (3) #define TnCCTL0_INT_ENB (1 << 6) //中断使能 #define TnCCTL0_CMP_SET (0 << 3) #define TnCCTL0_CMP_CLEAR (1 << 3) #define TnCCTL0_CMP_TOGGLE (2 << 3) //more... #define TnCCTL0_MODE_COMPARE (1 << 2) #define TnCCTL0_CAP_NO (0) #define TnCCTL0_CAP_RISING (1) #define TnCCTL0_CAP_FALLING (2) #define TnCCTL0_CAP_BOTH (3) #define FREQTUNE XREG( 0x6185 ) static void UartCB(uint8 port, uint8 event) { uint16 nLen; uint8 ucRxBuff[1]; nLen = HalUARTRead(port, ucRxBuff, sizeof(ucRxBuff)); if (nLen) { FREQTUNE = ucRxBuff[0]; } (void)event; } void main(void) { halUARTCfg_t tUartCfg; HAL_BOARD_INIT(); //系统时钟设置 P1SEL |= (1 << 3); T3CTL = TnCTL_DIV_1 | TnCTL_STAR | TnCTL_MODE_MODULO; T3CCTL0 = TnCCTL0_CMP_TOGGLE | TnCCTL0_MODE_COMPARE; T3CC0 = 159; //100Khz P1DIR |= (1 << 2); HalUARTInit(); memset(&tUartCfg, 0, sizeof(tUartCfg)); tUartCfg.baudRate = HAL_UART_BR_9600; tUartCfg.callBackFunc = UartCB; HalUARTOpen(HAL_UART_PORT_1, &tUartCfg); HAL_ENABLE_INTERRUPTS(); while(1) HalUARTPoll(); }
下表为网购的某一型号模块实际测量结果。可以看出,其频率牵引范围很窄,不到10ppm,在整个范围内模块频偏都没有超出协议规定容差(40ppm)。这个牵引范围同PCB设计、晶振选择有很大关系。 这个模块的牵引范围很窄,设置FREQTUNE起不到太大作用,调谐只能靠改变外接负载电容来实现,调整起来比较麻烦。但也有个好处,那就是我们拿它来烧自己的代码,可以不用考虑FREQTUNE取值。
FREQTUNE | 频率(Khz) | 偏差(ppm) |
0x0F | 100.007 | 7 |
0x0E | 100.006 | 6 |
0x0D | 100.005 | 5 |
0x0C | 100.004 | 4 |
0x0B | 100.004 | 4 |
0x0A | 100.003 | 3 |
0x09 | 100.002 | 2 |
0x08 | 100.002 | 2 |
0x07 | 100.001 | 1 |
0x06 | 100.001 | 1 |
0x05 | 100.000 | 0 |
0x04 | 100.000 | 0 |
0x03 | 100.000 | 0 |
0x02 | 99.9998 | -0.2 |
0x01 | 99.9995 | -0.5 |
0x00 | 99.9992 | -0.8 |